PGM EMDRIV
REL
**********************************************************
* *
* Device driver for 3270 emulator (nice pdriv) *
* *
**********************************************************
*
* 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
*
* remember interrupt vector contents
*
PUSH BX
MOV BX,(SI)
MOV OIVEC,BX
POP BX
*
*
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,OIVEC
PUSH BX
MOV BX,D.VEC(BX) get address to plug
ADD BX,!40
SHL BX
SHL BX
MOV (BX),AX plug it
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
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
OIVEC DW 0
PINITI DW PINIT
DW 0
PUNINI DW PUNIN
DW 0
END