d 	.TITLE	LPDRIVER - LP11/LS11/LV11 LINE PRINTER DRIVER
 	.IDENT	/X05/
,
;
; COPYRIGHT (C) 1977
X; DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS 01754
;
 ; THIS SOFTWARE IS FURNISHED  UNDER A LICENSE FOR USE ONLY ON A SINGLE
; COMPUTER  SYSTEM AND  MAY BE  COPIED ONLY WITH  THE INCLUSION OF THE
; ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE, OR ANY OTHER COPIES THEREOF,
L; MAY NOT BE PROVIDED OR  OTHERWISE MADE AVAILABLE TO ANY OTHER PERSON
; EXCEPT FOR USE ON SUCH SYSTEM AND TO ONE WHO AGREES TO THESE LICENSE
; TERMS.  TITLE TO AND  OWNERSHIP OF THE  SOFTWARE  SHALL AT ALL TIMES
x; REMAIN IN DEC.
;
@; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD  NOT BE CONSTRUED  AS A COMMITMENT  BY DIGITAL  EQUIPMENT
; CORPORATION.
l;
; DEC ASSUMES  NO  RESPONSIBILITY  FOR  THE USE OR  RELIABILITY OF ITS
4; SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DEC.
;
; R. HEINEN 6-SEP-76
`	;
	; MODIFIED BY:
(
;

;	D. N. CUTLER 20-AUG-77

;
T; LP11/LS11/LV11 LINE PRINTER DRIVER
;
; MACRO LIBRARY CALLS
;
 
	.LIBRARY "LIB.MLB"
H	$IDBDEF				;DEFINE IDB OFFSETS
	$IODEF				;DEFINE I/O FUNCTION CODES
	$IRPDEF				;DEFINE IRP OFFSETS
t	$LPDEF				;DEFINE LINE PRINTER CHARACTERISTICS
	$MSGDEF				;DEFINE SYSTEM MESSAGE TYPES
<	$PCBDEF				;DEFINE PCB OFFSETS
	$PRDEF				;DEFINE PROCESSOR REGISTERS
	$SSDEF				;DEFINE SYSTEM STATUS VALUES
h	$UCBDEF				;DEFINE UCB OFFSETS
 
0;
; LOCAL SYMBOLS
;
\; ARGUMENT LIST OFFSET DEFINITIONS
;
$ 
P1=0					;FIRST FUNCTION DEPENDENT PARAMETER
P2=4					;SECOND FUNCTION DEPENDENT PARAMETER
PP3=8					;THIRD FUNCTION DEPENDENT PARAMETER
P4=12					;FOURTH FUNCTION DEPENDEND PARAMETER
P5=16					;FIFTH FUNCTION DEPENDENT PARAMETER
|P6=20					;SIXTH FUNCTION DEPENDENT PARAMETER
 
D;
; CHARACTER CODE DEFINITIONS
;
p 
C_CR=13					;CARRIAGE RETURN
8C_FF=12					;FORM FEED
C_VT=11					;VERTICLE TAB
 C_LF=10					;LINE FEED
dC_TAB=9					;TABULATION
 
,;
; FLAG REGISTER BIT DEFINITIONS
;
X 
M_CRPEND=1				;CARRIAGE RETURN PENDING
 V_CRPEND=0				;
 
;
L; LP11/LS11/LV11 DEVICE REGISTER OFFSET DEFINITIONS
;
 
x	$DEFINI	LP
 
@$DEF	LP_CSR		.BLKW	1	;CONTROL STATUS REGISTER
$DEF	LP_DBR		.BLKW	1	;DATA BUFFER REGISTER
  
l 	$DEFEND	LP
  
4!;
!; DEFINE DEVICE DEPENDENT UNIT CONTROL BLOCK OFFSETS
!;
`" 
"	$DEFINI	UCB
(# 
#.=UCB$K_LENGTH				;
# 
T$$DEF	UCB$L_LP_MUTEX	.BLKL	1	;LINE PRINTER UCB MUTEX
$$DEF	UCB$B_LP_CURSOR	.BLKB	1	;CURRENT HORIZONAL POSITION
%$DEF	UCB$B_LP_LINCNT	.BLKB	1	;CURRENT LINE COUNT ON PAGE
%$DEF	UCB$B_LP_OFLCNT	.BLKB	1	;OFFLINE TIME COUNTER
%			.BLKB	1	;SPARE UNUSED BYTE
H& 
&	$DEFEND	UCB
' 
t';
'; LOCAL DATA
<(;
(; DRIVER DISPATCH TABLE
);
h) 
)	.PSECT	WIONONPAGED
0*LP$DDT::				;
*	.LONG	STARTIO			;START I/O OPERATION
*	.LONG	0			;UNSOLICITED INTERRUPT
\+	.LONG	FUNCTABLE		;FUNCTION TABLE
+	.LONG	IOC$CANCELIO		;CANCEL I/O
$,	.LONG	0,0			;NO DIAGNOSTIC OR ERROR LOG INFORMATION
,	.PAGE
,	.SBTTL	LP11/LS11/LV11 FUNCTION DECISION TABLE
P-;
-; LP11/LS11/LV11 FUNCTION DECISION TABLE
.;
|. 
.FUNCTABLE:				;FUNCTION DECISION TABLE
D/	FUNCTAB	,<WRITELBLK,WRITEPBLK,WRITEVBLK,SETCHAR,SETMODE> ;LEGAL FUNCTIONS
/	FUNCTAB	,<WRITELBLK,WRITEPBLK,WRITEVBLK> ;BUFFERED I/O FUNCTIONS
0	FUNCTAB LP_WRITE,<WRITELBLK,WRITEPBLK,WRITEVBLK> ;WRITE FUNCTIONS
p0	FUNCTAB	LP_SETMODE,<SETCHAR,SETMODE> ;SET CHARACTERISTICS FUNCTIONS
0	.PAGE
81	.SBTTL	SET CHARACTERISTICS AND SET MODE FUNCTION PROCESSING
1;+
 2; LP_SETMODE - SET CHARACTERISTICS AND SET MODE FUNCTION PROCESSING
d2;
2; THIS ROUTINE IS CALLED FROM THE FUNCTION DECISION TABLE DISPATCHER TO PROCESS
,3; A SET MODE FUNCTION TO A LINE PRINTER.
3;
3; INPUTS:
X4;
4;	R0 = SCRATCH.
 5;	R1 = SCRATCH.
5;	R2 = SCRATCH.
5;	R3 = ADDRESS OF I/O REQUEST PACKET.
L6;	R4 = CURRENT PROCESS PCB ADDRESS.
6;	R5 = ASSIGNED DEVICE UCB ADDRESS.
7;	R6 = ADDRESS OF CCB.
x7;	R7 = I/O FUNCTION CODE.
7;	R8 = FUNCTION DECISION TABLE DISPATCH ADDRESS.
@8;	R9 = SCRATCH.
8;	R10 = SCRATCH.
9;	R11 = SCRATCH.
l9;	AP = ADDRESS OF FIRST FUNCTION DEPENDENT PARAMETER.
9;
4:; OUTPUTS:
:;
:;	THE SPECIFIED CHARACTERISTICS ARE MOVED INTO THE DEVICE UCB AND THE
`;;	I/O IS COMPLETED.
;;-
(< 
<	.PSECT	Y$EXEPAGED
<LP_SETMODE:				;SET MODE FUNCTION PROCESSING
T=	MOVL	P1(AP),R1		;GET ADDRESS OF CHARACTERISTICS
=	IFNORD	#8,(R1),20$		;CAN CHARACTERISTICS QUADWORD BE READ?
>	PUSHL	R3			;SAVE PACKET ADDRESS
>	MOVAB	UCB$L_LP_MUTEX(R5),R0	;GET ADDRESS OF UCB MUTEX
>	JSB	SCH$LOCKW		;LOCK UCB FOR WRITE ACCESS
H?	CMPL	#IO$_SETMODE,R7		;SET MODE FUNCTION?
?	BEQL	10$			;IF EQL YES
@	MOVW	(R1),UCB$B_DEVCLASS(R5)	;SET DEVICE CLASS AND TYPE
t@10$:	MOVW	2(R1),UCB$W_DEVBUFSIZ(R5) ;SET DEFAULT BUFFER SIZE
@	MOVL	4(R1),UCB$L_DEVDEPEND(R5) ;SET DEVICE CHARACTERISTICS
<A	JSB	SCH$UNLOCK		;UNLOCK UCB
A	POPL	R3			;RESTORE PACKET
B	MOVZWL	#SS$_NORMAL,R0		;SET NORMAL COMPLETION STATUS
hB	JMP	EXE$FINISHIOC		;
B20$:	MOVZWL	#SS$_ACCVIO,R0		;SET ACCESS VIOLATION STATUS
0C	JMP	EXE$ABORTIO		;
C	.PAGE
C	.SBTTL	WRITE FUNCTION PROCESSING
\D;+
D; LP_WRITE - WRITE FUNCTION PROCESSING
$E;
E; THIS ROUTINE IS CALLED FROM THE FUNCTION DECISION TABLE DISPATCHER TO PROCESS
E; A WRITE PHYSICAL, WRITE LOGICAL, OR WRITE VIRTUAL FUNCTION TO A LINE PRINTER.
PF;
F; INPUTS:
G;
|G;	R0 = SCRATCH.
G;	R1 = SCRATCH.
DH;	R2 = SCRATCH.
H;	R3 = ADDRESS OF I/O REQUEST PACKET.
I;	R4 = CURRENT PROCESS PCB ADDRESS.
pI;	R5 = ASSIGNED DEVICE UCB ADDRESS.
I;	R6 = ADDRESS OF CCB.
8J;	R7 = I/O FUNCTION CODE.
J;	R8 = FUNCTION DECISION TABLE DISPATCH ADDRESS.
 K;	R9 = SCRATCH.
dK;	R10 = SCRATCH.
K;	R11 = SCRATCH.
,L;	AP = ADDRESS OF FIRST FUNCTION DEPENDENT PARAMETER.
L;
L; OUTPUTS:
XM;
M;	THE FUNCTION PARAMETERS ARE CHECKED AND THE USER'S BUFFER IS FORMATTED
 N;	AND COPIED INTO A SYSTEM BUFFER FOR PROCESSING BY THE LINE PRINTER
N;	DRIVER.
N;-
LO 
OLP_WRITE:				;WRITE FUNCTION PROCESSING
P	CLRL	R11			;CLEAR TOTAL NUMBER OF OVERHEAD BYTES
xP	CLRL	R10			;ASSUME WRITE PASS ALL FUNCTION
PFORMAT:	MOVL	FP,SP			;REMOVE ALL TEMPORARIES FROM STACK
@Q	PUSHR	#^M<R3,R4,R5,R6,R7,AP>	;SAVE REGISTERS
Q	MOVL	P1(AP),R8		;GET STARTING ADDRESS OF USER BUFFER
R	MOVZWL	P2(AP),R9		;GET LENGTH OF USER BUFFER
lR	CMPL	#IO$_WRITEPBLK,R7	;WRITE PHYSICAL BLOCK?
R	BEQL	10$			;IF EQL YES
4S	MOVL	P4(AP),IRP$B_CARCON(R3)	;INSERT CARRIAGE CONTROL INFORMATION
S	JSB	TT$CARRIAGE		;TRANSLATE CARRIAGE CONTROL INFORMATION
S	MOVZBL	IRP$B_CARCON(R3),R0	;GET NUMBER OF PREFIX CONTROL BYTES
`T	MOVZBL	IRP$B_CARCON+2(R3),R1	;GET NUMBER OF SUFFIX CONTROL BYTES
T	ADDL	R0,R1			;CALCULATE NUMBER OF CARRIAGE CONTROL BYTES
(U	MOVAB	32(R1)[R11],R10		;CALCULATE TOTAL NUMBER OF OVERHEAD BYTES
U10$:	TSTL	R9			;ANY BUFFER SPECIFIED?
U	BEQL	20$			;IF EQL NO
TV	MOVQ	R8,R0			;RETRIEVE BUFFER PARAMETERS
V	JSB	EXE$WRITECHK		;CHECK ACCESSIBILITY OF USER BUFFER
W20$:	MOVAB	12(R9)[R10],R1		;CALCULATE LENGTH OF BUFFER REQUIRED
W	JSB	EXE$BUFFRQUOTA		;CHECK IF PROCESS HAS SUFFICIENT QUOTA
W	BLBC	R0,45$			;IF LBC QUOTA CHECK FAILURE
HX	JSB	EXE$ALLOCBUF		;ALLOCATE BUFFER FOR LINE PRINTER OUTPUT
X	BLBC	R0,45$			;IF LBC ALLOCATION FAILURE
Y	MOVL	(SP),R3			;RETRIEVE ADDRESS OF I/O PACKET
tY	MOVL	R2,IRP$L_SVAPTE(R3)	;SAVE ADDRESS OF BUFFERED I/O PACKET
Y	SUBW	R1,PCB$W_BYTCNT(R4)	;ADJUST BUFFERED I/O QUOTA
<Z	MOVW	R1,IRP$W_BOFF(R3)	;SET NUMBER OF BYTES CHARGED TO QUOTA
Z	CLRL	IRP$L_MEDIA(R3)		;CLEAR LINE FEED COUNT IN PACKET
[	MOVW	R9,IRP$W_BCNT(R3)	;INSERT SIZE OF USER BUFFER
h[	MOVAB	12(R2),R2		;GET ADDRESS OF BUFFER DATA AREA
[	MOVAB	UCB$L_LP_MUTEX(R5),R0	;GET ADDRESS OF UCB MUTEX
0\	JSB	SCH$LOCKW		;LOCK UCB FOR WRITE ACCESS
\	CMPL	#IO$_WRITEPBLK,R7	;WRITE PASS ALL?
\	BEQL	50$			;IF EQL YES
\]	SUBW	#12,R1			;CALCULATE ACTUAL LENGTH OF DATA AREA
]	MOVZBL	UCB$B_LP_CURSOR(R5),R4	;GET CURRENT HORIZONAL CARRIAGE POSITION
$^	MOVZWL	UCB$W_DEVSTS(R5),R6	;GET CURRENT CARRIAGE RETURN PENDING FLAG
^	MOVZBL	UCB$B_LP_LINCNT(R5),R7	;GET CURRENT LINE ON PAGE
^	MOVZBL	UCB$W_DEVBUFSIZ(R5),R10	;GET WIDTH OF PRINTER CARRIAGE
P_	MOVL	#^X20,AP		;ASSUME PRINTER DOES NOT HAVE LOWER CASE
_	BBC	#LP$V_LOWER,UCB$L_DEVDEPEND(R5),35$ ;IF CLR, NO LOWER CASE
`	CLRL	AP			;SET FOR PRINTER WITH LOWER CASE
|`35$:	BSBB	70$			;INSERT PREFIX CARRIAGE CONTROL
`30$:	DECL	R9			;ANY MORE BYTES TO TRANSFER TO SYSTEM BUFFER?
Da	BLSS	40$			;IF LSS NO
a	MOVZBL	(R8)+,R0		;GET NEXT BYTE FROM USER BUFFER
b	BSBB	WRITE_BYTE		;WRITE BYTE IN SYSTEM BUFFER
pb	BRB	30$			;
b40$:	BSBB	80$			;INSERT SUFFIX CARRIAGE CONTROL IN BUFFER
8c	SUBL	IRP$L_SVAPTE(R3),R2	;CALCULATE LENGTH OF OUTPUT PLUS HEADER
c	SUBW3	#12,R2,IRP$L_MEDIA+2(R3) ;CALCULATE ACTUAL LENGTH OF OUTPUT BUFFER
 d	MOVB	R4,UCB$B_LP_CURSOR(R5)	;SAVE CURRENT HORIZONAL CARRIAGE POSITION
dd	INSV	R6,#V_CRPEND,#1,UCB$W_DEVSTS(R5) ;SAVE CARRIAGE RETURN PENDING
d	MOVB	R7,UCB$B_LP_LINCNT(R5)	;SAVE CURRENT LINE ON PAGE
,e	BRB	60$			;
e45$:	POPR	#^M<R3,R4,R5,R6,R7,AP>	;RESTORE REGISTERS
e	JMP	EXE$ABORTIO		;
Xf50$:	MOVW	R9,IRP$L_MEDIA+2(R3)	;INSERT NUMBER OF BYTES TO PRINT
f	MOVC	R9,(R8),(R2)		;MOVE CHARACTERS TO SYSTEM BUFFER
 g60$:	POPR	#^M<R3,R4,R5,R6,R7,AP>	;RESTORE REGISTERS
g	PUSHL	R3			;SAVE ADDRESS OF I/O PACKET
g	MOVAB	UCB$L_LP_MUTEX(R5),R0	;GET ADDRESS OF UCB MUTEX
Lh	JSB	SCH$UNLOCK		;UNLOCK UCB
h	POPL	R3			;RESTORE ADDRESS OF I/O PACKET
i	JMP	EXE$QIODRVPKT		;QUEUE I/O PACKET TO DRIVER
xi 
i;
@j; SUBROUTINE TO INSERT CARRIAGE CONTROL IN BUFFER
j;
k 
lk70$:	MOVZBL	IRP$B_CARCON(R3),-(SP)	;GET NUMBER OF CHARACTERS TO OUTPUT
k	BEQL	100$			;IF EQL NONE
4l	MOVZBL	IRP$B_CARCON+1(R3),R0	;GET CHARACTER TO OUTPUT
l	BRB	85$			;
l80$:	MOVZBL	IRP$B_CARCON+2(R3),-(SP) ;GET NUMBER OF CHARACTERS TO OUTPUT
`m	BEQL	100$			;IF EQL NONE
m	MOVZBL	IRP$B_CARCON+3(R3),R0	;GET CHARACTER TO OUTPUT
(n85$:	BNEQ	90$			;IF NEQ CHARACTER SPECIFIED
n	MOVZBL	#C_CR,R0		;GET CARRIAGE RETURN
n	BSBB	WRITE_BYTE		;WRITE BYTE IN SYSTEM BUFFER
To	MOVZBL	#C_LF,R0		;GET LINE FEED
o90$:	BSBB	WRITE_BYTE		;WRITE BYTE IN SYSTEM BUFFER
p	SOBGTR	(SP),90$		;ANY MORE LEFT TO INSERT?
p100$:	TSTL	(SP)+			;REMOVE COUNT FROM STACK
p	RSB				;
Hq	.PAGE
q	.SBTTL	WRITE BYTE INTO SYSTEM BUFFER
r;
tr; SUBROUTINE TO FORMAT AND FILL SYSTEM BUFFER WITH LINE PRINTER OUTPUT ONE BYTE
r; AT A TIME.
<s;
s 
tWRITE_BYTE:				;WRITE BYTE INTO BUFFER
ht	CMPL	#^A/ /,R0		;CONTROL CHARACTER?
t	BGTRU	40$			;IF GTRU YES
0u	BBSC	#V_CRPEND,R6,60$	;IF SET, CARRIAGE RETURN PENDING
u	CMPB	#^A/a/,R0		;POSSIBLY LOWER CASE CHARACTER?
u	BGTRU	10$			;IF GTRU NO
\v	CMPB	#^A/z/,R0		;LOWER CASE CHARACTER?
v	BLSSU	20$			;IF LSSU NO
$w	BICL	AP,R0			;CONVERT CHARACTER TO UPPER CASE
w10$:	CMPL	R4,R10			;STILL ROOM ON CURRENT LINE?
w	BGTRU	30$			;IF GTRU NO
Px	INCL	R4			;INCREMENT HORIZONAL POSITION
x20$:	DECL	R1			;ANY ROOM LEFT IN SYSTEM BUFFER?
y	BLSS	150$			;IF LSS NO
|y	MOVB	R0,(R2)+		;INSERT CHARACTER IN SYSTEM BUFFER
y30$:	RSB				;
Dz 
z;
{; CONTROL CHARACTER ENCOUNTERED
p{;
{ 
8|40$:	CMPL	#C_CR,R0		;CARRIAGE RETURN?
|	BLSSU	50$			;IF LSS NO
 }	BGTRU	70$			;IF GTRU NO
d}	BBS	#LP$V_CR,UCB$L_DEVDEPEND(R5),140$ ;IF SET, CARRIAGE RETURN REQUIRED
}	BISL	#M_CRPEND,R6		;SET CARRIAGE RETURN PENDING
,~	RSB				;
~50$:	BBCC	#V_CRPEND,R6,20$	;IF CLR, CARRIAGE RETURN NOT PENDING
~60$:	PUSHL	R0			;SAVE CURRENT CHARACTER
X	MOVZBL	#C_CR,R0		;GET CARRIAGE RETURN CHARACTER
	BSBB	140$			;INSERT CARRIAGE RETURN IN BUFFER
 	POPL	R0			;RETRIEVE CURRENT CHARACTER
	BRB	WRITE_BYTE		;
 
L;
; CHARACTER IS A TAB, LINE FEED, VERTICLE TAB, OR FORM FEED
;
x 
܂70$:	CMPL	#C_TAB,R0		;TABULATION CHARACTER?
@	BGTRU	50$			;IF GTRU NO
	BLSSU	80$			;IF LSSU NO
 
l;
Є; CHARACTER IS A TAB
4;
 
	BBSC	#V_CRPEND,R6,60$	;IF SET, CARRIAGE RETURN PENDING
`	PUSHAB	8(R4)			;CALCULATE NEXT TAB POSITION
Ć	BICL	#7,(SP)			;CLEAR EXCESS BITS
(	SUBL	R4,(SP)			;CALCULATE BLANK COUNT
	MOVZBL	#^A/ /,R0		;SET SPACE CHARACTER
	BRB	100$			;
T 
;
; CHARACTER IS A LINE FEED, VERTICLE TAB, OR FORM FEED
;
 
H80$:	CMPL	#C_VT,R0		;VERTICLE TAB?
	BEQL	50$			;IF EQL YES
	BGTRU	110$			;IF GTRU LINE FEED
t 
؋;
<; CHARACTER IS A FORM FEED
;
 
h	MOVZBL	UCB$L_DEVDEPEND+3(R5),R0 ;GET NUMBER OF LINES PER PAGE
̍	SUBL3	R4,R0,-(SP)		;CALCULATE NUMBER OF LINES TO END OF PAGE
0	BBC	#LP$V_MECHFORM,UCB$L_DEVDEPEND(R5),90$ ;IF CLR, NO MECHANICAL FEED
	ADDL	(SP)+,IRP$L_MEDIA(R3)	;UPDATE NUMBER OF LINES PRINTED
	MOVZBL	#C_FF,R0		;SET FORM FEED CHARACTER
\	BRB	120$			;
90$:	MOVZBL	#C_LF,R0		;SET LINE FEED CHARACTER
$100$:	BSBW	WRITE_BYTE		;INSERT BYTE IN SYSTEM BUFFER
	SOBGTR	(SP),100$		;ANY MORE BYTES TO INSERT?
	TSTL	(SP)+			;REMOVE LOOP COUNT FROM STACK
P	RSB				;
 
;
|; CHARACTER IS A LINE FEED
;
D 
110$:	INCL	R7			;INCREMENT LINE POSITION ON PAGE
	INCL	IRP$L_MEDIA(R3)		;INCREMENT NUMBER OF LINES PRINTED
p	CMPB	R7,UCB$L_DEVDEPEND+3(R5) ;END OF PAGE?
Ԕ	BNEQ	130$			;IF NEQ NO
8120$:	CLRL	R7			;CLEAR LINE POSITION ON PAGE
130$:	BICL	#M_CRPEND,R6		;CLEAR CARRIAGE RETURN PENDING
 140$:	CLRL	R4			;CLEAR HORIZONAL POSITION
d	BRW	20$			;
Ȗ 
,;
; OUTPUT WILL NOT FIT IN ALLOCATED BUFFER
;
X 
150$:	MOVL	IRP$L_SVAPTE(R3),R0	;GET ADDRESS OF BUUFER TO DEALLOCATE
 	CLRL	IRP$L_SVAPTE(R3)	;INDICATE NO BUFFER ALLOCATED
	MOVZWL	IRP$W_SIZE(R0),R10	;SAVE SIZE OF BUFFER
	JSB	EXE$DEANONPAGED		;DEALLOCATE BUFFER
L	MOVAB	-4*6(FP),SP		;REMOVE ALL TEMPORARIES FROM STACK
	POPR	#^M<R3,R4,R5,R6,R7,AP>	;RESTORE REGISTERS
	ADDW	R10,PCB$W_BYTCNT(R4)	;ADJUST BYTE COUNT QUOTA
x	ADDL	#32,R11			;ADJUST COUNT OF OVERHEAD BYTES
ܛ	PUSHL	R3			;SAVE ADDRESS OF I/O PACKET
@	MOVAB	UCB$L_LP_MUTEX(R5),R0	;GET ADDRESS OF UCB MUTEX
	JSB	SCH$UNLOCK		;UNLOCK UCB
	POPL	R3			;RESTORE ADDRESS OF I/O PACKET
l	BRW	FORMAT			;TRY AGAIN
Н	.PAGE
4	.SBTTL	LINE PRINTER DRIVER
;+
; STARTIO - START I/O OPERATION ON LINE PRINTERS
`;
ğ; THIS ROUTINE IS ENTERED WHEN THE ASSOCIATED UNIT IS IDLE AND A PACKET
(; IS AVAILABLE.
;
; INPUTS:
T;
;	R3 = ADDRESS OF I/O REQUEST PACKET.
;	R5 = UCB ADDRESS FOR IDLE UNIT.
;
; OUTPUTS:	
H;
;	NO EXPLICIT OUTPUTS - THE UNIT IS IN WAITING FOR INTERRPUT STATE
;				OR THE I/O IS COMPLETE.
t;-
ؤ 
<	.PSECT	WIONONPAGED
STARTIO:
	MOVL	UCB$L_IRP(R5),R3	;RETRIEVE ADDRESS OF I/O PACKET
h	MOVW	IRP$L_MEDIA+2(R3),UCB$W_BOFF(R5) ;SET NUMBER OF CHARACTERS TO PRINT
̦	MOVL	UCB$L_SVAPTE(R5),R3	;GET ADDRESS OF SYSTEM BUFFER
0	MOVAB	12(R3),R3		;GET ADDRESS OF DATA AREA
	MOVL	@UCB$L_CRB(R5),R4	;GET ADDRESS OF CSR
 
\;
; START NEXT OUTPUT SEQUENCE
$;
 
10$:	MOVW	UCB$W_BOFF(R5),R1	;GET NUMBER OF CHARACTERS REMAINING
P	MOVW	#^X8080,R2		;GET CONTROL REGISTER TEST MASK
20$:	DECW	R1			;ANY MORE CHARACTERS TO OUTPUT?
	BCS	80$			;IF CS NO
|	BITW	R2,LP_CSR(R4)		;PRINTER READY OR HAVE PAPER PROBLEM?
	BLEQ	30$			;IF LEQ NOT READY OR PAPER PROBLEM
D	MOVB	(R3)+,LP_DBR(R4)	;OUTPUT NEXT CHARACTER
	BRB	20$			;
 
p;
ԭ; PRINTER IS NOT READY OR HAS PAPER PROBLEM
8;
 
 30$:	BNEQ	40$			;IF NEQ PAPER PROBLEM
d	ADDW3	#1,R1,UCB$W_BOFF(R5)	;SAVE NUMBER OF CHARACTERS REMAINING
ȯ	DSBINT				;DISABLE INTERRUPTS
,	BISB	#^X40,LP_CSR(R4)	;SET INTERRUPT ENABLE
	WFIKPCH	40$,#12			;WAIT FOR INTERRUPT
	IOFORK				;CREATE A FORK PROCESS
X	BRB	10$			;
 
 ;
; PRINTER HAS PAPER PROBLEM
;
L 
40$:	CLRB	UCB$B_LP_OFLCNT(R5)	;CLEAR OFFLINE COUNTER
	ADDW3	#1,R1,UCB$W_BOFF(R5)	;SAVE NUMBER OF CHARACTERS REMAINING
x50$:	CLRW	LP_CSR(R4)		;DISABLE PRINTER INTERRUPT
ܴ	SETIPL	UCB$B_FIPL(R5)		;LOWER TO FORK LEVEL
@	TSTW	LP_CSR(R4)		;PRINTER STILL HAVE PAPER PROBLEM?
	BGEQ	STARTIO			;IF GEQ NO
	BBS	#UCB$V_CANCEL,UCB$W_STS(R5),70$ ;IF SET, CANCEL I/O OPERATION
l	ACBB	#15,#1,UCB$B_LP_OFLCNT(R5),60$ ;SKIP UNTIL TIMEOUT
ж	CLRB	UCB$B_LP_OFLCNT(R5)	;RESET COUNTER
4	PUSHR	#^M<R3,R4>		;SAVE REGISTERS
	MOVZBL	#MSG$_DEVOFFLIN,R4	;SET UP MESSAGE TYPE
	MOVAB	SYS$GL_OPRMBX,R3	;ADDRESS TARGET MAILBOX
`	BSBW	EXE$SNDEVMSG		;SEND MESSAGE IGNORE ERROR
ĸ	POPR	#^M<R3,R4>		;RESTORE REGISTERS
(60$:	DSBINT				;DISABLE INTERRUPTS
	WFIKPCH	50$,#2			;WAIT FOR AN INTERRUPT OR TIMEOUT 2 SEC
	IOFORK				;CREATE FOR PROCESS
T	BRB	50$			;
 
;
; I/O OPERATION CANCELED
;
H 
70$:	MOVZWL	#SS$_ABORT,R0		;SET OPERATION ABORTED STATUS
	BRB	90$			;
t 
ؽ;
<; I/O OPERATION SUCCESSFULLY COMPLETED
;
 
h80$:	MOVZWL	#SS$_NORMAL,R0		;SET NORMAL COMPLETION STATUS
̿	CLRW	UCB$W_BOFF(R5)		;CORRECT REMAINING CHARACTER COUNT
090$:	MOVL	UCB$L_IRP(R5),R3	;RETRIEVE ADDRESS OF I/O PACKET
	MOVZWL	IRP$L_MEDIA(R3),R1	;GET NUMBER OF LINES PRINTED
	SUBW	UCB$W_BOFF(R5),UCB$W_BCNT(R5) ;CALCULATE NUMBER OF CHARACTERS
\	INSV	UCB$W_BCNT(R5),#16,#16,R0 ;INSERT NUMBER OF CHARACTERS IN STATUS
	REQCOM				;COMPLETE I/O REQUEST
$	.PAGE
	.SBTTL	LP11/LS11/LV11 LINE PRINTER INTERRUPT DISPATCHER
;+
P; LP$INT - LP11/LS11/LV11 LINE PRINTER INTERRUPT DISPATCHER.
;
; THIS ROUTINE IS ENTERED VIA A JSB INSTRUCTION WHEN AN INTERRUPT OCCURS ON AN
|; LP11/LS11/LV11 LINE PRINTER CONTROLLER. THE STATE OF THE STACK ON ENTRY IS:
;
D;	00(SP) = ADDRESS OF IDB ADDRESS.
;	04(SP) = SAVED R3.
;	08(SP) = SAVED R4.
p;	12(SP) = SAVED R5.
;	16(SP) = INTERRUPT PC.
8;	20(SP) = INTERRUPT PSL.
;
 ; INTERRUPT DISPATCHING OCCURS AS FOLLOWS:
d;
;	IF THE INTERRUPT IS EXPECTED, THEN THE DRIVER IS CALLED AT ITS INTERRUPT
,;	WAIT ADDRESS. ELSE THE INTERRUPT IS DISMISSED.
;-
 
XLP$INT::				;ENTRY FROM DISPATCH
	MOVL	@(SP)+,R3		;GET ADDRESS OF IDB
 	MOVQ	IDB$L_CSR(R3),R4	;GET CONTROLLER CSR AND OWNER UCB ADDRESS
	BBCC	#UCB$V_INT,UCB$W_STS(R5),10$ ;IF CLR, INTERRUPT NOT EXPECTED
	CLRW	(R4)			;DISABLE OUTPUT INTERRUPTS
L	MOVL	UCB$L_FR3(R5),R3	;RESTORE REMAINDER OF DRIVER CONTEXT
	JSB	@UCB$L_FPC(R5)		;CALL DRIVER AT INTERRUPT WAIT ADDRESS
10$:	POPR	#^M<R3,R4,R5>		;RESTORE REGISTERS
x	REI				;RETURN
	.PAGE
@	.SBTTL	LINE PRINTER INTIAILIZATION
;+
; LP$INITIAL - INITIALIZE THE PRINTER
l;
; THIS ROUTINE IS CALLED AT SYSTEM STARTUP AND AFTER A POWER FAILURE. THE CSR
4; ADDRESS OF THE RESPECTIVE LP11/LS11/LV11 CONTROLLER IS READ TO INSURE ITS
; PRESENCE ON THE UBA.
;
`; INPUTS:
;
(;	R4 = LINE PRINTER CONTROLLER CSR ADDRESS.
;	R5 = IDB OF UNIT.
;
T; OUTPUTS:
;
;	ALL REGISTERS ARE PRESERVED.
;-
 
HLP$INITIAL::				;INITIALIZATION
	TSTW	(R4)			;SYNCHRONIZE UBA ACCESS
	RSB				;
t 
	.END
