Google
 

Trailing-Edge - PDP-10 Archives - bb-m780a-sm - monitor-sources/linepr.mac
There are 52 other files named linepr.mac in the archive. Click here to see a list.
; UPD ID= 2071, SNARK:<5.MONITOR>LINEPR.MAC.4,  24-May-81 15:36:00 by ZIMA
;TCO 5.1345 - correct LPINI and MTOPR function .MOSTS for MO%LCP handling.
; UPD ID= 1562, SNARK:<5.MONITOR>LINEPR.MAC.3,  15-Feb-81 16:56:13 by ZIMA
;Move 5.1256 to not step on any allocation changes made by the -11.
; UPD ID= 1509, SNARK:<5.MONITOR>LINEPR.MAC.2,  31-Jan-81 18:35:20 by ZIMA
;TCO 5.1256 - Fix lost data on online/offline transitions.
;<4.MONITOR>LINEPR.MAC.12,  2-May-79 15:02:02, EDIT BY KIRSCHEN
;FIX RELRNG BUGCHKS
;<4.MONITOR>LINEPR.MAC.11,  1-May-79 09:33:53, EDIT BY KIRSCHEN
;ADD UNIT NUMBER WHEN STORING INIPSI IN LPTCLZ
;<4.MONITOR>LINEPR.MAC.10, 23-Apr-79 15:50:18, EDIT BY OSMAN
;tco 4.2240 - Do INIT when done loading ram
;<4.MONITOR>LINEPR.MAC.9, 21-Apr-79 16:41:00, Edit by MCLEAN
;MAKE FLUSH WAIT FOR STATUS RETURN
;<4.MONITOR>LINEPR.MAC.8, 10-Apr-79 14:01:56, EDIT BY OSMAN
;tco 4.2229 - Check for INIPSI before calling PSIRQ at LPTCHK
;<4.MONITOR>LINEPR.MAC.7, 22-Mar-79 21:10:31, Edit by MCLEAN
;MAKE SETER2 SET LPSHA SO WE GET OUT OF STSWAT
;<4.MONITOR>LINEPR.MAC.6,  4-Mar-79 18:11:46, EDIT BY KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
;<4.MONITOR>LINEPR.MAC.5,  1-Mar-79 14:00:03, Edit by MCLEAN
;MAKE FLUSH CORRECTLY AND IMMEDIATELY FLUSH BUFFERS ON INIT OF BUFFERS
;<4.MONITOR>LINEPR.MAC.4, 17-Jul-78 23:33:43, Edit by MCLEAN
;MOVE GETWRD/PUTWRD TO JSYSF SINCE SYSTEM WITHOUT LP WITH CARDREADER DOESN'T ASSEMBLE
;<4.MONITOR>LINEPR.MAC.3, 14-Jul-78 12:47:19, Edit by MCLEAN
;<4.MONITOR>LINEPR.MAC.2, 14-Jul-78 02:01:01, Edit by MCLEAN
;<4.MONITOR>LINEPR.MAC.1, 14-Jul-78 00:51:35, Edit by MCLEAN
;CHECK TO SEE IF FILE OPEN IN MTOPR
;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (C) 1976,1977,1978,1979 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.

	SEARCH PROLOG

   IFN KLFLG,<
	TTITLE LINEPRINTER
	SEARCH PROKL
>
   IFN SMFLG,<
	TTITLE LINEPRINTER,LINPSM
	SEARCH PROKS
	SEARCH PROKL		;*********** THIS SHOULD BE REMOVED SOMETIME *********
	SEARCH SERCOD
>


;LOCAL STORAGE DECLARED IN STG.MAC

EXTN <FELPTN,KSLPTN,LPFLSZ,LPTRLP,LPTTIM,LPTTYP,LPTICT>
EXTN <NLPBF,LPTSTS,LPTST1,LPTST2,LPTST3,LPTCNT,LPTBUF>
EXTN <LPTCLS,LPTCCW,LPTCKT,LPTLCK,LPTERR>
EXTN <LPTOFN,PGDATA>

MAXLPT==2			;MAXIMUM NUMBER LPTS
MAXLPA==NLPBF*5			;DEFAULT LINE ALLOCATION
INIPSI==77			;PSI CHANNEL FIELD IF NO ENABLE HAS BEEN DONE
JSBITS==<FLD(.JSAOF,JS%DEV)+FLD(.JSAOF,JS%DIR)+FLD(.JSAOF,JS%GEN)+FLD(.JSAOF,JS%NAM)+FLD(.JSAOF,JS%TYP)+JS%PAF>

;SPECIAL AC DEFINITIONS USED HEREIN

DEFAC (U,Q1)			;UNIT NUMBER
DEFAC (STS,P1)			;SEE GTJFN FOR FUNCTIONS
DEFAC (JFN,P2)
DEFAC (DEV,P4)

; Externally defined symbols


; Entries to this part

INTERN	LPTCHK			; Check routine
; Parameters and fixed core locations


;DEFINITIONS FOR DEVICE DEPENDENT DISPATCH TABLE

SNDFLO=0		;SEND FLUSH
SNDLDP=1		;SPECIAL DEVICE FUNCTION
SENACK=2		;ACK
SNDDAT=3		;SEND DATA
SNDEOF=4		;SEND EOF
SNDSTD=5		;SEND STRING DATA
GLPTST=6		;LINPRINTER TEST
SNDRST=7		;RESTART
SNDINI=10		;INITILIZATION
FEIEN==11		;INTERRUPT ENABLE CHECK
SNDOPN==12		;OPEN PRINTER
FELPMX==13		;MAX TABLE SIZE

;SYMBOLS AND DEFSTR'S FOR LPTSTS

DEFSTR (LPDEVT,LPTTYP,35,18)


LP%FE==7777B11			;BYTES NOW IN THE FE
LP%MX==7777B23			;MAX BYTES ALLOWED IN FE
LP%ALP==1B35			;BUFFER POINTER
LP%ALI==1B34			;INTERRUPT BUFFER POINTER
LP%OPN==1B33			;LPT IS OPENED
LP%THN==1B32			;LPT IS HUNG (LINE PR CONTROL FAILED)
LP%TWT==1B31			;REQUEST ON QUEUE
LP%TBL==1B30			;LPT IS BLOCKED (OVER LINE ALLOCATION)
LP%OL==1B29			;LPT IS ON LINE
LP%ER==1B28			;VFU HAD AN ERROR
LP%MWS==1B27			;MTOPR WAITING FOR STATUS TO ARRIVE
LP%OBF==1B26			;OUTPUT BEING FLUSHED (E.G., ON CLOSE OR .MONOP)
LP%HE==1B25			;LPT HAS A HARD ERROR
LP%LHC==1B24			;LOADING HAS COMPLETED FLAG

DEFSTR (LPTFE,LPTSTS,11,12)	;BYTES NOW IN THE FE
DEFSTR (LPTMX,LPTSTS,23,12)	;MAX BYTES ALLOWED IN FE
DEFSTR (ALTP,LPTSTS,35,1)	;BUFFER POINTER
DEFSTR (ALTI,LPTSTS,34,1)	;INTERRUPT BUFFER POINTER
DEFSTR (LPOPN,LPTSTS,33,1)	;LPT IS OPENED
DEFSTR (LPTHN,LPTSTS,32,1)	;LINE PR CONTROL FAILED
DEFSTR (LPTWT,LPTSTS,31,1)	;BIT INDICATING REQUEST ON Q
DEFSTR (LPTBL,LPTSTS,30,1)	;LPT IS OVER ALLOCATION
DEFSTR (LPTOL,LPTSTS,29,1)	;LPT ON-LINE BIT
DEFSTR (LPTER,LPTSTS,28,1)	;LPT HAD AN ERROR
DEFSTR (LPMWS,LPTSTS,27,1)	;MTOPR IS WAITING FOR A STATUS TO ARRIVE
DEFSTR (LPOBF,LPTSTS,26,1)	;OUTPUT IS BEING FLUSHED
DEFSTR (LPTHE,LPTSTS,25,1)	;HARD ERROR ON THIS LPT
DEFSTR (LPLHC,LPTSTS,24,1)	;LOADING-HAS-COMPLETED FLAG FOR RAM OR VFU LOADS

;SYMBOLS AND DEFSTRS FOR SECOND STATUS WORD

LP%SST==177777B35		;SOFTWARE STATUS WORD
LP%LCP==1B18			;LOWER CASE PRINTER
LP%SHA==1B19			;STATUS HAS ARRIVED
LP%PAG==7777B17			;PAGE COUNTER FIELD
LP%PSI==77B5			;PSI CHANNEL FOR PAGE CTR & ON-LINE INTERRUPTS

DEFSTR (LPSST,LPTST1,35,16)	;SOFTWARE STATUS WORD
DEFSTR (LPLCP,LPTST1,18,1)	;LOWER-CASE PRINTER
MSKSTR (LPSHA,LPTST1,LP%SHA)	;STATUS HAS ARRIVED
DEFSTR (LPPAG,LPTST1,17,12)	;PAGE COUNTER
DEFSTR (LPPSI,LPTST1,5,6)	;CHANNEL NUMBER ON WHICH PSI'S ARE DESIRED

;DEFSTRS FOR LPTST2

DEFSTR (ARROWF,LPTST2,0,1)	;SAYS WE'RE CONVERTING CONTROL TO ARROW CHARACTER
DEFSTR (SAVBCT,LPTST2,12,12)	;SAVED BYTE COUNTER DURING ARROW HACK
DEFSTR (SAVBUS,LPTST2,28,16)	;SAVED BUS ADDRESS REGISTER
DEFSTR (LPTLOR,LPTST2,29,1)	;ON WHEN LOADING RAM

;DEFSTRS FOR LPTST3

DEFSTR (LPTCC,LPTST3,35,12)	;COUNT OF CHARACTERS SENT TO PRINTER
DEFSTR (SAVCHR,LPTST3,8,8)	;SAVED LP BUFFER CHARACTER WHILE SOING CONTROL HACK
DEFSTR (LPXBIT,LPTST3,0,1)	;ON IFF PRINTER EXISTS (AS DETERMINED DURING INITIALIZATION) CAUTION:  ONLY FOR KS (10/10/77)
;DEFSTR FOR LPTERR WORD

LP%ERR==177777B35		;HARDWARE STATUS FIELD
LP%FRK==777777B17		;FORK ID OF OWNING PROCESS
LP%MSG==1B18			;SUPPRESS STANDARD MESSAGE
LP%PCI==1B19			;PAGE COUNTER HAS INTERRUPTED

DEFSTR (LPERR,LPTERR,35,16)	;LAST ERROR INDICATION
DEFSTR (LPFRK,LPTERR,17,18)	;FORK ID OF OWNING PSI PROCESS
DEFSTR (LPMSG,LPTERR,18,1)	;IF =1, SUPPRESS STANDARD MESSAGE
DEFSTR (LPPCI,LPTERR,19,1)	;PAGE COUNTER HAS INTERRUPTED

; DEFSTRS FOR LPTOFN WORD

DEFSTR (VFUOFN,LPTOFN,17,18)	;VFU OFN
DEFSTR (RAMOFN,LPTOFN,35,18)	;RAM OFN

.LRPAG==10			;BYTE OFFSET TO PAGE COUNTER REGISTER
LP%IRP==1B32			;INTERRUPT REQUEST PENDING
LP%RBR==1B33			;RAM (OR VFU) BEING RELOADED
LP%LTR==1B34			;RAM REQUIRES RELOADING
LP%LVF==1B35			;VFU REQUIRES RELOADING


DEFSTR (PGFNC,PGDATA,15,16)	;FUNCTION CODE - LOAD PAGE COUNTER
DEFSTR (PGENB,PGDATA,16,1)	;ENABLE INTERRUPTS BIT
DEFSTR (PGCTR,PGDATA,31,15)	;PAGE COUNTER VALUE
DEFSTR (LPLVF,PGDATA,35,1)	;VFU REQUIRES RELOADING
DEFSTR (LPLTR,PGDATA,34,1)	;TRANSLATION RAM REQUIRES RELOADING
DEFSTR (LPRBR,PGDATA,33,1)	;RAM (OR VFU) BEING RELOADED
DEFSTR (LPIRP,PGDATA,32,1)	;INTERRUPT REQUEST PENDING

; DEFSTRS FOR LPTCLS WORD

LP%BSZ==77B5			;BYTE SIZE OF OPENF
LP%NOE==1B17			;NOTE OCCURRENCE OF END-OF-FILE
LP%RLD==1B16			;FRONT END WAS RELOADED

MSKSTR (LPBSZ,LPTCLS,LP%BSZ)	;BYTE SIZE OF OPENF
MSKSTR (LPNOE,LPTCLS,LP%NOE)	;NOTE OCCURRENCE OF EOF
MSKSTR (LPRLD,LPTCLS,LP%RLD)	;FRONT END WAS RELOADED
	SWAPCD			; IS SWAPPABLE
LPTDTB::DTBBAD (DESX9)		; Set directory
	DTBBAD (DESX9)		; Name lookup
	DTBBAD (DESX9)		; Extension
	DTBBAD (DESX9)		; Version
	DTBBAD (DESX9)		;PROTECTION INSERTION
	DTBBAD (DESX9)		;ACCOUNT INSERTION
	DTBBAD (DESX9)		;STATUS INSERTION
	DTBDSP (LPTOPN)
	DTBBAD (DESX9)
	DTBDSP (LPTSQO)		; Output
	DTBDSP (LPTCLZ)
	DTBBAD (DESX9)		; Rename
	DTBBAD (DESX9)		; Delete
	DTBBAD (DUMPX6)		; DUMPI
	DTBBAD (DUMPX6)		; DUMPO
	DTBBAD (DESX9)		; Mount
	DTBBAD (DESX9)		; Dismount
	DTBBAD (DESX9)		; Initialize directory
	DTBDSP (LPTMTO)		; MTOPR
	DTBDSP (LPDSTS)		; GET STATUS
	DTBBAD (DESX9)		; Set status
	DTBSKP			; RECORD OUT
	DTBDSP (RFTADN)		; READ TAD
	DTBDSP (SFTADN)		; SET TAD
	DTBDSP (BIOINP)		;SET JFN FOR INPUT
	DTBDSP (BIOOUT)		;SET JFN FOR OUTPUT
	DTBBAD (GJFX49)		;CHECK ATTRIBUTE

	DTBLEN==:.-LPTDTB	;GLOBAL LENGTH OF DISPATCH TABLE
; Initialize line printer

	RESCD

LPTINI::
	MOVEI U,FELPTN		;GET THE NUMBER OF FE LPT'S
	MOVEI B,FELPVT		;GET VECTOR TABLE ADDRESSES
FELPLP:	SOJL U,NXTLPT		;LEAVE LOOP IF NO MORE FE LPT'S
	STOR B,LPDEVT,(U)	;UPDATE UNIT NUMBER
	JRST FELPLP		;LOOP FOR REST OF FE LPT'S
NXTLPT:	MOVEI U,KSLPTN		;GET NUMBER OF LP20'S ON KS
	MOVEI B,FELPVT		;GET VECTOR TABLE NAME
KSLPIN:	SOJL U,NXTLP1		;LEAVE LOOP IF NO MORE
	STOR B,LPDEVT,(U)	;STORE VECTOR TABLE ADDRESS
	JRST KSLPIN		;LOOP FOR REST OF KS LP20'S
NXTLP1:	MOVEI U,0
	LOAD A,LPDEVT,(U)
	CALL @SNDINI(A)		;DO SYSTEM-DEPENDENT LINEPRINTER INITIALIZATION
	MOVSI U,-LPTN		;INIT ALL UNITS
LPI1:	MOVEI A,^D60000		;CHECK ALL UNITS ONCE A MINUTE
	ADD A,TODCLK		;FROM NOW
	MOVEM A,LPTCKT(U)	;LPTTIM INTERVAL
	SETZM LPTSTS(U)
	SETZM LPTST1(U)		;CLEAR SECOND STATUS WORD
	SETZM LPTERR(U)		;NO ERROR YET
	SETOM LPTOFN(U)		;INDICATE NO OFN'S FOR RAM, VFU FILES
	SETOM LPTCNT(U)
	SETOM LPTLCK(U)
	MOVEI C,MAXLPA		;DEFAULT LINE ALLOCATION
	STOR C,LPTMX,(U)	;DEFAULT LINE ALLOCATION
	MOVX C,INIPSI		;GET CODE INDICATING PSI NOT ENABLED
	STOR C,LPPSI,(U)	;MARK THAT PSI CHANNEL NOT DECLARED YET
	LOAD A,LPDEVT,(U)
	CALL @GLPTST(A)		;ASK FOR THE STATAS
	AOBJN U,LPI1
	RET

LPTRST::MOVSI U,-LPTN		;SET UP TO LOOP THRU LP'S
LPRST1:	LOAD A,LPDEVT,(U)	;GET TABLE ENTRY ADDRESS
	CALL @SNDRST(A)		;DO INIT
	AOBJN U,LPRST1		;LOOP UNTIL DONE
	RET			;RETURN
	SWAPCD

; Open line printer

LPTOPN:	SKIPN PROFLG		;EVER GOING TO USE PRIMARY PROTOCOL ?
	RETBAD (OPNX18)		;NO, DO NOT ALLOW ANY LPT OPEN'S
	HLRZ U,DEV		;GET UNIT NUMBER
	LOCK LPTLCK(U),<CALL LCKTST>
	JN LPOPN,(U),[	UNLOCK LPTLCK(U)
		MOVEI A,OPNX9
		RET]		;FAIL
	JE LPTOL,(U),[CALL CHKOFL ;SEE IF OPENF'S ALLOWED IF OFFLINE
		 SKIPA		;NO
		JRST .+1	;YES, LET THE OPENF PROCEDE
		UNLOCK LPTLCK(U) ;LPT IS OFFLINE
		MOVEI A,OPNX8	;TELL PROGRAM
		RET]		;AND DONE
	TQNE <WRTF>		;WANT WRITE?
	TQNE <READF>		;YES. AND NO READ?
	JRST [	UNLOCK LPTLCK(U) ;NO. CAN'T DO IT THAT WAY
		RETBAD (OPNX13)] ;BOMB IT
	SETONE LPOPN,(U)	;LPT IS NOW OPENED
	MOVE A,FORKX		;GET ID OF OPENER
	STOR A,LPFRK,(U)	;REMEMBER FOR SYSERR
	MOVX A,INIPSI		;GET FLAG INDICATING NO PSI ENABLED
	STOR A,LPPSI,(U)	;MARK THAT NO PSI IS ENABLED
	SETZB A,B		;SET TO 0, NO INTERRUPTS
	CALL LODPAG		;GO INITIALIZE THE PAGE COUNTER
	 JFCL			;SHOULD NOT FAIL
	SETZRO LPPCI,(U)	;INDICATE PAGE COUNTER HASN'T INTERRUPTED YET
	SETZRO LPTHE,(U)	;CLEAR HARD ERROR
	HRRZ A,LPTRLP(U)	;BUFFER ADDRESS
	MOVES (A)
	CALL FPTA		; Get ptn.pn for buffer
	CALL MLKPG		; Lock the RLP(U)	;BUFFER ADDRESS
	SETZRO LPNOE,(U)	;DO NOT NOTE OCCURRENCE OF EOF
	LDB A,PBYTSZ		;GET BYTE SIZE SPECIFIED ON OPENF
	STOR A,LPBSZ,(U)	;STORE BYTE SIZE OF OPENF
	CALL INIFIL		;GO SET UP ALL POINTERS
	SETZM FILBYN(JFN)	;INITIALIZE COUNT OF TOTAL BYTES OUTPUT
	LOAD A,LPDEVT,(U)	;GET DEVICE TYPE
	CALL @SNDOPN(A)		;DO DEVICE DEPENDENT OPEN FUNCTIONS
	UNLOCK LPTLCK(U)
	RETSKP
; ROUTINE TO INITIALIZE THE INTERRUPT COUNTS AND BUFFER FLAGS

INIFIL:	NOSKED			;TURN OFF SCHEDULER
	CHNOFF LPTCHN		;TURN OFF THE LP CHANNEL
	SETZRO <LPOBF,ALTP,ALTI>,(U) ;INTIALZIE POINTERS
	SETOM LPTCNT(U)		;YES MAKE STOP IMMEDIATELY
	SETZM LPTICT(U)		;ZERO INTERRUPT COUNT
	CHNON LPTCHN		;TURN ON LP CHANNEL
	OKSKED			;AND THE SCHEDULER
;	CALLRET SETBUF		;AND GO INIT BUFFERS AS WELL


; ROUTINE TO SET UP JFN BLOCK POINTERS AND COUNTS


SETBUF:	HRRZ A,LPTRLP(U)	;GET BASE ADDRESS OF LPT BUFFERS
	OPSTR <SKIPE>,ALTP,(U)	;USING SECOND BUFFER FOR THIS UNIT ?
	ADDI A,NLPBF		;YES, GET ADDRESS OF SECOND BUFFER
	HRLI A,(POINT 7,)	;GET POINTER FOR 7-BIT BYTES
	LOAD B,LPBSZ,(U)	;GET BYTE SIZE FROM OPENF
	CAIN B,^D8		;USING 8-BIT BYTES ?
	HRLI A,(POINT 8,)	;YES, GET POINTER FOR 8-BIT BYTES
	MOVEM A,FILBYT(JFN)	;STORE POINTER TO CURRENT BUFFER
	MOVEI A,^D36		;GET NUMBER OF BITS PER WORD
	LOAD B,LPBSZ,(U)	;GET BYTE SIZE FROM OPENF
	CAIE B,^D8		;USING 8-BIT BYTES ?
	MOVEI B,7		;NO, ASSUME 7-BIT BYTES
	IDIV A,B		;COMPUTE # OF BYTES PER WORD
	IMULI A,NLPBF		;COMPUTE # OF BYTES PER BUFFER
	MOVEM A,FILCNT(JFN)	;STORE # OF BYTES PER BUFFER
	RET			;RETURN
; Close line printer

LPTCLZ:	HLRZ U,DEV		;GET UNIT NUMBER
	JN LPOBF,(U),LPTCL2	;IF BEING CLOSED, DON'T BLOCK
	TXNN A,CZ%ABT		;DOING AN ABORT CLOSE ?
	JRST [	CALL LPTEOF	;NO. SEND LAST BUFFER
		TQNE <ERRF>	;SERVICE ROUTINE FOUND AN ERROR?
		RET		;YES. RETURN NOW
		LOAD A,LPDEVT,(U)
		CALL @SNDEOF(A)	;GO ASK FOR EOF JUST IN CASE
		MOVSI A,0(U)	;NO. SET UP SCHEDULER TEST
		HRRI A,LPTDIS	;TO WAIT FOR BUFFERS AND ACK
		RET]		;AND DONE
	CALL FLUSH		;YES. GO DO FLUSH
	 JFCL			;WILL GO
	JRST LPTCL3		;GO FORCE THE CLOSE

;NORMAL CLOSE. CHECK FOR ERROR

LPTCL2:	JN LPTHE,(U),[	SETZRO LPOBF,(U) ;NOT CLOSING ANYMORE
			JRST GIVERR] ;AND GIVE AN ERROR
LPTCL3:	LOCK LPTLCK(U),<CALL LCKTST> ;LOCK UP THIS LPT
	SETZM LPTCLS(U)		;CLEAR BYTE SIZE FROM OPENF
	SETOM LPTCNT(U)		;SET # OF BUFFERS TO ZERO
	SETZM LPTICT(U)		;NO BYTES TO SEND
	LOAD A,LPTOL,(U)	;GET ON-LINE INDICATION
	LOAD B,LPTMX,(U)	;SAVE ALLOCATION
	SETZM LPTSTS(U)		;CLEAR FLAGS
	STOR A,LPTOL,(U)	;PRESERVE THIS INDICATION
	STOR B,LPTMX,(U)	;RESTORE ALLOCATION
	MOVX A,INIPSI		;GET FLAG SAYING NO PSI ENABLE WAS DONE
	STOR A,LPPSI,(U)	;SAVE FLAG IN STATUS WORD
	SETZRO LPMSG,(U)	;DO NOT SUPPRESS CTY MESSAGES ANY MORE
	HRRZ A,LPTRLP(U)	;NOW UNLOCK BUFFER PAGE
	CALL FPTA
	CALL MULKPG
	UNLOCK LPTLCK(U)	;RELEASE THE LPT LOCK
	RETSKP

;SCHEDULER TEST FOR LPTCLZ

	RESCD
LPTDIS:	JN LPTHE,(A),1(4)	;IF FOUND ERROR, WAKE UP NOW
	OPSTR <SKIPN>,LPTFE,(A)	;BYTES STILL IN FE?
	SKIPL LPTCNT(A)		;NO. ALL BUFFERS CLEARED?
	JRST 0(4)		;CAN'T WAKE UP YET
	JRST 1(4)		;TEST SATISFIED
	SWAPCD			;RETURN TO SWAPPABLE MONITOR
; ROUTINE TO FORCE OUT REMAINING DATA TO LPT

LPTEOF:	MOVEI A,.CHNUL		;FILL REMAINDER OF BUFFER WITH NULLS
LPTEO1:	JN LPTHE,(U),[		;GOT AN ERROR?
		CALL GIVERR	;GENERATE ERROR, FIX BUFFERS
		RETBAD()]	;AND RETURN
	SKIPN FILCNT(JFN)	;AT END OF BUFFER NOW?
	JRST LPEOF1		;YES, GO WAIT FOR ALL BUFFERS TO FINISH
	CALL LPTSQO
	TQNN <ERRF>		;SERVICE ROUTINE FIND AN ERROR?
	TQNE <BLKF>		;SERVICE ROUTINE WANTS TO BLOCK?
	RET			;YES, TELL CALLER THAT
	JRST LPTEO1		;NO. FILL UP ALL OF BUFFER

LPEOF1:	SETONE LPOBF,(U)	;SET OUTPUT BEING FLUSHED
	AOSN LPTCNT(U)		;TELL INTERRUPT LEVEL OF THIS BUFFER
	CALL LPTSND		;START LPT IF WASNT GOING ALREADY
LPEOF2:	MOVSI A,0(U)		;SAVE UNIT NO OF LPT
	HRRI A,LPTDIS		;WAIT FOR END OF BUFFERS OR ERROR
	TQO <BLKF>		;REQUEST CALLER TO BLOCK
	RET			;AND RETURN
; Line printer sequential character output

LPTSQO:	ASUBR <CHARIN>		;ALLOCATE SPACE AND REMEMBER THE BYTE
	HLRZ U,DEV
LPSQO:	JE LPLVF,(U),LPSQ05	;VFU REQUIRE RELOADING ?
	JE LPTOL,(U),[LOAD A,LPDEVT,(U)
			CALL @SNDFLO(A) ;FLUSH REMAINING OUTPUT
		      JRST GIVERR] ;GIVE PROCESS ERROR AND RETURN
	MOVEI B,VFUFIL		;GET BASE ADDRESS OF VFU FILENAME BUFFER
	MOVEI C,.MOLVF		;GET FUNCTION TO PERFORM
	CALL LPTLOD		;GO RE-LOAD THE VFU
	 RET			;ERROR OR BLOCK NEEDED, RETURN TO SOUT

LPSQ05:	JE LPLTR,(U),LPSQ10	;DOES THE RAM NEED RELOADING ?
	MOVEI B,RAMFIL		;GET BASE ADDRESS OF RAM FILENAME BUFFER
	MOVEI C,.MOLTR		;GET FUNCTION TO PERFORM
	CALL LPTLOD		;GO RELOAD THE RAM
	 RET			;ERROR OR BLOCK NEEDED, RETURN TO SOUT

LPSQ10:	JN LPTHE,(U),GIVERR	;HARD ERROR UP ON DEVICE
	JN LPOBF,(U),[	CALL LPNOP2 ;IF WAITING FOR -11, CONTINUE
			 RET	;WANTS TO BLOCK, OR ERROR
			JRST .+1] ;ALL DONE WAITING
	SETZRO LPRLD,(U)	;FORGET RELOADED STATUS OF FRONT END
	SKIPN FILCNT(JFN)	;IS BUFFER READY FOR PRINTING?
	JRST [	AOSN LPTCNT(U)	;GIVE BUFFER TO INTERRUPT LEVEL
		CALL LPTSND	;AND START IT IF NECESSARY
		JRST .+1]
	SOSGE FILCNT(JFN)	;ANY MORE ROOM IN BUFFER?
	JRST [	CALL LPSQ20	;NO. GET ANOTHER BUFFER
		 RET		;WANTS TO BLOCK
		JRST LPSQO]	;GOT ONE. GO USE IT
	MOVE A,CHARIN		;RECOVER THE BYTE
	IDPB A,FILBYT(JFN)	;YES, STORE THE CHARACTER
	AOS FILBYN(JFN)		;INCREMENT TOTAL # OF BYTES OUTPUT
	RET			;THEN RETURN
;SUBROUTINE TO GET NEXT BUFFER FOR PRINTING.
;RETURNS:	+1 NO BUFFER AVAILABLE. ARRANGE FOR BLOCK
;		+2 BUFFER SET UP IN JFN BLOCK

LPSQ20:	CALL BUFWAT		;GO SEE IF THERE IS A BUFFER FREE
	 RET			;NO. RETURN TO BLOCK
	LOAD C,ALTP,(U)		;GET BUFFER POINTER
	XORI C,1		;TOGGLE IT
	STOR C,ALTP,(U)		;NEW POINTER
	CALL SETBUF		;GO SET UP JFN BLOCK COUNTS AND BUFFERS
	RETSKP			;DONE


; HERE TO GIVE PROCESS AN ERROR

GIVERR:	SETZRO LPTHE,(U)	;CLEAR ERROR BIT IN STATUS WORD
	CALL INIFIL		;RESET BUFFER POINTERS AND COUNTS
	TQO <ERRF>		;TELL PROCESS ABOUT ERROR
	RETBAD (IOX5)		;RETURN ERROR
; ROUTINE TO RE-LOAD THE VFU OR RAM WITH LAST FILE USED FOR LOADING
;
; CALL:	B/  RAMFIL	OR	 VFUFIL
;	C/  .MOLTR	OR	 .MOLVF
;		CALL LPTLOD
; RETURNS: +1	 ERROR, COULD NOT LOAD
;	   +2	SUCCESS

LPTLOD:	STKVAR <BASADR,CODE,CAPS>	;ALLOCATE SPACE FOR ADDRESS, CODE, CAPS
	MOVEM B,BASADR		;SAVE BASE ADR OF FILENAME BUFFER AREA
	MOVEM C,CODE		;SAVE FUNCTION TO PERFORM
	JE LPTHE,(U),LPTLD1	;WAS DATA POSSIBLY LOST ?
	CALL LPTFLO		;YES, FLUSH BUFFERS, AND INIT LPT
	 JFCL			;IT BETTER WORK
LPTLD1:	MOVE T1,CAPENB		;GET CURRENTLY ENABLE CAPABILITIES
	MOVEM T1,CAPS		;SAVE CURRENT CAPABILITIES
	MOVX T1,SC%WHL		;GET WHEEL CAPABILITY
	MOVEM T1,CAPENB		;MAKE THIS PROCESS A WHEEL
	MOVE B,BASADR		;GET BACK BASE ADDRESS OF FILENAME BUFFER
	MOVEI A,LPFLSZ		;GET SIZE OF FILENAME BUFFERS
	IMULI A,(U)		;GET OFFSET TO PROPER FILENAME BUFFER
	ADDI B,(A)		;GET POINTER TO PROPER FILENAME BUFFER
	MOVX A,177B6		;SEE IF NAME ASSIGNED YET
	TDNN A,0(B)		;IS IT
	JRST GIVERR		;NO. SET ERRF AND RETURN
	HRLI B,(POINT 7,)	;FORM POINTER TO FILENAME BUFFER
	MOVX A,GJ%SHT!GJ%OLD	;SHORT CALL GTJFN, EXISTING FILE
	GTJFN			;GET A JFN FOR FILE TO BE LOADED
	 JRST [	TQO <ERRF>	;SAY SOMETHING FAILED
		JRST FIXCAP]	;AND GO GIVE UP
	MOVE B,CODE		;GET FUNCTION TO BE PERFORMED
	CALL LODLPT		;CALL ROUTINE TO DO THE WORK
	 SKIPA			;FAIL, DO NOT SKIP RETURN
	AOS (P)			;SUCCESS, GIVE SKIP RETURN
				; AND FALL THROUGH TO FIXCAP

; HERE ON AN ERROR TO RESTORE ORIGINAL CAPABILITIES

FIXCAP:	MOVE T4,CAPS		;GET ORIGINAL CAPABILITIES
	MOVEM T4,CAPENB		;RESTORE INITIAL CAPABILITIES
	RET			;RETURN

; ROUTINE TO WAIT UNTIL A BUFFER IS FREE

BUFWAT:	SKIPG LPTCNT(U)		;ANY FREE BUFFERS?
	RETSKP			;YES, GIVE OK RETURN
	HRLI A,LPTCNT(U)	;GET ADDRESS OF COUNT
	HRRI A,DISLET		;WANT TO WAIT TILL ONE IS FREE
	TQO <BLKF>		;TELL BOUT TO BLOCK
	RET			;AND RETURN
;GET DEVICE DEPENDENT STATUS

LPDSTS:	HLRZ U,DEV		;GET UNIT
	LOAD A,LPPAG,(U)	;GET LAST PAGE COUNTER VALUE
	UMOVEM A,3		;STORE PAGE COUNTER IN USER'S AC 3
	CALLRET GETSTS		;GO GET SOFTWARE,,HARDWARE STATUS AND RETURN


; ROUTINE TO RETURN SOFTWARE,,HARDWARE STATUS
;
; CALL:		CALL GETSTS
; RETURNS: +1 ALWAYS, WITH
;		A/ SOFTWARE,,HARDWARE STATUS + MO%LCP IF LPT IS LOWER CASE

GETSTS:	LOAD A,LPERR,(U)	;GET LAST HARDWARE STATUS WORD
	LOAD B,LPSST,(U)	;GET LAST SOFTWARE STATUS WORD
	HRL A,B			;GET SOFTWARE,,HARDWARE STATUS
	LOAD B,LPLCP,(U)	;GET "PRINTER IS LOWER CASE" FLAG
	SKIPE B			;IS PRINTER LOWER CASE ?
	TXO A,MO%LCP		;YES, INDICATE LOWER CASE LPT
	JE LPRLD,(U),R		;DONE IF FRONT END HASN'T BEEN RELOADED,
	TXO A,MO%RLD		; ELSE, MARK THAT FRONT-END WAS RELOADED
	RET			;AND DONE


; JSYS TO INTITIALLY LOAD THE VFU AND RAM FILES
;
; ACCEPTS IN USER AC'S:
;	A/ JFN OF FILE TO BE LOADED
;	B/ MO%LCP IF LOWERCASE PRINTER + FUNCTION CODE
;					(.MOLVF TO LOAD VFU; .MOLTR TO LOAD RAM)
;	C/ UNIT NUMBER OF PRINTER
;		LPINI
; RETURNS +1 ALWAYS

.LPINI::MCENT			;MONITOR CONTEXT ENTRANCE
	MOVE A,CAPENB		;GET ENABLED CAPABILTIES
	TXNN A,SC%WHL!SC%OPR	;IS THIS PROCESS CURRENTLY PRIVILEGED ?
	ITERR (LPINX2)		;NO, ISSUE ERROR
	SKIPN PROFLG		;DOING PRIMARY PROTOCOL?
	ITERR (OPNX18)		;NO. DON'T LOAD IT THEN
	UMOVE U,3		;GET UNIT NUMBER TO BE LOADED
	CAIL U,0		;CHECK FOR VALID UNIT NUMBER,
	CAILE U,LPTN		; BETWEEN 0 AND LPTN
	ITERR (LPINX1)		;INVALID UNIT NUMBER
	JN LPOPN,(U),[ITERR (LPINX3)] ;ERROR IF ALREADY OPENED
	XCTU [HRRZ A,2]		;GET FUNCTION CODE
	UMOVE B,1		;GET JFN OF FILE TO BE LOADED
	CALL SAVNAM		;SAVE AWAY NAME OF FILE, EVEN IF LOADING ERROR
	UMOVE A,1		;GET JFN OF FILE TO BE LOADED
	UMOVE B,2		;GET FUNCTION CODE AND FLAG (.MOLVF OR .MOLTR)
	SETZRO LPLCP,(U)	;ASSUME PRINTER NOT LOWERCASE
	TXZE B,MO%LCP		;IS PRINTER SUPPOSED TO BE LOWERCASE ?
	JRST [ SETONE LPLCP,(U)	;YES, INDICATE PRINTER IS LOWERCASE
		JRST .+1]	;CONTINUE
	CALL LODLPT		;GO LOAD THE VFU OR RAM
	 JFCL			;IGNORE ERRORS
	JRST MRETN		;RETURN TO USER
;ROUTINE TO IMPLEMENT THE MTOPR FUNCTIONS

LPTMTO:	TQNN <OPNF>		;CHECK TO SEE IF OPENED
	RETBAD (CLSX1)		;ILLEGAL IF NOT OPENED
	HLRZ U,DEV		;GET UNIT NUMBER
	MOVSI A,-LPMSIZ		;SET UP AOBJN POINTER TO SEARCH FOR FUNCTION
LPMT10:	HLRZ C,LPMTAB(A)	;GET FUNCTION CODE FROM TABLE
	CAMN C,B		;FOUND REQUESTED FUNCTION ?
	JRST LPMT20		;YES, GO DISPATCH
	AOBJN A,LPMT10		;NO, LOOP OVER DISPATCH TABLE
	RETBAD (MTOX1)		;NOT FOUND, RETURN INVALID FUNCTION ERROR

; HERE WITH A VALID FUNCTION CODE

LPMT20:	HRRZ C,LPMTAB(A)	;GET ROUTINE TO PROCESS REQUEST
	CALLRET (C)		;CALL PROCESSING ROUTINE AND RETURN

; DISPATCH TABLE FOR LPT MTOPR FUNCTIONS

LPMTAB:	.MOLVF,,LPTLVF		;LOAD VFU
	.MOLTR,,LPTLTR		;LOAD TRANSLATION RAM
	.MOSTS,,LPSTAT		;SET STATUS
	.MORST,,LPRSTS		;READ STATUS
	.MORVF,,LPTRVF		;READ VFU FILE NAME
	.MORTR,,LPTRTR		;READ RAM FILE NAME
	.MOFLO,,LPTFLO		;FLUSH OUTPUT
	.MOPSI,,LPTPSI		;ENABLE INTERRUPTS
	.MONOP,,LPTNOP		;NOP (WAIT FOR I/O TO COMPLETE)

	LPMSIZ==.-LPMTAB	;SIZE OF LPMTAB
; .MOLVF - LOAD VFU FUNCTION

LPTLVF:	JN LPRBR,(U),LODCMP	;JUMP IF RAM ALREADY BEING RELOADED
	MOVEI T1,1		;GET OFFSET TO JFN IN ARGUMENT BLOCK
	CALL GETWRD		;GET JFN FROM USER
	 RETBAD (MTOX13)	;RETURN ARGUMENT BLOCK TOO SMALL
	MOVE A,B		;GET JFN OF VFU FILE
	MOVEI B,.MOLVF		;GET FUNCTION FOR "LOAD VFU"
	CALL LODLPT		;GO LOAD THE VFU
	 JRST LODBLK		;GO SEE IF BLOCK WANTED
	RETSKP			;SUCCESS, RETURN

; .MOLTR - LOAD TRANSLATION RAM

LPTLTR:	JN LPRBR,(U),LODCMP	;JUMP IF RAM ALREADY BEING RELOADED
	MOVEI A,1		;GET OFFSET TO JFN IN ARGUMENT BLOCK
	CALL GETWRD		;GET JFN FROM USER
	 RETBAD (MTOX13)	;RETURN ARGUMENT BLOCK TOO SMALL
	MOVE A,B		;GET JFN FOR RAM FILE
	MOVEI B,.MOLTR		;GET CORRECT FUNCTION CODE
	CALL LODLPT		;GO LOAD RAM
	 JRST LODBLK		;GO SEE IF BLOCK WANTED
	RETSKP			;RETURN


;HERE ON RETURN FROM LODLPT TO SEE IF BLOCK NEEDED

LODBLK:	TQNN <BLKF>		;BLOCK REQUESTED?
	RET			;NO. GIVE UP
	SETONE LPRBR,(U)	;YES. REMEBER ONCE HERE
	RET			;AND GO BLOCK

; HERE WHEN RAM ALREADY BEING RELOADED, INDICATE LOADING COMPLETE

LODCMP:	SETZRO LPRBR,(U)	;MARK THAT RAM NO LONGER BEING RELOADED
	RETSKP			;SUCCESS RETURN
; .MOPSI - ENABLE FOR PSI INTERRUPTS ON OPERATOR-ATTENTION CONDITIONS

LPTPSI:	MOVEI A,1		;GET OFFSET TO PSI CHANNEL IN ARG BLOCK
	CALL GETWRD		;GET PSI CHANNEL TO ENABLE
	 RETBAD (MTOX13)	;ARGUMENT BLOCK TOO SMALL
	CAIL B,0		;CHECK THAT GIVEN PSI CHANNEL IS A VALID
	CAILE B,5		; ASSIGNABLE CHANNEL
	JRST [	CAIL B,^D24	;CHECK THAT GIVEN PSI CHANNEL IS A VALID
		CAILE B,^D35	; ASSIGNABLE CHANNEL
		RETBAD (MTOX14)	;BAD PSI CHANNEL NUMBER GIVEN
		JRST .+1 ]	;PSI CHANNEL OK, RETURN
	STOR B,LPPSI,(U)	;SAVE PSI CHANNEL TO INTERRUPT ON
	MOVEI A,2		;GET OFFSET TO FLAG WORD
	CALL GETWRD		;GET FLAGS FROM USER
	 RETSKP			;NO FLAG WORD, RETURN
	TXNN B,MO%MSG		;USER WANT TO SUPPRESS MESSAGES ?
	RETSKP			;NO, RETURN
	SETONE LPMSG,(U)	;YES, MARK THAT "PROBLEM ON DEVICE" ISN'T WANTED
	RETSKP			;RETURN TO USER


; SCHEDULER TEST ROUTINE TO WAIT FOR COMPLETION OF RAM OR VFU LOADING

	RESCD
LODWAT:	JE LP%LHC,(1),0(4)	;RETURN IF LOADING-HAS-COMPLETED FLAG IS OFF
	JRST 1(4)		;LOADING-HAS-COMPLETED FLAG ON, RETURN SUCCESS
	SWAPCD
; .MOFLO - FLUSH OUTPUT TO LPT

LPTFLO:	CALL INIFIL		;GO INITIALIZE BUFFER FLAGS AND INTERRUPT COUNT
	JN LPMWS,(U),[	SETZRO LPMWS,(U) ;NOT WAITING FOR STATUS
			JRST RSKP]	;RETURN
	LOAD A,LPDEVT,(U)
	CALL @SNDFLO(A)		;NOW SEND A FLUSH TO THE -11
	LOAD A,LPDEVT,(U)
	CALL @GLPTST(A)		;ASK FOR STATUS IN CASE ITS NEEDED
;	JRST LPRSTS



; FLUSH - INTERNAL FLUSH ROUTINE

FLUSH:	CALL INIFIL		;GO INITIALIZE BUFFER FLAGS AND INTERRUPT COUNT
	LOAD A,LPDEVT,(U)
	CALL @SNDFLO(A)		;NOW SEND A FLUSH TO THE -11
	LOAD A,LPDEVT,(U)
	CALL @GLPTST(A)		;ASK FOR STATUS IN CASE ITS NEEDED
	RET			;DONE, RETURN
; .MORST - READ LINE PRINTER STATUS

LPRSTS:	JN LPMWS,(U),HAVSTS	;JUMP IF MTOPR WAITING FOR STATUS ALREADY
	SETZRO LPSHA,(U)	;INITIALIZE STATUS HAS ARRIVED FLAG
	LOAD A,LPDEVT,(U)
	CALL @GLPTST(A)		;GO ASK -11 FOR LPT STATUS
	SETONE LPMWS,(U)	;REMEBER WAITING FOR STATUS
	MOVSI A,LPTST1(U)	;GET STATUS WORD ADDRESS
	HRRI A,STSWAT		;GET ADR OF ROUTINE TO CHECK FOR STATUS ARRIVAL
	TQO <BLKF>		;TELL MTOPR TO BLOCK
	RET			;RETURN

; HERE WHEN STATUS REQUESTED BY .MORST HAS ARRIVED

HAVSTS:	SETZRO LPMWS,(U)	;MARK THAT MTOPR NOT WAITING FOR STATUS ANY MORE
	CALL GETSTS		;GET SOFTWARE,,HARDWARE STATUS IN A
	MOVE B,A		;COPY STATUS FOR PUTWRD ROUTINE
	MOVEI A,1		;GET OFFSET INTO USER'S ARGUMENT BLOCK
	CALL PUTWRD		;STORE STATUS IN USER ARGUMENT BLOCK
	 RETBAD (MTOX13)	;ARGUMENT BLOCK TOO SMALL
	MOVEI A,2		;GET OFFSET INTO USER'S ARGUMENT BLOCK
	LOAD B,LPPAG,(U)	;GET LPT PAGE COUNTER REGISTER
	CALL PUTWRD		;STORE PAGE COUNTER IN USER'S ARG BLOCK
	 RETBAD (MTOX13)	;ARGUMENT BLOCK TOO SMALL
	RETSKP			;RETURN TO USER

	RESCD
; ROUTINE TO TEST FOR STATUS ARRIVAL
; CALLED FROM SCHEDULER

STSWAT:	JE LP%SHA,(1),0(4)	;RETURN NON-SKIP IF STATUS NOT HERE YET
	JRST 1(4)		;RETURN SKIP, STATUS HAS ARRIVED

	SWAPCD
; .MOSTS - SET LPT STATUS

LPSTAT:	MOVEI A,1		;GET OFFSET INTO USER'S ARGUMENT BLOCK
	CALL GETWRD		;GET USER'S FLAGS
	 RETSKP			;RAN OUT OF ARGUMENTS, RETURN
	TXNE B,MO%SER		;CLEAR SOFTWARE ERROR ?
	CALL SNDACK		;YES, GO SEND AN ACK TO THE -11
	MOVEI A,1		;GET OFFSET INTO USER'S ARGUMENT BLOCK
	CALL GETWRD		;GET USER'S FLAGS
	 RETSKP			;RAN OUT OF ARGUMENTS, RETURN
	LOAD A,LPDEVT,(U)	;ASSUME CALL TO SNDEOF
	TXNE B,MO%EOF		;SEND AN EOF TO THE -11 ?
	CALL @SNDEOF(A)		;YES GO SEND AN EOF TO THE -11
	MOVEI T1,1		;GET OFFSET INTO USER'S ARGUMENT BLOCK
	CALL GETWRD		;GET USER'S FLAGS
	 RETSKP			;RAN OUT OF ARGUMENTS, RETURN
	LOAD T2,MO%LCP,T2	;GET THE LOWERCASE SETTING DESIRED
	STOR T2,LPLCP,(U)	; AND SET IT FOR THE PRINTER
	MOVEI A,2		;GET OFFSET TO PAGE COUNTER IN ARG BLOCK
	CALL GETWRD		;GET PAGE COUNTER FROM USER ARGUMENT BLOCK
	 RETSKP			;RETURN, PAGE COUNTER NOT GIVEN
	CAMN B,[-1]		;DID USER WANT TO IGNORE PAGE COUNTER ?
	RETSKP			;YES, RETURN
	MOVE A,B		;NO, GET VALUE TO SET INTO PAGE COUNTER
	SKIPE B			;DID USER WANT TO ENABLE PSI INTERRUPTS ?
	SETOM B			;YES, INDICATE INTERRUPTS SHOULD BE ENABLED
	CALL LODPAG		;GO LOAD THE PAGE COUNTER
	 JFCL			;SHOULD NOT FAIL
	RETSKP			;RETURN TO THE USER


; ROUTINE TO LOAD THE PAGE COUNTER
;
; CALL:	A/ VALUE TO BE LOADED INTO THE PAGE COUNTER
;	B/ 0 - DO NOT ENABLE FOR INTERRUPTS ON PAGE COUNTER OVERFLOW
;	   1 - ENABLE FOR INTERRUPTS ON PAGE COUNTER OVERFLOW
;		CALL LODPAG
; RETURNS: +1	 FAILURE, CALL TO LINE PR CONTROL FAILED
;	   +2	SUCCESS

LODPAG:	SETZRO LPPCI,(U)	;CLEAR PAGE COUNTER INTERRUPTED FLAG
	STOR A,PGCTR,(U)	;STORE VALUE TO BE LOADED INTO PAGE COUNTER
	STOR B,PGENB,(U)	;STORE ENABLE/DISABLE INTERRUPTS BIT
	MOVX A,.DFLPC		;GET SPECIAL DEVICE OPERATION: LOAD PAGE COUNTER
	STOR A,PGFNC,(U)	;STORE SPECIAL DEVICE OPERATION
	LOAD A,LPDEVT,(U)	;FIND CORRECT ROUTINE
	CALLRET @SNDLDP(A)
; ROUTINE TO SEND AN ACK TO THE FRONT-END

SNDACK:	SETZRO LPPCI,(U)	;CLEAR PAGE-COUNTER-INTERRUPTED FLAG
	LOAD A,LPDEVT,(U)	;FIND CORRECT ROUTINE
	CALL @SENACK(A)		;SEND ACK
	JFCL			;IGNORE ERROR
	RET			;RETURN
; .MORVF - READ FILENAME OF LAST VFU FILE LOADED
; .MORTR - READ FILENAME OF LAST RAM FILE LOADED

LPTRVF:	SKIPA C,[VFUFIL]	;GET BASE ADDRESS OF VFU FILENAME BUFFER
LPTRTR:	MOVEI C,RAMFIL		;GET BASE ADDRESS OF RAM FILENAME BUFFER
	STKVAR <REDCNT,REDIPT,REDOPT> ;ALLOCATE SPACE FOR COUNT AND POINTERS
	MOVEI D,LPFLSZ		;GET SIZE OF FILENAME BUFFERS
	IMULI D,(U)		;COMPUTE OFFSET TO PROPER BUFFER
	ADDI C,(D)		;GET ADDRESS OF PROPER FILENAME BUFFER
	HRLI C,(POINT 7,)	;FORM POINTER TO LAST FILENAME LOADED
	MOVEM C,REDIPT		;SAVE INPUT POINTER
	MOVEI A,1		;GET OFFSET TO POINTER IN USER ARG BLOCK
	CALL GETWRD		;GET POINTER TO USER BUFFER
	 RETBAD (MTOX13)	;ARG BLOCK TOO SMALL
	CAML B,[777777,,0]	;-1,,ADR GIVEN ?
	HRLI B,(POINT 7,)	;YES, CHANGE TO STANDARD POINTER
	MOVEM B,REDOPT		;SAVE POINTER TO USER BUFFER
	MOVEI A,2		;GET OFFSET TO COUNT IN USER ARG BLOCK
	CALL GETWRD		;GET COUNT FROM USER ARG BLOCK
	 RETBAD (MTOX13)	;USER ARG BLOCK TOO SMALL
	MOVEM B,REDCNT		;SAVE COUNT

; LOOP TO RETURN FILENAME STRING TO USER

LPTR10:	SOSGE REDCNT		;DECREMENT COUNT, SKIP IF A CHARACTER LEFT
	RETSKP			;DONE, RETURN
	ILDB A,REDIPT		;GET A CHARACTER FROM FILENAME
	XCTBU [IDPB A,REDOPT]	;STORE CHARACTER IN USER BUFFER
	JUMPN A,LPTR10		;IF NOT A NULL, GO CHECK NEXT CHARACTER
	MOVEI A,1		;GET OFFSET TO POINTER IN USER ARG BLOCK
	MOVE B,REDOPT		;GET FINAL POINTER TO USER SPACE
	CALL PUTWRD		;STORE POINTER IN USER ARG BLOCK
	 JFCL			;IGNORE FAILURE
	MOVEI A,2		;GET OFFSET TO COUNT IN USER ARGUMENT BLOCK
	MOVE B,REDCNT		;GET FINAL BYTE COUNT
	CALL PUTWRD		;STORE FINAL BYTE COUNT IN USER ARGUMENT BLOCK
	 JFCL			;IGNORE ERRORS
	RETSKP			;NULL SEEN, RETURN
; .MONOP - WAIT FOR I/O TO STOP
;
; THIS FUNCTION IS ACCOMPLISHED BY SENDING AN END-OF-FILE TO THE -11.  THIS
; TELLS THE -11 TO RETURN AN EOF BACK WHEN ALL DATA RECIEVED PRIOR TO THE
; EOF HAS BEEN OUTPUT.

LPTNOP:	JN LPOBF,(U),LPNOP2	;ALREADY BEEN HERE?
	SETZRO LPSHA,(U)	;CLEAR STATUS ARRIVED
	CALL LPTEOF		;NO. GO SEND SOME DATA
	TQNE <ERRF>		;MADE AN ERROR?
	RETBAD()		;YES. RETURN ERROR INFORMATION
	SETONE LPNOE,(U)	;NOTE OCCURRENCE OF EOF
	RET			;AND GO WAIT FOR BUFFERS TO CLEAR -10

LPNOP2:	JN LPTHE,(U),[	CALL GIVERR ;IF HARD ERROR, REPORT IT
			RETBAD()] ;AND REPORT ERROR UP
	SKIPE FILCNT(JFN)	;HAVE A BUFFER SET UP NOW?
	JRST LPNOP4		;YES. DON'T ALLOCATE A NEW ONE
	CALL LPSQ20		;NO. GO GET ONE
	 JRST [	JE LPTHE,(U),R	;IF WAITING, KEEP WAITING
		TQZ <BLKF>	;NOT BLOCKED
		RETBAD (IOX5)]	;REPORT THE ERROR

LPNOP4:	JE LPSHA,(U),LPNOP3	;HAS STATUS ARRIVED YET?
	SETZRO LPSHA,(U)	;SAY HAVE NO STATUS
	CALL GETSTS		;YES. GET IT
	TXNE A,MO%EOF		;EOF UP?
	JRST [	SETZRO <LPNOE,LPOBF>,(U) ;YES
		RETSKP]		;ALL DONE
LPNOP3:	MOVSI A,LPTST1(U)	;SET UP FOR TEST
	HRRI A,STSWAT		;WAIT FOR NEXT STATUS
	TQO <BLKF>		;SAY BLOCK
	RET			;AND RETURN
;ROUTINE TO LOAD THE VFU OR TRANSLATION RAM
;
; THE FILE TO BE LOADED IS EFFECTIVELY OPENED FOR WRITING BY ACQUIRING AN
; OFN ON IT, SO THAT NO OTHER PROCESS MAY ALTER THE FILE DURING THE TIME
; THAT IT MAY BE USED TO RELOAD THE VFU OR RAM.
;
; CALL:	A/ JFN OF FILE CONTAINING DATA TO LOAD
;	B/ FUNCTION CODE: .MOLVF OR .MOLTR TO LOAD VFU OR RAM
;		CALL LODLPT
; RETURNS: +1	 ERROR, CODE IN A
;	   +2	SUCCESS

LODLPT:	STKVAR <LODFCN,LODJFN,SVFDB>	;ALLOCATE STORAGE FOR FUNCTION CODE AND JFN
	MOVEM A,LODJFN		;SAVE JFN OF FILE
	MOVEM B,LODFCN		;SAVE FUNCTION CODE

; CHECK THAT THE FILE TO BE LOADED IS ON DISK

	IMULI A,MLJFN		;GET INDEXABLE VALUE
	HRRZ A,FILDEV(A)	;GET DISPATCH
	CAIE A,DSKDTB		;IS THIS A DISK?
	RETBAD (MTOX16,<TQO ERRF>) ;NO, RETURN ERROR

; CHECK THAT THE DEVICE HAS A DAVFU

	MOVE A,LODFCN		;GET FUNCTION TO PERFORM
	CAIE A,.MOLVF		;LOADING THE VFU ?
	JRST LPLD03		;NO, GO SEE IF THERE IS OUTPUT PENDING
	LOAD A,LPERR,(U)	;YES, GET LAST HARDWARE STATUS FROM -11
	TXNE A,MO%LVU		;DOES DEVICE HAVE AN OPTICAL VFU ?
	RETBAD (MTOX15,<TQO ERRF>) ;YES, RETURN ERROR

; CHECK THAT NO OUTPUT IS PENDING

LPLD03:	SKIPLE LPTICT(U)	;STILL DATA IN OUR BUFFER ?
	RETBAD (MTOX9,<TQO ERRF>) ;YES, RETURN ERROR
	;..
	;..

; GET OFN ON FILE TO BE LOADED

	LOAD A,VFUOFN,(U)	;GET PREVIOUS VFU FILE OFN
	MOVE B,LODFCN		;GET FUNCTION CODE
	CAIE B,.MOLVF		;LOADING THE VFU ?
	JRST [	LOAD A,RAMOFN,(U) ;NO, GET OFN FOR RAM FILE
		JRST .+1 ]	;CONTINUE IN MAIN-LINE CODE
	CAIE A,-1		;ANY OFN YET ?
	CALL RELOFN		;YES, RELEASE PREVIOUS OFN
	MOVE A,LODJFN		;GET JFN OF FILE TO BE LOADED
	MOVE B,[1,,.FBADR]	;GET ONE WORD, INDEX BLOCK ADDRESS
	MOVEI C,A		;PUT THE INDEX BLOCK ADDRESS IN AC A
	GTFDB			;GET THE INDEX BLOCK ADDRESS OF FILE TO LOAD
	TXO A,FILWB		;TURN ON FILE WRITE BIT (SO NO OTHER OPENS)
	MOVEM A,SVFDB		;SAVE IDX BLOCK
	MOVE B,LODJFN		;GET JFN AGAIN
	IMULI B,MLJFN		;GET INTERNAL INDEX
	HRRZ A,FILDDN(B)	;GET DIR NUMBER
	LOAD B,FILUC,(B)	;GET UNIQUE STR CODE
	HRL A,B			;BUILD 36-BIT DIR NUMBER
	CALL IGTDAL		;GET CURRENT ALLOCATION
	 TDZA A,A		;GIVE HIM ZERO
	SUB A,B			;CORRECT FORM FOR ASOFN
	MOVE D,A		;MOVE TO CORRECT PLACE
	MOVE A,LODJFN		;GET JFN AGAIN
	IMULI A,MLJFN		;CONVERT TO INTERNAL INDEX
	LOAD B,STR,(A)		;GET STR #
	HRRZ C,FILDDN(A)	;GET DIR #
	MOVE A,SVFDB		;RESTORE FDB ADDRS
	CALL ASGOFN		;GET AN OFN FOR FILE TO BE LOADED
	 SETOM A		;ALREADY A WRITER, INDICATE NO OFN FOR FILE
	MOVE B,LODFCN		;GET FUNCTION CODE
	CAIE B,.MOLVF		;LOADING VFU ?
	JRST LPLD05		;NO, SAVE OFN FOR RAM FILE
	STOR A,VFUOFN,(U)	;YES, SAVE OFN FOR VFU FILE
	JRST LPLD10		;GO ON TO READ DATA TO BE LOADED
LPLD05:	STOR A,RAMOFN,(U)	;SAVE OFN FOR RAM FILE
; STORE NAME OF FILE USED FOR LOADING

LPLD10:	MOVE T1,LODFCN		;GET FUNCTION CODE
	MOVE T2,LODJFN		;GET JFN OF FILE THAT WAS LOADED
	CALL SAVNAM		;GO SAVE AWAY NAME OF FILE THAT WAS JUST LOADED

; OPEN THE FILE TO BE LOADED FOR INPUT

	MOVE A,LODJFN		;GET JFN OF FILE TO BE LOADED
	MOVE B,[1,,.FBBYV]	;GET WORD WITH BYTE SIZE
	MOVEI C,C		;STORE IT HERE
	GTFDB			;GET FDB DATUM
	 ERJMP OPNFAI		;FAILED
	MOVX B,OF%RD		;GET ACCESS
	LOAD C,FB%BSZ,C		;EXTRACT BYTE SIZE OF FILE
	STOR C,OF%BSZ,B		;STASH IT AWAY
	OPENF			;OPEN THE FILE
OPNFAI:	 RETBAD (MTOX10,<TQO ERRF>) ;CANNOT OPEN VFU OR RAM FILE

; CHECK THAT PRINTER IS REALLY ON-LINE, DO NOT LOAD IF OFF-LINE

	JE LPTOL,(U),[ MOVX D,MTOX17	;GET ERROR CODE
			JRST LODERR ]	;GO GIVE PROCESS AN ERROR
	;..
	;..

; READ THE DATA TO BE LOADED

	MOVE A,LODJFN		;GET JFN OF FILE CONTAINING DATA
	MOVE B,LPTRLP(U)	;GET BASE ADDRESS OF LPT BUFFER
	OPSTR <SKIPN>,ALTP,(U)	;USING ALTERNATE BUFFER ?
	ADDI B,NLPBF		;NO, USE ALTERNATE BUFFER FOR RAM OR VFU DATA
	HRLI B,(POINT ^D16,)	;FORM BYTE POINTER TO BUFFER
	MOVNI C,2*NLPBF		;GET -<MAX # OF WORDS TO INPUT>
	SIN			;READ DATA TO BE LOADED
	 ERJMP LPLD15		;JUMP ON EOF
	JRST [	MOVX D,MTOX11	;DATA TOO LARGE FOR BUFFERS. GET ERROR CODE
		JRST LODERR ]	;GO CLOSE FILE AND GIVE PROCESS AN ERROR
LPLD15:	GTSTS			;GET CURRENT FILE STATUS
	TXNN B,GS%ERR		;FILE ERROR?
	TXNN B,GS%EOF		;NO. NOW AT EOF?
	JRST [	MOVX D,MTOX12	;NOT ALL DATA READ OR I/O ERROR
		JRST LODERR ]	;GO CLOSE FILE AND GIVE PROCESS AN ERROR
	MOVEI D,2*NLPBF(C)	;ALL OK, GET # OF BYTES READ
	ASH D,1			;COMPUTE # OF 8-BIT BYTES

; SEND DATA TO LPT VIA DTE REQUEST QUEUER

	MOVE C,LODFCN		;GET FUNCTION
	CAIN C,.MOLVF		;WANT TO LOAD THE VFU?
	JRST [	SETZRO LPLVF,(U) ;YES. CLEAR FLAG TO LOAD IT
		MOVSI B,.DFLVF	;GET PROPER FUNCTION
		JRST .+1]	;AND PROCEED
	CAIN C,.MOLTR		;WANT TO LOAD TRNASLATION RAM?
	JRST [	SETZRO LPLTR,(U) ;YES. CLEAR FLAG
		MOVSI B,.DFLTR	;GET PROPER FUNCTION
		JRST .+1]	;AND PROCEED
	SETZRO LPLHC,(U)		;SAY LOADING NOW IN PROGRESS
	LOAD A,LPDEVT,(U)
	CALL @SNDDAT(A)		;SEND DATA
	JFCL
	LOAD A,LPDEVT,(U)
	CALL @SNDEOF(A)		;GO SEND AN EOF TO THE -11
	;..
	;..

; CLOSE THE FILE THAT WAS JUST LOADED

	MOVE A,LODJFN		;GET JFN OF FILE THAT WAS LOADED
	CLOSF			;CLOSE THE FILE
	 JFCL			;IGNORE ERRORS
	MOVSI A,LPTSTS(U)	;GET UNIT NUMBER
	HRRI A,LODWAT		;GET SCHEDULER TEST FOR LOADING DATA SENT
	TQO <BLKF>		;MARK THAT PROCESS SHOULD BLOCK
	RET			;RETURN
; ROUTINE TO CLOSE RAM OR VFU FILE AND RETURN AN ERROR TO THE PROCESS
;
; ACCEPTS IN D/ ERROR CODE

LODERR:	MOVE A,LODJFN		;GET JFN OF FILE TO BE LOADED
	CLOSF			;CLOSE THE FILE AND RELEASE THE JFN
	 JFCL			;IGNORE ERRORS HERE
LDERR1:	TQO <ERRF>		;MARK ERROR
	MOVE A,D		;GET ERROR CODE
	RET			;RETURN


; ROUTINE TO MARK THAT DATA TO BE LOADED HAS BEEN SENT TO -11

	RESCD
LODDON:	SETONE LPLHC,(B)	;MARK THAT LOADING HAS COMPLETED
	RET			;RETURN
	SWAPCD


; ROUTINE TO SAVE AWAY NAME OF FILE TO BE LOADED

SAVNAM:	STKVAR <SVNAMJ>		;ALLOCATE SPACE FOR FUNCTION CODE AND JFN
	MOVEM B,SVNAMJ		;SAVE JFN
	MOVE D,A		;GET FUNCTION TO PERFORM
	MOVEI A,VFUFIL		;GET NAME OF VFU FILE BUFFER
	CAIE D,.MOLVF		;LOADING VFU ?
	MOVEI A,RAMFIL		;NO, GET RAM FILE NAME BUFFER
	MOVEI B,LPFLSZ		;GET SIZE OF FILENAME BUFFERS
	IMULI B,(U)		;COMPUTE OFFSET TO PROPER BUFFER
	ADDI A,(B)		;COMPUTE ADDRESS OF FILENAME BUFFER TO USE
	HRLI A,(POINT 7,)	;FORM POINTER TO FILENAME BUFFER
	MOVE B,SVNAMJ		;GET JFN USED FOR LOADING
	MOVX C,JSBITS		;GET FLAGS SAYING WHICH FIELDS TO OUTPUT
	JFNS			;STORE NAME OF FILE USED FOR LOADING
	 ERJMP .+1		;IGNORE ERRORS
	RET			;RETURN
	RESCD

; Line printer interrupt



LPTINT:	JSP CX,CHKLPT		;MAKE SURE IS A VALID LPT
	PUSH P,U		;SAVE UNIT INICATOR
	MOVEI U,0(B)		;MOVE UNIT NUMBER

;NOW UPDATE COUNTS FOR THIS BUFFER

	LOAD B,LPTFE,(U)	;BYTES IN FE
	ADDI B,0(A)		;INCREASE IT
	STOR B,LPTFE,(U)	;UPDATE IT
	MOVEI B,0(A)		;SAVE COUNT OF LAST TRANSFER
	SUB A,LPTICT(U)		;UPDATE THE COUNT
	MOVNM A,LPTICT(U)	;THE NEW COUNT
	ADJBP B,LPTCCW(U)	;UPDATE BYTE POINTER
	MOVEM B,LPTCCW(U)	;SAVE NEW BYTE POINTER

;BUFFER COMPLETE, SEE IF MORE TO DO

LPTNXT:	SKIPLE LPTICT(U)	;THIS BUFFER DONE?
	JRST [	CALL LPTSN5	;NO. GO FINISH IT
		POP P,U
		RET]		;AND DONE
	FSKED			;FLAG SCHED FOR POSSIBLE FORK UNBLOCK
	LOAD C,ALTI,(U)		;GET INTERRUPT BUFFER
	XORI C,1		;TOGGLE IT
	STOR C,ALTI,(U)		;AND PUT IT BACK
	SOSL LPTCNT(U)		;ANOTHER BUFFER READY?
	JRST [	CALL LPTSND	;YES, SET IT UP
		JRST LPTN10]	;GO RETURN
	JE LPNOE,(U),LPTN10	;NOTING OCCURRANCE OF EOF ?
	LOAD A,LPDEVT,(U)
	CALL @SNDEOF(A)		;YES, TELL -11 TO ADVISE US WHEN DONE
LPTN10:	POP P,U			;RESTORE U
	RET			;RETURN
;SETUP BUFFER POINTER AND OUTPUT THE BUFFER

LPTSND:	JN <LPTBL,LPTHN>,(U),R	;IF BLOCKED OR HUNG, RETURN NOW
	CONSZ PI,1B<LPTCHN+^D20> ;AT PI?
	JRST LPTSN1		;YES. GO ON THEN
	NOSKD1			;TURN OFF SCHEDULING
	CHNOFF LPTCHN		;AND PREVENT INTERRUPTS
LPTSN1:	SKIPLE LPTICT(U)	;HAVE A BUFFER YET?
	JRST LPTSN5		;YES. GO WORK ON IT
	MOVE A,LPTRLP(U)	;GET BUFFER BASE
	OPSTR <SKIPE>,ALTI,(U)	;USING SECOND BUFFER?
	ADDI A,NLPBF		;YES. GET TO IT
	HRLI A,(<POINT 7,0>)	;MAKE A 7-BIT BYTE POINTER
	LOAD B,LPBSZ,(U)	;GET BYTE SIZE OF OPENF
	CAIN B,^D8		;USING 8 BIT BYTES ?
	HRLI A,(POINT 8,)	;YES, USE 8-BIT BYTE POINTER
	MOVEM A,LPTCCW(U)	;SAVE POINTER IN THE POINTER WORD
	MOVEI A,^D36		;GET BITS PER WORD
	LOAD B,LPBSZ,(U)	;GET BYTESIZE OF OPENF
	CAIE B,^D8		;USING 8-BIT BYTES ?
	MOVEI B,7		;NO, ASSUME 7-BIT BYTES
	IDIV A,B		;COMPUTE # OF BYTES PER WORD
	IMULI A,NLPBF		;COMPUTE # OF BYTES PER BUFFER
	MOVEM A,LPTICT(U)	;TO COUNT WORD
	;..
LPTSN5:	JN <LPLTR,LPLVF>,(U),NOSEND ;IF A RAM NEEDS LOADING, BLOCK
	LOAD A,LPTFE,(U)	;GET COUNT OF BYTES IN FE
	LOAD B,LPTMX,(U)	;GET CURRENT LIMIT
	CAIL A,0(B)		;ROOM FOR MORE BYTES?
	JRST NOSEND		;NO, GO INDICATE PROCESS BLOCKED AND RETURN
	SUBI B,0(A)		;GET ROOM LEFT
	MOVE A,LPTICT(U)	;BYTES IN BUFFER
	CAILE A,0(B)		;ROOM FOR WHOLE THING?
	MOVEI A,0(B)		;NO. FILL QUOTA THEN
	PUSH P,F		;SAVE FLAGS
	MOVEI F,0(A)		;COUNT IS UNIQUE CODE
	LOAD A,LPDEVT,(U)	;FIND CORRECT ROUTINE
	CALL @SNDSTD(A)
	 JRST [	SETONE LPTHN,(U) ;SAY WE ARE HUNG
		MOVEI A,^D1000	;TIME FOR SCHEDULER CHECK
		CAMGE A,LPTTIM	;EARLIER THAN CURRENT?
		MOVEM A,LPTTIM	;YES. THIS ONE IS FIRST
		ADD A,TODCLK	;TIME FOR THIS CHECK
		MOVEM A,LPTCKT(U) ;SET IT UP
		POP P,F		;RESTORE FLAGS
		JRST INTOK]	;GO FIX UP INTS
	POP P,F			;RESTORE FLAGS
INTOK:	CONSZ PI,1B<LPTCHN+^D20>;AT PI?
	RET			;YES. ALL DONE
	CHNON LPTCHN		;TURN ON CHANNEL
	OKSKD1			;AND ENABLE SCHEDULER
	RET			;AND DONE

; HERE TO BLOCK PROCESS AND RETURN

NOSEND:	SETONE LPTBL,(U) 	;SAY WE BLOCKED
	JRST INTOK		;AND GO AWAY
;ROUTINE TO TAKE THE STATUS OF A LPT
;	B/ UNIT
;	D/POINTER TO BYTES
;	C/COUNT OF BYTES

LPTTLS::JUMPLE C,R		;MAKE SURE A BYTE IS THERE
	JSP CX,CHKLPT		;GO VERIFY ARGS
	STKVAR <TLSPSI,TLSCNT,TLSSST,TLSMSG>	;ALLOCATE STORAGE
	MOVEM C,TLSCNT		;SAVE COUNT OF BYTES IN STATUS MESSAGE
	SETZM TLSPSI		;ASSUME NO PSI INTERRUPT REQUIRED

; GET SOFTWARE STATUS WORD AND SAVE FOR PROCESS EXAMINATION

	ILDB A,D		;GET HIGH ORDER STANDARD STATUS BITS
	ILDB C,D		;GET LOW ORDER STATUS BITS
	LSH A,8			;PLACE HIGH ORDER BITS IN PROPER POSITION
	IOR A,C			;FORM COMPLETE STATUS
	STOR A,LPSST,(B)	;STORE SOFTWARE STATUS WORD FOR PROCESS USE
	MOVEM A,TLSSST		;SAVE SOFTWARE STATUS WORD
	LOAD C,LPTER,(B)	;GET PREVIOUS ERROR BIT
	LOAD A,LPTOL,(B)	;AND PREVIOUS ON-LINE BIT
	IORI C,-1(A)		;FORM EQV
	MOVE A,TLSSST		;RESTORE SOFTWARE STATUS WORD

; SEE IF PSI INTERRUPT NEEDED BECAUSE OF ON-LINE/OFF-LINE TRANSITION

	JE LPTOL,(B),LPTS05	;JUMP IF LPT WAS OFF-LINE
	TXNE A,.DVFOL!.DVFNX	;LPT WAS ON-LINE. IS IT OFF-LINE NOW ?
	SETOM TLSPSI		;YES, REQUEST PSI CAUSE LPT WENT OFF-LINE
	JRST LPTS10		;GO ON TO SAVE NEW STATUS
LPTS05:	TXNN A,.DVFOL!.DVFNX	;LPT WAS OFF-LINE. IS IT ON-LINE NOW ?
	SETOM TLSPSI		;YES, REQUEST PSI CAUSE LPT WENT ON-LINE

LPTS10:	SETONE LPTOL,(B)	;ASSUME IS ON-LINE
	SETZRO LPTER,(B)	;AND THAT NO ERRORS NOW EXIST
	TXNN A,.DVFOL!.DVFNX	;OFF LINE?
	JRST LPTS20		;NO
	SETZRO LPTOL,(B)	;YES. SAY SO
LPTS20:	TXNE A,.DVFFE		;FATAL ERROR ON LPT?
	CALL SETER2		;YES, FREE BUFFERS, MARK ERROR, AND ZERO COUNTS
	;..
	;..

; HERE TO SAVE HARDWARE STATUS, PAGE COUNTER, AND TO SEE IF MESSAGE NEEDED

LPTS30:	MOVEM C,TLSMSG		;SAVE MESSAGE-REQUIRED FLAG
	ILDB A,D		;GET HIGH ORDER BITS OF PRINTER STATUS
	ILDB C,D		;GET LOW EIGHT BITS
	LSH A,8			;POSITION HIGH ORDER BITS PROPERLY
	IOR C,A			;FORM COMPLETE HARDWARE STATUS
	STOR C,LPERR,(B)	;SAVE THE ERROR CODE FOR LATER
	TXNE C,MO%LPC		;PAGE COUNTER OVERFLOWED ?
	JRST [ JN LPPCI,(B),.+1	;YES, BUT RETURN IF INTERRUPT ALREADY REQUESTED
		SETONE LPPCI,(B) ;INDICATE INTERRUPT HAS BEEN REQUESTED
		SETOM TLSPSI	;INDICATE PSI INTERRUPT NEEDED
		JRST .+1 ]	;CONTINUE
	TXNE C,MO%LCI!MO%RPE	;CHARACTER INTERRUPT OR RAM PARITY ERROR ?
	JRST [SETONE LPLTR,(B)	;YES, MARK THAT RAM NEEDS RELOADING
		CALL SETERR	;FREE UP BUFFERS, MARK ERROR, CLEAR COUNTS
		JRST .+1]	;REJOIN MAIN-LINE CODE
	TXNE C,MO%LVF		;VFU ERROR ?
	JRST [	TXNE C,MO%LVU	;DOES THIS PRINTER HAVE A DAVFU?
		JRST .+1	;NO, IGNORE SPURIOUS ERRORS
		SETONE LPLVF,(B) ;YES, MARK THAT VFU NEEDS RELOADING
		SETONE LPLTR,(B) ;AND RELOAD THE RAM ALSO
		CALL SETERR	;MARK ERROR, FREE BUFFERS, CLEAR COUNTS
		JRST .+1]	;REJOIN MAIN-LINE CODE
	ILDB A,D		;GET # OF BYTES OF DEVICE-DEPENDENT DATA
	ADDI A,.LRPAG+1		;ADD # OF BYTES TO PAGE COUNTER, + 1 FOR
				;  COUNT OF # OF BYTES OF DEVICE REGISTERS
	CAMLE C,TLSCNT		;GOT ENOUGH BYTES FROM -11 ?
	JRST LPTS50		;NO, DO NOT TRY TO GET PAGE COUNTER
	ADJBP A,D		;INCREMENT POINTER TO PAGE COUNTER REGISTER
	MOVE D,A		;GET POINTER BACK
	ILDB A,D		;GET HIGH ORDER BITS OF PAGE COUNTER
	ILDB C,D		;GET LOW ORDER BITS OF PAGE COUNTER
	LSH A,8			;POSITION HIGH ORDER BITS PROPERLY
	IOR A,C			;FORM COMPLETE PAGE COUNTER VALUE
	STOR A,LPPAG,(B)	;STORE LATEST PAGE COUNTER VALUE
	;..
	;..

; HERE TO SEE IF PSI NEEDED

LPTS50:	MOVE A,TLSSST		;RESTORE SOFTWARE STATUS
	MOVE C,TLSMSG		;RESTORE MESSAGE-NEEDED FLAG
	SETONE LPSHA,(B)	;MARK THAT A STATUS HAS ARRIVED
	JE LPOPN,(B),R		;IF NOT OPENED, RETURN
	SKIPE TLSPSI		;PSI REQUEST NEEDED ?
	CALL REQPSI		;YES, GO REQUEST INTERRUPT IF FORK ENABLED
	OPSTR <SKIPE>,LPTFE,(B)	;FE HAS NO BYTES?
	TXNN A,.DVFHE!.DVFOL	;HARDWARE ERROR?
	RET			;NO. ALL DONE
	SETONE LPTER,(B)	;YES. SAY SO
	SKIPE C			;NEED MESSAGE?
	RET			;NO. DON'T DO ATTENTION
SNDPSI:	MOVE A,TODCLK		;NOW
	MOVEM A,LPTCKT(B)	;TIME TO CHECK THIS ONE
	SETZM LPTTIM		;AND TO INTIATE SCHEDULER ACTION
	RET			;ALL DONE
; ROUTINE TO MARK THAT A HARD ERROR HAS OCCURRED, FREE BUFFERS, AND
; CLEAR COUNTS

SETERR:	OPSTR <SKIPN>,LPTFE,(B)	;DATA STILL IN FE ?
	SKIPLE LPTICT(B)	;OR IN OUR BUFFER ?
	SKIPA			;YES, SET HARD ERROR
	JRST SETER1		;NO, LEAVE HARD ERROR ALONE
SETER2:	SETONE LPTHE,(B)	;MARK IT
	SETONE LPSHA,(B)	;CLAIM NEW STATUS SO WE GET OUT OF STSWAT
SETER1:	RET			;RETURN TO STATUS ROUTINE

; ROUTINE TO REQUEST A PSI INTERRUPT IF THE FORK OWNING THE LPT HAS
; ENABLED FOR INTERRUPTS
;
; CALL:	B/ UNIT NUMBER
;		CALL REQPSI
; RETURNS: +1 ALWAYS, TEMPORARY AC'S PRESERVED

REQPSI:	SAVET			;SAVE TEMPS
	LOAD A,LPPSI,(B)	;GET PSI CHANNEL FIELD
	CAIN A,INIPSI		;HAS PROCESS ENABLED FOR INTERRUPTS ?
	RET			;NO, RETURN
	SETONE LPIRP,(B)	;MARK THAT AN INTERRUPT REQUEST IS PENDING
	CALLRET SNDPSI		;ARRANGE FOR LPTCHK TO RUN TO GENERATE THE PSI



;ROUTINE CALLED FROM DTE SERVICE ROUTINES TO CHECK UNIT NUMBER
;OF LPT. CALLED BY
;	JSP CX,CHKLPT
;WITH:
;	B/ LPT UNIT

CHKLPT:	CAIL B,LPTN		;A VALID LPT?
	RET			;NO. GIVE IT UP THEN
	JRST 0(CX)		;YES. RETURN IN-LINE
;PERIODIC CHECK FOR HUNG LPT

LPTCHK:	MOVSI U,-LPTN		;CHECK ALL UNITS
	JUMPE U,R		;RETURN IF NO UNITS
	MOVSI A,(1B1)		;MAX TIME TO WAIT
	MOVEM A,LPTTIM		;SET IT
LPTCK1:	MOVE A,LPTCKT(U)
	CAMLE A,TODCLK		;TIME TO DO THIS ONE?
	JRST [	SUB A,TODCLK	;NO. GET RELATIVE TIME
		CAMGE A,LPTTIM	;IS HE NEXT?
		MOVEM A,LPTTIM	;YES. LET IT BE
		JRST LPTCK3]	;AND MOVE ON
	JN LPIRP,(U),[	SETZRO LPIRP,(U) ;IF PSI NEEDED, MARK THAT PSI REQUESTED
			LOAD A,LPPSI,(U) ;GET PSI CHANNEL FOR INTERRUPT
			LOAD B,LPFRK,(U) ;GET OWNING FORK FOR THIS LPT
			CAIE A,INIPSI	;MAKE SURE INTERRUPT CHANNEL HAS BEEN SPECIFIED
			CALL PSIRQ 	 ;REQUEST A PSI INTERRUPT
			JRST .+1 ]	 ;CONTINUE
	JE LPTHN,(U),LPTCK2	;NEED TO DO SOMETHING WITH THIS ONE
	SETZRO LPTHN,(U)	;SAY NOT HUNG ANYMORE
	CALL LPTSND		;TRY TO SEND IT OUT
LPTCK2:	JE LPTER,(U),LPTCK4	;NEED AN ERROR MESSAGE?
	SETZRO LPTER,(U)	;YES. TURN OFF INDICATOR
	JN LPMSG,(U),LPTCK4	;NEED ERROR MESSAGE?
	MOVE A,[ASCII /PLPT/]	;GET DEVICE TYPE
	MOVEI B,"0"(U)		;THE UNIT NUMBER
	DPB B,[POINT 7,A,34]	;PUT IN THE UNIT
	PUSH P,A		;THE STRING
	PUSH P,[0]
	HRROI A,-1(P)		;THE ADDRESS
	CALL DEVMSG		;OUTPUT THE MESSAGE
	SUB P,BHC+2		;FAST POP OF THE STACK
LPTCK4:	MOVEI A,^D60000		;WHEN TO CHECK AGAIN
	CAMG A,LPTTIM		;LESS THAN CURRENT MINIMUM?
	MOVEM A,LPTTIM		;YES
	ADD A,TODCLK		;WHEN TO MAKE THE CHECK
	MOVEM A,LPTCKT(U)	;TO THE CELL
LPTCK3:	LOAD A,LPDEVT,(U)	;GET DEVICE TYPE
	SKIPE A			;IF ZERO VECTORS NOT SETUP YET
	CALL @FEIEN(A)
	AOBJN U,LPTCK1		;CHECK THEM ALL
	RET
;ROUTINE TO OUTPUT A STANDARD DEVICE ERROR MESSAGE
;	A/DEVICE NAME
;RETURNS +1, CLOBBERING ALL TEMPORARIES

DEVMSG::PUSH P,A		;SAVE STRING
	HRROI A,[ASCIZ /
%PROBLEM ON DEVICE /]
	MOVE B,CTYLNO		;OUTPUT IT TO THE CTY
	CALL TTEMES		;DO IT
	POP P,A			;THE MESSAGE
	CALL TTEMES		;OUTPUT THE DEVICE NAME
	HRROI A,[ASCIZ /
/]
	CALL TTEMES		;FINISH IT OFF
	RET			;AND DONE