Google
 

Trailing-Edge - PDP-10 Archives - BB-JR93L-BB_1990 - 10,7/mon/dlpser.mac
There are 10 other files named dlpser.mac in the archive. Click here to see a list.
TITLE	DLPSER - LINEPRINTER SERVICE FOR MULTIPLE RSX-20F LINEPRINTERS - V041
SUBTTL	A. WILSON	17-APR-90

	SEARCH	F,S,DEVPRM,DTEPRM

	$RELOC
	$HIGH

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
; 1977,1978,1979,1980,1982,1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1977,1990>


XP VDLPSR,041			;DEFINE GLOBAL VERSION NUMBER FOR LOADER MAP

	PRMMIN==063		;DTEPRM MUST BE AT LEAST THIS RECENT

   IFL VDTPRM-PRMMIN,<PRINTX ?PLEASE USE LATEST VERSION OF DTEPRM
				PASS2
				END>


DLPSER::ENTRY	DLPSER
SUBTTL	SYMBOL DEFINITIONS


;DEVICE DEPENDENT BITS IN LH OF DEVIOS

	DLPSYN==Z(1B11)			;CRFF AFTER CLOSE HAS BEEN SENT
	DLPEND==Z(1B10)			;CLOSE UUO HAS BEEN DONE
	DLPOPB==Z(1B9)			;PARTIAL BUFFER ALREADY OUTPUT

;DEVICE DEPENDENT BITS IN RH OF DEVIOS

	DLPNFF==100			;SUPPRESS FREE CRFF



;LPT SPECIFIC STATUS BITS FROM RSX-20F

	DL.PGZ==1B35			;PAGE COUNTER PASSED ZERO
	DL.RCI==1B34			;CHARACTER INTERRUPT (FROM RAM)
	DL.VFE==1B33			;VFU ERROR--PAPER REALIGNMENT REQUIRED
	DL.LER==1B32			;ERROR FINDING/READING VFU/RAM FILE
	DL.OVF==1B31			;PRINTER HAS OPTICAL (NOT DA) VFU
	DL.RPE==1B30			;RAM PARITY ERROR--RELOAD REQUIRED
SUBTTL	AUTOCONFIGURE


;DRIVER CHARARCTERISTICS
;	DLP	= DLPCNF
;	LPT	= LINE PRINTER
;	7	= MAXIMUM DEVICES IN SYSTEM
;	0	= KONTROLLER TYPE
;	0	= MAXIMUM DRIVES PER KONTROLLER
;	0	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(DLP,LPT,7,0,0,0,MDSEC0,MDSEC0,<DR.GCC!DR.NET>)


	 .ORG	DEVLEN
DLPDUX:! BLOCK	1		;UNIT # ON FRONT-END,,DTE INDEX
DLPCDN:! BLOCK	1		;CPU,,DTE NUMBERS
DLPMLA:! BLOCK	1		;MAXIMUM LINE ALLOCATION
DLPRLA:! BLOCK	1		;REMAINING LINE ALLOCATION
DLPSNT:! BLOCK	1		;NUMBER OF WORDS ALREADY SENT
DLPFRM:! BLOCK	1		;FORMS TYPE NAME (SIXBIT)
DLPLEN:!			;LENGTH OF DTE PRINTER DDB
	 .ORG


	$LOW

DLPDDB:	DDBBEG	(DLP,DLPLEN)
	SETWRD	(DEVCHR,<6*HUNGST+DVLPTL,,LPTSIZ##>) ;DEVCHR
	SETWRD	(DEVSER,<MCSEC0+RLPDSP>)	;DEVSER
	SETWRD	(DEVMOD,<DVOUT!DVLPT,,<1_A+1_AL+1_BYTMOD+1_I>>) ;DEVMOD
	SETWRD	(DEVTYP,<<.TYLPT*.TYEST>!.SPLPT!DEPLEN,,0>) ;DEVTYP
	DDBEND
	$HIGH

EQUATE	(LOCAL,0,<DLPCKT,DLPICD,DLPICL,DLPINT,DLPKDB,DLPKLN,DLPUDB,DLPULN>)
EQUATE	(LOCAL,0,<DLPULB,DLPULP>)

DLPDSX:	DRVDSP	(DLP,0,DLPDDB,DLPLEN,URDDIA##)

;DEFAULT MONGEN'ED DEVICE TABLE
DEFMDT:	MDKL10	(7,200,0,0,<MD.KON>)	;DEVICE CODE 200
	MDKL10	(7,204,0,0,<MD.KON>)	;DEVICE CODE 204
	MDKL10	(7,210,0,0,<MD.KON>)	;DEVICE CODE 210
	MDKL10	(7,214,0,0,<MD.KON>)	;DEVICE CODE 214
	MDTERM

;BITS FOR MDT ENTRIES ARE ASSIGNED HERE
	LPT.UC==:1		;UPPER-CASE ONLY PRINTER
DLPCFG:	XMOVEI	T1,DLPMDT##	;MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;DEFAULT TABLE
	MOVNI	T3,1		;NO MASSBUS UNIT OR DRIVE INFORMATION
	MOVEI	T4,MD.KON	;MATCH ON KONTROLLER DEFINITION
	PUSHJ	P,AUTMDT##	;SCAN THE TABLES
	  JRST	CPOPJ1##	;NO MATCHES
	MOVE	T1,.CPCPN##	;OUR CPU NUMBER
	HRRZ	F,DTEMAS##(T1)	;FETCH MASTER DTE
	LDB	T1,[POINT 7,ETDCNI(F),9] ;GET DTE NUMBER
	HRRZ	T2,.CPDVC##	;AND DEVICE BEING CONFIGURED
	CAIE	T1,(T2)		;DOING THE MASTER DTE?
	JRST	CPOPJ1##	;NO
	MOVSI	T1,(ED.PPC)	;BIT TO TEST
	TDNE	T1,ETDSTS(F)	;PRIMARY PROTOCOL RUNNING?
	PJRST	DLPRDS		;YES--CAN REQUEST DEVICE STATUS DIRECTLY
	XMOVEI	T1,DLPRDS	;ROUTINE TO REQUEST DEVICE STATUS
	MOVEI	T2,1		;WAIT FOR PRIMARY PROTOCOL TO START
	PUSHJ	P,AUTCLK##	;QUEUE UP A CLOCK REQUEST
	JRST	CPOPJ1##	;MAYBE OTHER DTE-BASED DEVICES EXIST

;HERE WHILE PRIMARY PROTOCOL IS RUNNING TO REQUEST DEVICE STATUS
DLPRDS:	PUSHJ	P,SAVE4##	;SAVE SOME ACS
	MOVE	T1,.CPCPN##	;OUR CPU NUMBER
	HRRZ	F,DTEMAS##(T1)	;FETCH MASTER DTE
	LOAD.	P1,ED.DTN,(F)	;GET MASTER DTE NUMBER
	HRL	P1,.CPCPN##	;INCLUDE OUR CPU NUMBER
	MOVE	P2,[.EMLPT,,.EMRDS] ;FE DEVICE CODE,,FUNCTION CODE
	TDZA	P3,P3		;START WITH UNIT ZERO
DLPRD1:	HLLZS	P3		;READ STATUS TAKES UNIT,,0
	MOVE	P4,[POINT 8,P3,9] ;BYTE POINTER TO UNIT NUMBER
	SETZ	S,		;NO POST ADDRESS
	S0PSHJ	DTEQUE##	;QUEUE UP REQUEST FOR DEVICE STATUS
	  JFCL			;SHOULDN'T FAIL
	AOBJN	P3,.+1		;ADVANCE UNIT NUMBER
	TLNN	P3,-1-DLPMAX##+1 ;OVERFLOW?
	JRST	DLPRD1		;LOOP BACK FOR MORE
	JRST	CPOPJ1##	;MAYBE OTHER DTE-BASED DEVICES EXIST


;HERE WHILE PROCESSING A DEVICE STATUS MESSAGE FOR A PREVIOUSLY
;UNKNOWN DTE-BASED DEVICE TO ACTUALLY BUILD THE DTE DEVICE DATA BASE
;P1 - P4 SETUP WITH DEVICE STATUS MESSAGE POINTERS
DLPDTS:	SE1ENT			;ENTER SECTION ONE
	PUSHJ	P,AUTLOK##	;INTERLOCK THE DATA BASE
	  JRST	[PUSHJ	P,DLPRDS ;BUSY & INTERRUPT LEVEL--TRY AGAIN LATER
		   JFCL		;WILL MOST LIKELY SKIP
		 POPJ	P,]	;CALL THIS A FAILURE
	PUSH	P,F		;SAVE DDB ADDRESS OR ZERO
	MOVE	T1,.CPCPN##	;OUR CPU NUMBER
	HRRZ	F,DTEMAS##(T1)	;AND THE MASTER ETD FOR THIS CPU
	LDB	T1,[POINT 7,ETDCNI(F),9] ;DEVICE CODE
	XMOVEI	T2,DLPDSX	;DRIVER DISPATCH
	SETZ	T3,		;NO CHANNEL
	PUSHJ	P,AUTSET##	;SET UP AUTCON CALLS
	POP	P,F		;GET FLAG BACK
	JUMPN	F,DLPDT1	;JUMP IF A KNOWN DEVICE
	PUSHJ	P,AUTADN##	;ALLOCATE A DEVICE NUMBER
	HRLI	T1,'LPT'	;INCLUDE GENERIC DEVICE NAME
	SETZ	T2,		;LOCAL DEVICE
	PUSHJ	P,AUTDDB##	;CREATE A DDB
	  JRST	[PUSHJ	P,AUTULK## ;NO CORE
		 PJRST	AUTDDN##] ;DEALLOCATE DEVICE NUMBER
DLPDT1:	MOVEM	P1,DLPCDN(F)	;SAVE CPU,,DTE NUMBER
	HLLM	P3,DLPDUX(F)	;SAVE FE UNIT (LINE) NUMBER
	HRRM	P1,DLPDUX(F)	;SAVE DTE NUMBER (HISTORICAL)
	XMOVEI	T1,DLPMDT##	;POINT TO MONGEN'ED DEVICE TABLE
	XMOVEI	T2,DEFMDT	;GET DEVICE CODES FROM THE DEFAULT TABLE
	HLLO	T3,P3		;USE FE UNIT FOR UNIT NUMBER
	SETZ	T4,		;IGNORE FLAGS
	PUSHJ	P,AUTMDT##	;SEE IF WE HAVE DATA
	  JRST	DLPDT2		;THERE IS NONE
	MOVSI	T2,DVLPTL	;GET LOWER-CASE PRINTER BIT
	TRNE	T1,LPT.UC	;IF UPPER-CASE ONLY PRINTER
	ANDCAM	T2,DEVCHR(F)	;THEN CLEAR THE LOWER-CASE BIT
;ADD FUTURE MDT VALUE TESTS HERE
DLPDT2:	PUSHJ	P,AUTULK##	;RELEASE INTERLOCK
	JRST	CPOPJ1##	;RETURN
SUBTTL	DISPATCH TABLES

;UUOCON DISPATCH TABLE FOR RSX-20F LINEPRINTER(S)

	JRST	DLPONL			;SEE IF LPT ON-LINE NOW
	JRST	DLPDVP			;DEVOP. UUO
	JRST	REGSIZ##		;GET BUFFER SIZE FROM DDB
	JRST	DLPINI			;INITIALIZATION
	JRST	DLPHNG			;HUNG DEVICE ERROR
RLPDSP::JRST	DLPREL			;RELEASE
	JRST	DLPCLS			;CLOSE
	JRST	DLPOUT			;OUT/OUTPUT
	JRST	ILLINP##		;IN/INPUT


;DTESER DISPATCH TABLE FOR LPT

	IFIW	CPOPJ##		;(-1) LOST TO-10 INDIRECT MESSAGE
DLPDSP::DTEFNC			;(??) GENERATE DUMMY TABLE ENTRIES
	DTEFNC	(HDS,DLPTKS)	;(07) TAKE DEVICE STATUS
	DTEFNC	(ACK,DLPACK)	;(17) ACK
	DTEFNC	(HLA,DLPHLA)	;(23) LINE ALLOCATIONS
	DTEFNC	(AKA,DLPAAL)	;(25) ACK ALL
SUBTTL	MONITOR-LOAD DEVICE INITIALIZATION

;DLPINI IS CALLED AT SYSTEM INITIALIZATION TIME FROM IOGO IN SYSINI WITH
; THE DDB ADDRESS IN F.  DLPINI FORCES IOGO TO INVOKE DLPINI FOR EACH RSX-20F
; LINEPRINTER ON THE SYSTEM RATHER THAN FOR THE NORMAL CASE WHERE IT INVOKES
; THE INITIALIZATION CODE ONCE FOR EACH DISPATCH TABLE.  THEREFORE, THE CORRECT
; OPERATION OF DLPINI IS DEPENDENT ON THE IOGO CODE WHICH SHOULD BE:
;
;	PUSHJ	P,DINI(P3)
;	HRRZM	P3,SAVITM

DLPINI:	PUSHJ	P,DLPREL		;GO THROUGH RELEASE CODE
	PJRST	CPOPJ1##		;SKIP RETURN TO FORCE CALL FOR EACH LPT
SUBTTL	OUT/OUTPUT UUO

;HERE FROM UUOCON ON OUT OR OUTPUT UUO

DLPOUT:	TLO	S,IO			;INDICATE OUTPUT
	PUSHJ	P,DLPOFL		;IF TROUBLE, GET IT FIXED
	TLZE	S,IOBEG			;FIRST OUTPUT?
	PUSHJ	P,DLPSFF		;YES, SEE ABOUT SENDING FREE CRFF
	  JFCL
	TLZE	S,DLPOPB		;PARTIAL BUFFER ALREADY OUTPUT?
DLPOU0:	JRST	[SKIPLE DEVCTR(F)	;YES, BUT WERE WE DONE WITH IT
		 JRST DLPOU1		;NO, MORE TO PRINT
		 PUSHJ P,ADVBFE##	;GET NEXT BUFFER HERE
		 PJRST DLPSTP		;NO MORE, SHUT DOWN PRINTER
		 JRST .+1]		;RETURN INLINE FOR NEW BUFFER
	MOVE	T1,DEVOAD(F)		;PICK UP BUFFER ADDRESS
	HRRZ	T1,1(T1)		;PICK UP WORD COUNT
	MOVEM	T1,DEVCTR(F)		;SET DEVCTR UP WITH WORD COUNT
	SETZM	DLPSNT(F)		;NO DATA FROM THIS BUFFER YET
	JUMPE	T1,DLPOU0		;GET NEXT IF NO DATA
DLPOU1:	PUSHJ	P,DLPSND		;START DATA TRANSFER
	PJRST	SETACT##		;SET IOACT, STORE S, SET HUNG COUNT, RETURN



;HERE DURING OUTPUT UUO TO SEE IF LPT ON-LINE
;ARGS:	F/DDB ADDRESS
;	S/DEVIOS WORD FROM DDB
;CALL:	PUSHJ	P,DLPOFL
;	RETURN HERE WHEN ON-LINE (BOTHERING USER IF NECESSARY TO GET IT ON-LINE)

DLPOFL:	PUSHJ	P,DLPONL		;SEE IF LPT ON-LINE
	  JRST	DLPOF1			;IT'S NOT--TELL THE USER
	POPJ	P,			;IT IS--RETURN

DLPOF1:	MOVEM	S,DEVIOS(F)		;SAVE S
	MOVSI	T1,DEPADV
	IORM	T1,DEVADV(F)		;LEAVE BUFFERS ALONE
	MOVSI	T1,DVOFLN
	IORM	T1,DEVCHR(F)		;MARK DDB OFF-LINE
	PUSHJ	P,HNGSTP##		;HALT JOB AND COMPLAIN
	MOVSI	T1,DEPADV
	ANDCAM	T1,DEVADV(F)		;CLEAR BIT ON RETRY
	JRST	DLPOFL			;TRY AGAIN
;ROUTINE TO SEE IF LPT ON-LINE
;ARGS:	F/DDB ADDRESS
;CALL:	PUSHJ	P,DLPONL
;	  RETURN HERE IF OFF-LINE
;	RETURN HERE IF ON-LINE

DLPONL:	MOVEI	T1,EM.OFL+EM.NXD	;GET RSX-20F OFF-LINE BITS
	TDNN	T1,DEVSTS(F)		;OFF-LINE?
	AOS	(P)			;NO--SKIP RETURN FOR ON-LINE
	POPJ	P,			;YES--NON-SKIP RETURN



;HERE TO SEND INITIAL/FINAL CRFF IF NECESSARY
;ARGS:	F/DDB ADDRESS
;	S/DEVIOS WORD FROM DDB
;CALL:	PUSHJ	P,DLPSFF
;	  RETURN HERE IF CRFF NOT SENT
;	RETURN HERE IF SENT

DLPSFF:	TRNE	S,DLPNFF		;NEED TO SEND CRFF?
	POPJ	P,			;NO--NON-SKIP RETURN
	PUSHJ	P,SAVE4##		;SAVE P1-P4
	MOVE	P4,[POINT 7,LPCRFF]	;POINT TO CRFF
	MOVEI	T1,1			;ONLY 1 WORD
	PUSHJ	P,DLPSOU		;SEND THIS STRING
	PJRST	CPOPJ1##		;SKIP RETURN

LPCRFF:	BYTE	(7)	15,14,0		;CR,FF,0
SUBTTL	CLOSE AND RELEASE UUO'S

;HERE FROM UUOCON ON CLOSE UUO

DLPCLS:	TLO	S,DLPEND		;SET "CLOSE DONE"
	TLZ	S,DLPOPB+DLPSYN		;CLEAR TROUBLE AND SYNC BITS
	MOVEM	S,DEVIOS(F)		;STORE S
	JRST	OUT##			;TAKE CARE OF LAST BUFFER



;HERE FROM UUOCON ON RELEASE UUO

;SET UP SOME REASONABLE DEFAULTS FOR LP20-BASED LPT'S
;VARIABLE RAM, LP20/LP05, DAVFU

DLPHCW==INSVL.(.HCT20,HC.TYP)!INSVL.(.HCVTD,HC.VFT)!
	INSVL.(.HCCVR,HC.CST)!INSVL.(.HCULP,HC.TYU)

DLPHNG:					;HUNG DEVICE IS SAME AS RELEASE
DLPREL:	MOVSI	T1,(DLPHCW)		;GET INITIAL HCW WORD
	MOVSI	T2,DVLPTL		;LPT LOWERCASE BIT
	TDNE	T2,DEVCHR(F)		;IF SET,
	TLO	T1,(HC.LCP)		;THEN PROPAGATE TO HCW BITS
	MOVSI	T2,DL.OVF		;BIT FOR OPTICAL VFU
	TDNE	T2,DEVSTS(F)		;DID -20F SET IT?
	TLC	T1,(INSVL.(.HCVTD^!.HCVTO,HC.VFT)) ;YES--CHANGE TO OPTICAL
	HLLM	T1,DEVHCW(F)		;SET FOR PRYING EYES
	MOVSI	T1,DEPADV		;GET "DON'T ADVANCE BUFFER" BIT
	ANDCAM	T1,DEVADV(F)		;TURN IT OFF IN DDB
	TLZ	S,DLPOPB		;CLEAR PARTIAL BUFFER BIT
	PJRST	DLPSTP			;CLEAR ACTIVE I/O
SUBTTL	ACK MESSAGE ("OUTPUT DONE") PROCESSING

;HERE FROM DTESER ON ACK FOR LPT

DLPACK:	SUBI	P3,2		;ACCOUNT FOR TWO BYTES/ARGUMENT
	JUMPL	P3,CPOPJ##	;RETURN WHEN ARGUMENT COUNT EXHAUSTED
	ILDB	T3,P4		;GET UNIT NUMBER
	IBP	P4		;MOVE PAST UNUSED BYTE
	PUSHJ	P,FNDDLP	;FIND CORRECT DLP DDB
	  PUSHJ	P,DLPDON	;TREAT THIS AS DONE INTERRUPT
	JRST	DLPACK		;LOOP FOR MORE ARGUMENTS



;HERE FROM DTESER ON ACK ALL FOR LPT

DLPAAL:	SKIPE	F,DDBTAB##+.TYLPT ;POINT TO FIRST LPT IN SYSTEM
DLPAA1:	HLRZ	F,DEVSER(F)	;LINK TO NEXT
	JUMPE	F,CPOPJ##	;RETURN IF RUN OUT OF DDBS
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,.TYLPT	;CHECKED ALL LPTS?
	POPJ	P,		;ALL DONE
	HRRZ	T1,DEVSER(F)	;GET DISPATCH
	CAIE	T1,RLPDSP	;OWNED BY US?
	JRST	DLPAA1		;TRY ANOTHER
	CAMN	P1,DLPCDN(F)	;CPU#,,DTE# MATCH?
	PUSHJ	P,DLPDON	;YES--TREAT THIS AS DONE INTERRUPT
	JRST	DLPAA1		;GO CHECK OUT THE NEXT LPT
SUBTTL	HERE ARE LINE ALLOCATIONS PROCESSING

;HERE FROM DTESER ON HERE ARE LINE ALLOCATIONS FOR LPT

DLPHLA:	SUBI	P3,2			;ACCOUNT FOR TWO BYTES/ARGUMENT
	JUMPL	P3,CPOPJ##		;RETURN WHEN ARGUMENT COUNT EXHAUSTED
	ILDB	T2,P4			;GET ALLOCATION
	ILDB	T3,P4			;GET LINE NUMBER
	PUSHJ	P,FNDDLP		;FIND SPECIFIED DDB
	  MOVEM	T2,DLPMLA(F)		;SAVE LINE ALLOCATION
	JRST	DLPHLA			;LOOP FOR MORE
SUBTTL	OUTPUT DONE PROCESSING

;HERE IF RSX-20F ACKNOWLEDGED AN ACTIVE LINEPRINTER
;ARGS:	F/DDB ADDRESS
;	S/LPT STATUS WORD (DDB DEVIOS)
;CALL:	PUSHJ	P,DLPDON
;	RETURN HERE

DLPDON:	PUSHJ	P,IOSET##		;SET UP THE REST OF THE REGS
	MOVE	T1,DLPMLA(F)		;PICK UP MAX ALLOCATION
	MOVEM	T1,DLPRLA(F)		;THIS IS CURRENT ALLOCATION
	TRNN	S,IOACT			;OUTPUT ACTIVE?
	  POPJ	P,			;NO, RETURN
	SKIPLE	DEVCTR(F)		;OUTPUT REMAINING FROM PREVIOUS BUFFER?
	JRST	DLPDN1			;YES--WORK ON THAT BUFFER SOME MORE
	TLZE	S,DLPEND		;CLOSE DONE?
	JRST	DLPDN2			;YES--SEE ABOUT FINAL CRFF
	TLZN	S,DLPSYN		;NO--CRFF JUST OUTPUT?
DLPDN0:	PUSHJ	P,ADVBFE##		;NO--ADVANCE TO NEXT BUFFER
	  PJRST	DLPSTP			;CAN'T--SHUT DOWN LPT
	PUSHJ	P,SETIOD##		;ARRANGE FOR JOB TO RUN AGAIN
	MOVE	T1,DEVOAD(F)		;PICK UP BUFFER ADDRESS
	HRRZ	T1,1(T1)		;PICK UP WORD COUNT
	MOVEM	T1,DEVCTR(F)		;SET DEVCTR UP WITH WORD COUNT
	SETZM	DLPSNT(F)		;NO, THIS BUFFER IS DONE
	JUMPE	T1,DLPDN0		;IGNORE EMPTY BUFFERS
DLPDN1:	PUSHJ	P,DLPSND		;START UP NEXT OUTPUT
	PJRST	STOIOS##		;SAVE S, SET HUNG COUNT, RETURN

DLPDN2:	PUSHJ	P,DLPSFF		;SEE ABOUT SENDING CRFF
	  PJRST	DLPSTP			;NOT SENT--SHUT DOWN LPT
	TLO	S,DLPSYN		;REMEMBER CRFF SENT SO DON'T ADVANCE BUFFERS
	PJRST	STOIOS##		;SAVE S, SET HUNG COUNT, RETURN



;HERE TO STOP LPT AND START USER

DLPSTP:	TRZ	S,IOACT			;CLEAR IOACT
	MOVEM	S,DEVIOS(F)		;SAVE DEVIOS
	PUSHJ	P,SETIOD##		;START UP THE USER
	PJRST	RTEVMO##		;RETURN ANY EVM
SUBTTL	SEND LPT DATA TO FRONT-END

;HERE TO SEND OUTPUT DATA TO RSX-20F LPT FROM USER BUFFER
;ARGS:	F/DDB ADDRESS
;CALL:	PUSHJ	P,DLPSND
;	RETURN HERE

DLPSND:	PUSHJ	P,SAVE4##		;SAVE P1-P4
	MOVE	P4,DEVPTR(F)		;PICK UP DATA ADDRESS
	ADDI	P4,2			;POINT TO FIRST DATA WORD
	ADD	P4,DLPSNT(F)		;OFFSET POINTER TO REMAINING DATA
	HRLI	P4,440700		;ASSUME 7 BIT BYTES
	LDB	T1,PIOMOD##		;PICK UP I/O MODE
	CAIN	T1,BYTMOD		;REALLY BYTE MODE?
	HRLI	P4,441000		;YES, 8 BIT BYTES
	HRRZ	T1,DEVCTR(F)		;PICK UP REMAINING WORD COUNT
	PUSHJ	P,DLPSOU		;SEND THIS STRING
	ADDM	T1,DLPSNT(F)		;ACCUMULATE WORD COUNT
	MOVNS	T1			;NEED NEGATIVE OF COUNT
	ADDM	T1,DEVCTR(F)		;DECREMENT REMAINING COUNT
	POPJ	P,			;DONE

;HERE TO SEND STRING OUTPUT DATA TO RSX-20F LPT
;ARGS:	F/DDB ADDRESS
;	T1/WORD COUNT
;	P4/BYTE POINTER
;CALL:	PUSHJ	P,DLPSOU
;	RETURN HERE WITH WORDS SENT IN T1

DLPSOU:	LDB	T3,[POINT 6,P4,11]	;PICK UP BYTE SIZE
	MOVEI	T2,44			;36 BITS/WORD
	IDIVI	T2,(T3)			;NOW GOT BYTES/WORD
	MOVE	T3,DLPRLA(F)		;PICK UP REMAINING ALLOCATION
	IDIVI	T3,(T2)			;CONVERT TO WORDS
	CAMLE	T1,T3			;SMALLER THAN STRING LENGTH?
	MOVE	T1,T3			;YES, USE ALLOCATION
	JUMPLE	T1,CPOPJ##		;RETURN IF NO ALLOCATION LEFT
	MOVE	P3,DLPDUX(F)		;P3 IS UNIT #,,DLP DTE INDEX
	MOVE	P1,DLPCDN(F)		;P1 IS CPU#,,DTE#
	MOVE	P2,[.EMLPT,,EM.IND+.EMSTR] ;OUTPUT INDIRECT STRING TO LPT
	IMULI	T2,(T1)			;GET STRING LENGTH IN BYTES
	HRR	P3,T2			;PUT INTO ARG LIST
	MOVNS	T2			;NEGATE
	ADDM	T2,DLPRLA(F)		;UPDATE REMAINING ALLOCATION
	PUSH	P,S			;SAVE S
	PUSH	P,T1			;SAVE WORD COUNT
	MOVEI	S,0			;NO POST ADDRESS
	PUSHJ	P,DTEQUE##		;QUEUE THE REQUEST
	  JFCL				;FAILED--WAIT FOR HUNG TIME-OUT OR ACK ALL
	POP	P,T1			;RESTORE WORD COUNT
	POP	P,S			;RESTORE S
	POPJ	P,			;DONE
SUBTTL	TAKE DEVICE STATUS FROM FRONT-END

;HERE FROM DTESER TO TAKE LPT STATUS FROM FRONT-END (DTESER ALREADY RECEIVED IT)

DLPTKS:	PUSHJ	P,SETRGS		;SET UP NECESSARY ACS
	  PJRST	EATMSG##		;COULDN'T--IGNORE THIS MESSAGE
	ILDB	T1,P4			;GET FIRST STATUS (GENERAL) BYTE
	ILDB	T2,P4			;GET SECOND (LPT) BYTE
	HRL	T1,T2			;PUT THEM TOGETHER
	MOVEM	T1,DEVSTS(F)		;SAVE COMBINED STATUS BITS
	MOVEI	T2,.HCVTO		;CODE FOR OPTICAL VFU
	TLNE	T1,DL.OVF		;IS IT OPTICAL TYPE
	DPB	T2,[POINT 3,DEVHCW(F),5] ;YES, SAVE IN CHARACTERISTICS WORD
	MOVEI	T2,IOPAR%		;CODE FOR RAM ERROR
	TLNE	T1,DL.RCI+DL.RPE	;ANY RAM PROBLEMS?
	JRST	DLPIOE			;YES
	MOVEI	T2,IOVFE%		;NO, CODE FOR VFU PROBLEM
	TLNE	T1,DL.VFE		;VFU PROBLEM?
	JRST	DLPIOE			;YES
	MOVEI	T2,IODER%		;CODE FOR DEVICE ERROR
	TRNN	T1,EM.FER		;FATAL ERROR (ALL RETRIES FAILED)
	JRST	DLPTK2			;NO, GO CHECK FOR OFFLINE
DLPIOE:	DPB	T2,PDVESE##		;STORE THE CODE
	TRO	S,740000		;SET ALL ERROR FLAGS IN S
	TRO	T1,EM.OFL		;DECLARE PRINTER OFF-LINE
	PUSH	P,S			;SAVE STATUS
	PUSH	P,T1			;SAVE STATUS FOR A MOMENT
	PUSHJ	P,[PUSHJ P,SAVE4	;SAVE SOME REGS
		   HRRI P2,.EMFLO	;FLUSH ANY REMAINING OUTPUT
		   HRRI P3,0		;NO DATA
		   SETZB P4,S		;NO POST ROUTINE
		   PJRST DTEQUE##]	;SEND MESSAGE TO CFE
	JFCL				;IGNORE FAILURE
	POP	P,T1			;GET BACK STATUS
	POP	P,S			;RESTORE S
;HERE TO DEAL WITH OFF-LINE OR ON-LINE

DLPTK2:	MOVE	T2,DEVCHR(F)		;PICK UP OLD STATUS
	MOVSI	T3,DVOFLN		;OFF-LINE BIT
	TRNE	T1,EM.OFL!EM.NXD	;DEVICE THERE?
	  JRST	DLPTK3			;NO
	ANDCAM	T3,DEVCHR(F)		;ASSUME ON-LINE
	TLNE	T2,DVOFLN		;WAS IT OFF-LINE?
	PUSHJ	P,PSIONL##		;YES, TELL USER IT IS BACK AGAIN

	PJRST	EATMSG##		;DONE WITH THIS MESSAGE

DLPTK3:	MOVEM	S,DEVIOS(F)		;MAKE SURE ERROR BITS ARE SAVED
	TRNN	S,IOACT			;PRINTER ACTIVE NOW?
	PJRST	EATMSG##		;NO, DONE WITH THIS MESSAGE
	IORM	T3,DEVCHR(F)		;NOTE DEVICE OFF-LINE
	TLNN	T1,DL.RCI+DL.RPE+DL.VFE	;ANY ERRORS IN LPT?
	TLO	S,DLPOPB		;NO, INDICATE MINOR TROUBLE NOTICED
	PUSHJ	P,DLPSTP		;STOP LPT AND START USER
	PUSHJ	P,DEVERR##		;CAUSE UUOCON TO RETRY ON UUO LEVEL
	PJRST	EATMSG##		;DONE
SUBTTL	DEVOP. UUO INTERFACE

;HERE FROM UUOCON ON DEVOP. UUO
;ARGS:	F/DDB ADDRESS
;	T1/FUNCTION
;CALL:	PUSHJ	P,DLPDVP
;	  RETURN HERE ON ERROR OR INVALID FUNCTION
;	RETURN HERE ON SUCCESS, T1 CONTAINING ANY ARGUMENT RETURNED

DLPDVP:	MOVSI	T2,-DLPDVL		;MAKE AOBJN POINTER WITH TABLE LENGTH
DLPDV1:	HLRZ	T3,DLPDVT(T2)		;GET THE FUNCTION CODE
	HRRZ	T4,DLPDVT(T2)		;GET DISPATCH ADDRESS
	CAMN	T1,T3			;CODES MATCH?
	JRST	(T4)			;YES--DISPATCH
	AOBJN	T2,DLPDV1		;NO--TRY NEXT ONE
	PJRST	ECOD2##			;NO MATCH--ERROR

DLPDVT:	11,,DVPRAM			;LOAD LPT RAM
	12,,DVPVFU			;LOAD LPT VFU
	1004,,DVPSTS			;READ DEVICE STATUS
	1005,,DVPFTR			;READ FORMS TYPE
	2005,,DVPFTS			;SET FORMS TYPE
	DLPDVL==.-DLPDVT		;DISPATCH TABLE LENGTH

;HERE TO READ LPT STATUS

DVPSTS:	MOVEI	T1,0			;ZERO INITIAL STATUS
	MOVE	T2,DEVSTS(F)		;GET STATUS BITS SENT FROM FRONT-END
	TRNE	T2,EM.OFL+EM.NXD	;OFF-LINE?
	TLO	T1,(DV.OFL)		;YES
	TLNE	T2,DL.VFE		;VFU ERROR?
	TRO	T1,DV.VFE		;YES
	PJRST	STOTC1##		;STORE STATUS, SKIP RETURN

;HERE TO READ/SET FORMS TYPE NAME

DVPFTR:	MOVE	T1,DLPFRM(F)		;GET FORMS NAME
	JRST	STOTC1##		;RETURN IT TO THE USER

DVPFTS:	PUSHJ	P,GETWR1##		;FETCH USER'S ARGUMENT
	  JRST	RTM1##			;ADDRESS CHECK ERROR
	MOVEM	T1,DLPFRM(F)		;SET FOR POSTERITY
	JRST	CPOPJ1##		;SUCCESS RETURN
;ROUTINE TO LOAD LPT RAM/VFU
;ARGS:	F/DDB ADDRESS
;	M/USER ARGUMENT AREA ADDRESS
;CALL:	SAVE P1-P4
;	PUSHJ	P,DVPXXX		WHERE XXX IS RAM OR VFU
;	  RETURN HERE IF UNSUCCESSFUL
;	RETURN HERE IF SUCCESSFUL

DVPRAM:	TDZA	P2,P2			;REMEMBER LOADING RAM
DVPVFU:	MOVEI	P2,1			;REMEMBER LOADING VFU
	PUSHJ	P,DLPOFL		;MUST BE ON-LINE
	PUSHJ	P,GETWR1##		;GET RAM/VFU BYTE-COUNT ARG FROM USER
	  PJRST	ECOD3##			;ERROR
	JUMPLE	T1,ECOD3##		;ERROR IF BYTE COUNT NOT GREATER THAN ZERO
	MOVE	P3,T1			;REMEMBER BYTE COUNT
	ADDI	T1,3(P2)		;FUDGE REMAINDER
	IDIVI	T1,4(P2)		;MAKE T1 A WORD-COUNT
	CAILE	T1,^D128		;WITHIN REASON?
	PJRST	ECOD3##			;NO--OUT-OF-RANGE ERROR
	MOVN	P1,T1			;YES--GET -WC
	HRLZS	P1			;MAKE LH OF AOBJN POINTER
	PUSHJ	P,GETWR1##		;GET ADDRESS OF RAM/VFU DATA BLOCK
	  PJRST	RTM1##			;COULDN'T--GIVE ADDRESS-ERROR RETURN
	HRRI	M,-1(T1)		;PREPARE FOR CALL TO GETWR1
	MOVEI	T2,^D160		;WORDS OF MONITOR FREE CORE
	PUSHJ	P,GETWDS##		;ALLOCATE CORE
	  PJRST	ECOD3##			;NOT REALLY OUT OF RANGE, BUT ...
	MOVE	P4,T1			;REMEMBER ADDRESS OF FREE CORE
	HRR	P1,T1			;FINISH BUILDING AOBJN POINTER
	JUMPN	P2,DVPVF1		;GO GET VFU DATA
DVPMOV:	PUSHJ	P,GETWR1##		;GET WORD FROM USER
	  PJRST	[PUSHJ	P,DVPGIV	;ERROR--GIVE BACK FREE CORE
		 PJRST	RTM1##]		;GIVE ADDRESS-ERROR RETURN
	MOVEM	T1,(P1)			;SAVE WORD IN OUR BUFFER AREA
	AOBJN	P1,DVPMOV		;LOOP IF MORE DATA TO MOVE
	HRLI	P4,(POINT 18,)		;P4 IS BYTE POINTER
	MOVE	P2,[.EMLPT,,EM.16B+EM.IND+.EMLDR] ;FUNCTION WORD
	PUSH	P,P3			;SET UP THE BYTE COUNT
	JRST	DVPCMN			;GO TO COMMON PART
DVPVF1:	HRLI	P1,(POINT 8,0)		;MAKE OUTPUT BYTE POINTER
	MOVE	P2,P3			;PICK UP BYTE COUNT
	PUSHJ	P,DVPVB1		;GET A VFU BYTE
	CAIN	T2,25			;STANDARD START CODE?
	  MOVEI	T2,356			;YES
	CAIN	T2,26			;6 LPT?
	  MOVEI	T2,354			;YES
	CAIN	T2,27			;8 LPT?
	  MOVEI	T2,355			;YES
	SKIPA				;ALREADY HAVE FIRST BYTE
DVPVF2:	PUSHJ	P,DVPVFB		;GET ANOTHER BYTE
	PUSH	P,T2			;BYTES NEED TO SWAP
	SOJG	P2,DVPVF3		;COUNT IT
	SETZ	T2,			;PUT A ZERO BYTE FOR LAST
	JRST	DVPVF4			;GO STORE IT
DVPVF3:	PUSHJ	P,DVPVFB		;GET NEXT BYTE
	CAIN	T2,126			;STOP CODE?
	  MOVEI	T2,357			;YES
DVPVF4:	IDPB	T2,P1			;PUT BYTE INTO OUTPUT
	POP	P,T2			;GET SWAPPED BYTE
	IDPB	T2,P1			;PUT IT INTO OUTPUT ALSO
	SOJG	P2,DVPVF2		;LOOP THRU WHOLE VFU
	HRLI	P4,(POINT 16,)		;SET UP BYTE POINTER FOR DTESER
	MOVE	P2,[.EMLPT,,EM.16B+EM.IND+.EMLDV] ;SET UP FUNCTION WORD
	PUSH	P,P3			;SAVE ON STACK NOW
DVPCMN:	MOVE	P3,DLPDUX(F)		;P3 IS UNIT #,,DLP DTE INDEX
	MOVE	P1,DLPCDN(F)		;GET CPU#,,DTE#
	PUSH	P,S			;SAVE S
	HRRZ	S,P4			;SET S TO BUFFER ADDR
DVPPRT:	MOVEI	T1,300			;DO MAX OF 300 BYTE TRANSFERS
	CAML	T1,-1(P)		;FEWER BYTES REMAINING?
	MOVE	T1,-1(P)		;YEP, USE SMALLER NUMBER
	HRR	P3,T1			;PUT COUNT INTO MESSAGE
	MOVNS	T1			;CALCULATE REMAINING DATA
	ADDM	T1,-1(P)
	SKIPG	-1(P)			;LAST MESSAGE?
	HRLI	S,DVPGIV		;YES, GIVE BACK CORE ON THIS ONE
	PUSHJ	P,DTEQUE##		;YES--QUEUE THE REQUEST
	  PJRST	DLPERR			;ERROR--SAY DEVICE OFF-LINE
	ADDI	P4,300/4		;POINT TO NEXT PART OF STRING
	SKIPE	-1(P)			;DONE?
	JRST	DVPPRT			;NO, GO DO THE NEXT PART
	PUSHJ	P,DLPEOF		;SEND EOF TO TERMINATE LOAD FUNCTION
	  PJRST	DLPER1			;ERROR--SAY DEVICE OFF-LINE
	POP	P,S			;RESTORE S
	POP	P,(P)			;THROW AWAY COUNT
	PJRST	CPOPJ1##		;SKIP RETURN

DVPVFB:	TLNE	T3,760000		;MORE DATA STILL IN WORD?
	JRST	DVPVB2			;YES, GO GET IT
DVPVB1:	PUSHJ	P,GETWR1##		;NO, GET NEXT WORD
	  PJRST	[POP P,(P)		;POP OFF RETURN
		 PUSHJ	P,DVPGIV	;GIVE BACK CORE
		 PJRST	RTM1##]		;GIVE ADDRESS-ERROR RETURN
	MOVE	T3,[POINT 7,T1]		;RESET BYTE POINTER
DVPVB2:	ILDB	T2,T3			;GET A BYTE
	POPJ	P,			;RETURN

DLPERR:	PUSHJ	P,DVPGIV		;GIVE BACK FREE CORE
DLPER1:	POP	P,S			;RESTORE S
	POP	P,(P)			;THROW AWAY COUNT
	PJRST	ECOD7##			;SAY DEVICE OFF-LINE
;ROUTINE TO GIVE BACK MONITOR FREE CORE
;ARGS:	RH(S)/ADDRESS OF FREE CORE AREA
;CALL:	PUSHJ	P,DVPGIV
;	RETURN HERE

DVPGIV:	MOVEI	T1,^D160		;RETURN THE WORDS WE USED
	HRRZ	T2,S			;GET ADDRESS OF CORE AREA
	PJRST	GIVWDS##		;GIVE IT BACK



;ROUTINE TO SET EOF STATUS FOR FRONT-END LPT
;ARGS:	F/DDB ADDRESS
;CALL:	SAVE P1-P4,S
;	PUSHJ	P,DLPEOF
;	  RETURN HERE IF UNSUCCESSFUL
;	RETURN HERE IF EOF SENT SUCCESSFULLY

DLPEOF:	MOVE	P3,DLPDUX(F)		;P3 IS UNIT #,,DLP DTE INDEX
	MOVE	P1,DLPCDN(F)		;GET CPU#,,DTE#
	MOVE	P2,[.EMLPT,,EM.16B+EM.IND+.EMHDS] ;SET DEVICE STATUS FOR LPT
	HRRI	P3,2			;TWO 8-BIT BYTES OF STATUS
	MOVE	P4,[POINT 16,[BYTE (16) EM.EOF]]
	MOVEI	S,0			;NO POST ROUTINE OR VALUE TO SAVE
	PUSHJ	P,DTEQUE##		;QUEUE THE REQUEST
	  POPJ	P,			;ERROR--NON-SKIP RETURN
	PJRST	CPOPJ1##		;SUCCESS--SKIP RETURN
SUBTTL	GENERAL SUBROUTINES


;INTERRUPT REGISTER SETUP
;CALL WITH:
;	P1=CPU #,,DTE #
;	P3=LINE,,DATA COUNT
;	P4=BYTE POINTER TO MESSAGE

SETRGS:	MOVE	T1,P4		;COPY BYTE POINTER
	ILDB	T1,T1		;GET GENERAL STATUS BYTE
	TRNE	T1,EM.NXD	;NON-EXISTANT DEVICE?
	POPJ	P,		;THEN WE CERTAINLY DON'T KNOW ABOUT IT
	MOVE	F,DDBTAB##+.TYLPT ;POINT TO PROTOTYPE DDB
SETRG1:	HLRZ	F,DEVSER(F)	;LINK TO NEXT
	JUMPE	F,SETRG2	;GO CONFIGURE IF END OF CHAIN
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,.TYLPT	;STILL LOOKING AT RIGHT TYPE?
	JRST	SETRG2		;NO--MUST CONFIGURE
	HRRZ	T1,DEVSER(F)	;GET DISPATCH
	CAIN	T1,RLPDSP	;OWNED BY US?
	CAME	P1,DLPCDN(F)	;AND CPU,,DTE NUMBERS MATCH?
	JRST	SETRG1		;TRY NEXT DDB
	HLRZ	T1,DLPDUX(F)	;GET FE UNIT (LINE) NUMBER
	HLRZ	T2,P3		;AND THE ONE FROM THE MESSAGE
	CAIE	T1,(T2)		;MATCH?
	JRST	SETRG1		;TRY ANOTHER
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	IOSET##		;GET THE REST OF THE AC'S
	
SETRG2:	SETZ	F,		;UNKNOWN DEVICE
	PUSHJ	P,DLPDTS	;AUTOCONFIGURE A LINE PRINTER
	  POPJ	P,		;FAILED
	AOS	(P)		;GIVE SKIP RETURN
	PJRST	IOSET##		;GET THE REST OF THE AC'S


FNDDLP:	MOVE	F,DDBTAB##+.TYLPT ;POINT TO PROTOTYPE DDB
FNDDL1:	HLRZ	F,DEVSER(F)	;LINK TO NEXT
	JUMPE	F,CPOPJ1##	;NO LPTS??
	LDB	T1,PDVTYP##	;GET DEVICE TYPE
	CAIE	T1,.TYLPT	;STILL LOOKING AT RIGHT TYPE?
	JRST	CPOPJ1##	;GIVE UP
	HRRZ	T1,DEVSER(F)	;GET DISPATCH
	CAIN	T1,RLPDSP	;OWNED BY US?
	CAME	P1,DLPCDN(F)	;AND CPU,,DTE NUMBERS MATCH?
	JRST	FNDDL1		;TRY NEXT DDB
	HLRZ	T1,DLPDUX(F)	;GET FE UNIT (LINE) NUMBER
	CAIE	T1,(T3)		;MATCH?
	JRST	FNDDL1		;TRY ANOTHER
	POPJ	P,		;RETURN WITH DDB IN AC 'F'
SUBTTL	END

	END