PGM RDRIV REL ********************************************************** * * * Device driver for single character input devices ie. * * Console keyboard, paper tape reader etc. * * * ********************************************************** * * States and interrupt vectors * MPICMSK EQU #C2 COKRDY EQU 2 ERRVEC EQU #3FC * ERROR TRAP VECTOR BRKERR EQU #30 PARERR EQU 8 * * Device control block symbols * * 0 ; device driver ptr (BCPL) * 0 ; link to code (=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 RINITI * initialisation rtn DW RUNINI * 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 RINIT MOV D.START(BX),!RSTART MOV D.STOP(BX),!RSTOP MOV D.START+2(BX),CS MOV D.STOP+2(BX),CS PUSH SI MOV SI,!RINT 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 interrupt CS = 0 POP SI RETS * Device uninitialisation routine. It is entered with * the address of the DCB in BX, which must be preserved. RUNIN 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. RSTART MOV DX,D.IOW(BX) get address of i/o register IN ignore chars in buffer IN * work out which PIC bit should be unmasked MOV CX,D.VEC(BX) MOV DL,!1 SHL DL,CL NOT DL 0 bit now in correct position IN MPICMSK get current mask AND AL,DL OUT MPICMSK enable interrupt NOT DL return non-zero 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. RSTOP 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 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 RINT 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) MOV DX,D.CSW-D.I(BX) status register address MOV SI,D.WKQ-D.I(BX) get pkt MOV AX,CRNTSK SHL AX SHL SI MC pkt address JE RINTOUT XOR CX,CX prepare pkt RES2 IN get device status TEST AL,!COKRDY character received? JNE RINT2 ok USART agrees NOT CX error RINT2 MOV P.RES2(SI),CX set RES2 TEST AL,!BRKERR break hit? JE RINT2A probably not MOV P.RES2(SI),!1 MOV DX,D.IOW-D.I(BX) IN clear bum char MOV AL,!#37 MOV DX,D.CSW-D.I(BX) OUT clear error XOR AX,AX put 0 in pkt B RINT2B * RINT2A TEST AL,!PARERR parity error JE RINT2AB no MOV DX,D.IOW-D.I(BX) IN MOV AL,!#37 MOV DX,D.CSW-D.I(BX) OUT clear error MOV AX,CRNTSK SHL AX B RINTOUT * RINT2AB MOV DX,D.IOW-D.I(BX) get address of i/o register IN fetch character XOR AH,AH clear top byte of word RINT2B MOV P.RES1(SI),AX store char. in pkt MOV DX,(SI) deq pkt MOV D.WKQ-D.I(BX),DX OR DX,DX JNE RINT3 MOV CX,D.VEC-D.I(BX) last dequeued so stop device MOV DL,!1 SHL DL,CL IN MPICMSK OR AL,DL OUT MPICMSK * RINT3 MOV CX,D.ID-D.I(BX) id of sender MOV BX,CRNTSK setting args for MOVPKT SHL BX CIS DEVMVP RINTOUT JIS DEVINT exit via INTENT * EVEN DSEG RINITI DW RINIT DW 0 RUNINI DW RUNIN DW 0 END