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