.TITLE ZEDRIVER - Driver for example "pseudodevice" ACP .IDENT 'X01-000' ;++ ; ZEDRIVER - Driver for example "pseudodevice" ACP ; ; ABSTRACT: ; ; This driver passes write IRPs to ZEACP, which in turn issues ; corresponding $QIO requests to a physical device. ;-- .PAGE .SBTTL External and local symbol definitions ; standard VMS data structures .LIBRARY \SYS$LIBRARY:LIB\ $AQBDEF ; ACP queue block $CANDEF ; Cancel reason codes $CCBDEF ; Channel control block $CRBDEF ; Controller request block $DCDEF ; Device classes and types $DDBDEF ; Device data block $DDTDEF ; Driver dispatch table $DEVDEF ; Device characteristics $DYNDEF ; Data structure ID codes $IDBDEF ; Interrupt data block $IODEF ; I/O function codes $IPLDEF ; Hardware IPL definitions $IRPDEF ; I/O request packet $JIBDEF ; Job information block $PCBDEF ; Process control block $PRDEF ; Processor register names $PRVDEF ; Privilege bits $PSLDEF ; Processor status longword $SPLDEF ; Spinlock definitions $SSDEF ; System status codes $UCBDEF ; Unit control block $VCBDEF ; Volume control block $VECDEF ; Interrupt vector block $DEFINI UCB _VIELD UCB,0,<- ; bits in UCB$L_DEVDEPEND > . = UCB$K_LENGTH $DEF UCB_L_TMPLTUCB .BLKL 1 ; pointer to template UCB $DEF UCB_Q_PNDIRP .BLKQ 1 ; queue of IRPs started by ACP $DEF ZE_UCB_K_LENGTH $DEFEND UCB $DEFINI BUF ; I/O buffer $DEF BUF_L_SVAUSRDATA .BLKL 1 ; sva of user data in buffer $DEF BUF_L_PVAUSRBUFF .BLKL 1 ; process virt addr of user's buffer $DEF BUF_W_SIZE .BLKW 1 ; allocated size $DEF BUF_B_TYPE .BLKB 1 ; type = DYN$C_BUFIO $DEF BUF_B_spare .BLKB 1 ; not used $DEF BUF_T_DLL .BLKB 8 ; data link scratch area $DEF BUF_T_USRDATA ; end of header $DEFEND BUF ; Argument list (AP) offsets for device-dependent QIO parameters P1 = 0 ; first QIO parameter P2 = 4 ; second QIO parameter P3 = 8 ; third QIO parameter P4 = 12 ; fourth QIO parameter P5 = 16 ; fifth QIO parameter P6 = 20 ; sixth QIO parameter ; driver/ACP-specific values ZE_K_ACPTYPE = 252 ZE_K_ACPCLASS = 253 .PAGE .SBTTL Standard tables and local storage ; Driver prologue table DPTAB - ; DPT-creation macro END=ZE_END,- ; End of driver label ADAPTER=NULL,- ; Adapter type UCBSIZE=,- ; Length of UCB MAXUNITS=1,- ; Length of UCB vector in IDB NAME=ZEDRIVER,- ; Driver name FLAGS=DPT$M_SMPMOD ; Ok to run in SMP environment DPT_STORE INIT ; load initialization table DPT_STORE DDB,DDB$L_ACPD,L,<^A\ZE\> ; default ACP name DPT_STORE DDB,DDB$B_ACPCLASS,B,- ; ACP class ZE_K_ACPCLASS ; field DPT_STORE UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8; Device fork lock index DPT_STORE UCB,UCB$B_DIPL,B,20 ; Dvc IPL (not really used) DPT_STORE UCB,UCB$L_DEVCHAR,L,<- ; Device characteristics DEV$M_SQD!- ; sequential DEV$M_AVL!- ; available DEV$M_IDV!- ; input device DEV$M_ODV> ; output device DPT_STORE UCB,UCB$B_DEVCLASS,B,255 ; device class DPT_STORE UCB,UCB$B_DEVTYPE,B,255 ; and type DPT_STORE UCB,UCB$L_DEVDEPEND,L,0 ; flags DPT_STORE UCB,UCB$W_DEVBUFSIZ,W,0 ; Default buffer size DPT_STORE REINIT ; reload initialization table DPT_STORE DDB,DDB$L_DDT,D,ZE$DDT ; Address of DDT DPT_STORE CRB,- ; Address of controller CRB$L_INTD+VEC$L_INITIAL,- ; initialization routine D,ZE_CONTROL_INIT DPT_STORE CRB,- ; Address of unit CRB$L_INTD+VEC$L_UNITINIT,- ; initialization routine D,ZE_UNIT_INIT ; routine DPT_STORE END ; End of initialization ; tables ; Driver dispatch table DDTAB - DEVNAM=ZE,- ; Name of device FUNCTB=ZE_FUNCTABLE,- ; FDT address CLONEDUCB=ZE_CLONED_UCB ; Cloned UCB routine .PAGE .SBTTL Function Decision Table ZE_FUNCTABLE: FUNCTAB ,- ; Valid I/O functions ; writes FUNCTAB ,- ; Buffered I/O functions ; writes ; function selection masks FUNCTAB FDT_BUFFERED_WRITE, - FUNCTAB FDT_QUEUE_TO_ACP, - .PAGE .SBTTL FDT_BUFFERED_WRITE, FDT routine for write requests ;++ ; FDT_BUFFERED_WRITE, FDT routine for write requests ; ; This routine checks the user's buffer for access, allocates a system ; buffer, and copies the user's data to it. ;-- FDT_BUFFERED_WRITE: BBS #DEV$V_MNT,UCB$L_DEVCHAR(R5),1$ ; check "mounted" bit MOVZWL #SS$_DEVNOTMOUNT, R0 ; error, ACP doesn't exist JSB G^EXE$ABORTIO 1$: MOVL P1(AP), R0 ; get buffer address MOVZWL P2(AP), R1 ; get buffer length JSB G^EXE$WRITECHK ; check for accessibility PUSHR #^M ; save registers ADDL2 #BUF_T_USRDATA, R1 ; account for buffer header JSB G^EXE$DEBIT_BYTCNT_ALO ; check quota, allocate buffer BLBC R0, 30$ ; br if bad POPR #^M ; restore registers MOVW R1, IRP$W_BOFF(R3) ; save process BYTCNT charge ; initialize buffer MOVL R2, IRP$L_SVAPTE(R3) ; connect buffer to IRP MOVAB BUF_T_USRDATA(R2), (R2) ; set pointers to data region MOVL R0, BUF_L_PVAUSRBUFF(R2) ; of buffer and to user buffer BBS #IRP$V_FUNC, IRP$W_STS(R3), 10$ ; br if read function PUSHR #^M ; protect registers from MOVC3 MOVC3 P2(AP), (R0), BUF_T_USRDATA(R2) ; copy user data to sys buffer POPR #^M ; restore registers 10$: RSB ; come here with saved R0, R3 on stack, desired return status in R0 30$: POPR #^M ; clean up stack and return JMP G^EXE$ABORTIO ; quota or buffer error ;++ ; FDT_QUEUE_TO_ACP, FDT routine to queue IRP to ACP ; ; This routine checks for the existence of a VCB, then queues the IRP to ; the ACP. ;-- FDT_QUEUE_TO_ACP: MOVZWL #SS$_DEVNOTMOUNT, R0 ; assume sync error MOVL UCB$L_VCB(R5), R1 ; get VCB address BEQL ACP_REQ_ERR ; should never happen, but... ADAWI #1, VCB$W_TRANS(R1) ; bump VCB transaction count JMP G^EXE$QIOACPPKT ; queue IRP to ACP ACP_REQ_ERR: JMP G^EXE$ABORTIO .PAGE .SBTTL ZE_CONTROL_INIT, Controller initialization routine ;++ ; ZE_CONTROL_INIT, Readies controller for I/O operations ; ; Functional description: ; ; The operating system calls this routine in 2 places: ; during driver loading and reloading ; during recovery from a power failure ; ; Inputs: ; ; R4 - address of the CSR (controller status register) ; R5 - address of the IDB (interrupt data block) ; R6 - address of the DDB (device data block) ; R8 - address of the CRB (channel request block) ; ; Outputs: ; ; The routine must preserve all registers except R0-R3. ; ;-- ZE_CONTROL_INIT: MOVL #SS$_NORMAL, R0 RSB ; return .PAGE .SBTTL ZE_UNIT_INIT, Unit initialization routine ;++ ; ZE_UNIT_INIT, Readies unit for I/O operations ; ; Functional description: ; ; The operating system calls this routine after calling the ; controller initialization routine: ; ; during driver loading (but not reloading) ; during recovery from a power failure ; ; Inputs: ; ; R4 - address of the CSR (controller status register) ; R5 - address of the UCB (unit control block) ; ; Outputs: ; ; Sets the ONLINE bit in the UCB status longword. ; The routine must preserve all registers except R0-R3. ; ;-- ZE_UNIT_INIT: MOVL R5, UCB_L_TMPLTUCB(R5) ; save address of template UCB BBSS #UCB$V_ONLINE,UCB$L_STS(R5),10$ ; Set unit online ; if first time (not power failure), do other initializations ; (none for this driver) 10$: MOVL #SS$_NORMAL, R0 RSB ; Return .PAGE .SBTTL ZE_CLONED_UCB, Cloned UCB initialization routine ;++ ; ZE_CLONED_UCB, Cloned UCB initialization routine ; ; Functional description: ; ; The operating system calls this routine after creating a cloned ; UCB and doing the device-independent initialization thereof ; (see the "VMS Device Support Manual", Appendix D, page 5). ; ; Context: ; ; Called from the $ASSIGN channel system service, in the context of ; the requesting process. ; ; IPL = IPL$_ASTDEL ; ; The IOC$GL_MUTEX is held for write access. ; ; Inputs: ; ; R2 - address of cloned UCB ; R3 - address of DDT ; R4 - address of current PCB ; R5 - address of template UCB ; ; Outputs: ; ; R0 - return status (if low bit clear, the system will deallocate ; the cloned UCB, and return the error status to the user as ; the result of the $ASSIGN call) ; ; This routine should perform any required device-specific initialization ; of the cloned UCB. ; ; R2, R4, and R5 must be preserved. (The "VMS Device Support Manual" ; specifies only that R2 must be preserved, but inspection of the code ; indicates otherwise.) ;-- ZE_CLONED_UCB: CLRQ UCB_Q_PNDIRP(R2) ; init the pending IRP queue hdr MOVL #SS$_NORMAL, R0 ; return with good status RSB .PAGE .SBTTL ZE_END, End of driver ;++ ; Label that marks the end of the driver ;-- ZE_END: ; Last location in driver .END