.TITLE LP -- LINE PRINTER DRIVER .IDENT -000100- .LIST MEB ;+ ; LINE PRINTER DRIVER FOR RSX-11D ; ; AUTHOR: BRUCE WRIGHT ; CLINICAL EPIDEMIOLOGY LABORATORY ; DUKE UNIVERSITY MEDICAL CENTER ; DURHAM, N. C. 27706 ; ; DATE: 27-AUG-77 ; ; MODIFIED: 30-JAN-78, -000100-, BRUCE C. WRIGHT ; ; FIXED BUG IN INTERNAL CARRIAGE CONTROL HANDLING ; ADDED CHECK IN DL-11 BUFFER FULL CODE FOR AN ERROR ; OCCURRING AFTER BUFFER BECAME FULL. ; ; THIS PROGRAM OPERATES AS A NORMAL DEVICE DRIVER UNDER ; RSX-11D. IT DRIVES A LINE PRINTER INTERFACED TO THE PDP-11 BY A ; PARALLEL INTERFACE OR A SERIAL INTERFACE. ; ; TO USE THE DRIVER, THE QIO WRITE LOGICAL BLOCK OR ; WRITE VIRTUAL BLOCK FUNCTIONS ARE USED. ; ; IO.KIL KILL ALL CURRENT I/O REQUESTS ; IO.ATT ATTACH A PRINTER TO A TASK ; IO.DET DETACH A PRINTER FROM A TASK. ; IO.WVB WRITE A BUFFER TO A PRINTER. ; IO.WLB WRITE A BUFFER TO A PRINTER. ; ; TO TASK BUILD A PROGRAM USING THE DRIVER, INCLUDE A LINE ; ; TKB>ASG=LPNN:LUN ; ---- ; ; IN THE OPTIONS PART OF THE COMMAND FILE, WHERE LUN IS THE LOGICAL ; UNIT USED IN PROGRAM TO REFERENCE THE PRINTER. ; ;********************** SYSGEN CONSIDERATIONS *********************** ; ; TO GENERATE THE DRIVER, IT IS FIRST NECESSARY TO SYSGEN AN ; RSX-11D SYSTEM WITH THE APPROPRIATE INTERRUPT VECTORS AND ; EXTERNAL PAGE ADDRESSES DECLARED TO SYSGEN PHASE 1. ; THE LEGAL DEVICE CHARACTERISTICS ARE: ; ; 000001 U2.LRC PRINTER HAS LOWER CASE ; 000002 U2.S11 PRINTER IS AN LS-11 ; 000004 U2.DLI PRINTER IS ON A DL-11 INTERFACE ; ; FOR EXAMPLE: ; ; DEV=LP0,<0,0,0,0>,VEC,PRI,EPA ; ; WHERE: ; ; VEC INTERRUPT VECTOR ADDRESS ; PRI INTERRUPT PRIORITY ; EPA EXTERNAL PAGE ADDRESS ; ; ONE OF THESE LINES WILL BE NECESSARY FOR EACH PRINTER. ; ; NEXT IT IS NECESSARY TO ASSEMBLE THE DRIVER. EDIT THE ; SOURCE AND CHANGE THE VARIABLE "NO.LPT" TO THE NUMBER OF ; PRINTERS TO BE HANDLED, AND MAKE ANY OTHER CHANGES ; NECESSARY IN THE ASSEMBLY PARAMETERS. ASSEMBLE THE DRIVER: ; ; MAC>LP,LP/-SP/LI:TTM=LP ; ---- ; ; NOW TASK BUILD IT AS A NORMAL DEVICE DRIVER, ; USING A TKB FILE LIKE THIS: ; ; TKB>LP/PR/-CP/-AB/-FX/-FP/-TA,LP/-SP=LP,[1,1]EXEC.STB/SS ; ---- ; TKB>/ ; ---- ; ENTER OPTIONS ; ------------- ; TKB>TASK=LP.... ; ---- ; TKB>STACK=32 ; ---- ; TKB>UIC=[1,1] ; ---- ; TKB>PRI=248 ; ---- ; TKB>// ; ---- ; ; INSTALL THE DRIVER, AND LOAD IT. SAVE THE SYSTEM IF ; DESIRED. ; ;********************** DRIVER LOGIC *********************** ; ; THE DRIVER CAN SERVICE NO MORE THAN 16 PRINTERS SINCE ; AN RSX INTERRUPT CAN SERVICE NO MORE THAN 16 DEVICES. ; ; THE DRIVER HAS ALMOST NO TABLES, USING FREE SPACE IN ; THE SYSTEM NODE POOL. THE CURRENT STATE OF ALL OF THE LINES IS ; KEPT IN WORD U.C3 OF THE PUD FOR THAT PHYSICAL LINE. THE BIT ; DEFINITIONS ARE UNDER "HANDLER STATE EQUATES" FOR THE CURIOUS. ; THE DRIVER ALSO USES THE WORK AREA IN THE I/O REQUEST NODE ; TO KEEP TRACK OF SOME OF THE TEMPORARY RESULTS FOR THAT REQUEST. ; THE USAGES ARE: ; ; R.WA+1 1 BYTE OFFSET FROM THE PAGE REGISTER INTO THE ; USER'S BUFFER. ; R.WA+2 2 BYTES USER BYTE COUNT ; R.WA+4 2 BYTES PAGE DISCRIPTOR REGISTER FOR MAPPING ; INTO THE USER'S TASK ; R.WA+6 2 BYTES PAGE ADDRESS REGISTER FOR MAPPING ; INTO THE USER'S TASK ; ;**************************************************************** ; ; DL-11 INTERFACES ; ; THE DRIVER SUPPORTS DL-11 INTERFACES AS AN OPTION. THE ; "CARRIER DETECT" BIT IS ASSUMED TO BE SET TO 1 IF THE PRINTER ; BUFFER CAN RECEIVE AND A 0 IF THE BUFFER IS FULL. THE ; "CLEAR TO SEND" BIT IS ASSUMED TO BE SET TO A 0 IF THE ; PRINTER HAS NO ERRORS CURRENTLY, AND A 1 IF THE PRINTER ; IS OFF LINE. THIS OPERATION IS THAT USED BY THE PRINTRONIX ; BRAND PRINTERS WHEN INTERFACED TO A SERIAL PORT. ;- .SBTTL ASSEMBLY PARAMETERS ; ; THE MAXIMUM UNIT NUMBER TO BE SERVICED, PLUS 1. ; NO.LPT = 1 ; ; THE NUMBER OF DEVICES ACTUALLY SERVICED. ; NO.DEV = 1 ; ; THE MAXIMUM BUFFER SIZE TO ALLOCATE PER PRINTER. ; THIS PARAMETER SHOULD BE COMPUTED AS FOLLOWS: ; ; ALLOW THE MAXIMUM BUFFER SIZE TO BE SUPPORTED ; IN THE PUD. ADD 3 BYTES TO THIS TO ALLOW ; CARRIAGE CONTROL INFORMATION TO BE PLACED ; IN THE INTERNAL BUFFER. ROUND UP TO THE NEXT ; EVEN NUMBER TO OBTAIN THE BUFFER SIZE GIVEN ; BELOW. ; LPBFSZ = 132.+3.+1. ;BUFFER SIZE. ; ; DEFINE THE FOLLOWING SYMBOL TO OBTAIN SUPPORT FOR ; LS-11 DEVICES AS DOCUMENTED IN THE DEVICE HANDLER'S ; REFERENCE MANUAL. I CANNOT UNDERSTAND WHY THIS ; DIFFERENT TREATMENT IS INTERESTING, AND BESIDES THE ; SUPPORT REQUIRES MORE SPACE, SO THE DEFAULT IS NO ; UNIQUE LS-11 SUPPORT. ; ;LS11 = 1 ;HANDLER IS TO SUPPORT LS-11 ; ; DEFINE THE FOLLOWING SYMBOL TO HAVE THE STANDARD ; ACTION ON CARRIAGE CONTROL AS DEFINED IN THE DEVICE ; HANDLERS REFERENCE MANUAL. THIS STRIKES ME AS STRANGE, ; SINCE A '+' CONTROL CHARACTER IS NOT DEFINED AS ; CAUSING A TRAILING CARRIAGE RETURN. LEAVING OUT THIS ; DEFINITION WILL CAUSE IT TO REQUEST A CARRIAGE RETURN. ; NOTE: THIS WILL NORMALLY NOT BE OF INTEREST; HOWEVER ; SOME PRINTERS WILL NOT DUMP THE BUFFER UNTIL A ; , , OR IS SEEN. THIS COULD CAUSE ; LOSS OF OUTPUT IF THE '+' LINE IS THE LAST IN ; THE FILE. ; ;STNDCR = 1 ;STANDARD CARRIAGE CONTROL ; ; DEFINE THE FOLLOWING SYMBOL IF THE DRIVER IS TO SUPPORT ; DL-11 INTERFACES ON THE PRINTERS. ; ;DL11IF = 1 ; ; DEFINE THE FOLLOWING SYMBOL IF THE DRIVER IS TO ; SUPPORT LP-11 TYPE INTERFACES ON THE PRINTERS. ; LP11IF = 1 .SBTTL MACRO CALLS USED ; .MCALL DIR$,EXIT$S,SPRA$,WTLO$,ASTX$S,MRKT$,CMKT$,QIO$ .MCALL CALL,RETURN ; ; .MACRO .INHIB MOV @#PS.EXP,-(SP) BIS #340,@#PS.EXP .ENDM ; .MACRO .ENABL MOV (SP)+,@#PS.EXP .ENDM ; .MACRO CLRLPT CALL CLRLP$ .ENDM ; .MACRO ENALPT CALL ENALP$ .ENDM ; .MACRO WRILPT CALL WRILP$ .ENDM ; .SBTTL PRINTER ADDRESS OFFSETS AND BIT SETTINGS. .SBTTL PARALLEL PRINTER EQUATES ; .IF DF LP11IF LP.STA = 0 ;PRINTER CONTROL REGISTER. LP.BUF = 2 ;PRINTER BUFFER REGISTER. ; LS.IEA = 000100 ;INTERRUPT ENABLE LS.RDY = 000200 ;PRINTER READY. LS.ERR = 100000 ;ERROR .ENDC ; .SBTTL SERIAL PRINTER EQUATES ; .IF DF DL11IF DL.RCR = 0 ;RECEIVER STATUS REGISTER DL.RBF = 2 ;RECEIVER BUFFER REGISTER DL.XCR = 4 ;TRANSMITTER STATUS REGISTER DL.XBF = 6 ;TRANSMITTER BUFFER REGISTER ; DR.DSC = 100000 ;DATASET STATUS CHANGE DR.RDT = 040000 ;RING DETECT DR.CTS = 020000 ;CLEAR TO SEND DR.CDT = 010000 ;CARRIER DETECT DR.RAC = 004000 ;RECEIVER ACTIVE DR.SRD = 002000 ;SECONDARY RECEIVED DATA DR.RDN = 000200 ;RECEIVER DONE DR.RIE = 000100 ;RECEIVER INTERRUPT ENABLE DR.DIE = 000040 ;DATASET INTERRUPT ENABLE DR.STD = 000010 ;SECONDARY TRANSMITTED DATA DR.RTS = 000004 ;REQUEST TO SEND DR.DTR = 000002 ;DATA TERMINAL READY DR.REN = 000001 ;READER ENABLE ; DX.RDY = 000200 ;TRANSMITTER READY DX.TIE = 000100 ;TRANSMITTER INTERRUPT ENABLE DX.MNT = 000004 ;MAINTENANCE MODE DX.BRK = 000001 ;BREAK REQUEST .ENDC ; .SBTTL EVENT FLAGS ; DV.DNE = 000004 ;I/O DONE DV.MKT = 000010 ;MARK TIME EN.DNE = 3 ;I/O DONE EFN NUMBER EN.MKT = 4 ;MARK TIME EFN NUMBER EN.QIO = 5 ;QI/O TO CONSOLE EFN NUMBER ; .SBTTL BIT DEFINITIONS FOR U.C2 ; U2.LRC = 000001 ;PRINTER HAS LOWER CASE U2.S11 = 000002 ;PRINTER IS AN LS-11 U2.DLI = 000004 ;INTERFACE IS A DL-11 ; .SBTTL HANDLER STATE EQUATES ; HS.CON = 000001 ;DEVICE IS CONNECTED. HS.ISD = 000002 ;INTERRUPT SERVICE ROUTINE IS ACTIVE HS.ABT = 000004 ;LINE IS IN PROCESS OF BEING ABORTED HS.WRI = 000010 ;LINE CURRENTLY HAS A WRITE ACTIVE HS.ERR = 000020 ;LINE CURRENTLY HAS AN ERROR HS.MSG = 000040 ;LINE HAS HAD ERROR MESSAGE SENT HS.LER = 000100 ;LINE JUST PRINTED WAS TOO LONG. HS.BUF = 000200 ;DL-11 LINE BUFFER FULL. ; .SBTTL CHARACTER EQUATES ; BEL = 7 ; TAB = 11 ; LF = 12 ; FF = 14 ; CR = 15 ; RUBOUT = 177 ; ; .SBTTL MISCELLANEOUS EQUATES. ; LUNCON = 1 ;LUN FOR THE CONSOLE. MAXFNC = /4 ;MAXIMUM ALLOWABLE FUNCTION CODE VALUE. APR3OF = 60000 ;OFFSET FOR APR3 MAPPING. .SBTTL INITIALIZATION CODE. ; ; COME HERE TO INITIALIZE THE DRIVER. ; ; DECLARE THE HANDLER AS RESIDENT. ; LPBUFA: LPINIT: MOV .CRTSK,CRTSK ;GET .CRTSK FOR ISR MOV #LPUIT,R0 ;UNIT INFORMATION TABLE ADDRESS. MOV #"LP,R2 ;DEVICE NAME MOV #UF.RH,R3 ;SET HANDLER RESIDENT CODE. CALL ..DSUT ;DECLARE US AS RESIDENT. BCC 10$ ;EXIT IF FAILURE. JMP LPEXT0 ; ; CONNECT TO ALL PRINTERS ; 10$: .IF NE NO.LPT-NO.DEV MOV #LPBUFA,LPBUFA .ENDC MOV #-2,R4 ;INIT PRINTER COUNT. INITNX: TST (R4)+ ;INCREMENT POINTER. CMP #,R4 ;OVER TOP? BEQ ENDINI ;END INITIALIZATION IF SO. MOV @UITPTR(R4),R0 ;R0 -> PUD ENTRY FOR THIS DEVICE. BEQ INITNX ;NO PUD ADDR, LEAVE. CLR U.C3(R0) ;CLEAR ANY GARBAGE FROM STATE VARS. .IF NE NO.LPT-NO.DEV CMP LPBUFA,#LPPOLL ;OVER TOP OF BUFFER AREA? BHIS INITNX ;YES -- INIT NEXT PRINTER. .ENDC CLRLPT ;CLEAR LINE PRINTER STATUS. MOV R4,R3 ;GET UNIT NUMBER. ROR R3 ;CONVERT TO 0-15 BISB U.IP(R0),R3 ;GET INTERRUPT PRIORITY. MOV #HI.ISR,R1 ;INTERRUPT SERVICE ROUTINE. CLR R2 ;ISR RELOCATION WRT THIS MODULE. MOV R0,R5 ;SAVE PUD ADDR MOV U.TV(R0),R0 ;GET TRAP VECTOR ADDRESS. .IF DF DL11IF .IF DF LP11IF BIT #U2.DLI,U.C2(R5) ;IS THIS A DL-11? BEQ 10$ ;NO .ENDC CMP (R0)+,(R0)+ ;BUMP TRANSFER VECTOR POINTER. .ENDC 10$: CALL ..CINT ;CONNECT TO THIS INTERRUPT. BCS INITNX ;LEAVE IF ERROR. BIS #HS.CON,U.C3(R5) ;SET ONLINE. .IF NE NO.LPT-NO.DEV MOV LPBUFA,BUFIPT(R4) ;SET INITIAL BUFFER POINTER. ADD #LPBFSZ,LPBUFA ;GET TO NEXT BUFFER. .ENDC BR INITNX ;INIT NEXT UNIT. ; ; ALL UNITS CONNECTED. SET UP POWER FAILURE EXIT. ; ENDINI: DIR$ #$SPRA ;SETUP FOR POWER FAIL. BCC 10$ ;EXIT ON FAILURE. JMP LPEXT2 ; 10$: JMP LPPOLL ;AND START POLLING. ; ; USE INITIALISATION AREA FOR BUFFERS. ; .IF GT +LPBUFA-. .BLKB +LPBUFA-. .ENDC .SBTTL MAIN POLLING LOOP. ; ; MAIN POLLING LOOP. ; LPPOLL: MOV .CRTSK,R4 ;GET ATL POINTER FROM .SCOM. MOV #LPUIT,R0 ;GET UIT TABLE ADDRESS FOR SYSTEM. MOV A.EF(R4),R3 ;GET EVENT FLAGS 1-16 BIT #DV.DNE,R3 ;IO COMPLETION? BEQ 10$ ;YES, HANDLE IT JMP IODONE 10$: BIT #EF.XIR,R3 ;EXPRESS REQUEST? BNE IOEXP ;DO EXPRESS REQUEST IF SO BIT #DV.MKT,R3 ;MARK TIME OVER? BNE STATUS ;YES -- STATUS TEST IS READY MOV #..DQRN,R5 ;GET ADDRESS OF ROUTINE TO CALL. BIT #EF.NIR,R3 ;'NORMAL' REQUEST? BNE IONORM ;YES, PROCESS. DIR$ #$WAIT4 ;WAIT FOR FLAGS. BR LPPOLL ;FIND OUT WHAT HAPPENED. .SBTTL PRELIMINARY REQUEST PROCESSING ; ; THESE ROUTINES DEQUE REQUESTS FROM THE DEVICE QUEUES. ; IF A REQUEST CANNOT BE DEQUED (IE ANOTHER REQUEST IS IN PROGRESS) ; THE ROUTINE RETURNS TO POLLING. OTHERWISE, IODISP IS ENTERED ; TO VALIDATE USER ACCESS RIGHTS AND INSURE THAT THE FUNCTION ; CODE IS WITHIN THE RANGE OF THE DISPATCH TABLE. ..DISP IS THEN ; CALLED TO TRANSFRE CONTROL TO THE APPROPRIATE CALLING CODE. ; ; ENTER WITH THE UIT ADDRESS IN R0. ; IOEXP: MOV #..DQRE,R5 ;TRY TO DEQUE AN EXPRESS REQUEST. IONORM: CALL (R5) ;CALL APPROPRIATE ROUTINE. BCS LPPOLL ;SKIP IF NONE. ; ; MAIN DISPATCHING ROUTINE. ; ; ENTER WITH: ; ; R0 UIT ADDRESS ; R1 RNA ADDRESS ; R2 ADDRESS OF PUD POINTER. ; MOV (R2),R5 ;GET ADDRESS OF PUD. BIT #HS.CON,U.C3(R5) ;CONNECTED? BEQ 5$ ;NO -- PRIVILEGE VIOLATION. CALL ..VACC ;CHECK FOR PROTECTION. BCC 10$ 5$: JMP ILLPRI ;CAN'T DO OPERATION. 10$: CMPB R.FC+1(R1),#MAXFNC ;VALID FUNCTION CODE? BLO 20$ JMP ILLFNC ;DO ILLEGAL FUNCTION CODE PROCESSING. 20$: JMP ..DISP ;DISPATCH THE REQUEST. .SBTTL MARK TIME IS DONE. SEE IF STATUS HAS CHANGED. ; ; ROUTINE TO CHECK STATUS OF DEVICES. THE EVENT FLAG ; DV.MKT IS SET WHEN AN ERROR OCCURRS; THE ROUTINE ; RESCHEDULES ITSELF UNTIL ALL ERRORS GO AWAY. ; ; ENTER WITH: ; ; R4 ATL NODE OF DRIVER. ; STATUS: DIR$ #$CMKT ;CANCEL ANY MARK TIMES. BIC #DV.MKT,A.EF(R4) ;CLEAR THE EVENT FLAG CLR R3 ;CLEAR MARK TIME INDICATOR. MOV #-2,R4 ;POINT TO -1 DEVICE. STATLP: TST (R4)+ ;POINT TO NEXT DEVICE. CMP R4,#<2*NO.LPT> ;OVER TOP? BEQ STATEL ;YES MOV @UITPTR(R4),R0 ;GET A(PUD) BEQ STATLP ;LEAVE IF NONE. BIT #HS.ERR!HS.BUF,U.C3(R0) ;ERROR ON THIS LINE? BEQ STATLP ;NO .IF DF DL11IF BIT #HS.ERR,U.C3(R0) ;IS IT REALLY AN ERROR? BEQ MARKT ;NO -- JUST BUFFER FULL .ENDC BIT #HS.MSG,U.C3(R0) ;MESSAGE SENT? BNE MARKT ;YES TST MSGINP ;MESSAGE STILL IN PROGRESS ON ANOTHER LINE? BNE MARKT ;YES MOVB U.UN(R0),R2 ;GET THE UNIT NUMBER. MOV R2,R1 ;SAVE NUMBER ASH #-3,R2 ;SHIFT TO RIGHT POSITION BIC #70,R1 ;ELIMINATE GARBAGE PORTION SWAB R1 ;MOVE LOW ORDER TO PROPER BYTE. BIS R1,R2 ;GET BOTH DIGITS. BIS #"00,R2 ;MAKE INTO CHARACTER FORM. MOV R2,DEVNUM ;AND PUT INTO BUFFER. INC MSGINP ;SIGNAL MESSAGE IN PROGRESS. DIR$ #$QIO ;PRINT THE ERROR MESSAGE. BIS #HS.MSG,U.C3(R0) ;NOTE THAT WE SENT THE MESSAGE. MARKT: MOV U.DA(R0),R2 ;GET EPA ADDR .IF DF LP11IF&DL11IF BIT #U2.DLI,U.C2(R0) ;IS IT A DL-11? BNE 1$ ;YES .ENDC .IF DF LP11IF BIT #LS.ERR!LS.RDY,LP.STA(R2) ;ERROR PERSISTS? BMI 100$ ;YES -- DO NOTHING. BEQ 100$ ;NOT READY YET. .ENDC .IF DF DL11IF .IF DF LP11IF BR 2$ .ENDC 1$: BIT #DR.CTS,DL.RCR(R2) ;IS THERE CLEAR TO SEND? BNE 90$ ;YES -- WAIT A WHILE (ERROR). BIT #DR.CDT,DL.RCR(R2) ;IS THE BUFFER FULL? BEQ 100$ ;YES -- WAIT A WHILE .ENDC 2$: BIC #HS.MSG!HS.ERR!HS.BUF,U.C3(R0) ; ; THIS RECOVERY MECHANISM SIMPLY CONTINUES PRINTING WHERE ; IT LEFT OFF. THIS IS NOT THE BEST POSSIBLE MECHANISM, BUT ; WORKS BETTER THAN THE DEC HANDLER, WHICH ATTEMPTS TO OVERPRINT ; THE LINE WITH THE CORRECT LINE. UNFORTUNATELY, THAT HANDLER ; LOSES TRACK OF ITS STATE SO MUCH THAT IT REALLY DOESN'T KNOW ; WHAT LINE IT'S ON OR EXACTLY WHERE. THIS HANDLER MIGHT DO BETTER ; WITH THE FOLLOWING CODE: ; ; MOV BUFPTR(R4),R1 ;GET CURRENT BUFFER POINTER ; MOV BUFIPT(R4),R5 ;AND CURRENT BASE ADDRESS ; SUB R5,R1 ;COMPUTE TOTAL LENGTH OF BUFFER ; MOV R1,BUFCTR(R4) ;SAVE NEW BUFFER COUNTER ; CMP R5,BUFPTR(R4) ;DID WE START THE I/O? ; BEQ 50$ ;NO -- SKIP ; ; AND THEN RESETTING BUFPTR(R4) TO BUFIPT(R4) AT 50$, BUT ; THAT HAS UNFORTUNATE CONSEQUENCES WHICH MAY BE WORSE THAN ; THE DISEASE. FOR EXAMPLE, IF THE USER IS DOING IMBEDDED ; CARRIAGE CONTROL I/O (USING A 0 FOR THE FORTRAN CARRIAGE CONTROL ; FLAG), THEN THIS MAY TRASH UP THE PRINTOUT IF HE DID A QIO WHICH ; STARTED IN THE MIDDLE OF A LINE (I. E., THE PREVIOUS QIO LEFT THE ; PRINTER IN THE MIDDLE OF A LINE AND THE CURRENT ONE STARTS WHERE ; THE PREVIOUS ONE LEFT OFF). THIS PRACTICE IS USED OFTEN, FOR ; EXAMPLE BY TKB. THIS WOULD BE TRICKY TO FIX, SINCE IF WE ALWAYS ; SET UP EXPLICIT CARRIAGE CONTROL I/O BUFFERS SUCH THAT THE CURRENT ; PRINTER LINE POSITION (KEPT TRACK OF IN TABCNT(R4)) IS ALSO THE ; OFFSET INTO OUR INTERNAL BUFFER WHERE OUR I/O ON HIS DATA STARTS, ; THEN WE CANNOT FIND THIS STARTING POINT IN THIS CODE, SINCE THAT ; INFORMATION HAS ALREADY BEEN DESTROYED (THIS ADDRESS MUST BE ; FOUND SO THAT WE CAN TELL IF THE TRANSFER STARTED AND IF SO, ; WHETHER ANY LF'S OR FF'S HAVE ALREADY GONE OUT AND PRESUMABLY ; BEEN EXECUTED BY THE PRINTER). THIS CAN BE FIXED WITH THE ; ADDITION OF A FEW MORE TABLES TO KEEP TRACK OF THE INITIAL ; BUFFER TRANSFER ADDRESS, BUT THE ADDITIONAL COMPLEXITY MAKES IT ; A SOMEWHAT LENGTHY EXERCISE, FOR RELATIVELY LITTLE GAIN. ; MOV BUFIPT(R4),R5 ;GET BUFFER. CMP BUFPTR(R4),R5 ;WAS LINE STARTED? BEQ 50$ ;NO -- DON'T FIDDLE MOV #2,R1 ;WILL TRY THIS TWICE. 3$: CMPB (R5),#LF ;WAS IT A ? BNE 5$ ;NO MOVB #CR,(R5) ;MOVE IN 5$: CMPB (R5),#FF ;WAS IT ? BNE 10$ ;NO MOVB #CR,(R5) ;MOVE IN 10$: INC R5 ;POINT TO NEXT CHAR. SOB R1,3$ ;FIXUP FIRST TWO CHARS. 50$: .IF DF DL11IF DEC BUFCTR(R4) ;DECREMENT BUFFER COUNT. BLE 80$ ;FORCE I/O DONE IF DONE. INC BUFPTR(R4) ;INCREMENT BUFFER POINTER. MOVB @BUFPTR(R4),R5 ;PICK UP CHARACTER. WRILPT ;START UP THE LINE PRINTER. BR STATLP ;AND LOOP. 80$: CALL SETIOD ;FORCE I/O DONE. BR STATLP ;AND LOOP .IFF MOV U.DA(R0),R5 ;GET EXTERNAL PAGE ADDRESS BIS #LS.IEA,LP.STA(R5) ;RE-ENABLE INTERRUPTS BR STATLP ;AND LOOP. .ENDC .IF DF DL11IF 90$: BIS #HS.ERR,U.C3(R0) ;SET ERROR ON THIS LINE. .ENDC 100$: INC R3 ;INDICATE THAT A MARK TIME WILL BE DONE. BR STATLP ;AND LOOP. STATEL: TST R3 ;ANY REQUESTS ACTIVE? BEQ 20$ ;NO DIR$ #$MRKT ;YES -- SET UP MARK TIME. 20$: JMP LPPOLL ;AND LOOP. .SBTTL I/O COMPLETION PROCESSING. ; ; THIS ROUTINE IS ENTERED WHENEVER THE I/O DONE EVENT ; FLAG IS SET. ; IODONE: BIC #DV.DNE,A.EF(R4) ;CLEAR IO DONE EVENT FLAG. MOV #-2,R4 ;GET READY TO LOOP OVER DEVICES IOLOOP: TST (R4)+ ;INCREMENT TO NEXT DEVICE. CMP R4,#<2*NO.LPT> ;OVER TOP? BEQ IODNF ;LEAVE IF SO. MOV UITPTR(R4),R5 ;GET A(UIT) MOV (R5),R0 ;GET A(PUD) BEQ IOLOOP ;LEAVE IF NONE. MOV 2(R5),R1 ;GET RNA ADDRESS. BEQ IOLOOP ;LEAVE IF NO REQUESTS PENDING BIT #HS.ABT,U.C3(R0) ;ABORT IN PROGRESS? BEQ IONAB ;NO -- SKIP MOV #IE.ABO,R3 ;MOVE IN ABORTED RETURN CODE. IOBAD: CALL BADIO ;SET I/O DONE. BR IOCNT ;AND LOOP. IONAB: BIT #HS.WRI,U.C3(R0) ;WAS A WRITE IN PROGRESS? BEQ IOLOOP ;NO BIT #HS.ISD,U.C3(R0) ;DID THE ISR COMPLETE YET? BNE IOLOOP ;LOOP IF NOT. TST R.WA+2(R1) ;DONE WITH WHOLE USER BUFFER? BGT IOQUE ;NO BIT #HS.LER,U.C3(R0) ;WAS THERE AN ERROR? BNE IOERR ;YES -- RETURN IT TO USER. CALL GOODIO ;SET I/O DONE. IOCNT: BIC #HS.ABT!HS.ISD!HS.ERR!HS.MSG!HS.LER!HS.WRI!HS.BUF,U.C3(R0) ;CLEAR FLAGS. BR IOLOOP ;AND LOOP. IODNF: JMP LPPOLL ;AND GO BACK TO POLLING. IOERR: MOV #IE.DAO,R3 ;GET TERMINATION CODE -- TOO LONG. BR IOBAD ;AND CONTINUE. IOQUE: MOV R.WA+4(R1),-(SP) ;PDR MOV R.WA+6(R1),-(SP) ;PAR CALL ..SPD3 ;SWAP PAGE REGISTER 3 CMP (SP)+,(SP)+ ;CLEAN STACK. MOVB R.WA+1(R1),R2 ;GET THE OFFSET FROM APR3. ADD R.PB+2(R1),R2 ;POINT TO LAST BYTE IN BUFFER. SUB R.WA+2(R1),R2 ;POINT TO NEXT UNUSED LOCATION. ADD #APR3OF,R2 ;POINT TO THE ACTUAL LOCATION. MOV BUFIPT(R4),R3 ;GET AN INTERNAL BUFFER. MOV R3,BUFPTR(R4) ;SET CURRENT BUF PTR CMP R.PB+2(R1),R.WA+2(R1) ;IS THIS THE FIRST BATCH? BNE LPMAIN ;NO CLR CRFLAG(R4) ;CLEAR TRAILING CR FLAG TSTB R.PB+4(R1) ;IS THIS 0 CARRIAGE CONTROL? BEQ LPMAIN ;YES .IF NDF LS11 CLR TABCNT(R4) ;CLEAR TAB COUNT. .ENDC CMPB #'$,R.PB+4(R1) ;IS CARRIAGE CONTROL A $? BNE 5$ ;NO .IF DF LS11 BIT #U2.S11,U.C2(R0) ;THIS AN LS-11? BNE LPMAIN ;YES CLR TABCNT(R4) ;CLEAR TAB COUNT. .ENDC MOVB #LF,(R3)+ ;MOVE IN A BR LPMAIN ;AND CONTINUE. 5$: .IF DF LS11 CLR TABCNT(R4) ;CLEAR TAB COUNT. .ENDC .IF NDF STNDCR INC CRFLAG(R4) .ENDC CMPB #'+,R.PB+4(R1) ;IS THE CARRIAGE CONTROL A +? BNE 10$ ;NO MOVB #CR,(R3)+ ;MOVE IN A BR LPMAIN ;AND CONTINUE. 10$: .IF DF STNDCR INC CRFLAG(R4) .ENDC CMPB #'1,R.PB+4(R1) ;IS IT A 1? BNE 15$ ;NO MOVB #FF,(R3)+ ;MOVE IN BR LPMAIN ;AND CONTINUE. 15$: MOVB #LF,(R3)+ ;'0' AND ' ' -- GET 1 LF CMPB #'0,R.PB+4(R1) ;IS IT '0' CC? BNE 20$ ;NO -- SKIP NEXT LF MOVB #LF,(R3)+ ;YES -- MOVE IN 2 LF'S BR LPMAIN ;AND SKIP ' ' CODE 20$: .IF DF LS11 BIT #U2.S11,U.C2(R0) ;IS IT AN LS-11? BEQ LPMAIN ;NO CLR CRFLAG(R4) ;THEN CLEAR CR REQUEST. .ENDC LPMAIN: MOV U.C4(R0),R5 ;GET PRINTER LINE SIZE CMP R5,#LPBFSZ-4. ;IS THE PUD BUFFER SIZE ... BLOS LPLOOP ; ... LESS THAN OURS? IGNORE ... MOV #LPBFSZ-4.,R5 ; ... IF SO, ELSE FORCE TO OURS. LPLOOP: DEC R5 ;DECREMENT BYTE COUNT. BMI BUFBIG ;TOO MANY CHARS? CMPB #RUBOUT,(R2) ;IS IT A RUBOUT? BEQ RBSKIP ;YES CMPB #' ,(R2) ;IS IT A TAB? BEQ TABFND ;YES CMPB #CR,(R2) ;IS IT A ? BEQ CARFND ;YES CMPB #FF,(R2) ;OR A ? BEQ CARFND ;YES CMPB #LF,(R2) ;OR A ? BEQ CARFND ;YES INC TABCNT(R4) ;INCREMENT COLUMN POINTER. MOVB (R2)+,(R3)+ ;MOVE DATA. BIT #U2.LRC,U.C2(R0) ;LOWER CASE SUPPORTED? BNE CHAROK ;YES CMPB -1(R3),#140 ;OVER TOP? BLO CHAROK ;NO -- DON'T UPPER IT BICB #40,-1(R3) ;MAKE IT UPPER CASE. CHAROK: DEC R.WA+2(R1) ;DECREMENT BYTE COUNT. BGT LPLOOP ;AND LOOP. CRCHK: TST CRFLAG(R4) ;CAR RETURN NEEDED? BEQ STRTLP ;NO MOVB #CR,(R3)+ ;MOVE ONE IN. TABCLR: CLR TABCNT(R4) ;CLEAR OUR TAB COUNT. STRTLP: SUB BUFIPT(R4),R3 ;COMPUTE LENGTH OF BUFFER. MOV R3,BUFCTR(R4) ;SAVE IT IN COUNTER. MOVB @BUFIPT(R4),R5 ;GET CHARACTER WRILPT ;WRITE IT. JMP IOLOOP ;AND LOOP ; TBLOOP: DEC R5 ;DECREMENT BYTE COUNT. BMI BUFBIG ;TOO BIG? TABFND: MOVB #' ,(R3)+ ;MOVE IN A SPACE. INC TABCNT(R4) ;INCREMENT TAB COUNT. BIT #7,TABCNT(R4) ;IS IT TO A TAB STOP? BNE TBLOOP ;NO RBSKIP: TSTB (R2)+ ;SKIP A RUBOUT OR A TAB. BR CHAROK ;AND CONTINUE CARFND: DEC R.WA+2(R1) ;DECREMENT BYTE COUNT. MOVB (R2)+,(R3)+ ;MOVE IN TERMINATOR (CR OR FF) BR TABCLR ;AND START LP. BUFBIG: BIS #HS.LER,U.C3(R0) ;SET ERROR BIT -- LINE LONG. 10$: CMPB (R2),#FF ;IS IT A FF? BEQ CARFND ;YES CMPB (R2),#LF ;OR A LF? BEQ CARFND ;YES CMPB (R2),#CR ;OR A CR? BEQ CARFND ;YES INC R2 ;GET TO NEXT CHARACTER. DEC R.WA+2(R1) ;DECREMENT BYTE COUNTER. BGT 10$ ;LOOP IF STILL MORE IN BUFFER. BR CRCHK ;AND PUT A IN IF NECESSARY. .SBTTL EXPRESS REQUEST PROCESSING. ; ; EXPRESS REQUESTS ARE HANDLED HERE. THEY ARE THE 'KILL', ; 'FLUSH', AND 'EXIT' REQUESTS. ; ; KILL ABORTS THE ANY TRANSFERS IN PROGRESS FOR THE ; REQUESTOR, THEN SETS UP HIS REQUEST NODE TO LOOK LIKE ; 'FLUSH' AND PURGES HIS REQUESTS FROM THE QUEUE VIA A CALL ; TO ..FLSH. ; ; I/O 'FLUSH' IS USED TO ELIMINATE REQUESTS FOR ANY USER ; AND IS THEREFORE ONLY VALID WHEN ISSUED BY THE EXEC. AS ; IMPLIED ABOVE I/O FLUSH REQUIRES AN RNA SET UP AS FOLLOWS: ; PARAM0: ATL NODE ADDRESS, TASK TO BE FLUSHED (VICTIM). ; PARAM1: STD ADDRESS (VICTIM). ; PARAM2: PUD POINTER. ; ; EXIT IS ISSUED BY THE EXECUTIVE AND CAUSES THE HANDLER ; TO TERMINATE ANY I/O IN PROGRESS AND EXIT THE SYSTEM ; GRACEFULLY. ; ; ON ENTRY, ; ; R1 = RNA ADDRESS (REQUESTOR). ; R2 = ADDRESS OF PUD POINTER. ; EXPFNS: BIT R.FC(R1),#IQ.Q ;MAKE SURE WE GOT HERE VIA EXPRESS QUEUE BNE 10$ JMP ILLFNC ;NO 10$: CMP R.FC(R1),#IO.KIL ;KILL SUBFUNCTION? BNE LPFLSH ;NO, CHECK FOR FLUSH. ; MOV R.AT(R1),R3 ;GET ATL NODE(REQUESTOR) MOV R3,R.PB(R1) ;ATL ADDRESS (REQUESTOR) MOV R.TD(R1),R.PB+2(R1) ;STD ADDRESS. MOV (R2),R.PB+4(R1) ;PUD ADDRESS BR FLSHTK ;SIMULATE FLUSH LOGIC. ; ; THE FUNCTION MUST BE EITHER AN I/O RUNDOWN (FLUSH) OR ; AN EXIT. BOTH CAN ONLY BE ISSUED BY THE EXEC. CHECK HERE ; TO SEE IF WE WERE CALLED BY THE EXEC. ; LPFLSH: TST R.AT(R1) ;IS IT THE EXEC? BEQ 10$ ;SKIP IF SO. JMP ILLFNC ;NO -- NAUGHTY NAUGHTY 10$: CMP R.FC(R1),#IO.RDN ;I/O RUNDOWN? BNE LPEXIT ;NO, CHECK FOR EXIT DIRECTIVE. MOV R.PB(R1),R3 ;OK. GET ATL OF VICTIM. ; ; COMMON CODE FOR THE FLUSH AND KILL FUNCTIONS. ; ; THIS ROUTINE DETACHES THE VICTIM IF NECESSARY ; AND CHECKS TO SEE IF HE WAS DOING I/O. IF SO, THE ROUTINE ; CALLS SETIOD TO FAKE AN I/O COMPLETION EVENT SO 'IODONE' ; WILL BE CALLED WITHOUT WAITING FOR AN INTERRUPT FROM THE ; PRINTER. IODONE WILL INSPECT THE ABORT FLAG, WHICH IS SET HERE, ; AND WILL TERMINATE THE TRANSFER WITH -15 ERROR RETURN AND ; RELEASE THE NODE. ; ; FINALLY, ..FLSH IS CALLED TO PURGE THE QUEUE OF ANY ; REQUESTS MADE BY THE VICTIM. ; ; ENTER WITH: ; ; R1 = RNA ADDRESS (REQUESTOR) ; R2 = ADDRESS OF PUD POINTER ; R3 = ATL ADDRESS OF VICTIM ; FLSHTK: MOV 2(R2),R4 ;GET RNA OF LAST NORMAL REQUEST. BEQ FLEXT ;NONE PENDING, CONTINUE. CMP R3,R.AT(R4) ;WAS THE VICTIM DOING I/O? BNE FLEXT ;NO. MOV (R2),R0 ;GET PUD ADDRESS. BIS #HS.ABT,U.C3(R0) ;SET FLAG TO PREVENT DATA TRANSFER. BIC #HS.ISD!HS.ERR!HS.MSG!HS.BUF,U.C3(R0) ;CLEAR FLAGS. ; CLRB R.FN(R4) ;CANCEL FLAG ON I/O DONE. CLR R.AE(R4) ;AND AST(VICTIM). ; ; CALL SETIOD ;CALL THIS ROUTINE TO FAKE AN INTERRUPT. ; FLEXT: CALL ..FLSH ;FLUSH THE VICTIM. JMP SUCCES ;FINISH THE REQUEST. ; ; EXIT REQUEST. ; ; THIS CODE IS ENTERED WHEN THE HANDLER HAS BEEN INSTRUCTED ; TO EXIT THE SYSTEM. EXIT IS ONLY LEGAL WHEN ISSUED BY THE EXEC. ; THE ROUTINE TERMINATES ANY NORMAL REQUEST IN PROGRESS WITH AN ; ERROR CODE OF -2, RETURNS ALL NODES TO THE POOL (VIA ..IODN), ; AND TRANSFERS CONTROL TO THE EXIT ROUTINES FOR FINAL CLEANUP. ; ; ON ENTRY: ; ; R1 = RNA ; R2 = PUD POINTER ; LPEXIT: CMP R.FC(R1),#IO.UNL ;EXIT REQUEST? BEQ 10$ ;YES -- CONTINUE JMP ILLFNC ;NO -- ILLEGAL 10$: CLR R2 ;ADJUST UNITY DECREMENT. MOV #IS.SUC,R3 ;SUCCESS FOR THIS REQUEST. CLR R4 ;'0' DATA TRANSFERRED. CALL ..IODN ;FINISH THE REQUEST. MOV #-2,R5 ;START LOOP THRU DEVICES. LASTNX: TST (R5)+ ;GET TO NEXT ONE CMP R5,# ;OVER TOP ? BEQ LASTLT ;YES -- LEAVE. MOV UITPTR(R5),R3 ;GET A(UIT) MOV (R3),R0 ;GET PUD ADDR BEQ LASTNX ;LEAVE IF NO PUD ADDR CLRLPT ;DISABLE ANY INTERRUPTS. MOV 2(R3),R1 ;GET RNA ADDR OF NORMAL I/O BEQ LASTNX ;LOOP IF NONE. MOV #IE.IFC,R3 ;FLAG REQUEST AS ILLEGAL. CALL ..IODN ;SET I/O DONE. BR LASTNX ;AND LOOP THRU ALL DEVICES. LASTLT: .SBTTL EXIT PROCESSORS. ; ; DISCONNECT FROM INTERRUPTS ; LPEXT2: MOV #-2,R4 ;INIT POINTER. EXITNX: TST (R4)+ ;INCREMENT POINTER. CMP #<2*NO.LPT>,R4 ;DONE? BEQ LPEXT1 ;LEAVE IF SO. MOV @UITPTR(R4),R0 ;GET PUD ADDRESS FOR UNIT. BEQ EXITNX ;LEAVE IF NO PUD ADDR BIT #HS.CON,U.C3(R0) ;CONNECTED? BEQ EXITNX ;SKIP IF NEVER CONNECTED. CLRLPT ;CLEAR STATUS. .IF DF DL11IF&LP11IF MOV R0,R5 .ENDC MOV U.TV(R0),R0 ;GET TRANSFER VECTOR ADDR .IF DF DL11IF .IF DF LP11IF BIT #U2.DLI,U.C2(R5) ;IS THIS A DL-11? BEQ 10$ ;NO .ENDC CMP (R0)+,(R0)+ ;YES -- DISCONNECT XFER VECT. 10$: .ENDC CALL ..DINT ;DISCONNECT. BR EXITNX ;AND LOOP. ; ; DECLARE NON-RESIDENCY ; LPEXT1: MOV #LPUIT,R0 ;DISPATCH TABLE ADDRESS. CALL ..DNRC ;DECLARE NON-RESIDENT. ; ; AND SCRAM ; LPEXT0: EXIT$S ;EXIT HANDLER. HALT ;SHOULD NEVER BE EXECUTED. .SBTTL NORMAL REQUEST PROCESSING. ; ; COME HERE TO ATTACH THE DEVICE ; ; R1 = RNA ; R2 = PUD POINTER ; LPATT: CALL ..ATUN ;TRY TO ATTACH. BCS ILLATD ;CAN'T ATTACH -- ERROR BR SUCCES ;RETURN SUCCESS ; ; DETACH USER HERE ; ; R1 = RNA ; R2 = PUD POINTER ; LPDET: CALL ..DTUN ;TRY TO DETACH. BCS ILLNAT ;NEVER WAS ATTACHED. MOV (R2),R0 ;GET A(PUD) MOVB U.UN(R0),R5 ;GET UNIT NUMBER. ASL R5 ;CONVERT TO WORD OFFSET. CLR BUFCTR(R5) ;FORCE 0 TRANSFER ON THIS LINE. MOV #LF,R5 ;GET A WRILPT ;AND PRINT IT. CLRLPT ;FORCE NO INTERRUPTS. SUCCES: CALL GOODIO ;COMPLETE I/O JMP LPPOLL ;AND LOOP. .SBTTL ERROR RETURNS ; ILLFNC: MOV #IE.IFC,R3 ;BAD FUNCTION CODE. BR CALERR ; ILLPRI: MOV #IE.PRI,R3 ;PRIVILEGE VIOLATION. BR CALERR ; ILLATD: MOV #IE.DAA,R3 ;DEVICE ALREADY ATTACHED. BR CALERR ; ILLNAT: MOV #IE.DNA,R3 ;DEVICE NOT ATTACHED. BR CALERR ; ILLPRM: MOV #IE.BAD,R3 ;BAD PARAMETERS. BR CALERR ; ILLSPC: MOV #IE.SPC,R3 ;PART OF BUFFER OUT OF USER SPACE. CALERR: CALL BADIO ;SET I/O DONE JMP LPPOLL ;AND RESUME POLLING. .SBTTL WRITE REQUEST PROCESSING ; ; WRITE REQUESTS ARE PROCESSED HERE. ON ENTRY, THE USER'S ; NODE IS EXPECTED TO CONTAIN THE FOLLOWING: ; ; PARAM0: BUFFER ADDRESS ; PARAM1: BYTE COUNT ; ; ON ENTRY: ; ; R1 = RNA ; WRITE: MOV R.PB(R1),R2 ;GET VIRTUAL BUFFER ADDRESS. MOV R.PB+2(R1),R3 ;AND TRANSFER COUNT. CMP R3,#8192.-64. BHIS ILLSPC ;ILLEGAL BYTE COUNT. MOV #1,R5 ;SET TRANSFER DIRECTION. CALL ..VXFR ;VALIDATE THIS TRANSFER. BCS ILLPRM ;CAN'T ACCESS THIS BUFFER. ; ASH #-4,R4 ;MOVE HIGH ADDR BITS TO LEFT OF REG. ASHC #12,R4 ;COMPUTE MOD(32 WORDS) ASH #-12,R5 ;GET OFFSET ADDR OF USER BUFFER. BIC #177700,R5 ;CLEAN UP HIGH ORDER GARBAGE. MOVB R5,R.WA+1(R1) ;SAVE USER BUFFER POINTER. MOV R3,R.WA+2(R1) ;SAVE USER BYTE COUNT. BIC #77,R3 ;TRUNCATE TO PREVIOUS 32-WORD BOUNDARY. ADD #100,R3 ;MOVE UP TO NEXT 32-WORD SEGMENT. ASH #2,R3 ;SET UP FOR APR. BIS #2,R3 ;SET FOR R-O MOV R3,R.WA+4(R1) ;SAVE PDR IN RNA NODE. MOV R4,R.WA+6(R1) ;SAVE PAR IN RNA NODE. MOV R.PD(R1),R0 ;GET A(PUD) BIC #HS.ABT!HS.ERR!HS.MSG!HS.ISD!HS.LER!HS.BUF,U.C3(R0) ;CLEAR STATUS BITS. BIS #HS.WRI,U.C3(R0) ;MARK AS DOING A WRITE. MOV .CRTSK,R4 ;GET OUR ATL NODE BIS #DV.DNE,A.EF(R4) ;FAKE I/O DONE TO WRITE BUFFER. JMP LPPOLL ;AND WAIT FOR COMPLETION. .SBTTL SUBROUTINE TO FINISH UP I/O ; GOODIO: MOV #IS.SUC,R3 ;SUCCESS ; ; DATA TRANSFERS ARE TERMINATED HERE. ENTER WITH SUCCESS ; INDICATOR IN R3. IF R3 IS POSITIVE, THE ROUTINE WILL PLACE ; THE NUMBER OF BYTES READ (6) IN R4 FOR INSERTION IN WORD 2 ; IF THE IO STATUS BLOCK. OTHERWISE R4 CONTAINS THE DEVICE ; CHARACTERISTICS WORD. ; ; R1 RNA ADDRESS ; R3 SUCCESS INDICATOR. ; ; REGISTERS CHANGED: R2,R3 ; BADIO: MOV R4,-(SP) MOV R.PB(R1),R4 ;MOVED REQUESTED AMT. TST R3 ;IS STATUS GOOD? BPL 10$ ;GOOD TRANSFER, TERMNATE. CLR R4 ;FAILED, GET CHARACTERISTICS. BIC #177400,R3 ;CLEAR HI-BYTE. ; 10$: TST R1 ;ANYTHING IN RNA? BEQ 20$ ;NOTHING TO RETURN, JUST EXIT. MOV R.PD(R1),R2 ;R2 -> PUD MOVB U.UN(R2),R2 ;R2 = UNIT # ASL R2 ;ADJUST FOR WORDS. MOV UITPTR(R2),R2 ;R2 -> UIT ENTRY BIT #IQ.Q,R.FC(R1) ;NORMAL OR EXPRESS REQUEST? BEQ 15$ ;NORMAL TST (R2)+ ;EXPRESS -- BUMP POINTER. 15$: MOV R2,-(SP) ;SAVE IT CLR R2 ;SET FUDGE FACTOR FOR UNITY DECREMENT. CALL ..IODN ;RETURN THIS NODE, GIVE COMPLETION ;TO USER. MOV (SP)+,R2 ;RECOVER R2 CLR 2(R2) ;RE-ENABLE DEQUEING. 20$: MOV CRTSK,R4 ;GET OUR ATL NODE BIS #EF.NIR,A.EF(R4) ;FORCE NORMAL REQUEST PROCESS. MOV (SP)+,R4 ;RESTORE R4 RETURN ;RETURN TO CALLER .SBTTL I/O DONE SERVICE ROUTINE. ; ; THE FOLLOWING ROUTINE REMOVES THE PRINTER FROM THE INTERRUPT SYSTEM, AND ; CALLS '..SETF' TO SET THE I/O DONE EVENT FLAG AND DECLARE A ; SIGNIFICANT EVENT. NOTE THAT THIS ROUTINE MUST BE RE-ENTRANT. ; ; ENTER WITH: ; ; R0 PUD ADDRESS ; SETIOD: MOV R1,-(SP) ;SAVE R1 CLRLPT ;TURN OFF INTERRUPTS. BIC #HS.ISD,U.C3(R0) ;SET INTERRUPT DONE FLAG. MOV #DV.DNE,R1 ;GET EVENT FLAG CALL @#..STEF ;DECLARE SIGNIFICANT EVENT, SET EVF. MOV (SP)+,R1 ;RESTORE THE REGISTERS RETURN ;AND EXIT .SBTTL INTERRUPT SERVICE ROUTINE. ; ; THE FOLLOWING ROUTINE IS ENTERED ONLY ON AN INTERRUPT FROM THE ; PRINTER. ; HI.ISR: JSR R1,(PC) ;SAVE R1. MOV @#PS.EXP,R1 ;RECOVER PS (AND UNIT #) MOV R0,-(SP) ;SAVE R0 MOV R2,-(SP) ;SAVE R2 MOV R3,-(SP) ;SAVE R3 BIC #177760,R1 ;ISOLATE UNIT # ASL R1 ;GET WORD OFFSET. MOV UITPTR+APR3OF(R1),R2 ;GET OFFSET OF UIT. MOV APR3OF(R2),R0 ;GET A(PUD) MOV U.DA(R0),R3 ;GET EXTERNAL PAGE ADDRESS MOV BUFPTR+APR3OF(R1),R2 ;GET THE BUFFER POINTER ADD #APR3OF+1,R2 ;ADDRESS IT FROM APR3 ; ; NOW, ; ; R0 = A(PUD) ; R1 = UNIT # * 2 ; R2 = A(BUFFER) ; R3 = A(EPA) ; .IF DF DL11IF&LP11IF BIT #U2.DLI,U.C2(R0) ;IS IT A DL-11? BNE INTDL ;YES .ENDC .IF DF LP11IF INTLP: BIT #LS.ERR!LS.RDY,LP.STA(R3) ;ERROR? BMI INTERR ;PROCESS IT IF SO. BEQ INTEXT ;LEAVE IF NOT READY DEC BUFCTR+APR3OF(R1) ;DEC COUNT. BLE INTDNE ;STOP IF DONE. MOVB (R2)+,LP.BUF(R3) ;OUTPUT THE CHAR. INC BUFPTR+APR3OF(R1) ;INCREMENT THE POINTER. NOP NOP ;WAIT A BIT BR INTLP ;DONE -- TRY ANOTHER. .ENDC .IF DF DL11IF INTDL: BIT #DR.CTS,DL.RCR(R3) ;CLEAR TO SEND? BNE INTERR ;NO -- ERROR BIT #DR.CDT,DL.RCR(R3) ;CARRIER DETECT? BEQ INTDLF ;FULL - STOP A WHILE. DEC BUFCTR+APR3OF(R1) ;DEC COUNT. BLE INTDNE ;DONE -- STOP. MOVB (R2)+,DL.XBF(R3) ;MOVE TO BUFFER. INC BUFPTR+APR3OF(R1) ;INC POINTER. BIT #DX.RDY,DL.XCR(R3) ;IS IT READY FOR ANOTHER? BNE INTDL ;YES -- DO IT AGAIN. .ENDC INTEXT: MOV (SP)+,R3 ;RESTORE R3 MOV (SP)+,R2 ;RESTORE R2 MOV (SP)+,R0 ;RESTORE R0 MOV (SP)+,R1 ;RESTORE R1 JMP @#..INTX ;RETURN TO THE INTERRUPT. INTDNE: CALL SETIOD ;SET I/O DONE. BR INTEXT ;AND EXIT INTERRUPT. INTERR: BIC #HS.MSG,U.C3(R0) ;SAY NO MESSAGE SENT BIS #HS.ERR,U.C3(R0) ;BUT THERE IS AN ERROR INTERF: CLRLPT ;CLEAR LINE PRINTER. MOV CRTSK,R0 ;GET OUR ATL NODE BIS #DV.MKT,A.EF(R0) ;SET OUR ERROR FLAG BR INTEXT ;AND LEAVE .IF DF DL11IF INTDLF: BIS #HS.BUF,U.C3(R0) ;SET ERROR BITS. BR INTERF ;AND CONTINUE ERROR. .ENDC .SBTTL POWER FAILURE AST SERVICE. ; ; THIS IS ENTERED ON A POWER FAILURE. THE ROUTINE CHECKS ; TO SEE IF A WRITE IS UNDERWAY, AND IF SO, SETS INTERRUPTS ON AGAIN. ; HI.PWR: MOV R4,-(SP) ;SAVE R4 MOV R0,-(SP) ;SAVE R0 MOV R2,-(SP) ;SAVE R2 MOV #-2,R4 ;START UP SCAN OF PUD. PWRLP: TST (R4)+ ;SKIP TO NEXT DEVICE. CMP R4,#<2*NO.LPT> ;OVER TOP? BEQ PWREND ;LEAVE IF SO. MOV UITPTR(R4),R0 ;R0 = A(UIT) TST 2(R0) ;IS THERE AN ACTIVE REQUEST? BEQ PWRLP ;NO -- CONTINUE MOV (R0),R0 ;R0 = A(PUD) BEQ PWRLP ;LOOP IF NONE. CLRLPT ;DISABLE INTERRUPTS. BIT #HS.WRI,U.C3(R0) ;WAS A WRITE IN PROGRESS HERE? BEQ 10$ ;NO -- SKIP. BIT #HS.ISD,U.C3(R0) ;WAS THE INTERRUPT SERVICE ROUTINE DONE? BEQ 10$ ;YES -- SKIP BIS #HS.ERR!HS.MSG,U.C3(R0) ;SIGNAL ERROR. MOV CRTSK,R0 ;GET OUR ATL NODE. BIS #DV.MKT,A.EF(R0) ;FORCE AN ERROR SCAN. 10$: BR PWRLP ;AND LOOP. PWREND: MOV (SP)+,R2 ;RESTORE R2 MOV (SP)+,R0 ;RESTORE R0 MOV (SP)+,R4 ;RESTORE R4 ASTX$S ;AND EXIT FROM AST. .SBTTL QI/O DONE AST SERVICE. ; ; THIS IS ENTERED WHEN A QI/O COMPLETES. IT CLEARS THE ; QI/O IN PROGRESS FLAG SO THAT ANOTHER MESSAGE CAN BE PRINTED ; IF NECESSARY. ; HI.QIO: TST (SP)+ ;POP OFF I/O STATUS BLOCK CLR MSGINP ;CLEAR QI/O IN PROGRESS FLAG. ASTX$S ;AND LEAVE. .SBTTL UTILITY SUBROUTINES FOR HARDWARE I/O ; ; SUBROUTINE 1. CLEAR PRINTER STATUS. ENTER WITH: ; ; R0 PUD ADDRESS ; CLRLP$: MOV R1,-(SP) ;SAVE R1 MOV U.DA(R0),R1 ;GET EPA ADDRESS .IF DF DL11IF&LP11IF BIT #U2.DLI,U.C2(R0) ;IS THIS DL-11 OR LP-11? BNE 10$ ;DL-11 .ENDC .IF DF LP11IF CLR LP.STA(R1) ;CLEAR IT .IF DF DL11IF BR EXIT$$ .ENDC .ENDC .IF DF DL11IF 10$: CLR DL.RCR(R1) ;CLEAR RECEIVER STATUS. CLR DL.XCR(R1) ;AND TRANSMITTER STATUS. .ENDC EXIT$$: MOV (SP)+,R1 ;RESTORE R1 RETURN ;AND RETURN. ; ; SUBROUTINE 2. WRITE A BYTE TO THE LINE PRINTER. ; AND ENABLE INTERRUPTS FOR THE REST OF LINE. ; ; ENTER WITH: ; ; R0 PUD ADDRESS ; R5 CHARACTER TO BE PRINTED ; WRILP$: MOV R1,-(SP) BIS #HS.ISD,U.C3(R0) ;SIGNAL ISR AS ACTIVE. MOV U.DA(R0),R1 .IF DF DL11IF&LP11IF BIT #U2.DLI,U.C2(R0) ;IS IT A DL-11? BNE 10$ ;YES .ENDC .IF DF LP11IF MOVB R5,LP.BUF(R1) ;MOVE IT OUT BIS #LS.IEA,LP.STA(R1) ;ENABLE LP-11 INTERRUPTS. BR EXIT$$ ;AND EXIT. .ENDC .IF DF DL11IF 10$: .INHIB BIS #DX.TIE,DL.XCR(R1) ;SET TRANSMITTER INT. MOVB R5,DL.XBF(R1) ;MOVE OUT THE CHARACTER. .ENABL BR EXIT$$ ;AND LEAVE .ENDC .SBTTL HANDLER TALBES. .MACRO DCLDSP,CNTRL,ADDR .WORD CNTRL,ADDR .ENDM ; ; DEFINITIONS OF THE CONTROL BITS IN THE CONTROL WORD. ; DSPDCF = 000010 ;DCF MUST BE PERMITTED TO PERFORM FUNCTION. DSPATT = 000020 ;VOLUME MUST BE ATTACHABLE TO PERFORM FUNCTION. DSPNUN = 000040 ;VOLUME MUST NOT BE SET FOR UNLOADING DSPF11 = 000100 ;VOLUME MUST BE A FILES-11 VOLUME. DSPMNT = 000200 ;VOLUME MUST BE MOUNTED. DSPRED = 000400 ;USER MUST HAVE READ PRIVILEGES. DSPWRT = 001000 ;USER MUST HAVE WRITE PRIVILEGES. DSPEXT = 002000 ;USER MUST HAVE EXTEND PRIVILEGES. DSPDEL = 004000 ;USER MUST HAVE DELETE PRIVILEGES. DSPEXP = 020000 ;EXPRESS BIT MUST BE 0. DSPSUB = 040000 ;SUB-FUNCTION CODE MUST BE 0. DSPASC = 100000 ;WORD B CONTAINS BINARY VALUE OF ASCII CHARS IN SEND. ; ; START OF THE DISPATCH TABLE. ; LPDSP: .WORD 0 ;ADDR OF BAD SEND/RECEIVE PROCESS .WORD 0 ;ADDR OF GOOD SEND/RECEIVE PROCESS. ; MINFN: DCLDSP ,EXPFNS ;EXPRESS FUNCTIONS. DCLDSP DSPDCF!DSPWRT!DSPEXP!DSPSUB,WRITE ;WRITE LOGICAL BLOCK. DCLDSP DSPDCF!DSPRED!DSPEXP!DSPSUB,ILLFNC ;READ LOGICAL BLOCK. DCLDSP DSPATT!DSPEXP!DSPSUB,LPATT ;ATTACH PRINTER. DCLDSP DSPATT!DSPEXP!DSPSUB,LPDET ;DETACH PRINTER. DCLDSP DSPDCF,ILLFNC ;CONTROL DCLDSP ,ILLFNC ; DCLDSP ,ILLFNC ; DCLDSP ,ILLFNC ; DCLDSP DSPNUN!DSPF11!DSPEXP!DSPSUB,ILLFNC ;FIND DCLDSP ,ILLFNC ; DCLDSP DSPNUN!DSPF11!DSPEXP!DSPSUB,ILLFNC ;REMOVE DCLDSP DSPNUN!DSPF11!DSPEXP!DSPSUB,ILLFNC ;ENTER DCLDSP DSPNUN!DSPF11!DSPRED!DSPEXP!DSPSUB,SUCCES ;ACCESS DCLDSP DSPNUN!DSPF11!DSPRED!DSPWRT!DSPEXP!DSPSUB,SUCCES ;ACCESS R/W DCLDSP DSPNUN!DSPF11!DSPRED!DSPWRT!DSPEXT!DSPEXP!DSPSUB,SUCCES ;ACCESS R/W/E DCLDSP DSPF11!DSPEXP!DSPSUB,SUCCES ;DEACCES DCLDSP DSPF11!DSPRED!DSPEXP!DSPSUB,ILLFNC ;READ VIRTUAL DCLDSP DSPF11!DSPWRT!DSPEXP!DSPSUB,WRITE ;WRITE VIRTUAL MAXFN: ; .MACRO UIT1,$ .WORD $ ;PUD POINTER FOR UNIT $ .WORD 0 ;LAST NORMAL RNA FOR UNIT $ .WORD 0 ;LAST EXPRESS RNA FOR UNIT $ .ENDM ; ; THE UNIT IDENTIFICATION TABLE (UIT) ; LPUIT: .WORD LPDSP ;ADDRESS OF THE DISPATCH TABLE .BYTE NO.LPT,0 ;NUMBER OF PRINTERS TO BE SERVICED .WORD 0,0,0 ;STATUS INFORMATION $=0 .REPT NO.LPT UIT1 \$ $=$+1 .ENDR ; .MACRO .WORD. $,BASE,LENGTH,STRING .IF NB BASE .WORD BASE+<$*LENGTH> ;STRING $ .IFF .WORD 0 ;STRING $ .ENDC .ENDM ; ; THE UIT POINTER TABLE. ALLOWS A UIT TO BE ; ACCESSED BY UNIT NUMBER. ; $=0 UITPTR: .REPT NO.LPT .WORD. \$,LPUIT+10.,6, $=$+1 .ENDR ; ; BUFFER POINTERS ; $=0 BUFIPT: .REPT NO.LPT .WORD. \$,LPBUFA,\LPBFSZ, $=$+1 .ENDR ; ; BUFFER COUNTERS ; $=0 BUFCTR: .REPT NO.LPT .WORD. \$,,, $=$+1 .ENDR ; ; POINTER TO CURRENT BUFFER POSITION ; $=0 BUFPTR: .REPT NO.LPT .WORD. \$,,, $=$+1 .ENDR ; ; TAB COUNTERS ; $=0 TABCNT: .REPT NO.LPT .WORD. \$,,, $=$+1 .ENDR ; ; CARRIAGE RETURN FLAGS ; $=0 CRFLAG: .REPT NO.LPT .WORD. \$,,, $=$+1 .ENDR ; ; MISCELLANEOUS VARIABLES. ; MSGINP: .WORD 0 ;QI/O TO CONSOLE IN PROGRESS. CRTSK: .WORD 0 ;.CRTSK FOR USE IN ISR .SBTTL DIRECTIVE PARAMETER BLOCKS. ; $WAIT4: WTLO$ 0,DV.DNE!EF.XIR!EF.NIR!DV.MKT $SPRA: SPRA$ HI.PWR $MRKT: MRKT$ EN.MKT,6,1 $CMKT: CMKT$ EN.MKT $QIO: QIO$ IO.WVB,LUNCON,EN.QIO,,,HI.QIO, .NLIST BIN ERRMSG: .ASCII / *** LP/ DEVNUM: .ASCII /00 NOT READY/ ERRLEN = .-ERRMSG .EVEN .END LPINIT