        .TITLE  ZFDRIVER - Driver for example "File System" ACP
        .IDENT  'X01-000'

;++
; ZFDRIVER - Driver for example "File System" ACP
;
; ABSTRACT:
;
;       This driver, in conjunction with ZFACP, implements file create, 
;       write, and file close functions on a mythical file-structured device.  
;       The driver also supports the IO$_MOUNT and IO$_ACPCONTROL (dismount)
;       $QIO functions.  
;--

        .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

        ; bits in UCB$L_DEVDEPEND

        $DEFINI UCB
        _VIELD  ZF,0,<<FOPEN,,M>>               ; file is open
        $DEFEND UCB

;       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

ZF_K_ACPTYPE = 250
ZF_K_ACPCLASS = 251

        .PAGE
        .SBTTL  Standard tables and local storage

; Driver prologue table

        DPTAB   -                               ; DPT-creation macro
                END=ZF_END,-                    ; End of driver label
                ADAPTER=NULL,-                  ; Adapter type
                UCBSIZE=<UCB$K_LENGTH>,-        ; Length of UCB
                MAXUNITS=1,-                    ; Length of UCB vector in IDB
                NAME=ZFDRIVER,-                 ; 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\ZF\>     ; default ACP name
        DPT_STORE DDB,DDB$B_ACPCLASS,B,-        ; ACP class 
                ZF_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,ZF$DDT        ; Address of DDT
        DPT_STORE CRB,-                         ; Address of controller 
                CRB$L_INTD+VEC$L_INITIAL,-      ;  initialization routine
                D,ZF_CONTROL_INIT
        DPT_STORE CRB,-                         ; Address of unit 
                CRB$L_INTD+VEC$L_UNITINIT,-     ;  initialization routine
                D,ZF_UNIT_INIT                  ; routine

        DPT_STORE END                           ; End of initialization
                                                ; tables

; Driver dispatch table

        DDTAB   -
                DEVNAM=ZF,-                     ; Name of device
                START=ZF_START,-                ; Start I/O routine
                FUNCTB=ZF_FUNCTABLE             ; FDT address

        .PAGE
        .SBTTL  Function Decision Table

ZF_FUNCTABLE:

        FUNCTAB ,-                              ; Valid I/O functions
                <CREATE,WRITEOF,-               ;  open and close file
                WRITEPBLK,WRITELBLK,WRITEVBLK,- ;  writes
                MOUNT,ACPCONTROL>               ;  mount and dismount ACP

        FUNCTAB ,<>                             ; Buffered I/O functions - none

        ; function selection masks

        FUNCTAB FDT_CHECK_LOCK_BUFFER,-
                <CREATE, WRITEOF,-              ; open and close file
                WRITEPBLK,WRITELBLK,WRITEVBLK>  ;  writes

        FUNCTAB FDT_QUEUE_TO_DRIVER,-
                <WRITEPBLK,WRITELBLK,WRITEVBLK> ; writes

        FUNCTAB FDT_MOUNT, <MOUNT>              ; mount ACP

        FUNCTAB FDT_MNTDMT,-                    ; common for mount and 
                <MOUNT,ACPCONTROL>              ;  dismount funcs

        FUNCTAB FDT_QUEUE_TO_ACP,-
                <CREATE,WRITEOF,-               ;  open and close file
                MOUNT,ACPCONTROL>               ;  mount and dismount ACP

        .PAGE
        .SBTTL  FDT routines for mount and dismount

;++
; FDT_MOUNT, FDT routine for mount requests
;
; This routine performs the `mounting' consistency check for the 
; MOUNT function.  
;--

FDT_MOUNT:
        MOVZWL  #SS$_DEVNOTMOUNT, R0            ; assume sync error
        BBCCI   #UCB$V_MOUNTING, UCB$W_STS(R5),-;  br if so
                ACP_REQ_ERR
        RSB

;++
; FDT_MNTDMT, FDT routine for ACP mount and dismount requests
;
; This routine ensures proper context for ACP mount and control requests.
;--

FDT_MNTDMT:
        MOVZWL  #SS$_NOPRIV, R0                 ; assume insuff. priv.
        IFNPRIV MOUNT, ACP_REQ_ERR              ;  check for MOUNT
        IFNPRIV OPER, ACP_REQ_ERR               ;  and OPER privs
        RSB

;++
; 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  FDT Routines for data transfer requests

;++
; FDT_CHECK_LOCK_BUFFER, check user buffer for readability 
;       (ie for writes to the device) and lock it into physical memory
;--

FDT_CHECK_LOCK_BUFFER:
        MOVL    P1(AP), R0                      ; get address of user buffer
        MOVZWL  P2(AP), R1                      ;  and length
        JSB     G^EXE$WRITELOCK                 ; probe and lock buffer
        RSB     

;++
; FDT_QUEUE_TO_DRIVER, queue IRP to driver's start I/O routine
;--

FDT_QUEUE_TO_DRIVER:
        JMP     G^EXE$QIODRVPKT

        .PAGE
        .SBTTL  ZF_START, Start I/O routine

;++
; ZF_START - Do a write transfer on the device
;
; Functional description:
;
;       Simulates starting and completion of a write transfer on the device.
;--

ZF_START:

        EXTZV   S^#IO$V_FCODE, S^#IO$S_FCODE,-  ; get function code from IRP,
                IRP$W_FUNC(R3), R0              ;  ignoring modifier bits

        CMPL    R0, #IO$_CREATE                 ; is it a "file open" function?
        BNEQ    10$                             ;  br if no

        BBCS    #ZF_V_FOPEN,-                   ; set the file open bit,
                UCB$L_DEVDEPEND(R5), 100$       ;  br if was clear

        MOVZWL  #SS$_FILALRACC, R0              ; trying to open file, but
        CLRL    R1                              ;  it's already open
        REQCOM

        ; if we get here the IRP is a write request, either from the user or
        ; the ACP (the latter on behalf of a user's file close request).  

10$:    BBS     #ZF_V_FOPEN,-                   ; br if file 
                UCB$L_DEVDEPEND(R5), 100$       ;  is "open"
        MOVZWL  #SS$_FILNOTACC, R0              ; else complete the request
        CLRL    R1                              ;  with a "file not open"
        REQCOM                                  ;  status

100$:
        ; (if we were talking to a real device, this is where we 
        ; would start the transfer, WFIKPCH, IOFORK, etc.)

        CLRL    R1
        MOVW    #SS$_NORMAL, R0
        INSV    IRP$W_BCNT(R3), #16, #16, R0
        REQCOM

        .PAGE
        .SBTTL  ZF_CONTROL_INIT, Controller initialization routine

;++
; ZF_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.
;
;--

ZF_CONTROL_INIT:
        MOVL    #SS$_NORMAL, R0
        RSB                                     ; return

        .PAGE
        .SBTTL  ZF_UNIT_INIT, Unit initialization routine

;++
; ZF_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.
;
;--

ZF_UNIT_INIT:
        BBSS    #UCB$V_ONLINE,UCB$L_STS(R5),10$ ; Set unit online

        ; if first time, do other initializations
        
10$:    MOVL    #SS$_NORMAL, R0
        RSB                                     ; Return

        .PAGE
        .SBTTL  ZF_END, End of driver

;++
; Label that marks the end of the driver
;--

ZF_END:                                         ; Last location in driver
        .END

