
; SCCSID = @(#)prtddtsk.asm     6.23 92/01/07
;/**********************************************************************
;/*                                                                    *
;/*                       IBM/Microsoft Confidential                   *
;/*                                                                    *
;/*                 Copyright (c) IBM Corporation  1987, 1990          *
;/*                 Copyright (c) Microsoft Corp.  1987, 1990          *
;/*                           All Rights Reserved                      *
;/*                                                                    *
;/**********************************************************************
 TITLE PRINTDD - PRINTER DEVICE DRIVER TASK TIME ROUTINES
 NAME PRINTDD
PAGE ,132
.286C

;***********************************************************************
; CODING CONVENTIONS
; all psuedo-ops, equates, documentation, publics,and externs are in uppercase.
; all code and data names are in lowercase.
;
; ROUTINES IN THIS MODULE:
;       PRTREQST
;       PRTERROR
;       PRTREAD
;       PRTNONDESRD
;       PRTCOMPLETE
;       PRTSTATUS
;       PRTOPEN
;       PRTCLOSE
;       GETPID
;       PRTBLOCK
;       BLOCK
;       PRTSTOUT
;       FILLCACHE
;       FLUSHCACHE
;       OUTSPOOL
;       PRTMONCLOSE
;       MONWRITE
;       DEVDONE
;       MONNOTIFY
;       PRTBUFTOREQPKT
;       SENDSNAGAS
;       RESUME_CPF
;       PRTLPT1
;       PRTLPT2
;       PRTLPT3
;       MONNOTIFY_1
;       MONNOTIFY_2
;       MONNOTIFY_3
;       SENDMONERPKT,HYBRID
;***********************************************************************

        .XCREF
        .XLIST
        INCLUDE basemaca.inc            ; VARIOUS MACRO'S (BREAK, LJC, ETC.)
        INCLUDE osmaca.inc
        INCLUDE devsym.inc
        INCLUDE devhlp.inc              ; DEFINITION OF DEVICE HELP CALLS.
        INCLUDE infoseg.inc             ; STRUCTURES DEFINING THE INFOSEG.
        INCLUDE filemode.inc            ; FILE SYSTEM FILE MODE EQUATES.
        INCLUDE ioctl.inc               ; IOCTL EQUATES.
        INCLUDE gas.inc                 ; GENERIC ALERT EQUATES.
        .LIST
        .CREF
        INCLUDE prtdd.inc               ; PRINTER DEVICE DRIVER INCLUDE FILE
;****************************************************************************** ;@IBM J-FUNC(A)
;|                                                                              ;@IBM J-FUNC(A)
;****************************************************************************** ;@IBM J-FUNC(A)
J_FUNC_101      MACRO                                                           ;@IBM J-FUNC(A)
                local   skip01                                                  ;@IBM J-FUNC(A)
        .lall                                                                   ;@IBM J-FUNC(A)
        ;                                                                       ;@IBM J-FUNC(A)
        ; GET/RELEASE SUPPORT - CHECK PROCESS ID                                ;@IBM J-FUNC(A)
        ;                                                                       ;@IBM J-FUNC(A)
        test    [di].commonflags,MONREG2                ; IF SPOOLER EXISTS     ;@IBM J-FUNC(A)
        jnz     skip01                                  ; THEN PROCEED          ;@IBM J-FUNC(A)
        test    [di].m_flag,M_GET                       ; IF PRT.IS NOT GOTTEN  ;@IBM J-FUNC(A)
        jz      skip01                                  ; THEN PROCEED          ;@IBM J-FUNC(A)
        call    getpid                                  ; GET PROCESS ID IN AX  ;@IBM J-FUNC(A)
        cmp     [di].prt_get_pid,ax                                             ;@IBM J-FUNC(A)
        je      skip01                                  ; IF THE SAME PROC.ID   ;@IBM J-FUNC(A)
        ;                                                                       ;@IBM J-FUNC(A)
        ; THIS REQUEST IS NOT ALLOWED, FORCE TO THE WRITEFAULT ERROR            ;@IBM J-FUNC(A)
        ;                                                                       ;@IBM J-FUNC(A)
        sti                                             ; ENABLE INTERRUPT      ;@IBM J-FUNC(A)
        mov     bx,si                                   ; OFFSET OF REQ.PACKET  ;@IBM J-FUNC(A)
        mov     es:[bx].PktStatus,WRITEFAULT            ; SET WRITE FAULT       ;@IBM J-FUNC(A)
        mov     dl,DevHlp_DevDone                       ; DEVDONE FUNCTION      ;@IBM J-FUNC(A)
        call    dword ptr [device_help]                 ; CALL DEVHLP TO DEVDONE;@IBM J-FUNC(A)
        stc                                             ; SET FLAG FOR PRTBLOCK ;@IBM J-FUNC(A)
        jmp     short blockret                          ; EXIT                  ;@IBM J-FUNC(A)
skip01:                                                                         ;@IBM J-FUNC(A)
        .xall                                                                   ;@IBM J-FUNC(A)
                ENDM                                                            ;@IBM J-FUNC(A)
                                                                                ;@IBM J-FUNC(A)

BREAK <DATA FOR THE PRINTER DEVICE DRIVER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME: PRTDATA                                           */
;/*                                                                    */
;/* DESCRIPTIVE NAME: PRINTER DEVICE DRIVER DATA DECLARATIONS          */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
DSEG    SEGMENT PUBLIC  'data'

        PUBLIC  glinfoseg
        PUBLIC  dosvar
        PUBLIC  device_help
        PUBLIC  numofprts
        PUBLIC  flags
        PUBLIC  perprtarea
        PUBLIC  moncache
        EXTRN   doserrors:WORD

;
; DEVICE DRIVER HEADER
;

; ? = FILLED IN BY LOADER
        EVEN
prndev  LABEL   WORD
        dw      lpt1dev                 ; POINTER TO NEXT HEADER
        dw      ?                       ; POINTER TO NEXT HEADER
        dw      DEV_CHAR_DEV OR DEVLEV_3 OR DEV_30  ; ATTRIBUTE
        dw      OFFSET  prtlpt1         ; POINTER TO STRATEGY ROUTINE
        dw      OFFSET  prtpdd_entry    ; POINTER TO PDD-PDD IDC ROUTINE
        db      'PRN     '              ; DEVICE NAME
        dw      ?                       ; SELECTOR OF CS SEGMENT
        dw      ?                       ; SELECTOR OF DS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF CS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF DS SEGMENT
        dd      DEV_IOCTL2 OR DEV_PARALLEL ; CAPABILITIES BIT STRIP

lpt1dev LABEL   WORD
        dw      lpt2dev                 ; POINTER TO NEXT HEADER
        dw      ?                       ; POINTER TO NEXT HEADER
        dw      DEV_CHAR_DEV OR DEVLEV_3 OR DEV_30  ; ATTRIBUTE
        dw      OFFSET  prtlpt1         ; POINTER TO STRATEGY ROUTINE
        dw      OFFSET  prtpdd_entry    ; POINTER TO PDD-PDD IDC ROUTINE
        db      'LPT1    '              ; DEVICE NAME
        dw      ?                       ; SELECTOR OF CS SEGMENT
        dw      ?                       ; SELECTOR OF DS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF CS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF DS SEGMENT
        dd      DEV_IOCTL2 OR DEV_PARALLEL ; CAPABILITIES BIT STRIP

lpt2dev LABEL   WORD
        dw      lpt3dev                 ; POINTER TO NEXT HEADER
        dw      ?                       ; POINTER TO NEXT HEADER
        dw      DEV_CHAR_DEV OR DEVLEV_3 OR DEV_30  ; ATTRIBUTE
        dw      OFFSET  prtlpt2         ; POINTER TO STRATEGY ROUTINE
        dw      OFFSET  prtpdd_entry    ; POINTER TO PDD-PDD IDC ROUTINE
        db      'LPT2    '              ; DEVICE NAME
        dw      ?                       ; SELECTOR OF CS SEGMENT
        dw      ?                       ; SELECTOR OF DS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF CS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF DS SEGMENT
        dd      DEV_IOCTL2 OR DEV_PARALLEL ; CAPABILITIES BIT STRIP

lpt3dev LABEL   WORD
        dd      -1                      ; LAST ON THE CHAIN
        dw      DEV_CHAR_DEV OR DEVLEV_3 OR DEV_30  ; ATTRIBUTE
        dw      OFFSET  prtlpt3         ; POINTER TO STRATEGY ROUTINE
        dw      OFFSET  prtpdd_entry    ; POINTER TO PDD-PDD IDC ROUTINE
        db      'LPT3    '              ; DEVICE NAME
        dw      ?                       ; SELECTOR OF CS SEGMENT
        dw      ?                       ; SELECTOR OF DS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF CS SEGMENT
        dw      ?                       ; SEGMENT NUMBER OF DS SEGMENT
        dd      DEV_IOCTL2 OR DEV_PARALLEL ; CAPABILITIES BIT STRIP

;
; GLOBAL VARIABLES
;
glinfoseg       dd      ?               ; GLOBAL INFO SEGMENT
dosvar          dd      ?               ; LOCAL INFO SEGMENT
device_help     dd      ?               ; ADDRESS OF DEVICE HELPER ROUTINE
mwrite_to       dw      12ffh           ; TIMEOUT FOR MONWRITE CALL (4 sec)
numofprts       db      ?               ; NUMBER OF PARALLEL PORTS INSTALLED
flags           db      0               ; BIT 0
                                        ; 0 = NOT INITIALIZED
                                        ; 1 = INITIALIZED

startcommands   db      CMDOUTPUT,CMDOUTPUTV,CMDClose,CMDGenIOCTL
STARTCMMNDMAX   EQU     $ - startcommands

stratcommand_tbl LABEL  WORD
        dw      OFFSET  prterror        ; 0 INITIALIZE LOADABLE DEV DRIVERS
        dw      OFFSET  prterror        ; 1 MEDIA CHECK
        dw      OFFSET  prterror        ; 2 BUILD BPB
        dw      OFFSET  prterror        ; 3 RESERVED
        dw      OFFSET  prtread         ; 4 READ
        dw      OFFSET  prtnondesrd     ; 5 NON-DESTRUCTIVE READ
        dw      OFFSET  prtcomplete     ; 6 INPUT STATUS
        dw      OFFSET  prtcomplete     ; 7 INPUT FLUSH
        dw      OFFSET  prtblock        ; 8 OUPUT(WRITE)
        dw      OFFSET  prtblock        ; 9 OUPUT(WRITE) /V
        dw      OFFSET  prtstatus       ; 10 OUTPUT STATUS
        dw      OFFSET  prtoutflush     ; 11 OUTPUT FLUSH
        dw      OFFSET  prterror        ; 12 RESERVED
        dw      OFFSET  prtopen         ; 13 OPEN
        dw      OFFSET  prtclose        ; 14 CLOSE
        dw      OFFSET  prterror        ; 15 REMOVABLE MEDIA
        dw      OFFSET  prtioctl        ; 16 GENERIC IOCTL
        dw      OFFSET  prterror        ; 17 RESET MEDIA
        dw      OFFSET  prterror        ; 18 GET LOG. DRIVE MAP
        dw      OFFSET  prterror        ; 19 SET LOG. DRIVE MAP
        dw      OFFSET  prtdeinstall    ; 20 DEINSTALL
        dw      OFFSET  prterror        ; 21 PORT ACCESS
        dw      OFFSET  prterror        ; 22 PART.FIXED DISKS
        dw      OFFSET  prterror        ; 23 GET FIXED DISK/LUMAP
        dw      OFFSET  prterror        ; 24 RESERVED
        dw      OFFSET  prterror        ; 25 RESERVED
        dw      OFFSET  prterror        ; 26 RESERVED
        dw      OFFSET  prtinit         ; 27 INITIALIZE BASE DEV DRIVERS
        dw      OFFSET  prtoutflush     ; 28 SYSTEM SHUT DOWN
STRATCMDMAX     EQU     ($ - stratcommand_tbl)/2

startcommand_tbl LABEL  WORD
        dw      OFFSET  prtstout        ; 8 OUPUT(WRITE)
        dw      OFFSET  prtstout        ; 9 OUPUT(WRITE)/V
        dw      OFFSET  prtmonclose     ; 14 MONITOR CLOSE
        dw      OFFSET  prtstioc        ; 16 GENERIC IOCTL

PUBLIC  monnotify_tbl
monnotify_tbl   LABEL   WORD
        dw      OFFSET  monnotify_1     ; NOTIFY ROUTINE FOR LPT1
        dw      OFFSET  monnotify_2     ; NOTIFY ROUTINE FOR LPT2
        dw      OFFSET  monnotify_3     ; NOTIFY ROUTINE FOR LPT3

perprtarea      printer_database MAXPRINTERS DUP(<>)

moncache        db MAXPRINTERS * (SIZE mcache) DUP (00H)

snalert label byte
        loghead32 <,,snalertend-$-4,SNAGENALERT,,,,,,,>
        psids <>
PrtGAS  gas <0Bh,GAS_GEN_ALERT,0000h,GAS_PERM_LOSS,,>
PrtPCS  gas_pcs <04h,GAS_PROB_CAUSE,GAS_PCD_PRINTER>
PrtUCS  gas_ucs <0Ah,GAS_USER_CAUSE,04h,GAS_UC_USER,,04h,GAS_UC_RECACT,>
snalertend label  byte

;------------------------------------------------------------------------------
;       dw      0001h                           ; PACKET VERSION NUMBER
;       dw      0001h                           ; NUMBER OF LOG PACKETS
;       dw      snalertend - $                  ; LENGTH OF LOG PACKET
;       dw      SNAGENALERT                     ; PACKET ID -  SNA GEN ALERT
;       dd      0                               ; STATUS (no processname)
;       db      'GA  '                          ; QUALIFIER NAME 'GEN ALERT'
;       dd      0                               ; RESERVED
;       dd      00000000h                       ; TIME FIELD
;       dd      00000000h                       ; DATE FIELD
;       db      'OS/2    '                      ; ORIGINATOR NAME
;       db      12 dup(0)                       ; Formatting DLL name(none)
;------------------------------------------------------------------------------
;       db      0Bh                             ; LENGTH
;       db      GAS_GEN_ALERT                   ; KEY=GENERIC ALERT SUBVECTOR
;       dw      0000h                           ; FLAGS
;       db      GAS_PERM_LOSS                   ; TYPE=PERMANENT LOSS
;       dw      ?                               ; DESC=
;       dd      ?                               ; ALERT ID-CRC FIELD CALCED
;------------------------------------------------------------------------------
;       db      04h                             ; LENGTH
;       db      GAS_PROB_CAUSE                  ; KEY=PROBABLE CAUSES SUBVEC
;       dw      GAS_PCD_PRINTER                 ; DESC=PRINTER DEVICE
;------------------------------------------------------------------------------
;       db      0Ah                             ; LENGTH
;       db      GAS_USER_CAUSE                  ; KEY=USER CAUSE SUBVECTOR
;       db      04h                             ; LENGTH
;       db      GAS_UC_USER                     ; KEY=USER CAUSE SUBFIELD
;       dw      ?                               ; CAUSE=
;       db      04h                             ; LENGTH
;       db      GAS_UC_RECACT                   ; KEY=RECOMMEND ACT SUBFIELD
;       dw      ?                               ; ACTION=
;------------------------------------------------------------------------------
;snalertend label  byte

DSEG    ENDS

        EXTRN    prtinit:FAR
        EXTRN    printblock:FAR
        EXTRNFAR getstatus                                                      ;@IBM J-PTR #JS03277(A)
;UCCTry(D)        EXTRNFAR prterp                                                         ;@IBM J-PTR #JS03277(A)

SWAPSEG SEGMENT PUBLIC  'code'
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        EXTRN   prtreqdirect:NEAR
        EXTRN   prtreldirect:NEAR
        EXTRN   prtdeinstall:NEAR
        EXTRN   prtioctl:NEAR
        EXTRN   prtstioc:NEAR
        EXTRN   flushcpqueue:NEAR

BREAK <COMMON REQUEST HANDLER>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTREQST                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT REQUEST HANDLER.                          */
;/*                                                                    */
;/* FUNCTION:  CALL THE APPRORPRIATE ROUTINE TO PROCESS THE REQUEST.   */
;/*                                                                    */
;/* ENTRY POINT: PRTREQST                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = PHYSICAL SEGMENT OF REQUEST BLOCK                  */
;/*            BX = PHYSICAL OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET INTO PERPRTAREA                             */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  N/A                                                  */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = INVALIDCOMMD                     */
;/*                                                                    */
;/* INTERNAL REFERENCES:  see command_tbl                              */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
;/**********************************************************************/
;/*                                                                    */
;/* THIS ROUTINE HAS BEEN MODIFIED IN ORDER TO BE COMPATIBLE WITH      */
;/* PC/DOS BY RETURNING SUCCESSFUL OPERATIONS FOR DEVICES NOT ATTACHED */
;/* TO THE SYSTEM WHEN THE SPOOLER IS NOT ACTIVE, AND AT THE SAME TIME */
;/* ALLOW THESE NON-EXISTENT DEVICES TO BE RE-DIRECTED BY THE SPOOLER  */
;/* IF SO DESIRED. THIS DESIGN IMPLEMENTATION REQUIRES THAT THE INI-   */
;/* TIALIZATION PORTION OF THE DEVICE DRIVER RETAIN THE ABILITY TO     */
;/* DETERMINE HOW MANY DEVICES ARE ATTACHED TO THE SYSTEM BUT ALWAYS   */
;/* ALLOW FOR THE MAXIMUM NUMBER OF PRINTERS IN THE DATA SEGMENT.      */
;/*                                                                    */
;/**********************************************************************/
Procedure prtreqst far
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        add     di,OFFSET perprtarea                    ; DI -> DEVICE DATA AREA

        cmp     es:[bx].Pktcmd,STRATCMDMAX-1            ; TOO BIG FOR TABLE?
        jbe     reqst10                                 ; NO, VALID COMMAND CODE
        mov     es:[bx].PktStatus,INVALIDCOMMD          ; RET ERR CODE
        jmp     SHORT reqst60                           ; TAKE QUICK WAY OUT
reqst10:
        cmp     es:[bx].PktCmd,CMDInitBase              ; IS THIS INIT BASE?
        jne     reqst20                                 ; NO - IT IS NOT INIT
        call    prtinit                                 ; YES - CALL INIT RTN
        jmp     reqst60                                 ; INIT DONE JUMP END
;/**********************************************************************/
;/* REGARDLESS IF A PORT EXISTS, IF A READ REQUEST, CALL ROUTINE TO    */
;/* RETURN ZERO BYTES READ IN ORDER TO BE COMPATIBLE WITH DOS.         */
;/**********************************************************************/
reqst20:
        cmp     es:[bx].PktCmd,CMDINPUT                 ; IF A READ CMD
        je      reqst50                                 ; CALL READ ROUTINE

        test    [di].commonflags1,PORTEXISTS            ; IF PORT EXISTS
        jnz     reqst50                                 ; PROCESS REQUEST

        ; NON EXISTENT PORT

        cmp     es:[bx].PktCmd,CMDGenIOCTL              ; IF A GENERIC IOCTL
        jne     reqst30                                 ; DO NEXT TEST
        cmp     es:[bx].GioFunction,IOMO_RE             ; A MON REG REQUEST THEN
        je      reqst50                                 ; CONTINUE PROCESS
reqst30:
        test    [di].commonflags,MONREG1                ; IS A MONITOR REG'D?
        jnz     reqst50                                 ; CONTINUE REQUEST
        mov     es:[bx].PktStatus,REQDONE               ; RET GOOD RC
        jmp     SHORT reqst60                           ; RETURN

reqst50:
        mov     al,es:[bx].PktCmd                       ; GET COMMAND CODE.
        xor     ah,ah                                   ; MAKE AH 0
        mov     si,ax                                   ; PUT INTO INDEX REG.
        sal     si,1                                    ; GET WORD INDEX
        call    WORD PTR stratcommand_tbl[si]           ; CALL ROUTINE
reqst60:
        ret
EndProc prtreqst

BREAK <ERROR ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTERROR                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER ERROR ROUTINE.              */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS ROUTINE IS TO RETURN WITH AN       */
;/*            INVALID ERROR CODE IN THE REQUEST BLOCK.                */
;/*                                                                    */
;/* ENTRY POINT: PRTERROR                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].STATUS = INVALIDCMMD                         */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prterror near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     es:[bx].PktStatus,INVALIDCOMMD          ; RET ERROR INVALIDCMMD
        ret
EndProc prterror

BREAK <PRINT DD READ ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTREAD                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER READ ROUTINE.               */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO RETURN 0 BYTES    */
;/*            TRANSFERED.                                             */
;/*                                                                    */
;/* ENTRY POINT: PRTREAD                                               */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].IOcount   = 0                                */
;/*               ES:[BX].PrtStatus = REQDONE                          */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtread near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     es:[bx].IOcount,0                       ; SET READ COUNT TO 0
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
        ret
EndProc prtread

BREAK <PRINT DD NON-DESTRUCTIVE READ ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTNONDESRD                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER NON-DESTRUCTIVE READ ROUTINE*/
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO RETURN BUSY.      */
;/*                                                                    */
;/* ENTRY POINT: PRTNONDESRD                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONEBUSY                      */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtnondesrd near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     es:[bx].PktStatus,REQDONEBUSY           ; SET BUSY & DONE BITS
        ret
EndProc prtnondesrd

BREAK <COMPLETE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCOMPLETE                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER COMPLETE.                   */
;/*                                                                    */
;/* FUNCTION:  SIGNAL REQUEST IS COMPLETE.                             */
;/*                                                                    */
;/* ENTRY POINT: PRTCOMPLETE                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*                                                                    */
;/* EXIT-ERROR:   N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtcomplete near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
        ret
EndProc prtcomplete

BREAK <RETURN OUTPUT STATUS ON DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTSTATUS                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER STATUS ROUTINE.             */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO RETURN THE STATUS */
;/*            OF THE DEVICE . IF I/O IS ACTIVE ON THAT DEVICE THEN    */
;/*            THE BUSY BIT OF THE STATUS WORD WILL BE SET TO A 1. IF  */
;/*            I/O IS INACTIVE ON THAT DEVICE THEN THE BUSY BIT WILL   */
;/*            BE SET TO 0.                                            */
;/*                                                                    */
;/* NOTE:  IF A MONITOR IS REGISTERED THIS ROUTINE WILL ALWAYS RETURN  */
;/*        NOT BUSY.                                                   */
;/*                                                                    */
;/* ENTRY POINT: PRTSTATUS                                             */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE or REQDONEBUSY           */
;/*                                                                    */
;/* EXIT-ERROR:   N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtstatus near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
; @IBM  test    [di].commonflags,MONREG1                ; IF MONITORS REG       ;@IBM J-FUNC(C)
        test    [di].commonflags,MONREG2                ; IF MONITORS REG       ;@IBM J-FUNC(C)
        jnz     statret                                 ; ALWAYS RET NOT BUSY
        test    [di].commonflags,IOACTIVE               ; IF I/O INACTIVE
        jz      statret                                 ; THEN RETURN
        mov     es:[bx].PktStatus,REQDONEBUSY           ; SET BUSY & DONE BITS
statret:
        ret
EndProc prtstatus

BREAK <FLUSH OUTPUT DEVICE BUFFERS>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTOUTFLUSH                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER OUTPUT FLUSH ROUTINE.       */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO FLUSH THE OUTPUT  */
;/*            BUFFERS OF THE DEVICE.  BY TURNING ON THE CANMONPKT     */
;/*            FLAG, ANY OUTPUT REQUEST ACTIVE ON THE DEVICE WILL BE   */
;/*            CANCELLED NO MATTER IF THE DEVICE IS IN ERROR OR NOT.   */
;/*            THE CANCEL IS ONLY IN EFFECT UNTIL THE CURRENT OUTPUT   */
;/*            REQUEST COMPLETES.                                      */
;/*                                                                    */
;/* NOTE: DOSBUFRESET generates this call.                             */
;/*                                                                    */
;/* ENTRY POINT: PRTOUTFLUSH                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*               DS:[DI].COMMONFLAGS1 = CANMONPKT                     */
;/*                                                                    */
;/* EXIT-ERROR:   N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtoutflush near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [di].commonflags,MONREG1                ; MONITOR REGISTERED?
        jz      prtoutflush0                            ; NO, CHECK STRAT REQ
        test    [di].commonflags,MONPRINTING            ; OUTPUT REQ IN PROG?
        jz      prtoutflush2                            ; NO, EXIT
        jmp     SHORT prtoutflush1                      ; YES, SET CANCEL FLAG

prtoutflush0:
        test    [di].commonflags,IOACTIVE               ; REQUEST IN PROGRESS?
        jz      prtoutflush2                            ; NO, EXIT
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        mov     bx,[di].dosoffset                       ; REQ PKT OFFSET
        mov     es,[di].dosrqseg                        ; REQ PKT SELECTOR
        cmp     es:[bx].PktCmd,CMDOUTPUT                ; OUTPUT REQUEST?
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        jne     prtoutflush2                            ; NO, EXIT
prtoutflush1:
        or      [di].commonflags1,CANMONPKT             ; TURN ON CANCEL FLAG
prtoutflush2:
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
        ret
EndProc prtoutflush

BREAK <OPEN ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTOPEN                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER OPEN ROUTINE.               */
;/*                                                                    */
;/* FUNCTION:  IF MONITOR REGISTERED SERIALIZE AND SPOOL OPEN COMMAND. */
;/*                                                                    */
;/* ENTRY POINT: PRTOPEN                                               */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:   ES:[BX].PktStatus = REQDONE                         */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  AllocReqPacket                  */
;/*    ROUTINES:                       PushRequest                     */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtopen near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        inc     [di].accessctr                          ; INCREASE # USING PDD
        test    [di].commonflags,MONREG1                ; IF MONITOR !REGISTERED
        jz      prtopen2                                ; THEN SET RETCODE, EXIT
        test    es:[bx].PktStatus,open_monitor          ; MON ISSUED OPEN REQ
        jnz     prtopen2                                ; THEN DON'T SPOOL IT

        mov     cx,es:[bx].OCSFN                        ; GET SFN FROM REQ BLK
        SaveReg <es,bx>
        xor     dh,dh                                   ; WAIT FOR REQ PKT
        mov     dl,DevHlp_AllocReqPacket                ; ALLOCATE REQ PKT
        call    DWORD PTR [device_help]                 ; CALL DEVHELP
        mov     es:[bx].PktCmd,CMDOpen                  ; SAVE CMD IN REQ PKT
        mov     es:[bx].OCSFN,cx                        ; SAVE SFN IN REQ PKT

        lea     si,[di].cpqueue                         ; GET START OF QUEUE
        mov     dl,DevHlp_PushRequest                   ; ADD REQ PKT TO QUEUE
        call    DWORD PTR [device_help]                 ; CALL DEVHELP
        RestoreReg <bx,es>
prtopen2:
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
        ret
EndProc prtopen

BREAK <CLOSE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCLOSE                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER CLOSE ROUTINE.              */
;/*                                                                    */
;/* FUNCTION:  IF MONITOR REGISTERED SERIALIZE AND SPOOL CLOSE         */
;/*            COMMAND.                                                */
;/*                                                                    */
;/* NOTE:  ONCE THE MONITOR IS LOADED, IT CAN ISSUE A CLOSE REQUEST TO */
;/*        DEREGISTER ITSELF.  THE FILE SYSTEM WILL SET BIT 3 IN THE   */
;/*        PKTSTATUS TO ALERT US TO DEREGISTER THE MONITOR INSTEAD OF  */
;/*        SPOOLING THE REQUEST.                                       */
;/*                                                                    */
;/* ENTRY POINT: PRTCLOSE                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:   ES:[BX].PktStatus = REQDONE                         */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  DeRegister                      */
;/*    ROUTINES:                       MonitorCreate                   */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtclose near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        dec     [di].accessctr                          ; REDUCE # USING PDD

        test    [di].commonflags,MONREG1                ; IF MONITOR REGISTERED
        jnz     prtclose0                               ; SEND MON PKT OR DEREG
        jmp     SHORT prtclose31                        ; THEN SET RETCODE, EXIT

prtclose0:
        test    es:[bx].PktStatus,open_monitor          ; MON ISSUED CLOSE REQ
        jnz     prtclose1                               ; THEN DEREGISTER MON
        call    prtblock                                ; WAIT TIL I/O INACTIVE
        jmp     SHORT prtclose5                         ; EXIT

;/**********************************************************************/
;/*                                                                    */
;/*     A MONITOR IS SHUTTING DOWN AND WE NEED TO DE-REGISTER IT FROM  */
;/*     THE CHAIN AND POSSIBLY REMOVE THE CHAIN IF THIS IS THE LAST    */
;/*     MONITOR ON THIS CHAIN.                                         */
;/*                                                                    */
;/**********************************************************************/

;/**********************************************************************/
;/*     DE-REGISTER THIS MONITOR FROM THE "DATA" CHAIN.                */
;/**********************************************************************/

prtclose1:
        push    bx                                      ; ELSE DEREGISTER MON
        call    getpid                                  ; GET CALLER'S PROC ID
        mov     bx,ax                                   ; MONITOR PROCESS ID
        mov     ax,[di].monhandle                       ; MONITOR HANDLE
        mov     dl,DevHlp_DeRegister                    ; DEREGISTER
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jc      prtclose4                               ; EXIT ON ERROR

        cmp     ax,0                                    ; IS THIS THE LAST ONE?
        jne     prtclose2                               ; JUMP IF NOT

;/**********************************************************************/
;/*     REMOVE THIS CHAIN IF NO MORE MONITORS ARE REGISTERED ON IT.    */
;/**********************************************************************/

        and     [di].commonflags,NOT MONREG1            ; TURN OFF MON REG BIT
        mov     ax,[di].monhandle                       ; MONITOR HANDLE
        mov     dl,DevHlp_MonitorCreate                 ; REMOVE THE CHAIN
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jc      prtclose4                               ; EXIT ON ERROR

        mov     [di].monhandle,0
        and     [di].commonflags,NOT MONCHAIN1          ; TURN OFF MON REG BIT
        and     [di].commonflags,NOT INFINRETRY         ; TURN OFF INFRETRY BIT

;/**********************************************************************/
;/*     NOW, DE-REGISTER THIS MONITOR FROM THE "CODE PAGE" CHAIN.      */
;/**********************************************************************/

prtclose2:
; NO ARCHITECTED WAY TO KNOW IF USER REGISTERED MONITOR ON BOTH CHAIN 1 AND 2.
; ASSUME IF SOME MONITOR IS REGISTERED IT MUST BE THIS MONITOR.

        test    [di].commonflags,MONREG2                ; CP REG FOR DEVICE?
        jz      prtclose3                               ; NO
        mov     ax,[di].cpfhandle                       ; CODE PAGE HANDLE
        mov     dl,DevHlp_DeRegister                    ; DEREGISTER
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jc      prtclose4                               ; EXIT ON ERROR

        cmp     ax,0                                    ; IS THIS THE LAST ONE?
        jne     prtclose3                               ; JUMP IF DONE

;/**********************************************************************/
;/*     REMOVE THIS CHAIN IF NO MORE MONITORS ARE REGISTERED ON IT.    */
;/**********************************************************************/

        and     [di].commonflags,NOT MONREG2            ; TURN OFF MON REG BIT
        mov     ax,[di].cpfhandle                       ; MONITOR HANDLE
        mov     dl,DevHlp_MonitorCreate                 ; REMOVE THE CHAIN
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jc      prtclose4                               ; EXIT ON ERROR

        mov     [di].cpfhandle,0
        and     [di].commonflags,NOT MONCHAIN2          ; TURN OFF MON REG BIT

prtclose3:
        pop     bx                                      ; RESTORE BX
prtclose31:
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
        jmp     SHORT prtclose5                         ; GO TO FINISH

prtclose4:
        pop     bx                                      ; RESTORE BX
        mov     es:[bx].PktStatus,WRITEFAULT            ; MON WRITE ERROR CODE

prtclose5:
        ret
EndProc prtclose

BREAK <GET PROCESS ID ROUTINE>
;/*********************** END OF SPECIFICATIONS ************************/
;/*                                                                    */
;/* SUBROUTINE NAME:  GETPID                                           */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER GET PROCESS ID ROUTINE      */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS ROUTINE IS TO GET THE CURRENT      */
;/*            PROCESS'S ID.                                           */
;/*                                                                    */
;/* ENTRY POINT:  GETPID                                               */
;/*    LINKAGE :  CALL NEAR                                            */
;/*                                                                    */
;/* INPUT:      ES = VIRTUAL SEGMENT OF REQUEST BLOCK                  */
;/*             BX = VIRTUAL OFFSET OF REQUEST BLOCK                   */
;/*             DI = OFFSET TO APPROPRIATE PERPRTDATA AREA             */
;/*                                                                    */
;/* REGISTERS USED:  ALL REGISTERS SAVED BY THE KERNEL                 */
;/*                                                                    */
;/* EXIT-NORMAL:  ax  = current process id                             */
;/*                                                                    */
;/* EXIT-ERROR:   same as above.                                       */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure getpid near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,DWORD PTR dosvar                     ; GET LOCAL INFO SEG
        les     bx,DWORD PTR es:[bx]
        mov     ax,es:[bx].LIS_CurProcID                ; GET PROCESS ID
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        ret
EndProc getpid

BREAK <PRINTER DEVICE DRIVER SYNCHRONIZATION ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTBLOCK                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER REQUEST BLOCKER.            */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO START THE REQUEST */
;/*            IF I/O IS NOT ACTIVE ON THAT DEVICE AND IF ACTIVE, TO   */
;/*            BLOCK THE THREAD UNTIL I/O IS COMPLETE ON THE DEVICE.   */
;/*                                                                    */
;/* ENTRY POINT: PRTBLOCK                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  N/A                                                  */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  block                                        */
;/*    ROUTINES:          see startcommand_tbl                         */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtblock near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        call    block                                   ; BLOCK IF I/O ACTIVE
        jc      prtblkret                               ; RETURN IF INTERRUPTED
        SaveReg <es,di>                                 ; SAVE REGISTERS
        mov     al,es:[bx].PktCmd                       ; GET COMMAND CODE
        mov     cx,STARTCMMNDMAX                        ; # OF STRATEGY CMDS
        push    ds                                      ; DATA SEGMENT ADDRESS
        pop     es                                      ; DATA SEGMENT ADDRESS
        mov     di,OFFSET startcommands                 ; OFFSET COMMAND CODES
        repnz   scasb                                   ; SEARCH FOR COMMND CODE
        mov     si,di                                   ; SEARCH INDEX
        RestoreReg <di,es>                              ; RESTORE REGISTERS

        ; COMMAND CODE VALIDATED IN PRTREQUEST ROUTINE
        dec     si                                      ; ADJUST SI
        sub     si,OFFSET startcommands                 ; ADJUST SI
        sal     si,1                                    ; GET WORD INDEX
        call    WORD PTR startcommand_tbl[si]           ; CALL ROUTINE
prtblkret:
        ret
EndProc prtblock

BREAK <PRINTER DEVICE DRIVER BLOCK ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  BLOCK                                            */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER REQUEST BLOCKER.            */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO CALL DEVHLP TO    */
;/*            BLOCK THE CURRENT THREAD IF I/O IS ACTIVE ON THE DEVICE.*/
;/*                                                                    */
;/* ENTRY POINT: BLOCK                                                 */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  [DI].commonflags = IOACTIVE                          */
;/*               [DI].dosoffset = BX                                  */
;/*               [DI].dosrqseg = ES                                   */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = CHARIOINT                        */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcBlock                       */
;/*    ROUTINES:                       DevDone                         */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure block near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     si,bx                                   ; OFF. OF DOS REQ BLK
retest:
        cli                                             ; DISABLE INTERRUPTS
        test    [di].commonflags,IOACTIVE               ; IF I/O !ACTIVE
        jz      ioidle                                  ; THEN PROCEED

        ; I/O IS ACTIVE ON THAT DEVICE
        push    di
        mov     ax,[di].dosrqseg                        ; SEG. OF LAST REQ BLK
        mov     bx,[di].dosoffset                       ; OFF. OF LAST REQ BLK
        mov     cx,BLOCKLOWVALUE                        ; -1 NEVER TIMEOUT
        mov     di,BLOCKHIVALUE                         ; -1 NEVER TIMEOUT
        mov     dh,BLOCKSLEEPINT                        ; SLEEP INTERRUPTIBLE
        mov     dl,DevHlp_ProcBlock                     ; BLOCK FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO BLOCK
        pop     di
        jnc     retest                                  ; JMP IF WAKEUP OK
        jz      retest                                  ; JMP IF TIMEOUT

        sti                                             ; ENABLE INTERRUPTS
        mov     bx,si                                   ; OFF.OF DOS REQ BLOCK
        mov     es:[bx].PktStatus,CHARIOINT             ; SET CHAR I/O INT ERR
        mov     dl,DevHlp_DevDone                       ; DEVICE DONE
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        stc                                             ; SET FLAG FOR PRTBLOCK
        jmp     SHORT blockret                          ; EXIT
ioidle:
        J_FUNC_101                                                              ;@IBM J-FUNC(A)
        or      [di].commonflags,IOACTIVE               ; SET I/O ACTIVE
        sti                                             ; ENABLE INTERRUPTS
        ; SET UP THE ACTIVE REQUEST POINTER
        mov     [di].dosoffset,si                       ; OFF. OF DOS REQ BLOCK
        mov     [di].dosrqseg,es                        ; SEG. DOS REQ BLOCK
        mov     bx,si                                   ; OFF.OF DOS REQ BLOCK
        clc                                             ; CLR FLAG FOR PRTBLOCK
blockret:
        ret
EndProc block

BREAK <START OUTPUT ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTSTOUT                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  START OUTPUT ROUTINE.                           */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO CONVERT THE       */
;/*            PHYSICAL ADDRESS PASSED ON THE DOSWRITE REQUEST TO A    */
;/*            GDT SELECTOR WHICH IS SAVED IN THE DEVICE DATA AREA.    */
;/*            IF A MONITOR IS REGISTERED, THIS SUBROUTINE WILL CALL   */
;/*            THE ROUTINE TO CACHE/PROCESS THE REQUEST OTHERWISE IT   */
;/*            WILL CALL THE ROUTINE TO SEND THE DATA TO THE DEVICE.   */
;/*                                                                    */
;/* ENTRY POINT: PRTSTOUT                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  N/A                                                  */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  outspool                                     */
;/*    ROUTINES:          prtreqdirect                                 */
;/*                       printblock                                   */
;/*                       sendsnagas                                   */
;/*                       prtreldirect                                 */
;/*                       devdone                                      */
;/*                       flushcpqueue                                 */
;/*                       fillcache                                    */
;/*                       flushcache                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  PhysToGDTSelector               */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtstout near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [di].commonflags,MONREG1                ; IF MONITOR NOT CREATED
        jnz     outst1                                  ; GIVE DATA TO DEVICE
        call    prtreqdirect                            ; REQUEST PORT ACCESS
        jc      outst8                                  ; IF ERROR, EXIT
        call    printblock                              ; PRINT A BLOCK OF CHARS
        call    sendsnagas                              ; LOG GEN ALERT VECTOR
        call    prtreldirect                            ; RELEASE PORT ACCESS
        jmp     outst8                                  ; DEVDONE, EXIT
outst1:
        push    bx                                      ; SAVE REGISTER
        mov     cx,es:[bx].IOcount                      ; GET USER BUF LENGTH
        mov     ax,WORD PTR es:[bx].IOpData+2           ; GET USER BUFFER SEG
        mov     bx,WORD PTR es:[bx].IOpData             ; GET USER BUF OFFSET
        mov     si,[di].gdtuserbuf                      ; GET GDT SELECTOR
        mov     dl,DevHlp_PhysToGDTSelector             ; CONVERT PHYS TO GDT
        call    DWORD PTR [device_help]                 ; DO ADDRESS CONVERSION
        pop     bx                                      ; RESTORE REGISTER

        call    flushcpqueue                            ; FLUSH QUEUED REQS
        jc      outst11                                 ; IF ERROR, EXIT
        cmp     cx,CACHESIZE                            ; IF SMALL WRITE REQ
        jb      outst2                                  ; THEN CACHE SMALL BUF

        ; LARGE WRITE REQUEST; IF SAME SFN AS IN CACHE, FLUSH CACHE.  THEN
        ; FORMAT LARGE WRITE REQUEST INTO MONITOR PACKETS AND SEND THEM.

        mov     cx,es:[bx].IOSFN                        ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH SMALL BUFFER
        jnc     outst7                                  ; IF !ERROR, BUF EMPTY
outst11:
        mov     es:[bx].IOcount,0                       ; ELSE BYTES WRITTEN=0
        jmp     SHORT outst8                            ; EXIT
outst2:

        ; SMALL WRITE REQUEST, IF SAME SFN AS IN CACHE, ADD TO CACHE OTHERWISE
        ; FORMAT SMALL WRITE REQUEST INTO MONITOR PACKET AND SEND IT.

        mov     si,[di].cache_off                       ; SI -> DEV MON CACHE
        cmp     [si].savesfn,0                          ; IF CACHE EMPTY
        je      outst3                                  ; THEN START BUFFERING
        mov     ax,es:[bx].IOSFN                        ; GET SFN OF REQUEST
        cmp     ax,[si].savesfn                         ; IF SFN != CACHE SFN
        jne     outst7                                  ; THEN SEND BUF TO MON
outst3:
        call    fillcache                               ; CACHE SMALL BUFFER
        jmp     SHORT outst8                            ; EXIT
outst7:
        call    outspool                                ; SPOOL OUTPUT
outst8:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtstout

BREAK <FILL CACHE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  FILLCACHE                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINTER DEVICE DRIVER FILL CACHE ROUTINE.       */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO BUFFER SMALL      */
;/*            WRITE REQUESTS INTO A CACHE AND ONCE THE CACHE IS FULL  */
;/*            TO FORMAT AND SEND THE MONITOR PACKET TO THE MONITOR.   */
;/*                                                                    */
;/* ENTRY POINT: FILLCACHE                                             */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DS = DEVICE DRIVER DATA SELECTOR ADDRESS                */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            SI = OFFSET TO APPROPRIATE MONITOR CACHE AREA           */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  N/A                                                  */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  flushcache                                   */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure fillcache near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        ; UPDATE FIXED CACHE (MONITOR) RECORD FIELDS

        mov     cx,es:[bx].IOSFN                        ; GET REQUESTED SFN
        mov     [si].savesfn,cx                         ; SAVE SFN
        mov     [si].saveflags,MONCLEAR                 ; SET MONWRITE FLAG

        ; GET VIRTUAL POINTER TO USER (RING 3) BUFFER ADDRESS AND LENGTH

        xor     ax,ax                                   ; CLEAR AMT MOVED CNT
        mov     dx,CACHESIZE                            ; GET MAX SIZE OF CACHE
        sub     dx,[si].saveindex                       ; DX = ROOM REMAINING
        mov     cx,es:[bx].IOcount                      ; GET REQUESTED COUNT
        cmp     cx,dx                                   ; OUTPUT <= REMAINING
        jbe     fillcache1                              ; JMP IF YES
        mov     cx,dx                                   ; CX = AMT TO FILL BUF
fillcache1:
        SaveReg <es,bx,ds,di,si>                        ; CX=MOVE AMT,AX=MOVED
        lea     bx,[si].savedata                        ; GET START ADDRESS
        add     bx,[si].saveindex                       ; ADD OFFSET
        push    ds                                      ; GET DEV DRIVER ADDR
        pop     es                                      ; SET DEV DRIVER ADDR
        mov     ds,[di].gdtuserbuf                      ; SET VIRT ADDR - SEL
        mov     di,bx                                   ; ES:DI -> TARGET
        xor     si,si                                   ; SET VIRT ADDR - OFF

        ; COPY USER DATA TO DEVICE DRIVER CACHE AND UPDATE LENGTH OF CACHE

        SaveReg <cx>                                    ; SAVE AMOUNT TO MOVE
        add     si,ax                                   ; INDEX INTO USER BUF
        cld                                             ; CLEAR DIRECTION FLAG
        rep     movsb                                   ; MOVE DATA TO MON BUF

        RestoreReg <cx,si,di,ds,bx,es>                  ; AX=MOVED,CX=MOVE AMT
        add     [si].saveindex,cx                       ; ADD TO TOTAL
        cmp     [si].saveindex,CACHESIZE                ; IF CACHE NOT FULL
        jne     fillcache4                              ; THEN EXIT

        ; DEVICE DRIVER CACHE FULL AND MORE TO COPY, FLUSH CACHE AND COPY REST

        add     ax,cx                                   ; ADD TO AMT MOVED
        mov     cx,es:[bx].IOSFN                        ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH BUFFER TO MON
        jc      fillcache2                              ; IF ERROR, EXIT

        cmp     es:[bx].IOcount,ax                      ; REMAINING TO MOVE?
        je      fillcache4                              ; NO, EXIT
        mov     cx,es:[bx].IOSFN                        ; SFN WAS CLEARED
        mov     [si].savesfn,cx                         ; SAVE SFN
        mov     cx,es:[bx].IOcount                      ; GET BUFFER LENGTH
        sub     cx,ax                                   ; CX=REMAINING TO MOVE
        jmp     SHORT fillcache1                        ; BUFFER REMAINING
fillcache2:
        cmp     es:[bx].IOcount,ax                      ; REMAINING TO MOVE?
        jne     fillcache3                              ; YES

        ; ABLE TO BUFFER ENTIRE REQUEST, RETURN ERROR ON NEXT WRITE REQUEST

        mov     es:[bx].PktStatus,REQDONE               ; REMOVE ERROR
        jmp     SHORT fillcache4                        ; EXIT

        ; ABLE TO BUFFER PARTIAL REQUEST, MUST RETURN ERROR NOW
fillcache3:
        mov     es:[bx].IOcount,ax                      ; UPDATE CNT W BUF AMT
fillcache4:
        ret
EndProc fillcache

BREAK <FLUSH CACHE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  FLUSHCACHE                                       */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER FLUSH CACHE ROUTINE.        */
;/*                                                                    */
;/* FUNCTION:  TO FLUSH BUFFER TO MONITOR CHAIN.                       */
;/*                                                                    */
;/* NOTE:                                                              */
;/*                                                                    */
;/* ENTRY POINT: FLUSHCACHE                                            */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DS = DEVICE DRIVER DATA SELECTOR ADDRESS                */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            CX = SFN OF CURRENTLY ACTIVE REQUEST                    */
;/*                                                                    */
;/* REGISTERS USED:                                                    */
;/*                                                                    */
;/* EXIT-NORMAL:  NC = NO ERRORS, FLUSH DONE IF NECESSARY              */
;/*                                                                    */
;/* EXIT-ERROR :  CY = MONWRITE ERROR                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  monwrite                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure flushcache near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     si,[di].cache_off                       ; SI -> DEV MON CACHE
        cmp     cx,[si].savesfn                         ; IF SFN != SAVE SFN
        jne     fcache1                                 ; THEN DON'T FLUSH CACHE

        mov     cx,[si].saveindex                       ; VAR SIZE OF MON REC
        or      cx,cx                                   ; IF ZERO
        jz      fcache1                                 ; THEN JUST EXIT

        add     cx,TOMONFIXEDLEN                        ; FIXED SIZE OF MON REC
        mov     dh,MONTIMEOUT                           ; TIMEOUT
        call    monwrite                                ; GIVE DATA TO MONITOR
        jc      fcache2                                 ; IF ERROR, EXIT
        mov     [si].savesfn,0                          ; CLEAR SAVEAREA SFN
        mov     [si].saveindex,0                        ; CLEAR SAVEAREA COUNT
fcache1:
        clc                                             ; NO ERROR
fcache2:
        ret
EndProc flushcache

BREAK <OUTPUT TO SPOOLER ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME: OUTSPOOL                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME: PRINT DEVICE DRIVER OUTPUT SPOOL ROUTINE.        */
;/*                                                                    */
;/* FUNCTION: THE FUNCTION OF THIS ROUTINE IS TO SEND THE CURRENT      */
;/*           OUTPUT REQUEST TO THE FIRST MONITOR ON THE CHAIN FOR     */
;/*           THIS DEVICE.                                             */
;/*                                                                    */
;/* ENTRY POINT: OUTSPOOL                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DS = DEVICE DRIVER DATA SELECTOR ADDRESS                */
;/*            SI = OFFSET TO APPROPRIATE MONITOR BUFFER               */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:   ES:[BX].PktStatus = REQDONE                         */
;/*                ES:[BX].IOcount = count sent to monitor             */
;/*                                                                    */
;/* EXIT-ERROR:    ES:[BX].PktStatus = Error Code                      */
;/*                ES:[BX].IOcount = count sent to monitor             */
;/*                                                                    */
;/* INTERNAL REFERENCES:  monwrite                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure outspool near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx,ds>                              ; SAVE REGISTERS

        ; UPDATE FIXED MONITOR RECORD FIELDS

        mov     ax,es:[bx].IOSFN                        ; GET SFN FROM REQ BLK
        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON PKT
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLEAR                ; MONWRITE FLAG

        ; GET VIRTUAL POINTER TO USER (RING 3) BUFFER ADDRESS AND LENGTH

        mov     cx,es:[bx].IOcount                      ; SAVE INITIAL COUNT
        xor     si,si                                   ; SET VIRT ADDR - OFF

        ; DETERMINE MONITOR RECORD SIZE AND UPDATE VARIABLE MONITOR RECORD
        ; FIELDS BY COPYING USER DATA TO DEVICE DRIVER

outspool1:
        push    cx                                      ; SAVE REMAINING
        mov     dx,[di].configbufsize                   ; GET MON PKT SIZE
        sub     dx,FROMMONFIXEDLEN                      ; CALC MAX VARIABLE SIZE
        cmp     cx,dx                                   ; IF REMAIN <= MAXVARSIZ
        jbe     outspool2                               ; MUST USE REMAINING
        mov     cx,dx                                   ; MUST USE MON REQ SIZE
outspool2:
        push    cx                                      ; SAVE MON REQ SIZE
        SaveReg <cx,di,ds,es>                           ; SAVE REGISTERS
        cld                                             ; CLEAR DIRECTION FLAG
        push    ds                                      ; GET DEV DRIVER ADDR
        pop     es                                      ; SET DEV DRIVER ADDR
        mov     ds,[di].gdtuserbuf                      ; SET VIRT ADDR - SEL
        mov     di,es:[di].tomonbuf_off                 ; ES:DI -> TO MON PKT
        lea     di,[di].tomonbuf                        ; OFFSET OF TO MON DATA
        rep     movsb                                   ; MOVE BYTES INTO BUFFER
        RestoreReg <es,ds,di,cx>                        ; RESTORE REGISTERS

        ; SEND PARALLEL PORT MONITOR PACKET TO MONITOR DISPATCHER

        add     cx,TOMONFIXEDLEN                        ; ADD CTRL FIELD SIZE
        mov     dh,MONTIMEOUT                           ; BLOCK BUT TIMEOUT
        push    si                                      ; SAVE VIRT ADDR OFF
        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON PKT
        call    monwrite                                ; GIVE DATA TO MONITOR
        pop     si                                      ; RESTORE VIRT ADDR OFF

        pop     dx                                      ; RESTORE MON REQ SIZE
        pop     cx                                      ; RESTORE REMAINING
        jc      outspool3                               ; IF ERROR, EXIT
        sub     cx,dx                                   ; CALC NEW REMAINING
        jnz     outspool1                               ; IF !ZERO, SEND MORE
outspool3:
        RestoreReg <ds,bx,es>                           ; RESTORE REGISTERS
        sub     es:[bx].IOCount,cx                      ; UPDATE COUNT WRITTEN
        ret
EndProc outspool

BREAK <MONITOR CLOSE ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTMONCLOSE                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINTER DEVICE DRIVER MONITOR CLOSE ROUTINE.    */
;/*                                                                    */
;/* FUNCTION:  NOTIFY THE PRINT SPOOLER THAT IT CAN CLOSE ALL THE      */
;/*            FILES THAT IT HAS OPEN FOR THIS PROCESS AND QUEUE       */
;/*            THEM TO BE PRINTED.                                     */
;/*                                                                    */
;/* ENTRY POINT: PRTMONCLOSE                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = WRITEFAULT or CHARIOINT          */
;/*                                                                    */
;/* INTERNAL REFERENCES:  flushcpqueue                                 */
;/*    ROUTINES:          monwrite                                     */
;/*                       devdone                                      */
;/*                       flushcache                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtmonclose near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        call    flushcpqueue                            ; FLUSH KERNEL CP REQS
; @IBM  jc      prtmoncls1                              ; IF ERROR, EXIT        ;chg
        jnc     prtmoncls0                              ; IF NO ERROR, CONTINUE ;chg

;*===========================================================================*  ;@IBM J-PTR #JS03089(A)
;|  All pushed Request Packets, which was created at the timeout of the         ;@IBM J-PTR #JS03089(A)
;|  MonWrite Device Helper request, have to be removed from CP queue and to     ;@IBM J-PTR #JS03089(A)
;|  be free, because no module pulled the Request Packets.                      ;@IBM J-PTR #JS03089(A)
;*===========================================================================*  ;@IBM J-PTR #JS03089(A)
        pusha                                           ; SAVE ALL REGISTERS    ;@IBM J-PTR #JS03089(A)
        push    es                                                              ;@IBM J-PTR #JS03089(A)
prtmonflushcpq:                                                                 ;@IBM J-PTR #JS03089(A)
        lea     si,[di].cpqueue                         ; GET TOP OF THE QUEUE  ;@IBM J-PTR #JS03089(A)
        mov     dl,DevHlp_PullRequest                   ; GET KERNEL REQ PKT    ;@IBM J-PTR #JS03089(A)
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO PULL   ;@IBM J-PTR #JS03089(A)
        jc      prtmonflushcpq_end                      ; IF NO REQ PKTS, EXIT  ;@IBM J-PTR #JS03089(A)
        mov     dl,DevHlp_FreeReqPacket                 ; FREE ALLOC REQ PKT    ;@IBM J-PTR #JS03089(A)
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO FREE   ;@IBM J-PTR #JS03089(A)
        jmp     short prtmonflushcpq                    ; FOR OTHER REQ PKTS    ;@IBM J-PTR #JS03089(A)
prtmonflushcpq_end:                                                             ;@IBM J-PTR #JS03089(A)
        pop     es                                      ; RESTORE ALL REGISTERS ;@IBM J-PTR #JS03089(A)
        popa                                                                    ;@IBM J-PTR #JS03089(A)
        jmp     prtmoncls1                                                      ;add
                                                                                ;add
prtmoncls0:                                                                     ;add
        mov     cx,es:[bx].OCSFN                        ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH BUF TO MON
        jc      prtmoncls1                              ; IF ERROR, EXIT

        ; FORMAT AND SEND CLOSE REQUEST TO MONITOR

        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON PKT
        mov     ax,es:[bx].OCSFN                        ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLOSE                ; MONCLOSE FLAG
        mov     cx,TOMONFIXEDLEN                        ; FIXED SIZE OF MON REC
        mov     dh,MONTIMEOUT                           ; TIMEOUT
        call    monwrite                                ; GIVE DATA TO MONITOR
        jnc     prtmoncls1                              ; IF NO ERROR, EXIT
;@IBM TEMP ;*===========================================================================*  ;@IBM DEFECT 49236(A)
;@IBM TEMP ;|  If a close packet cannot write to the monitor chain when a cancel monitor   ;@IBM DEFECT 49236(A)
;@IBM TEMP ;|  packet flag is on, the SFN should be saved in latestsfn.  The flushcpqueue  ;@IBM DEFECT 49236(A)
;@IBM TEMP ;|  function generates and writes another close packet using the SFN at the     ;@IBM DEFECT 49236(A)
;@IBM TEMP ;|  top of the next print job.                                                  ;@IBM DEFECT 49236(A)
;@IBM TEMP ;*===========================================================================*  ;@IBM DEFECT 49236(A)
;@IBM TEMP ;;      jc      prtmoncls1                              ; IF ERROR, EXIT        ;@IBM DEFECT 49236(D)
;@IBM TEMP         jnc     prtmoncls1                              ; IF NO ERROR, CONTINUE ;@IBM DEFECT 49236(A)
;@IBM TEMP         test    [di].commonflags1,CANMONPKT             ; CANCEL MON PKTS?      ;@IBM DEFECT 49236(A)
;@IBM TEMP         jz      prtmoncls1                              ; NO, EXIT              ;@IBM DEFECT 49236(A)
;@IBM TEMP         mov     ax,es:[bx].OCSFN                        ; SAVE THE SFN          ;@IBM DEFECT 49236(A)
;@IBM TEMP         mov     [di].latestsfn,ax                       ; INTO LATEST SFN       ;@IBM DEFECT 49236(A)
;@IBM TEMP         jmp     short prtmoncls4                        ; EXIT                  ;@IBM DEFECT 49236(A)
        cmp     es:[bx].PktStatus,CHARIOINT             ; IF CTRL C PRESSED
        je      prtmoncls1                              ; EXIT

        ; MONITOR CHAIN IS FULL, MUST QUEUE CLOSE REQUEST FOR MONITOR
        ; FILE SYSTEM IGNORES DEVICE DRIVER CLOSE ERRORS AND INVALIDATES HANDLE
        ; APPLICATIONS DO NOT REISSUE CLOSE REQUEST WHEN ERROR RETURNED

        mov     cx,es:[bx].OCSFN                        ; GET SFN FROM REQ BLK
        SaveReg <es,bx>
        xor     dh,dh                                   ; WAIT FOR REQ PKT
        mov     dl,DevHlp_AllocReqPacket                ; ALLOCATE REQ PKT
        call    DWORD PTR [device_help]                 ; CALL DEVHELP
        mov     es:[bx].PktCmd,CMDClose                 ; SAVE CMD IN REQ PKT
        mov     es:[bx].OCSFN,cx                        ; SAVE SFN IN REQ PKT

        lea     si,[di].cpqueue                         ; GET START OF QUEUE
        mov     dl,DevHlp_PushRequest                   ; ADD REQ PKT TO QUEUE
        call    DWORD PTR [device_help]                 ; CALL DEVHELP
        RestoreReg <bx,es>
        mov     es:[bx].PktStatus,REQDONE               ; SET GOOD RETURN CODE
prtmoncls1:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtmonclose

BREAK <MONITOR WRITE ROUTINE>
;/*********************** END OF SPECIFICATIONS ************************/
;/*                                                                    */
;/* SUBROUTINE NAME:  MONWRITE                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  MONITOR WRITE ROUTINE.                          */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS ROUTINE IS TO WRITE A BUFFER TO    */
;/*            THE MONITOR.                                            */
;/*                                                                    */
;/* NOTES:  THE SPOOLER AND WORKPLACE SHELL ARE IN THE SAME PROCESS.   */
;/*         OPEN AND CLOSE APIS TAKE THE FILE SYSTEM SEMAPHORE AND NO  */
;/*         OTHER THREADS IN THE SAME PROCESS CAN GET INTO THE FILE    */
;/*         SYSTEM UNTIL THESE REQUESTS RETURN.  IT IS IMPORTANT THAT  */
;/*         THESE OPEN AND CLOSE REQUESTS DO NOT BLOCK AS OTHER QUEUE  */
;/*         PROCESSOR AND SHELL THREADS ARE NOT ABLE TO PERFORM FILE   */
;/*         SYSTEM ACCESSES UNTIL THE OPEN/CLOSE THREAD RELEASES ITS   */
;/*         SEMAPHORE.  DEADLOCKS CAN OCCUR.                           */
;/*                                                                    */
;/* ENTRY POINT:  MONWRITE                                             */
;/*    LINKAGE :  CALL NEAR                                            */
;/*                                                                    */
;/* INPUT:      ES = VIRTUAL SEGMENT OF REQUEST BLOCK                  */
;/*             BX = VIRTUAL OFFSET OF REQUEST BLOCK                   */
;/*             SI = OFFSET TO MONITOR BUFFER                          */
;/*             DI = OFFSET TO APPROPRIATE PERPRTDATA AREA             */
;/*             CX = COUNT TO WRITE TO MONITOR DISPATCHER              */
;/*             FLAGS, SFN, AND BUFFER FILLED IN                       */
;/*             DH = MONWAIT, MONNOWAIT, or MONTIMEOUT                 */
;/*                                                                    */
;/* REGISTERS USED:  ALL REGISTERS SAVED BY THE KERNEL                 */
;/*                                                                    */
;/* EXIT-NORMAL:  NC - CARRY FLAG NOT SET, PktStatus unchanged         */
;/*                                                                    */
;/* EXIT-ERROR:   CY - CARRY FLAG SET, PktStatus = WRITEFAULT or       */
;/*                                                CHARIOINT           */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  MonWrite                        */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure monwrite near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        LocalVar _LoopCtr,WORD                          ; LOOP CONTROL VARIABLE

        EnterProc
        mov     _LoopCtr,5                              ; SET INITIAL VALUE
        SaveReg <ax,si,dx>                              ; SAVE REGISTERS
monwrite00:
        mov     ax,[di].monhandle                       ; MONITOR HANDLE
        mov     dl,DevHlp_MonWrite                      ; MONTIOR WRITE FUNCTION
        SaveReg <bx,di>                                 ; SAVE REGISTERS
        cmp     dh,2                                    ; REQUEST FOR TIMEOUT
        jne     monwrite0                               ; NO
        mov     bx,mwrite_to                            ; TIMEOUT LOW IN MS
        xor     di,di                                   ; TIMEOUT HIGH IN MS
monwrite0:
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        RestoreReg <di,bx>                              ; RESTORE REGISTERS
        jnc     monwrite2                               ; IF NO ERROR, EXIT
        mov     es:[bx].PktStatus,CHARIOINT             ; ASSUME UNUSUAL WAKEUP
        cmp     ax,ERROR_INTERRUPT                      ; IF PROCESS DYING
        je      monwrite1                               ; EXIT
        cmp     dh,2                                    ; REQUEST FOR TIMEOUT
        jne     monwrite10                              ; NO
        cmp     ax,ERROR_SEM_TIMEOUT                    ; IF !SEMAPHORE TIMEOUT
        jne     monwrite10                              ; THEN DO NOT RETRY
        dec     _LoopCtr                                ; DEC LOOP CTR
        jnz     monwrite00                              ; IF !ZERO, RETRY
monwrite10:
        mov     es:[bx].PktStatus,WRITEFAULT            ; SET DEFAULT ERROR
        cmp     [di].xmiterror,0                        ; IF NO ERROR
        je      monwrite1                               ; THEN CONTINUE
        mov     ax,STDON + STERR                        ; SET DONE AND ERROR BIT
        mov     al,[di].xmiterror                       ; GET XMIT ERROR
        mov     es:[bx].Pktstatus,ax                    ; SAVE RC IN REQ PKT
        mov     [di].xmiterror,0                        ; CLEAR CURRENT ERROR
monwrite1:
        stc
monwrite2:
        RestoreReg <dx,si,ax>                           ; RESTORE REGISTERS
        LeaveProc
        ret
EndProc monwrite

BREAK <ISSUE DEVICE DONE ON THE CURRENT REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  DEVDONE                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Device Done Routine                             */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to issue Device Done */
;/*            to the file system to inform the user the request has   */
;/*            completed.                                              */
;/*                                                                    */
;/* NOTES:  The DEVHLP DevDone function sets the done bit in the       */
;/*         PktStatus field and runs any thread blocked on the address */
;/*         of the kernel request packet (block id) with a priority    */
;/*         boost.  This device driver blocks incoming requests when   */
;/*         the device is currently busy and wants the scheduler to    */
;/*         prioritize the highest priority request to execute next.   */
;/*         Using DevDone and its priority boost defeats this logic,   */
;/*         consequently ProcRun is being used instead of DevDone.     */
;/*                                                                    */
;/* ENTRY POINT: DEVDONE                                               */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:  ES = virtual segment of request block                      */
;/*         BX = virtual offset of request block                       */
;/*         DI = offset to appropriate perprtdata area                 */
;/*                                                                    */
;/* EXIT-NORMAL:  [DI].commonflags = NOT IOACTIVE                      */
;/*                                                                    */
;/* EXIT-ERROR :  See EXIT-NORMAL above.                               */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcRun                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure devdone near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        and     [di].commonflags,NOT IOACTIVE           ; SET I/O ACTIVE OFF
        or      es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
        mov     ax,es                                   ; BLOCK ID
        mov     dl,DevHlp_ProcRun                       ; RUN FUNCTION
        call    DWORD PTR [device_help]                 ; START MONNOTIFY THREAD
        ret
EndProc devdone

BREAK <COMMON NOTIFICATION ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  MONNOTIFY                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME: PRINTER DD. MONITOR NOTIFICATION ROUTINE         */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO PROCESS      */
;/*            THE CONTENTS OF A BUFFER THAT WAS FILLED IN BY THE      */
;/*            MONITOR DISPATCHER.                                     */
;/*                                                                    */
;/* NOTE: DS AND ES ARE BOTH THE DEVICE DRIVER DATA SEGMENT            */
;/*                                                                    */
;/* ENTRY POINT: MONNOTIFY                                             */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF BUFFER THAT IS FILLED IN       */
;/*            SI = VIRTUAL  OFFSET OF BUFFER THAT IS FILLED IN        */
;/*            DS = DATA SELECTOR ADDRESS                              */
;/*            DI = OFFSET INTO PERPRTAREA                             */
;/*                                                                    */
;/* EXIT-NORMAL:  N/A                                                  */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  resume_cpf                                   */
;/*    ROUTINES:          prtbuftoreqpkt                               */
;/*                       sendmonerpkt                                 */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure monnotify far
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        add     di,OFFSET perprtarea                    ; CALC PTR TO DEV AREA

        lea     cx,[di].moncpbufsize                    ; VERIFY CP BUF OFFSET
        cmp     si,cx                                   ; IF ES:SI <> CP BUF
        jne     monn0                                   ; THEN DATA BUFFER
;
; CODE PAGE REQUEST
;
        test    BYTE PTR [di].moncpinflgs +1,MONCPFREQ  ; CODE PAGE REQ?
        jz      monn01                                  ; NO
        call    resume_cpf                              ; YES
monn01:
        jmp     monn6                                   ; EXIT
monn0:
        mov     cx,[di].frommonbuf_off                  ; VERIFY DATA BUF OFF
        cmp     si,cx                                   ; IF ES:SI = DATA BUF
        je      monn1                                   ; THEN CONTINUE
        jmp     SHORT monn6                             ; EXIT ERROR, NOP
;
; DATA REQUEST (OPEN, JOB TITLE, WRITE, CLOSE, OR ERROR PACKET)
;
monn1:
        cmp     BYTE PTR [si].frommonflags,MONOPEN      ; IF !OPEN REQUEST
        jne     monn2                                   ; THEN CONTINUE
        and     [di].commonflags,NOT MONERRPKTSENT      ; ELSE RESET FLAG
        or      [di].commonflags1,MONPROCESSING         ; SET MON PROCESSING
        jmp     SHORT monn6

monn2:
        cmp     BYTE PTR [si].frommonflags,MONCLOSE     ; IF !CLOSE REQUEST
        jne     monn3                                   ; THEN CONTINUE
        and     [di].commonflags1,NOT MONPROCESSING     ; CLEAR MON PROCESSING
        jmp     SHORT monn6
monn3:
        test    BYTE PTR [si].frommonflags +1,MONPJOBTITLE ; JOBTITLE PACKET?
        jnz     monn6                                   ; YES, IGNORE IT
        test    BYTE PTR [si].frommonflags +1,MONCPFERRPKT ; ERROR PACKET?
        jnz     monn6                                   ; YES, IGNORE IT

        cmp     BYTE PTR [si].frommonflags,MONCLEAR     ; IF NOT WRITE PACKET
        jne     monn6                                   ; THEN EXIT
        cmp     [si].monfinalbufsize,FROMMONFIXEDLEN    ; WRITE 0 BYTES?
        jbe     monn6                                   ; YES, EXIT

        test    [di].commonflags1,PORTEXISTS            ; IF PORT EXISTS
        jnz     monn5                                   ; THEN PROCESS THIS REQ

        ; NON EXISTENT DEVICE - IF ERROR PACKET HAS NOT BEEN SENT, SEND ONE
        ; FOR EACH FILE (OPEN TO CLOSE).  EXIT AND IGNORE ALL PACKETS.

        test    [di].commonflags,MONERRPKTSENT          ; ERR PKT ALREADY SENT
        jnz     monn6                                   ; YES
        mov     [di].cancelflags,CANIOERROR             ; ELSE SET ERROR CODE
        CALLFAR sendmonerpkt                            ; SEND MON ERROR PKT
        jmp     monn6                                   ; IGNORE REQ, NO DEV

        ; EXISTENT DEVICE - TRANSMIT DATA
monn5:
        call    prtbuftoreqpkt                          ; CONVERT/PRINT BUFFER
monn6:
        ret
EndProc monnotify

BREAK <PRINTER BUFFER TO PRINT REQUEST ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTBUFTOREQPKT                                   */
;/*                                                                    */
;/* DESCRIPTIVE NAME: PRINTER BUFFER TO REQUEST PACKET ROUTINE         */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO ALLOCATE A KERNEL */
;/*            REQUEST PACKET, INITIALIZE IT AS A WRITE REQUEST AND    */
;/*            POINT IT TO THE MONITOR FINAL BUFFER. THEN CALL THE     */
;/*            PRINTBLOCK ROUTINE TO PROCESS THE PRINT REQUEST.        */
;/*                                                                    */
;/* ENTRY POINT: PRTBUFTOREQPKT                                        */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     DS = DEVICE DRIVER DATA SEGMENT                         */
;/*            SI = Offset to appropriate monitor buffer               */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:  AX = return code (actual transmission error)         */
;/*                                                                    */
;/* EXIT-ERROR :  AX = WRITEFAULT (could not allocate request packet)  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtreqdirect                                 */
;/*    ROUTINES:          printblock                                   */
;/*                       sendsnagas                                   */
;/*                       prtreldirect                                 */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  AllocReqPacket                  */
;/*    ROUTINES:                       FreeReqPacket                   */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtbuftoreqpkt near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx>                                 ; SAVE REGISTERS

        ; ALLOCATE A KERNEL REQUEST PACKET

        mov     dh,WAITFLAG                             ; WAIT TIL PACKET AVAIL
        mov     dl,DevHlp_AllocReqPacket                ; ALLOC. FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jc      prtbuf1                                 ; IF ERROR, RETURN

        ; SAVE ADDRESS OF REQUEST PACKET FOR BLOCK/RUN BLOCK ID

        mov     WORD PTR [di].monoffset,bx              ; SAVE BLOCK ID
        mov     WORD PTR [di].monseg,es                 ; SAVE BLOCK ID

        ; INITIALIZE KERNEL REQUEST PACKET

        mov     es:[bx].PktCmd,CMDOUTPUT                ; OUTPUT COMMAND
        mov     es:[bx].PktStatus,0                     ; INITIAL REQSTATUS
        mov     es:[bx].Pktlen,PktHeadSize + LENIO      ; SIZE OF REQ BLOCK
        mov     cx,[si].frommonsfn                      ; GET SFN FROM MONITOR
        mov     es:[bx].IOSFN,cx                        ; SET SFN FROM MONITOR

        mov     cx,[si].monfinalbufsize                 ; SIZE OF DATA
        sub     cx,FROMMONFIXEDLEN                      ; SUB CNT,FLAGS,SFN SIZE
        mov     es:[bx].IOcount,cx                      ; SIZE OF DATA TO PRINT

        mov     cx,[di].physbufoff                      ; GET PHYS ADDR - LOW
        mov     ax,[di].physbufseg                      ; GET PHYS ADDR - HIGH
        mov     WORD PTR es:[bx].IOpData,cx             ; SAVE PHYS ADDR - LOW
        mov     WORD PTR es:[bx].IOpData+2,ax           ; SAVE PHYS ADDR - HIGH

        ; INITIALIZE MONPRINTING FLAG TO VALIDATE BLOCK ID AND CALL PRINTBLOCK

        or      [di].commonflags,MONPRINTING            ; SET MON PRINTING ON
        SaveReg <es,bx,di>                              ; SAVE REGISTERS
        call    prtreqdirect                            ; REQUEST PORT ACCESS
        jc      prtbuf0                                 ; IF ERROR, EXIT
        call    printblock                              ; PRINTBLOCK OF CHAR
        call    sendsnagas                              ; LOG GEN ALERT VECTOR
        call    prtreldirect                            ; RELEASE PORT ACCESS
prtbuf0:
        RestoreReg <di,bx,es>                           ; RESTORE REGISTERS
        and     [di].commonflags,NOT MONPRINTING        ; TURN OFF MONPRINTING
        mov     ax,es:[bx].PktStatus                    ; RETURN THE RETURN CODE

        ; RELEASE KERNEL REQUEST PACKET

        mov     dl,DevHlp_FreeReqPacket                 ; FREE REQUEST PACKET
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
        jmp     SHORT prtbuf2                           ; EXIT
prtbuf1:
        mov     ax,WRITEFAULT                           ; RETURN THE RETURN CODE
prtbuf2:
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        ret
EndProc prtbuftoreqpkt

BREAK <SEND SNA GENERIC ALERT SUBVECTOR>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  SENDSNAGAS                                       */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Send SNA Generic Alert Subvector.               */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to send a SNA Generic*/
;/*            Alert Subvector when an error is detected on the device.*/
;/*                                                                    */
;/* ENTRY POINT:  SENDSNAGAS                                           */
;/*    LINKAGE:  CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:  ES = Virtual segment of request packet                     */
;/*         BX = Virtual offset of request packet                      */
;/*         DI = Offset to appropriate printer data area               */
;/*                                                                    */
;/* EXIT-NORMAL:  NONE                                                 */
;/*                                                                    */
;/* EXIT-ERROR:  NONE                                                  */
;/*                                                                    */
;/* EFFECTS:                                                           */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP - LogEntry                       */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure sendsnagas near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    es:[bx].PktStatus,STERR                 ; IF ERROR BIT OFF
        jz      sendsnagas5                             ; THEN EXIT
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,DWORD PTR glinfoseg                  ; GLOBAL INFO SEG PTR
        test    es:[bx].SIS_SysLog,LF_LOGENABLE         ; IF LOGGING DISABLED
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        jz      sendsnagas5                             ; THEN EXIT
sendsnagas1:
        cmp     es:[bx].PktStatus,NOACCESS              ; IF NOT SELECT ERROR
        jne     sendsnagas2                             ; THEN CHECK FOR OTHERS

        mov     PrtGAS.gas_desc,GAS_ADC_PRINTER         ; SET ERROR DESCRIPT
;       mov     PrtGAS.gas_alertid,0                    ; SET ALERT ID
        mov     PrtUCS.gas_ucs_causecd,GAS_UCC_PRTPOWEROFF  ; CAUSE CODE
        mov     PrtUCS.gas_ucs_recact,GAS_RAC_READY_DEVICE  ; REC ACTION
        jmp     SHORT sendsnagas4

sendsnagas2:
        cmp     es:[bx].PktStatus,PAPEROUTERR           ; IF NOT PAPER OUT ERROR
        jne     sendsnagas3                             ; THEN CHECK WRITEFAULT

        mov     PrtGAS.gas_desc,GAS_ADC_PRTOUTOFPAPER   ; SET ERROR DESCR
;       mov     PrtGAS.gas_alertid,0                    ; SET ALERT ID
        mov     PrtUCS.gas_ucs_causecd,GAS_UCC_OUTOFPAPER  ; CAUSE CODE
        mov     PrtUCS.gas_ucs_recact,GAS_RAC_ADD_PAPER    ; REC ACTION
        jmp     SHORT sendsnagas4

sendsnagas3:

        mov     PrtGAS.gas_desc,GAS_ADC_PRTNOTREADY     ; SET ERROR DESCRIP
;       mov     PrtGAS.gas_alertid,0                    ; SET ALERT ID
        mov     PrtUCS.gas_ucs_causecd,GAS_UCC_PRTNOTREADY  ; CAUSE CODE
        mov     PrtUCS.gas_ucs_recact,GAS_RAC_READY_DEVICE  ; REC ACTION

sendsnagas4:
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        push    ds
        pop     es
        mov     bx,OFFSET snalert                       ; ES:BX -> GAS
        mov     cx,LOGERROR32                           ; FUNCTION IDENTIFIER
        mov     dl,DevHlp_LogEntry                      ; LOG SNA GEN ALERT
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
sendsnagas5:
        ret
EndProc sendsnagas

BREAK <CODE PAGE/FONT RESUME>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  RESUME_CPF                                       */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Resume Code Page/Font Request.                   */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine will be to unblock      */
;/*            the thread of execution that is waiting for the         */
;/*            Code Page/Font Switcher results.                        */
;/*                                                                    */
;/* ENTRY POINT: RESUME_CPF                                            */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     DI = Offset to appropriate printer data area            */
;/*            CPFINPROGRESS FLAG ON = DO PROCRUN                      */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcRun                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure resume_cpf near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [di].commonflags,CPFINPROGRESS          ; CPF IN PROGRESS?
        jz      resume1                                 ; NO - NO PROCRUN
        and     [di].commonflags,NOT CPFINPROGRESS      ; CLEAR THE INPROG FLAG
        mov     bx,[di].dosoffset                       ; OFF. OF THIS REQ BLK
        inc     bx                                      ; MAKE BLOCK ID UNIQUE
        mov     ax,[di].dosrqseg                        ; SEG. OF THIS REQ BLK
        mov     dl,DevHlp_ProcRun                       ; RESUME CODE PAGE REQ
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO RUN
resume1:
        mov     [di].moncpinflgs,0                      ; CLEAR FOR NEXT REQ
        ret
EndProc resume_cpf

SWAPSEG ENDS

CSEG    SEGMENT PUBLIC  'code'
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        EXTRN   prtint07:NEAR
        EXTRN   prtpdd_entry:FAR

BREAK <PRTLPT1 STRATEGY ENTRY POINT>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTLPT1                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  LPT1 AND PRN ENTRY ROUTINE.                     */
;/*                                                                    */
;/* FUNCTION:  IDENTIFY PRINTER DEVICE 0 AND CALL THE PRTREQST TO DO   */
;/*            INITIAL SETUP AND PROCESS THE REQUEST.                  */
;/*                                                                    */
;/* ENTRY POINT: PRTLPT1                                               */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:     ES = TILED SELECTOR OF KERNEL REQUEST PACKET            */
;/*            BX = TILED OFFSET OF KERNEL REQUEST PACKET              */
;/*                                                                    */
;/* REGISTERS USED:  ALL REGISTERS SAVED BY THE KERNEL                 */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:BX = TILED POINTER TO KERNEL REQUEST PACKET       */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtreqst                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtlpt1 far
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     di,(LPT1_INDEX * SIZE printer_database) ; DEVICE INDEX FOR LPT1
        call    prtreqst                                ; DISPATCH ROUTINE
        ret
EndProc prtlpt1

BREAK <PRTLPT2 STRATEGY ENTRY POINT>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTLPT2                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  LPT2 ENTRY ROUTINE.                             */
;/*                                                                    */
;/* FUNCTION:  IDENTIFY PRINTER DEVICE 1 AND CALL THE PRTREQST TO DO   */
;/*            INITIAL SETUP AND PROCESS THE REQUEST.                  */
;/*                                                                    */
;/* ENTRY POINT: PRTLPT2                                               */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:     ES = TILED SELECTOR OF KERNEL REQUEST PACKET            */
;/*            BX = TILED OFFSET OF KERNEL REQUEST PACKET              */
;/*                                                                    */
;/* REGISTERS USED:  ALL REGISTERS SAVED BY THE KERNEL                 */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:BX = TILED POINTER TO KERNEL REQUEST PACKET       */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtreqst                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtlpt2 far
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     di,(LPT2_INDEX * SIZE printer_database) ; DEVICE INDEX FOR LPT2
        call    prtreqst                                ; DISPATCH ROUTINE
        ret
EndProc prtlpt2

BREAK <PRTLPT3 STRATEGY ENTRY POINT>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTLPT3                                          */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  LPT3 ENTRY ROUTINE.                             */
;/*                                                                    */
;/* FUNCTION:  IDENTIFY PRINTER DEVICE 2 AND CALL THE PRTREQST TO DO   */
;/*            INITIAL SETUP AND PROCESS THE REQUEST.                  */
;/*                                                                    */
;/* ENTRY POINT: PRTLPT3                                               */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:     ES = TILED SELECTOR OF KERNEL REQUEST PACKET            */
;/*            BX = TILED OFFSET OF KERNEL REQUEST PACKET              */
;/*                                                                    */
;/* REGISTERS USED: ALL REGISTERS SAVED BY THE KERNEL                  */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:BX = TILED POINTER TO KERNEL REQUEST PACKET       */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtreqst                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtlpt3 far
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     di,(LPT3_INDEX * SIZE printer_database) ; DEVICE INDEX FOR LPT3
        call    prtreqst                                ; DISPATCH ROUTINE
        ret
EndProc prtlpt3

BREAK <MONITOR DISPATCHER NOTIFICATION ROUTINE FOR LPT1>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  MONNOTIFY_1                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: MONITOR NOTIFICATION ROUTINE FOR LPT1            */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO PROCESS      */
;/*            THE CONTENTS OF A BUFFER THAT WAS FILLED IN BY THE      */
;/*            MONITOR DISPATCHER FOR LPT1.                            */
;/*                                                                    */
;/* NOTE:      THIS ROUTINE IS CALLED BY THE MONITOR DISPATCHER IN     */
;/*            PROTECT MODE ONLY.                                      */
;/*                                                                    */
;/* ENTRY POINT: MONNOTIFY_1                                           */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:     ES = SELECTOR OF BUFFER                                 */
;/*            SI = OFFSET OF BUFFER                                   */
;/*            DS = DATA SELECTOR ADDRESS                              */
;/*                                                                    */
;/* EXIT-NORMAL:  SAME AS INPUT                                        */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  monnotify                                    */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure monnotify_1 far                               ; NOTIFY FOR LPT1
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pusha                                           ; SAVE REGISTERS
        push    es                                      ; SAVE ES
        mov     di,(LPT1_INDEX * SIZE printer_database) ; DEVICE INDEX FOR LPT1
        call    monnotify                               ; GEN. NOTIF ROUTINE
        pop     es                                      ; RESTORE ES
        popa                                            ; RESTORE REGISTERS
        ret
EndProc monnotify_1

BREAK <MONITOR DISPATCHER NOTIFICATION ROUTINE FOR LPT2>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  MONNOTIFY_2                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: MONITOR NOTIFICATION ROUTINE FOR LPT2            */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO PROCESS      */
;/*            THE CONTENTS OF A BUFFER THAT WAS FILLED IN BY THE      */
;/*            MONITOR DISPATCHER FOR LPT2.                            */
;/*                                                                    */
;/* NOTE:      THIS ROUTINE IS CALLED BY THE MONITOR DISPATCHER IN     */
;/*            PROTECT MODE ONLY.                                      */
;/*                                                                    */
;/* ENTRY POINT: MONNOTIFY_2                                           */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:     ES = SELECTOR OF BUFFER                                 */
;/*            SI = OFFSET OF BUFFER                                   */
;/*            DS = DATA SELECTOR ADDRESS                              */
;/*                                                                    */
;/* EXIT-NORMAL:  SAME AS INPUT                                        */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  monnotify                                    */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure monnotify_2 far                               ; NOTIFY FOR LPT2
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pusha                                           ; SAVE REGISTERS
        push    es                                      ; SAVE ES
        mov     di,(LPT2_INDEX * SIZE printer_database) ; DEVICE INDEX FOR LPT2
        call    monnotify                               ; GEN. NOTIF. ROUTINE
        pop     es                                      ; RESTORE ES
        popa                                            ; RESTORE REGISTERS
        ret
EndProc monnotify_2

BREAK <MONITOR DISPATCHER NOTIFICATION ROUTINE FOR LPT3>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  MONNOTIFY_3                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: MONITOR NOTIFICATION ROUTINE FOR LPT3            */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO PROCESS      */
;/*            THE CONTENTS OF A BUFFER THAT WAS FILLED IN BY THE      */
;/*            MONITOR DISPATCHER FOR LPT3.                            */
;/*                                                                    */
;/* NOTE:      THIS ROUTINE IS CALLED BY THE MONITOR DISPATCHER IN     */
;/*            PROTECT MODE ONLY.                                      */
;/*                                                                    */
;/* ENTRY POINT: MONNOTIFY_3                                           */
;/*    LINKAGE : CALL FAR                                              */
;/*                                                                    */
;/* INPUT:     ES = SELECTOR OF BUFFER                                 */
;/*            SI = OFFSET OF BUFFER                                   */
;/*            DS = DATA SELECTOR ADDRESS                              */
;/*                                                                    */
;/* EXIT-NORMAL:  SAME AS INPUT                                        */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  monnotify                                    */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure monnotify_3 far                               ; NOTIFY FOR LPT3
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pusha                                           ; SAVE REGISTERS
        push    es                                      ; SAVE ES
        mov     di,(LPT3_INDEX * SIZE printer_database) ; DEVICE INDEX FOR LPT3
        call    monnotify                               ; GEN. NOTIF. ROUTINE
        pop     es                                      ; RESTORE ES
        popa                                            ; RESTORE REGISTERS
        ret
EndProc monnotify_3

BREAK <SEND MONITOR ERROR PACKET>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  SENDMONERPKT                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Send Monitor Error Packet.                      */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to send an error     */
;/*            packet to the monitor (spooler).                        */
;/*                                                                    */
;/* NOTE: This routine can only be called once the monitor dispatcher  */
;/*       has called the printer device driver at its notify entry pt. */
;/*                                                                    */
;/* ENTRY POINT:  SENDMONERPKT                                         */
;/*    LINKAGE :  CALL NEAR OR FAR                                     */
;/*                                                                    */
;/* INPUT:  ES = Virtual segment of request block                      */
;/*         BX = Virtual offset of request block                       */
;/*         DI = Offset to appropriate printer data area               */
;/*         [di].commonflags = MONREG1                                 */
;/*         [di].cancelflags = error code to be sent                   */
;/*                                                                    */
;/* EXIT-NORMAL:   [di].commonflags = MONERRPKTSENT                    */
;/*                                                                    */
;/* EXIT-ERROR :   [di].commonflags = NOT MONERRPKTSENT                */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  MonWrite                        */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure sendmonerpkt,HYBRID
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     [di].errorflags,MONCLEAR                ; CLEAR FLAGS
        mov     BYTE PTR [di].errorflags +1,MONCPFERRPKT ; SET MON FLAGS
        mov     si,[di].frommonbuf_off                  ; GET MON BUF OFFSET
        mov     ax,[si].frommonsfn                      ; GET SFN FROM PACKET
        mov     [di].errorsfn,ax                        ; SET MONITOR SFN
        xor     ah,ah
        mov     al,[di].cancelflags                     ; GET INDEX TO RETCODE
        mov     si,ax
        sal     si,1                                    ; BYTE TO WORD OFFSETS
        mov     ax,doserrors[si]                        ; GET RETCODE
        mov     [di].errorstatus,al                     ; SET RETCODE
        mov     [di].xmiterror,al                       ; SAVE AS STRATEGY RC

        mov     ax,[di].monhandle                       ; GET HANDLE
        mov     cx,MONERRPKTLEN                         ; GET LENGTH
        lea     si,[di].errorflags                      ; GET PKT ADDRESS
        mov     dh,MONNOWAIT                            ; CAN'T WAIT IF FULL
        mov     dl,DevHlp_MonWrite                      ; MONITOR WRITE FUNC
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jc      sendmonerpkt1                           ; IF ERROR, EXIT
        or      [di].commonflags,MONERRPKTSENT          ; SET FLAG TO PKT SENT
sendmonerpkt1:
        ret
EndProc sendmonerpkt

CSEG    ENDS
        END
