PGM DKDRIV REL ********************************************************** * * * Driver for Intel floppy disk system (double density). * * The actions recognised are read, write, seek and dummy * * (gets status). * * * * Graham Adams 2 May 1980 * * 20 May 1980 * * 10 September 1980 * * 19 June 1981 * * 11 August 1981 * * * ********************************************************** * * States etc. * ERRVEC EQU #3FC * error trap vector * * Device control block symbols * * 0 * device driver ptr (BCPL) * 0 * 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 D.I EQU D.CALL+6 * offset for interrupt rtn D.VEC EQU 24 * interrupt vector D.UMASK EQU 26 * unit error bits mask * IOPB starts here D.IOPB EQU 27 D.CHANWD EQU 27 * channel word D.DISKIN EQU 28 * diskette instruction D.NUMREC EQU 29 * no. of records D.TRACK EQU 30 * track address D.SECTOR EQU 31 * sector address D.BUFF EQU 32 * buffer address (16 bits) * 33 * end of IOPB D.REQFLG EQU 34 * * * 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 P.A2 EQU 12 P.A3 EQU 14 P.A4 EQU 16 P.A5 EQU 18 P.A6 EQU 20 P.ACT EQU P.TYPE * controller action P.DERR EQU P.RES1 * controller error code P.STAT EQU P.RES2 * drive status P.BUFF EQU P.A1 * store buffer addr P.WCNT EQU P.A2 * word count P.DRIV EQU P.A3 * drive number P.CYL EQU P.A4 * disc cylinder P.SUR EQU P.A5 * disc surface P.SEC EQU P.A6 * disc sector * * Device actions * A.DUMMY EQU 1000 * dummy - gets status A.READ EQU 1001 * read from disc A.WRITE EQU 1002 * write to disc A.SEEK EQU 1008 * seek track * * I/O addresses for the channel DKBASE EQU #78 * base address of channel WSTART EQU DKBASE+1 * write IOPB address and start RESET EQU DKBASE+7 * reset (output) RDSS EQU DKBASE+0 * read subsystem status RDRESTP EQU DKBASE+1 * read result type RDRESBT EQU DKBASE+3 * read result byte * * diskette operations * NOOP EQU 0 SEEKOP EQU 1 FORMOP EQU 2 RECALOP EQU 3 READOP EQU 4 VEROP EQU 5 WRITEOP EQU 6 WDELOP EQU 7 * * MPICMSK EQU #C2 * master PIC address STOPREQ EQU 1 INTPEND EQU 4 CALREQ EQU 2 ACTREQ EQU 4 * * 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 DKINITI * initialisation rtn DW DKUNINI * uninitialisation rtn * Device initialisation routine. It is entered with the * address of the DCB in BX. BX and DI must be preserved. DKINIT MOV D.START(BX),!DKSTART MOV D.STOP(BX),!DKSTOP MOV D.START+2(BX),CS MOV D.STOP+2(BX),CS PUSH SI MOV SI,!DKINT calculate CALL offset MOV D.INT(BX),SI put in DCB MOV D.INT+2(BX),CS correct code seg in DCB MOV SI,D.VEC(BX) get interrupt number ADD SI,!40 calculate interrupt vector address SHL SI SHL SI MOV (SI),BX plug vector with address of CALL ADD (SI),!D.CALL MOV 2(SI),!0 code segment = 0 POP SI DKINITA1 IN RDSS if interrupt pending TEST AL,!INTPEND JE DKINIT1 IN RDRESTP clear by reading result PUSH BX POP BX IN RDRESBT DKINIT1 OUT RESET JMP DKENINT enable interrupts and return RETS * Device uninitialisation routine. It is entered with * the address of the DCB in BX, which must be preserved. DKUNIN PUSH BX MOV AX,ERRVEC MOV BX,D.VEC(BX) MOV CX,BX ADD BX,!40 calculate address to reset SHL BX SHL BX MOV (BX),AX plug it MOV AX,ERRVEC+2 MOV 2(BX),AX MOV DL,!1 SHL DL,CL IN MPICMSK OR AL,DL OUT MPICMSK POP BX 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. DKSTART PUSH SI SHL SI pkt ptr MOV AX,CRNTSK SHL AX MOV DKTSK,AX CALL DKACT POP SI RETS * Device stop routine. This is entered if the head pkt * is dequeued from the device. It is entered with the * address of the packet in SI and the DCB in BX, which * must be preserved. * CX must also be preserved. DKSTOP IN RDSS TEST AL,!INTPEND interrupt pending? JNE DOSTOP yes, ok to stop OR D.REQFLG(BX),!STOPREQ[B] set stop request state RETS * DOSTOP IN RDRESTP clear interrupt IN RDRESBT RETS * * * Disc interrupt routine. * This is entered whenever the disc completes the last * requested action. This can be when a read or write or seek * is complete, in which case the packet which requested * it is returned. If the disc interrupts to give an error, * the error field of the packet will be set non-zero. * If the interrupt is due to the ready status of one of the * drives changing, check for drive ready and see if any pkts * are waiting. * The DCB address may be found from the subroutine return address * on the stack. DKINT PUSH BX PUSH AX PUSH CX PUSH DX PUSH SI MOV BX,SP MOV BX,10(BX) find return address in DCB SUB BX,!D.I calculate start of DCB MOV SI,D.WKQ(BX) head pkt SHL SI MC head pkt ptr MOV AX,CRNTSK SHL AX MOV DKTSK,AX IN RDRESTP read result type MOV AH,AL IN RDRESBT read result byte OR AH,AH res type=0? (error bits) JNE DKINT7 ready status has changed MOV DKTEMP,AL save error bits MOV AL,D.REQFLG(BX) TEST AL,!STOPREQ stop device? JE DKINT1 * stop device AND D.REQFLG(BX),!~STOPREQ[B] clear PUSH CS CALL DOSTOP B DKINT6 INTRET * DKINT1 TEST AL,!CALREQ recalibrating? JE DKINT1A * was recalibrating so now try Action AND D.REQFLG(BX),!~CALREQ[B] clear flag MOV AX,CRNTSK SHL AX B DKINT3 check for pkts * DKINT1A TEST AL,!ACTREQ JE DKINT6 IGNORE * action complete, return pkt DKINT2 TEST DKTEMP,!4[B] seek error? JNE DKINTR yes, recalibrate AND D.REQFLG(BX),!~ACTREQ CALL SENDPKT DKINT3 MOV SI,D.WKQ(BX) SHL SI * * * JE DKINT5 no more pkts CALL DKACT initiate next action JE DKINT3 pkt was sent back DKINT5 JIS DEVINT exit via INTENT DKINT6 JIS DEVRET exit via INTRET * the ready state of one of the drives has changed DKINT7 IN RDSS MOV DKTEMP,!0[B] clear error bits MOV AX,CRNTSK set task SHL AX B DKINT3 check for pkts * set up recalibrate operation DKINTR MOV AX,P.DRIV(SI) get drive number SHL AL SHL AL SHL AL SHL AL OR AL,!RECALOP construct DISKINS byte MOV D.DISKIN(BX),AL OR D.REQFLG(BX),!CALREQ[B] MOV AX,BX ADD AX,!D.IOPB get IOPB address OUT WSTART MOV AL,AH OUT WSTART+1 go B DKINT6 exit * * This routine initiates a disc action or returns a status * request pkt. It is entered with the MC pkt address in SI * and the MC DCB address in BX. * If the pkt is sent back then ZF is set (0 return). * New TCB is in AX. DKACT MOV AX,P.DRIV(SI) get unit number SHL AL SHL AL SHL AL SHL AL shifted left four places MOV D.DISKIN(BX),AL put in IOPB MOV AX,P.CYL(SI) get track MOV D.TRACK(BX),AL MOV AX,P.SEC(SI) get sector SHL AL SHL AL INC AL h/w address = 4*sector + 1 MOV D.SECTOR(BX),AL MOV AX,P.WCNT(SI) OR AL,AL JE DKACT1 exact multiple of 256? INC AH no DKACT1 SHL AH logical -> physical SHL AH MOV D.NUMREC(BX),AH number of physical records * * CMP P.ACT(SI),!A.DUMMY status request? JE SENDPKT yes IN RDSS * see if drive is ready, if expanded to 4 drives this will * need changing. MOV AH,P.DRIV(SI) INC AH TEST AL,AH test ready bit in status byte JE DKACT4A not ready, wait for interrupt * ok, setup the action MOV DX,P.BUFF(SI) get buffer address SHL DX MOV D.BUFF(BX),DX store in IOPB * Set ACT flag OR D.REQFLG(BX),!ACTREQ MOV AX,P.ACT(SI) get action CMP AX,!A.READ JNE DKACT3 OR D.DISKIN(BX),!READOP[B] B DKACT4 DKACT3 CMP AX,!A.WRITE JNE SENDPKT OR D.DISKIN(BX),!WRITEOP[B] DKACT4 MOV AX,BX ADD AX,!D.IOPB get IOPB address OUT WSTART MOV AL,AH OUT WSTART+1 start the channel DKACT4A MOV AX,DKTSK return set task, clear ZF CMP AX,!0 RET * SENDPKT IN RDSS get subsys. status XOR AH,AH MOV P.STAT(SI),AX goes to RESULT2 in SENDPKT AND AL,D.UMASK(BX) XOR AL,D.UMASK(BX) if bits are 1 -> 0 MOV AH,DKTEMP get saved error bits MOV P.DERR(SI),AX becomes result of SENDPKT (in BLIB) MOV CX,D.ID(BX) id for MOVPKT MOV DX,(SI) DEQ pkt MOV D.WKQ(BX),DX PUSH SI PUSH BX MOV BX,DKTSK task with which to compare priority CIS DEVMVP MOVPKT POP BX POP SI MOV DKTSK,AX XOR DX,DX set ZF, new TCB in AX RET * DKENINT MOV DL,!1 MOV CX,D.VEC(BX) SHL DL,CL NOT DL IN MPICMSK AND AL,DL OUT MPICMSK RETS * DSEG * save area! EVEN DKINITI DW DKINIT DW 0 DKUNINI DW DKUNIN DW 0 DKTEMP DB 0 DKTSK DW 0 END