        GLOBAL  DRVSPOOL
        
;
; file :  drv.spool.text
; date :  22-February-1984   dp  changes by kb
;
; This is the source for the spooler driver.  I used the file
; drv.apio.text, dated 20-september-1983, as a basis for this code.
;
; INCLUDE FILES USED :
;       /ccos/os.gbl.asm.text                    ;OS GLOBAL EQUATES
;
; INCLUDE OS GLOBALS HERE
;
            LIST       OFF
;;;;;;;     INCLUDE    'OS.GBL.ASM.TEXT'               ;for at home no CCOS
            INCLUDE    '/CCOS/OS.GBL.ASM.TEXT'
            LIST       ON
;
  page
; Unit I/O Command codes
;
READCMD     EQU        1                         ; read command
WRCMD       EQU        2                         ; write command
BUSYCMD     EQU        4                         ; busy command
STATCMD     EQU        5                         ; status command
UNMCMD      EQU        6                         ; unmount command
;
; Status Register values
;
CARRYST     EQU        $0001                     ; CCR with carry set
;
; ASCII character codes
;
CR          EQU        $0D                       ;CARRIAGE RETURN
LF          EQU        $0A                       ;LINE FEED
CntrlZ      EQu         26                       ;control z
Escape      EQU        $1B                       ;ESCAPE CHARACTER
SpSTrf      EQU        $27                       ;Apostrophe character "'"
Minus       EQU        $2D                       ;Minus character  "-"
;
; error codes (IORESULT)
;
INVCMD      EQU        IOEioreq                  ;invalid cmd-(invalid I/O request)
INVTBLID    EQU        IOEtblid                  ;invalid table id
INVPRM      EQU        IOEuiopm                  ;invalid parameter
INVFNC      EQU        IOEfnccd                  ;invalid function code
PADERR      EQU        IOEpaderr                 ;invalid prop spacing/need to much extra space
;
; Miscellaneous definitions
;
TRUE        EQU        1                         ; Pascal true boolean value
FALSE       EQU        0                         ; Pascal false boolean value
ON          EQU        1                         ;LISTING CONTROL - START LISTING
OFF         EQU        0                         ;LISTING CONTROL - STOP LISTING
LFsprsflg   EQU      $0C               ; linefeed suppress flag- bit 2 or 3
BUFSIZE  EQU    255
SLOTIO      EQU        30                        ;slot io unit number
  page
;
; Parameters:   D0.W - Unit number
;               D1.L - Address of buffer
;               D2.W - Count
;               D3.W - Block Number
;               D4.W - Command
;               D5.W - Access Mode
;
;                   Input Parameters:              Result values:
;     Command       Unit  Addr  Count Block Mode   IORESULT  Busy
;
;    0 - Install    D0.W                            D7.W
;    1 - Read       D0.W  D1.L  D2.W  D3.W  D5.W    D7.W
;    2 - Write      D0.W  D1.L  D2.W  D3.W  D5.W    D7.W
;    3 - Clear      D0.W                            D7.W
;    4 - Busy       D0.W                            D7.W     D0.B
;    5 - Status     D0.W  D1.L  D2.W                D7.W
;    6 - Unmount    D0.W                            D7.W
;

; Global register useage :
;        D0
;        to : temps
;        D5
;
;        D6 : mode flag save
;
;        A0
;        to : temps
;        A3
;
;        A4 : addr of PiIndex
;        A5 : user data buffer address
;        A6 : addr of flag byte (PiFlags)
  page
DRVSPOOL BRA.S    START          ;start of code
         data.b  0               ;device not blocked
         data.b  31              ;valid commands
         data.b  84,02,22        ;date February 22, 1984
         data.b  0               ;fill
         data.b  hmlen           ;header message length
hm       data.b  'Spool driver v 1.0a '
hmlen    equ     %-hm            ;
         data.b  0               ; word alignment

START    MOVEQ     #IOEioreq,D7                  ;assume invalid command
         CMPI.W    #UNMCMD,D4                    ;VALID COMMAND
         BHI.S     SpolERR                       ;no, exit
         CLR.L     D7                            ;clear IOresult
         MOVEM.L   D1-D6/A0-A6,-(SP)             ;SAVE REGISTERS
         LEA       SpTabl,A2
         LSL.W     #1,D4                         ;INDEX TO THE FUNCTION
         MOVE.W    0(A2,D4.W),D4
         JSR       0(A2,D4.W)                    ;DO FUNCTION
         MOVEM.L   (SP)+,D1-D6/A0-A6             ;RESTORE registers
SpolERR  RTS

SpTABL   data.w  SpINST-SpTABL
         data.w  SpRD-SpTABL
         data.w  SpWR-SpTABL
         data.w  SpCLR-SpTABL
         data.w  SpBSY-SpTABL
         data.w  SpST-SpTABL
         data.w  SpUNMT-SpTABL
 page
; SpUNMT, SpCLR: unmount/clear
;
SpUNMT
SpCLR    LEA       PiFlags, A6         ;mark pipe closed
         BCLR      #PiOpen, (A6)       ;test and clear
         BOFF.S    SPCUexit            ;already closed
         BSR       Closepipe           ;close pipe
SPCUexit RTS

; SpBSY - unitbusy
;
; Returns: D0.B - Result
;
SpBSY    CLR.B     D0        ; always ready!?
         RTS
;
; SpRD - unitread
;
SpRD     RTS

; SpINST : unitinstall
;
SpINST ; initialize variables
         LEA       PiFlags, A6         ;clear all flags
         CLR.W     (A6)

         LEA       PiIndex, A4         ;reset index into buffer
         CLR.W     (A4)

         LEA       PiName, A0          ;pipe name
         MOVE.L    DefPiName, (A0)+    ;8 bytes
         MOVE.L    DefPiName+4, (A0)

         LEA       AttUnitNo, A0       ;set attached unit number
         MOVE.W    DefUnit, (A0)

         LEA       UserName, A0        ;put user name in default msg
         LEA       $71C.W, A1          ;from static ram location
         MOVEQ     #UsrNmLen-1, D0     ;   OS saves it in
SIuser   MOVE.B    (A1)+, (A0)+
         DBF       D0, SIuser

         LEA       DefPiMesg, A0       ;put default message into
         LEA       PiMsg, A1           ;current pipe message area
         MOVEQ     #DfMgLen, D0        ;msg length
         MOVE.B    D0, (A1)+           ;put in msg string
         SUBQ.W    #1, D0              ;change to loop counter
SImesg   MOVE.B    (A0)+, (A1)+        ;move message
         DBF       D0, SImesg

         BSR       GETSLTTBL           ;get system slot table
         MOVE.W    (A0)+, D0           ;boot slot
         MOVE.W    (A0),  D1           ;boot server
         LSL.W     #8, D1              ;shift server to multiply by 256
         ADD.W     D1, D0
         LEA       PiAddr, A0          ;save net address of pipes area
         MOVE.W    D0, (A0)
         RTS
 page
; SpST - UnitStatus functions for DTACOM compatibility
;        Plus spool control functions : close pipe, change message
;        and change pipe name

SpST     CMPI.B  #TBLSTATE,D2   ; check for valid function code
         BHI.S   ASTERR         ; no good
         MOVEA.L D1,A3          ; A3==> user buffer
         MOVE.W  (A3),D0        ; get parameter
         LEA     ASTTBL,A1      ; convert function code
         LSL.W   #1,D2          ; to table index
         MOVE.W  0(A1,D2.W),D2
         JMP     0(A1,D2.W)     ; do function

ASTERR   MOVEQ   #INVFNC,D7     ; invalid function code
STNOP    RTS

TBLSTATE EQU     21             ; highest valid function code

; first 17 functions necessary to make driver work with DRV.EPRNT
; functions 18,19, 20 and 21 are functions for this driver

ASTTBL   DATA.W  STWBUF-ASTTBL  ; 0 - write buffer free space
         DATA.W  STNOP-ASTTBL   ; 1 - set baud rate
         DATA.W  STNOP-ASTTBL   ; 2 - set parity
         DATA.W  ASTERR-ASTTBL  ; 3 - not used
         DATA.W  STNOP-ASTTBL   ; 4 - set word size
         DATA.W  STNOP-ASTTBL   ; 5 - set handshake method
         DATA.W  STBFSTS-ASTTBL ; 6 - tell buffer control status
         DATA.W  ASTERR-ASTTBL  ; 7 - not used
         DATA.W  STWTSTS-ASTTBL ; 8 - tell write status
         DATA.W  ASTERR-ASTTBL  ; 9 - not used
         DATA.W  ASTERR-ASTTBL  ; 10- not used
         DATA.W  ASTERR-ASTTBL  ; 11- not used
         DATA.W  ASTERR-ASTTBL  ; 12- not used
         DATA.W  ASTERR-ASTTBL  ; 13- not used
         DATA.W  ASTERR-ASTTBL  ; 14- not used
         DATA.W  ASTERR-ASTTBL  ; 15- not used
         DATA.W  ASTERR-ASTTBL  ; 16- not used
         DATA.W  STATOLF-ASTTBL ; 17- toggle auto linefeed flag
         DATA.W  PSSTPIPE-ASTTBL ; 18- change pipe name
         DATA.W  PSCLPIPE-ASTTBL ; 19- close pipe
         DATA.W  PSSTMESG-ASTTBL ; 20- change message
         DATA.W  PSSTSERV-ASTTBL ; 20- change slot and server
  page
STWBUF   ; buffer status: return 255 for amount of space avail
         MOVE.W  #BUFSIZE,(A3)
         RTS

STBFSTS  ; buffer control status
         MOVE.W  #6,(A3)+       ; baud rate
         CLR.W   (A3)+          ; parity
         CLR.W   (A3)+          ; datacom
         MOVE.W  #1,(A3)+       ; wordsize = 8
         MOVE.W  #9,(A3)        ; handshake = none
         RTS

STWTSTS  ; get the write buffer status
         MOVE.W  #BUFSIZE,(A3)+       ; buffer size
         MOVE.W  #BUFSIZE,(A3)+       ; free space
         CLR.W   (A3)+          ; chars between ENQs
         CLR.W   (A3)+          ; input,output disable = false
         LEA     PiFlags,A6     ; addr of flag byte
         BTST    #AutoLF,(A6)   ; create a pascal boolean
         SNE     D0             ;  representing the state
         ANDI.B  #TRUE,D0       ;  of the bit flag.
         MOVE.B  D0,(A3)+       ; auto linefeed flag
         CLR.B   (A3)+          ; alt buffer avail = false
         CLR.L   (A3)+          ; alt buffer addr = 0
         CLR.W   (A3)+          ; alt buffer size = 0
         RTS

STATOLF  ; toggle auto linefeed flag
         LEA     PiFlags,A6
         BCHG    #AutoLF,(A6)        ; toggle 0 <==> 1
         RTS
  page
;
; PSSTMESG - Change message
; Entry : (A3) = pointer to pascal string of message
;                length = 0, then use default message
;
PSSTMESG LEA       PiMsg, A0           ;ptr to message save area
         MOVE.B    (A3)+, D0           ;get length
         BNE.S     PSMGchck            ;not zero then use it
         LEA       DefPiMesg, A3       ;else use default
         MOVEQ     #DfMgLen, D0

PSMGchck EXT.W     D0                  ;make length a word
         CMPI.B    #79, D0             ;if length > 79 then
         BLS.S     PSMGless
         MOVEQ     #79, D0             ; make it 79

PSMGless MOVE.B    D0, (A0)+           ;save msg length
         SUBQ.B    #1,D0               ;move in message
PSMGmove MOVE.B    (A3)+, (A0)+
         DBF       D0,PSMGmove
         RTS
;
; PSSTPIPE - Change pipe name
; Entry : (A3) = pointer to pascal string of pipe name
;                length = 0, then use default pipe name
;
PSSTPIPE LEA       PiName, A0          ;ptr to pipe name save area
         MOVE.B    (A3)+, D0           ;get length
         BNE.S     PSPNinit            ;not zero then use it
         LEA       DefPiName, A3       ;else use default
         MOVEQ     #PiNmLen, D0

PSPNinit MOVEQ     #PiNmLen-1, D1      ;blank fill the
PSPNlop1 MOVE.B    #' ', 0(A0,D1)      ;  pipe name area
         DBF       D1,PSPNlop1

         EXT.W     D0                  ;make length a word
         CMPI.B    #PiNmLen, D0        ;if length > 8 then
         BLS.S     PSPNless
         MOVEQ     #PiNmLen, D0        ; make it 8

PSPNless SUBQ.B    #1,D0               ;move in pipe name
PSPNlop2 MOVE.B    (A3)+, (A0)+
         DBF       D0,PSPNlop2
         RTS
  page
;
; PSSTSERV - Change slot and server number
; Entry : (A3) = pointer to a record
;                  Slot : integer;
;                  Server: integer;
;
PSSTSERV LEA       PiAddr, A0          ;ptr to slot and server

         MOVE.W    (A3)+, D0           ;get slot number
         BMI.S     PSSRerr             ;negativer -error
         CMPI.B    #5, D0              ;greater than 5
         BHI.S     PSSRerr             ;yes, to big

         MOVE.W    (A3), D1            ;get server number
         BMI.S     PSSRerr             ;negative - error
         CMPI.B    #63, D1             ;greater than 63
         BHI.S     PSSRerr             ;yes, invalid host number

         LSL.W     #8, D1              ;server is in hi byte
         OR.W      D1, D0              ;put in 1 word
         MOVE.W    D0, (A0)            ;save it
         BRA.S     PSSRexit            ;done

PSSRerr  MOVEQ     #IOEuiopm, D7       ;bad slot or server number
PSSRexit RTS
;
; PSCLPIPE - Close pipe
; Closepipe - entry for call from unitwrite section
;
PSCLPIPE    LEA        PiFlags, A6     ;get addr of flag byte
            BTST       #PiOpen, (A6)   ;is it open?
            BOFF.S     CLexit          ;no
Closepipe   BSR        Writepipe       ;dump last block
            BCS.S      CLexit          ;check error

            LEA        PiClsPN, A0     ;get pipe number
            MOVE.B     Pinumber, (A0)
            LEA        PiClsWr, A0     ;send pipe close command
            MOVE.L     A0, D1
            MOVEQ      #PiClLen, D2
            MOVE.W     PiAddr, D5
            BSR        SendCmd
            BCS.S      CLexit

            BCLR       #PiOpen, (A6)   ;set pipe open flag to false
CLexit      RTS
 page
;
; SpWR - unitwrite
;
; init global registers
;
SpWR     LEA       PiIndex, A4         ; pipe buffer index
         MOVEA.L   D1,A5               ; address of user buffer
         LEA       PiFlags, A6         ; addr of flag byte
         MOVE.L    D5, D6              ; save mode flag

SWRloop  SUBQ.W    #1,D2               ; More to write?
         BMI.S     SWRexit             ; No.

SWRout   MOVE.W    D2, -(SP)           ; save user count
         BSR.S     OutChar             ; output character
         MOVE.W    (SP)+, D2           ; restore user count
         TST.W     D7                  ; get an I/O error
         BNE.S     SWRexit             ; yes, exit

; check for carriage return
;
         MOVE.B    (A5)+, D0           ; Get character just processed
         CMPI.B    #CR,D0              ; is it CR?
         BNE.S     SWRloop             ; no, do next

; determine if auto LF is needed
;
         BTST      #AutoLF, (A6)       ; auto LF mode?
         BOFF.S    SWRloop             ; no
         MOVE.W    D6,D0               ; get mode flags
         ANDI.W    #LFsprsflg,D0       ; if LF suppress flag set
         BNE.S     SWRloop             ;   then don't send LF
         MOVEQ     #LF,D0              ; output a linefeed char
         BRA.S     SWRout

SWRexit  RTS
  page
;
; OutChar - process one character
; Entry : A5 = address of character
;         A6 = address of flag byte
;         A4 = address of pipe buffer index
; Exit  : D7 = IORESULT code
;
OutChar  BTST      #PiOpen, (A6)       ;is pipe open
         BON.S     OCopen              ;yes

         BSR.S     Openpipe            ;no, open it
         BCS.S     OCHexit             ;if error then exit

OCopen   MOVE.W    (A4), D0            ;get current pipe buffer index
         CMPI.W    #PiBfEnd, D0        ;buffer full?
         BNE.S     OCstop              ;not full, so check if 2nd ctrlz
         BSR       WritePipe           ;send the buffer
         BCS.S     OCHexit             ;I/O error, exit
         BSR       Reinitpipe          ;set up buffer again

OCstop   MOVE.B    (A5), D1            ;get next character
         BCLR      #PiStop, (A6)       ;checking for 2nd ctl-z
         BOFF.S    OCctrlz             ;no, then look for 1st
         CMPI.B    #CntrlZ, D1         ;is it 2nd ctrl-z?
         BNE.S     OCsendcz            ;no, then send 1st and then this char
         BSR       Closepipe           ;yes, close pipe
         BRA.S     OCHexit             ;done, don't send ctl-z's

OCsendcz MOVEQ     #CntrlZ, D1         ;get a control-z
         BSR.S     OCmvchar            ;send it to pipe
         BRA.S     OCopen              ;restart to send cur char @A5

OCctrlz  CMPI.B    #CntrlZ, D1         ;check for 1st control-z
         BNE.S     OCmvchar            ;no, send this char to pipe
         BSET      #PiStop, (A6)       ;yes, show got 1
         BRA.S     OCHexit             ;and see if another

OCmvchar LEA       PiBuf1, A0          ;pipe buffer address
         MOVE.W    (A4), D0            ;get index
         MOVE.B    D1, 0(A0,D0)        ;save char in buffer
         ADDQ.W    #1, (A4)            ;bump index

OCHexit  RTS
  page
;
; Openpipe - open pipe, save pipe number, set pipe open flag,
;            and write preamble block
;
Openpipe LEA       PiOpWr, A0          ;get pipe command
         MOVE.L    A0, D1
         MOVEQ     #PiOpLen, D2        ;command length
         MOVE.W    PiAddr, D5          ;get net address
         BSR.S     SendCmd
         BCS.S     OPexit

         LEA       Pinumber, A0        ;save pipe number
         MOVE.B    PiRes2, (A0)
         BSET      #PiOpen, (A6)       ;set pipe open flag
         BSR.S     Reinitpipe          ;init pipe buffer

; write preamble block
;
         LEA       PiBuf1, A0          ;send preamble block
         CLR.B     (A0)+               ;1st byte always 0
         MOVE.L    Pifile, (A0)+       ;file name always 8 bytes
         MOVE.L    PiFile+4, (A0)+     ;buffer starts on a odd boundary

         LEA       PiMloc, A0          ;put in message
         LEA       PiMsg, A1           ;message area
         CLR.L     D0                  ;get rid of garbage
         MOVE.B    (A1)+, D0           ;get length
         MOVE.B    D0, (A0)+           ;put in preamble
         SUBQ.B    #1, D0              ;if length = 0
         BMI.S     OPnomsg             ;  then no message
OPloop   MOVE.B    (A1)+, (A0)+        ;move message
         DBF       D0, OPloop

OPnomsg  LEA       PiTloc, A0          ;put in file type
         MOVE.B    #48, (A0)+
         BSR.S     Writepipe
         BCS.S     OPexit              ;check error
         BSR.S     Reinitpipe          ;set up pipe buffer again
OPexit   RTS
 page
;
; WritePipe - pipe write of 512 bytes
;
WritePipe
         LEA       PiWrite, A0         ;get pipe command
         MOVE.L    A0, D1
         MOVE.W    #PiWrLen, D2        ;command length
         MOVE.W    PiAddr, D5          ;get net address
         BSR.S     SendCmd
         RTS
;
; Reinitpipe - reset PiIndex and zero pipe buffer
;
Reinitpipe
         CLR.W     (A4)                ;reset index
         LEA       PiBuf1, A0          ;addr of buffer
         MOVE.W    #PiBfEnd-1, D0      ;number of bytes in buffer

REloop   CLR.B     (A0)+               ;clear buffer
         DBF       D0, REloop
         RTS
  page
;
; Sendcmd - send command to unitio driver
;      Entry : D1 = address of cmd buffer
;              D2 = length of command
;              D5 = Server # * 256 + slot number
;      Exit  : (C) = I/O error reported by attached driver
;              (NC) = I/O result good
;              D7 = IORESULT
;
; UNIT I/O PARAMETER PASSING DEFINITION
;
; COMMAND - D4    UNIT   ADDR   COUNT   BLOCK   MODE     IORESULT   BUSY
; 2 - WRITE       D0.W   D1.L   D2.W            D5.W     D7.W
; 2 - CDSEND      D0.W   Cmd    # of bytes 0    PiAddr
; 1 - CDRECV             Result max #      0    PiAddr
;
SendCmd  MOVEQ     #WRCMD, D4          ;unitwrite command code
         CLR.L     D3

         MOVEM.L   D0-D6/A0-A6, -(SP)
         BSR.S     GoAttUnit           ;puts unit number in D0
         MOVEM.L   (SP)+, D0-D6/A0-A6
         TST.W     D7                  ;see if driver had error
         BNE.S     SCMerr              ;if error set carry

SCMrecv  MOVEQ     #READCMD, D4        ;unitread command code
         LEA       PiResult, A0        ;result buffer
         MOVE.L    A0, D1
         MOVEQ     #PiReslen, D2       ;result length
         MOVEQ     #0, D3
         MOVE.W    PiAddr, D5
         MOVEM.L   D0-D6/A0-A6, -(SP)
         BSR.S     GoAttUnit           ;puts unit number in D0
         MOVEM.L   (SP)+, D0-D6/A0-A6
         TST.W     D7                  ;see if driver had error
         BNE.S     SCMerr              ;if error set carry

         MOVEQ     #4, D7              ;assume error
         MOVE.B    Piresult, D1        ;check return code
         BMI.S     SCMerr              ;bad drive code
         MOVE.B    PiRes1, D1          ;check pipe code
         BNE.S     SCMerr              ;bad pipe code
         CLR.L     D7                  ;no error
         BRA.S     SCMexit             ;carry cleared by CLR
SCMerr   MOVE.W    #CARRYST,CCR        ;error
SCMexit  RTS
  page
;
; GETSLTTBL: sets A0==> start of slot table
;
GETSLTTBL   MOVEA.L    PSYSCOM.W,A0
            MOVE.L     SCslttbl(A0),A0
            RTS


; GETDEVTBL: sets A0==> 1st device in device table, D0=MAXDEV
;
GETDEVTBL   MOVEA.L    PSYSCOM.W,A0
            MOVE.L     SCdevtab(A0),A0           ; A0=> device table
            MOVE.W     (A0)+,D0                  ; D0 = #device entries, A0=> 1st entry
            RTS

; GETDRVR: input- A0==> 1st device in device table, D0=unit#
;          returns A0 = address of unit driver
;          and D0 = index to entry
;
GETDRVR     MULU       #UTlen,D0                 ; calc offset of device entry
            MOVE.L     UTiodrv(A0,D0.W),A0       ; A0 = address of driver
            RTS

; GoAttUnit - call attached unit
;
GoAttUnit   BSR.S      GETDEVTBL                 ; get table address in A0
            MOVE.W     AttUnitNo, D0             ; unit to find
            BSR.S      GETDRVR                   ; get driver entry address
            MOVE.W     AttUnitNo, D0             ; get unit number
            JMP        (A0)                      ; call unit
  page
;
;Constants
;
; default values
;
DefUnit     DATA.W SLOTIO              ;default unit number
DefPiName   DATA.B 'PRINTER '          ;default pipe name
DefPiMesg   DATA.B 'User :  '          ;default message
UserName    DATA.B '          '        ;username 10 bytes
UsrNmLen    EQU    %-UserName          ;length of user name
DfMgLen     EQU    %-DefPiMesg         ;length of default message

; Attached unit number
;
AttUnitNo   DATA.W     0

; Pipe state
;
PiFlags  DATA.W    0                   ;Flags - all flags currently in hi byte
AutoLF   EQU       0                   ;auto linefeed mode flag
PiOpen   EQU       1                   ;pipe open flag
PiStop   EQU       2                   ;pipe stop flag if get another control-z

PiIndex  DATA.W    0                   ;pipe buffer index

PiFile   DATA.B    7                   ;file name length
         DATA.B    'SPOOL  '           ;file name
PiMsg    DATA.L    0,0,0,0,0,0,0,0,0,0 ;80 bytes
         DATA.L    0,0,0,0,0,0,0,0,0,0
PiAddr   DATA.W    0                   ;pipe slot and server

; Pipe commands
;
PiOpWr   DATA.B    $1B                 ;pipe open write command
         DATA.B    $80
PiName   DATA.B    0,0,0,0,0,0,0,0     ;pipe name - 8 bytes
PiNmLen  EQU       %-PiName            ;pipe name length
PiOplen  EQU       %-PiOpWr            ;pipe open command length
;
PiClsWr  DATA.B    $1A                 ;pipe close command
         DATA.B    $40
PiClsPN  DATA.B    0                   ;pipe number
         DATA.B    $FE                 ;close write
         DATA.B    0                   ;don't care
PiCllen  EQU       %-PiClsWr           ;pipe close/purge command length
         DATA.B    0                   ;filler
;
PiWrite  DATA.B    $1A                 ;pipe write
         DATA.B    $21
PiNumber DATA.B    0                   ;pipe number
         DATA.B    0                   ;number of bytes (low  byte) - always 512
         DATA.B    2                   ;number of bytes (high byte)
PiBuf1   DATA.B    0,0,0               ;first 3 bytes
         DATA.L    0,0,0,0,0,0,0,0     ;bytes 4-35
         DATA.L    0,0,0,0,0,0,0,0     ;bytes 36-67
         DATA.L    0,0,0               ;bytes 68-79
         DATA.B    0,0,0               ;bytes 80-82
PiMloc   DATA.B    0                   ;byte 83
         DATA.L    0,0,0,0,0,0,0,0     ;bytes 84-115
         DATA.L    0,0,0,0,0,0,0,0     ;bytes 116-147
         DATA.L    0,0,0,0             ;bytes 148-163
PiTloc   DATA.L    0,0,0,0             ;bytes 164-195
         DATA.L    0,0,0,0,0,0,0,0     ;bytes 196-227
         DATA.L    0,0,0,0,0,0,0       ;bytes 228-255
         DATA.L    0,0,0,0,0,0,0,0     ;bytes 256-511
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0,0,0,0,0
         DATA.L    0,0,0,0             ;added 16 bytes to make exactly 512
         DATA.B    0                   ;last byte
PiBfEnd  EQU       %-PiBuf1            ;number of bytes in buffer
PiWrlen  EQU       %-PiWrite           ;pipe write command length
PiBuf2   DATA.B    0                   ;filler
;
PiResult DATA.B    0                   ;disk code
PiRes1   DATA.B    0                   ;pipe code
PiRes2   DATA.B    0                   ;pipe number on open
         DATA.B    0,0,0,0,0,0,0,0,0   ;rest of 12 bytes
PiReslen EQU       %-PiResult          ;pipe result buffer length

         end     DRVSPOOL
