PGM PDRIV REL ********************************************************** * * * Device driver for single character output devices ie. * * Console printer, paper tape punch etc. * * * ********************************************************** * * States and interrupt vectors * MPICMSK EQU #C2 COPRDY EQU 1 ERRVEC EQU #3FC * ERROR TRAP VECTOR * * Device control block symbols * * 0 ; DEVICE DRIVER PTR (BCPL) * 0 ; CODE LINK (=0) * 0 D.ID EQU 6 * id D.WKQ EQU 8 * work queue D.START EQU 10 * start routine - for QPKT D.STOP EQU 14 * stop routine - for DQPKT D.CALL EQU 18 * subroutine jump to D.INT EQU 20 * interrupt routine offset address D.I EQU D.CALL+6 * offset for interrupt rtn D.VEC EQU 24 * interrupt vector number D.CSW EQU 26 * control and status word D.IOW EQU 28 i/o address * * Packet symbols * P.ID EQU 2 * task or device id P.TYPE EQU 4 * type or action P.RES1 EQU 6 * first result P.RES2 EQU 8 * second result P.A1 EQU 10 * argument 1 * * The rootnode * CRNTSK EQU #506 DEVMVP EQU #51A * MOVPKT for device drivers (MC addr) DEVINT EQU #51E * INTENT for device drivers (MC addr) DEVRET EQU #522 * INTRET for device drivers (MC addr) DW PINITI * initialisation rtn DW PUNINI * uninitialisation rtn * Device initialisation routine. It is entered with the * address of the DCB in BX. BX and DI must be preserved. * assume console USART has been set up by the monitor PINIT MOV D.START(BX),!PSTART MOV D.STOP(BX),!PSTOP MOV D.START+2(BX),CS MOV D.STOP+2(BX),CS PUSH SI MOV SI,!PINT make offset for CALL in DCB MOV D.INT(BX),SI MOV D.INT+2(BX),CS correct code seg in DCB MOV SI,D.VEC(BX) get interrupt vector number ADD SI,!40 SHL SI SHL SI MOV (SI),BX plug interrupt vector with ADD (SI),!D.CALL address MOV 2(SI),!0 CS := 0 for interrupt POP SI RETS * Device uninitialisation routine. It is entered with * the address of the DCB in BX, which must be preserved. PUNIN PUSH AX MOV AX,ERRVEC PUSH BX MOV BX,D.VEC(BX) get address to plug ADD BX,!40 SHL BX SHL BX MOV (BX),AX plug it MOV AX,ERRVEC+2 MOV 2(BX),AX POP BX POP AX RETS * Device start routine. This is entered whenever a pkt * is sent to the device and its work queue is empty. It * is entered with the address of the DCB in BX, and the * BCPL address of the packet in SI. It returns non-zero. PSTART MOV DX,D.CSW(BX) get address of status register IN TEST AL,!COPRDY device ready? JNE PST yes - write immediately PSTARTI MOV DL,!1 no - enable interrupts MOV CX,D.VEC(BX) interrupt vector number SHL DL,CL NOT DL IN MPICMSK AND AL,DL OUT MPICMSK RETS * Device stop routine. This is entered if the head pkt * is dEQUeued from the device. It is entered with the * DCB in BX, which must * be preserved. PSTOP PUSH CX MOV DL,!1 MOV CX,D.VEC(BX) get interrupt number SHL DL,CL IN MPICMSK OR AL,DL OUT MPICMSK POP CX RETS * This routine writes the head pkt and returns it PST SHL SI * check for line-feed, if found send 3 idles CMP P.A1(SI),!#A line feed? JNE PSTA1 MOV P.A1(SI),!0 set up idling MOV P.RES2(SI),!3 idle count MOV AL,!#A MOV DX,D.IOW(BX) OUT PUSH CS CALL PSTARTI enable interrupts B PSTA2 * PSTA1 CMP P.A1(SI),!0 idling? JNE PSTA3 no DEC P.RES2(SI) JE PSTA3 handle last idle normally CMP P.RES2(SI),!3 see if count in range JAE PSTA3 not one of mine PUSH CS CALL PSTARTI enable interrupts with impunity MOV DX,D.IOW(BX) XOR AL,AL OUT PSTA2 MOV AX,CRNTSK SHL AX RETS * PSTA3 MOV DX,(SI) dequeue pkt MOV D.WKQ(BX),DX OR DX,DX JNE PST1 MOV CX,D.VEC(BX) disable interrupts MOV DL,!1 SHL DL,CL IN MPICMSK OR AL,DL OUT MPICMSK PST1 MOV CX,D.ID(BX) MOV DX,D.IOW(BX) write char after disabling MOV AX,P.A1(SI) get it OUT write it MOV BX,CRNTSK SHL BX getting args ready for MOVPKT JIS DEVMVP MOVPKT will execute RETS instruction * This code is entered by the subroutine jump in the DCB * which in turn was entered via the interrupt vector. The last * word pushed onto the m/c stack therefore is the address of the * DCB + D.I PINT PUSH BX PUSH AX PUSH CX PUSH DX PUSH SI MOV BX,SP get stack pointer MOV BX,10(BX) get IP (points into DCB) SUB BX,!D.I MOV SI,D.WKQ(BX) get BCPL pkt ptr OR SI,SI JE PINTOUT MAY GET SPUROUS INT. AFTER STOPPING PUSH CS CALL PST JIS DEVINT return via INTENT PINTOUT JIS DEVRET * EVEN DSEG EVEN PINITI DW PINIT DW 0 PUNINI DW PUNIN DW 0 END