;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/

; SCCSID = @(#)prtioctl.asm     6.14 91/10/04
;/**********************************************************************
;/*                                                                    *
;/*                                                                    *
;/*                                                                    *
;/**********************************************************************
 TITLE PRINTDD - PRINTER DEVICE DRIVER TASK TIME IOCTL 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:
;       PRTIOCTL
;       PRTQRYMON
;       PRTCHECKFC
;       PRTIOCTL_IR
;       PRTIOCTL_ST
;       PRTCHECK_CPF
;       PRTCHECK_PJT
;       PRTCHECK_TO
;       PRTCHECK_DM
;       PRTSTIOC
;       PRTMONREG
;       CHAINMONITOR
;       REGISTERMONITOR
;       PRTIOCTL_FC
;       PRTIOCTL_IN
;       PRTIOCTL_CPF
;       BLOCK_CPF
;       PRTIOCTL_PJT
;       PRTIOCTL_TO
;       PRTIOCTL_DM
;       VERLOCKDATA
;       UNLOCKDATA
;       FLUSHCPQUEUE
;***********************************************************************

        .XCREF
        .XLIST
        INCLUDE basemaca.inc
        INCLUDE osmaca.inc
        INCLUDE devsym.inc
        INCLUDE devhlp.inc              ; DEFINITION OF DEVICE HELP CALLS.
        INCLUDE infoseg.inc             ; STRUCTURES DEFINING THE INFOSEG.
        INCLUDE struc.inc               ; STRUCTURED MACRO SUPPORT.
        INCLUDE ioctl.inc               ; IOCTL EQUATES
        .LIST
        .CREF
        INCLUDE prtdd.inc               ; PRINTER DEVICE DRIVER INCLUDE FILE

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'
        EXTRN   dosvar:DWORD
        EXTRN   device_help:DWORD
        EXTRN   monnotify_tbl:WORD

                EVEN
        iopc_disp       LABEL   WORD
                dw      OFFSET  prtqrymon       ; 40/60 REG/QRY A MONITOR
                dw      OFFSET  prterror        ; 41 - ILLEGAL COMMAND
                dw      OFFSET  prtcheckfc      ; 42/62 SET/RET FRAME CONTROL
                dw      OFFSET  prterror        ; 43/63 SET/RET REDIRECT
                dw      OFFSET  prtioctl_ir     ; 44/64 SET/RET INFIN. RETRY
                dw      OFFSET  prterror        ; 45 - ILLEGAL COMMAND
                dw      OFFSET  prtioctl_st     ; 46/66 INIT PRT/RET STATUS
                dw      OFFSET  prterror        ; 47/67 - RESERVED IBM JAPAN
                dw      OFFSET  prtcheck_cpf    ; 48 - CODE PAGE/FONT-ACTIVATE
                dw      OFFSET  prtcheck_cpf    ; 69 - CODE PAGE/FONT-QUERY
                dw      OFFSET  prtcheck_cpf    ; 6A - CODE PAGE/FONT-VERIFY
                dw      OFFSET  prterror        ; 4B/6B - RESERVED 16 BIT ONLY
                dw      OFFSET  prterror        ; 4C/6C - UNUSED COMMAND
                dw      OFFSET  prtcheck_pjt    ; 4D - SET PRINT JOB TITLE
                dw      OFFSET  prtcheck_to     ; 4E/6E - SET/RET TIMEOUT
                dw      OFFSET  prterror        ; 4F/6F - RESERVED IBM JAPAN
                dw      OFFSET  prterror        ; 50/70 - UNUSED COMMAND
                dw      OFFSET  prtcheck_dm     ; 51/71 - SET/QRY DIRECT-MODE

        iopc_dispatch   LABEL   WORD
                dw      OFFSET  prtmonreg       ; 40/60 REG A MONITOR
                dw      OFFSET  prterror        ; 41 - ILLEGAL COMMAND
                dw      OFFSET  prtioctl_fc     ; 42/62 SET/RET FRAME CONTROL
                dw      OFFSET  prterror        ; 43/63 SET/RET REDIRECT
                dw      OFFSET  prterror        ; 44/64 SET/RET INFIN. RETRY
                dw      OFFSET  prterror        ; 45 - ILLEGAL COMMAND
                dw      OFFSET  prtioctl_in     ; 46/66 INIT PRT/RET STATUS
                dw      OFFSET  prterror        ; 47/67 - RESERVED IBM JAPAN
                dw      OFFSET  prtioctl_cpf    ; 48 - CODE PAGE/FONT-ACTIVATE
                dw      OFFSET  prtioctl_cpf    ; 69 - CODE PAGE/FONT-QUERY
                dw      OFFSET  prtioctl_cpf    ; 6A - CODE PAGE/FONT-VERIFY
                dw      OFFSET  prterror        ; 4B/6B - RESERVED 16 BIT ONLY
                dw      OFFSET  prterror        ; 4C/6C - UNUSED COMMAND
                dw      OFFSET  prtioctl_pjt    ; 4D - SET PRINT JOB TITLE
                dw      OFFSET  prtioctl_to     ; 4E/6E - SET/RET TIMEOUT
                dw      OFFSET  prterror        ; 4F/6F - RESERVED IBM JAPAN
                dw      OFFSET  prterror        ; 50/70 - UNUSED COMMAND
                dw      OFFSET  prtioctl_dm     ; 51/71 - SET/QRY DIRECT-MODE

;/**********************************************************************/
;/*                                                                    */
;/*        PRINTER DEVICE DRIVER INITIALIZE STRING DESCRIPTION         */
;/*                                                                    */
;/*  12H = 18  = DC2  ÄÄ Set 10 chars per inch print                   */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  32H = 50  = 2    ÄÙ Start text line spacing                       */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  39H = 57  = 9    ÄÙ Cancel ignore paper end (Graphics printer)    */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  43H = 67  = C     ³ Set form length in lines and top of form      */
;/*  42H = 66  = 66   ÄÙ                                               */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  46H = 70  = F    ÄÙ Cancel emphasized printing                    */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  48H = 72  = H    ÄÙ Cancel double strike printing                 */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  54H = 84  = T    ÄÙ Cancel subscript/superscript                  */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  57H = 87  = W     ³ Cancel double wide printing                   */
;/*  00  = 00  = 00   ÄÙ                                               */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  49H = 73  = I     ³ Change print quality to data processing qual  */
;/*  01  = 01  = 01   ÄÙ                            (Color Printer)    */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  55H = 85  = U     ³ Return to two direction printing              */
;/*  00  = 00  = null ÄÙ                                               */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  6EH = 110 = n     ³ Set aspect ratio (Color printer)              */
;/*  00  = 00  = null ÄÙ                                               */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  2DH = 45  = -     ³ Cancel continuous overscore                   */
;/*  00  = 00  = null ÄÙ                                               */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  5FH = 95  = _     ³ Cancel continuous underscore                  */
;/*  00  = 00  = null ÄÙ                                               */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  37H = 55  = 7    ÄÙ Select character set 1                        */
;/*  1BH = 27  = ESC  Ä¿                                               */
;/*  43H = 67  = C     ³                                               */
;/*  00  = 00  = 00    ³ Set form length in inches                     */
;/*  0BH = 11  = 11   ÄÙ                                               */
;/*                                                                    */
;/**********************************************************************/

        initstring      db 12H,1BH,32H,1BH,39H,1BH,43H,42H,1BH,46H,1BH,48H
                        db 1BH,54H,1BH,57H,00,1BH,49H,01,1BH,55H,00,1BH,6EH
                        db 00,1BH,2DH,00,1BH,5FH,00,1BH,37H,1BH,43H,00,0BH
        initstringlen   dw      $-initstring

        ioctlcombs      db IOMO_RE,IOC_MO               ;   40,10 FUNC,CAT
                        db IOLW_FC,IOC_PC               ;   42,05
                        db IOLW_IR,IOC_PC               ;   44,05
                        db IOLW_IP,IOC_PC               ;   46,05
                        db IOLW_AF,IOC_PC               ;   48,05
                        db IOLW_ST,IOC_PC               ;   4D,05
                        db IOLW_TO,IOC_PC               ;   4E,05
                        db IOLW_DM,IOC_PC               ;   51,05
                        db IOBC_MS,IOC_BC               ;   60,11
                        db IOLR_FC,IOC_PC               ;   62,05
                        db IOLR_IR,IOC_PC               ;   64,05
                        db IOLR_GS,IOC_PC               ;   66,05
                        db IOLR_QF,IOC_PC               ;   69,05
                        db IOLR_VF,IOC_PC               ;   6A,05
                        db IOLR_TO,IOC_PC               ;   6E,05
                        db IOLR_DM,IOC_PC               ;   71,05
        IOCTLMAX        EQU ($-ioctlcombs)/2            ;MAX # OF IOCTL COMBS.

        frmctrlcomb     db LINES6_INCH,CHARS80_LINE     ; FRAME CTRL COMBINATION
                        db LINES8_INCH,CHARS80_LINE     ; FRAME CTRL COMBINATION
                        db LINES6_INCH,CHARS132_LINE    ; FRAME CTRL COMBINATION
                        db LINES8_INCH,CHARS132_LINE    ; FRAME CTRL COMBINATION
        FRAMECTRLMAX    EQU ($-frmctrlcomb)/2           ;MAX # OF FRM CTRL COMBS


        framectrldata   db ENDCOMPRESSED,ONESIXTH,ENDCOMPRESSED,ONEEIGHTH
                        db COMPRESSED,ONESIXTH,COMPRESSED,ONEEIGHTH

DSEG    ENDS

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

        EXTRNFAR getstatus

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

        EXTRN   prtblock:NEAR
        EXTRN   prtbuftoreqpkt:NEAR
        EXTRN   prterror:NEAR
        EXTRN   getpid:NEAR
        EXTRN   flushcache:NEAR
        EXTRN   monwrite:NEAR
        EXTRN   devdone:NEAR
        EXTRN   prtreqdirect:NEAR
        EXTRN   prtreldirect:NEAR
        EXTRN   initialprt:NEAR

BREAK <GENERIC IOCTL ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINT DEVICE DRIVER IOCTL ROUTINE.              */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO VALIDATE THE */
;/*            REQUEST AND CALL PRTBLOCK TO BLOCK THE THREAD UNTIL THE */
;/*            REQUEST IS COMPLETE.                                    */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR:    ES:[BX].PktStatus = INVALIDCMMD                     */
;/*                                                                    */
;/* INTERNAL REFERENCES:  see iopc_disp table                          */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        ; VALIDATE CATEGORY AND FUNCTION CODE COMBINATIONS

        SaveReg <es,di>                                 ; SAVE REGISTERS
        cld
        mov     ah,es:[bx].GIOCategory                  ; GET FUNCTION CODE
        mov     al,es:[bx].GIOFunction                  ; GET FUNCTION CODE
        mov     cx,IOCTLMAX                             ; # OF FUNCS SUPPORTED
        push    ds                                      ; GET DSEG ADDRESS
        pop     es                                      ; SET DSEG ADDRESS
        mov     di,OFFSET ioctlcombs                    ; OFFSET IOCTL FUNCS
        repne   scasw                                   ; SEARCH FOR VALID FUNC
        RestoreReg <di,es>                              ; RESTORE REGISTERS
        je      prtioctl0                               ; IF NO ERROR, DISPATCH

        ; SET THE ERROR CODE IN THE STATUS WORD OF THE REQUEST BLOCK.

        mov     es:[bx].PktStatus,INVALIDCOMMD          ; ELSE SET ERROR STATUS
        jmp     prtioctl1                               ; RETURN TO CALLER

prtioctl0:
        and     ax,NOT IOCTLMASK                        ; PRODUCE INDEX
        mov     si,ax                                   ; BYTE INDEX
        sal     si,1                                    ; MAKE WORD INDEX
        call    WORD PTR iopc_disp[si]                  ; CALL ROUTINE
prtioctl1:
        ret
EndProc prtioctl

BREAK <QUERY MONITOR SUPPORT>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTQRYMON                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINTER DD QUERY MONITOR SUPPORT ROUTINE.       */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO RETURN THAT THE   */
;/*            PRINTER DEVICE DRIVER SUPPORTS MONITORS.                */
;/*                                                                    */
;/* NOTE:                                                              */
;/*                                                                    */
;/* ENTRY POINT: PRTQRYMON                                             */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:   ES:[BX].PktStatus = REQDONE                         */
;/*                                                                    */
;/* EXIT-ERROR :   ES:[BX].PktStatus = REQDONE                         */
;/*                                                                    */
;/* INTERNAL REFERENCES:  verlockdata                                  */
;/*  ROUTINES:            prtblock                                     */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtqrymon near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        cmp     es:[bx].GIOFunction,IOMO_RE             ; IF REGISTER A MONITOR
        je      prtmonq1                                ; THEN REGISTER

        ; QUERY MONITOR SUPPORT

        mov     es:[bx].PktStatus,REQDONE               ; MONITORS SUPPORTED
        jmp     prtmonq2                                ; EXIT TO CALLER

        ; REGISTER A MONITOR

prtmonq1:
        mov     cx,MONREGDBLEN                          ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtmonq2                                ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE
        call    prtblock                                ; SERIALIZE REGISTER
        RestoreReg <cx,ax>                              ; RESTORE LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtmonq2:
        ret
EndProc prtqrymon

BREAK <VALIDATE FRAME CONTROL PARAMETERS>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCHECKFC                                       */
;/*                                                                    */
;/* DESCRIPTIVE NAME: IOCTL CHECK OR RETURN PRINTER FRAME CONTROL.     */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO VALIDATE     */
;/*            THE PRINTER FRAME CONTROL. IF INVALID THE REQUEST WILL  */
;/*            BE TERMINATED.  IF VALID THE CALL WILL BE SERIALIZED    */
;/*            TO THE DEVICE BY THE PRTBLOCK ROUTINE.                  */
;/*                                                                    */
;/* ENTRY POINT: PRTCHECKFC                                            */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:  PERPRTDATA FILLED IN                                 */
;/*               FRAMECTRL.CHARSPERLINE = NEW VALUE                   */
;/*               FRAMECTRL.LINESPERINCH = NEW VALUE                   */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = INVALIDCOMMD                     */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINES:          verlockdata                                  */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtcheckfc near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     cx,FRAMECTRLDBLEN                       ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtcheckfc3                             ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE

        cmp     es:[bx].GIOFunction,IOLR_FC             ; FUNC = RET FRMCTRL
        je      prtcheckfc1                             ; THEN RET FRAME CTRL
                                                        ; ELSE MUST BE SET
        SaveReg <es,bx,di>                              ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; GET USER'S DATA ADDR
        mov     ah,es:[bx].charsperline                 ; GET CHARSPERLINE
        mov     al,es:[bx].linesperinch                 ; GET LINESPERINCH
        cld                                             ; SET FORWARD DIRECTION
        mov     cx,FRAMECTRLMAX                         ; # OF FRAME CTRL COMB.
        push    ds                                      ; DATA SEGMENT ADDRESS
        pop     es                                      ; DATA SEGMENT ADDRESS
        mov     di,OFFSET frmctrlcomb                   ; OFF OF FRM. CTRL COMB.
        repnz   scasw                                   ; CHECK IF PARMS VALID
        mov     si,di                                   ; OFFSET OF COMB TO DI
        RestoreReg <di,bx,es>                           ; RESTORE REGISTERS
        jz      prtcheckfc1                             ; JUMP IF PARMS VALID
        mov     es:[bx].PktStatus,INVALIDPARM           ; RETURN ERROR IN REQBLK
        jmp     SHORT prtcheckfc2                       ; RETURN TO CALLER
prtcheckfc1:
        call    prtblock                                ; SERIALIZE VALID REQ
prtcheckfc2:
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtcheckfc3:
        ret
EndProc prtcheckfc

BREAK <VALIDATE AND SET/RETURN INFINITE RETRY>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_IR                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: GENERIC IOCTL SET/RETURN INFINITE RETRY STATUS   */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE WILL BE TO SET AND      */
;/*            RETURN THE PRINTER INFINITE RETRY STATUS. A USER MAY    */
;/*            REQUEST THAT INFINITE RETRIES MAY BE MADE TO SEND DATA  */
;/*            TO THE PRT. IF IS BUSY OR IN ERROR BY USING THE MODE    */
;/*            COMMAND. THE MODE COMMAND WILL THEN ISSUE AN IOCTL      */
;/*            CALL TO THIS DEVICE DRIVER TO SET THE PRINTER INFINITE  */
;/*            RETRY STATUS.                                           */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_IR                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*               RETRYREQ.RETRY = ENABLE / DISABLE INFINITE RETRY     */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = INVALIDCOMMD                     */
;/*                                                                    */
;/* INTERNAL REFERENCES:  verlockdata                                  */
;/*  ROUTINES:            unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_ir near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     cx,INFRETRYDBLEN                        ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtinfin5                               ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE

        SaveReg <es,bx>                                 ; SAVE REGISTERS
        mov     ah,es:[bx].GIOFunction                  ; GET FUNCTION CODE
        les     bx,es:[bx].GIODataPack                  ; VIRT ADDR DATA AREA

        cmp     ah,IOLW_IR                              ; IF FUNC = SETINFRETRY
        je      prtinfin1                               ; THEN SET INF RETRY

        ; RET INFINITE RETRY

        mov     es:[bx].retry,DISABLEIR                 ; SET INFRETRY DISABLED
        test    [di].commonflags,INFINRETRY             ; IF INFINITE RETRY !SET
        jz      prtinfin3                               ; THEN ASSUMED CORRECTLY
        mov     es:[bx].retry,ENABLEIR                  ; ELSE RET INF ENALBLED
        jmp     SHORT prtinfin3                         ; EXIT

prtinfin1:
        ; SET INFINITE RETRY - VALIDATE INFINITE RETRY REQUEST

        cmp     es:[bx].retry,ENABLEIR                  ; IF NEED TO DISABLE
        jbe     prtinfin2                               ; THEN DISABLE INFIN
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        mov     es:[bx].PktStatus,INVALIDCOMMD          ; SET ERROR CODE
        jmp     SHORT prtinfin4                         ; RETURN TO CALLER

prtinfin2:
        test    [di].commonflags,MONREG1                ; IF MONITOR REG
        jnz     prtinfin3                               ; DO NOT ALLOW CHANGE
        and     [di].commonflags,NOT INFINRETRY         ; TURN OFF INFRETRY BIT
        cmp     es:[bx].retry,DISABLEIR                 ; IF DISABLE REQUEST
        je      prtinfin3                               ; DONE, EXIT
        or      [di].commonflags,INFINRETRY             ; TURN ON INFINRETRY BIT
prtinfin3:
        pop     bx                                      ; RESTORE REGISTERS
        pop     es                                      ; RESTORE REGISTERS
        mov     es:[bx].PktStatus,REQDONE               ; SET DONE BIT
prtinfin4:
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtinfin5:
        ret
EndProc prtioctl_ir

BREAK <GENERIC IOCTL RETURN STATUS OF DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_ST                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: PRINT IOCTL STATUS ROUTINE.                      */
;/*                                                                    */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO RETURN THE STATUS  */
;/*           OF THE REQUESTED DEVICE. IT WILL CALL GETSTATUS TO GET   */
;/*           THE STATUS OF THE DEVICE.  IF THE REQUEST IS AN INITIAL  */
;/*           IZE REQUEST, THE REQUEST WILL BE SERIALIZED BY CALLING   */
;/*           PRTBLOCK.                                                */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_ST                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*               STATUS.PRNSTATUS  = DEVICE STATUS                    */
;/*                                                                    */
;/* EXIT-ERROR :  N/A                                                  */
;/*                                                                    */
;/* INTERNAL REFERENCES:  verlockdata                                  */
;/*    ROUTINES:          prtblock                                     */
;/*                       prtreqdirect                                 */
;/*                       getstatus                                    */
;/*                       prtreldirect                                 */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_st near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
     .IF <es:[bx].GIOFunction EQ IOLW_IP>               ; IF FUNC = INIT PRINTER
        call    prtblock                                ; SERIALIZE ACCESS
     .ELSE
        mov     cx,STATUSREQDBLEN                       ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prt_in20                                ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE

        test    [di].commonflags,MONREG1                ; MONITOR REGISTERED?
        jz      prt_in05                                ; JUMP IF NOT
        mov     ah,NORMALSTAT                           ; FORCE NORMAL
        jmp     SHORT prt_in10                          ; RETURN STATUS

prt_in05:
        test    [di].commonflags,IOACTIVE               ; IO CURRENTLY !ACTIVE
        jz      prt_in07                                ; THEN CALL GETSTATUS
        mov     ah,NORMALSTAT                           ; ELSE GET STATUS
        and     ah,NOT NOTBUSY                          ; TURN BUSY BIT ON
        jmp     SHORT prt_in10                          ; RETURN IT
prt_in07:
        call    prtreqdirect                            ; REQUEST PORT ACCESS
        jc      prt_in15                                ; IF UNUSUAL WAKEUP
        CALLFAR getstatus                               ; GET DEVICE STATUS
        call    prtreldirect                            ; RELEASE PORT ACCESS
prt_in10:
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; VIRT. ADDR. DATA AREA
        mov     es:[bx].prntstatus,ah                   ; RETURN DEVICE STATUS
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        mov     es:[bx].PktStatus,REQDONE               ; SET THE DONE BIT
prt_in15:
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prt_in20:
     .ENDIF
        ret
EndProc prtioctl_st

BREAK <CHECK CODE PAGE/FONT REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCHECK_CPF                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Check Code Page/Font Request.                    */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine will be to check        */
;/*            the Code Page/Font request. It is possible to get       */
;/*            a Code Page/Font request without a spooler or other     */
;/*            monitor being registered. If this happens it will be    */
;/*            caught here and an error returned.                      */
;/*                                                                    */
;/* ENTRY POINT: PRTCHECK_CPF                                          */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINE:           verlockdata                                  */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  AllocReqPacket                  */
;/*    ROUTINE:                        PushRequest                     */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtcheck_cpf near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [di].commonflags,MONREG2                ; TEST MONITOR FLAG
        jnz     prtcheck_cpf2                           ; NZ = REGISTERED
        mov     es:[bx].PktStatus,INVALIDCOMMD          ; SET ERROR RC
        or      es:[bx].PktStatus,USERRETCODE           ; SET USER RETURN CODE
        jmp     prtcheck_cpf7                           ; EXIT
prtcheck_cpf2:
        mov     cx,CPFDBLEN                             ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtcheck_cpf7                           ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE

        ; DUE TO KERNEL/SPOOLER DEADLOCK OVER THE KERNEL SEMAPHORE, THE PDD
        ; WILL NOT ISSUE DEVHLP_MONWRITE CALL WITH BLOCK OPTION ON KERNEL
        ; [ACTIVATE] CODE PAGE REQUESTS.  IF THE REQUEST DOES NOT SUCCEED WITH
        ; NO BLOCK OPTION, REQUEST IS QUEUED AND TRIED AGAIN LATER WHEN BLOCK
        ; OPTION WILL NOT CAUSE DEADLOCK [DOS REQUEST DOES NOT PASS FILENAME].

        cmp     es:[bx].GIOFunction,IOLW_AF             ; IF !ACTIVATE CP REQ
        jne     prtcheck_cpf5                           ; THEN DO IOCTL REQ
        mov     si,word ptr es:[bx].GIODataPack+2       ; GET IOCTL DATA ADDR
        and     si,3h                                   ; MASK OFF TO GET RING
        or      si,si                                   ; IF !RING 0
        jnz     prtcheck_cpf5                           ; THEN CONTINUE

        mov     dx,es:[bx].GIOSFN                       ; GET SFN FROM REQ PKT
        SaveReg <es,bx,dx>
        les     bx,es:[bx].GIODataPack                  ; GET IOCTL DATA ADDR
        mov     ax,es:[bx].ioctlpage                    ; GET CODE PAGE
        mov     cx,es:[bx].ioctlfont                    ; GET FONT

        xor     dh,dh                                   ; WAIT ON REQ PKT
        mov     dl,DevHlp_AllocReqPacket                ; ALLOCATE REQ PKT
        call    DWORD PTR [device_help]                 ; CALL DEVHELP
        RestoreReg <dx>

        mov     es:[bx].PktCmd,CMDGenIOCTL              ; SAVE CMD IN REQ PKT
        mov     es:[bx].GIOSFN,dx                       ; SAVE SFN IN REQ PKT
        mov     word ptr es:[bx].GIODataPack,ax         ; SAVE CODE PAGE/FONT
        mov     word ptr es:[bx].GIODataPack+2,cx       ; IN DATA ADDR OF 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 RETURN CODE
        jmp     prtcheck_cpf6                           ; EXIT

        ; DISPATCH THE APPROPRIATE IOCTL ROUTINE

prtcheck_cpf5:
        call    prtblock                                ; CONTINUE OPERATION
prtcheck_cpf6:
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtcheck_cpf7:
        ret                                             ; RETURN TO CALLER
EndProc prtcheck_cpf

BREAK <CHECK SET PRINT JOB TITLE REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCHECK_PJT                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Check Set Print Job Title Request.               */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is verify access        */
;/*            to the set print job title IOCtl request.  If the       */
;/*            printer device driver can get access, then the request  */
;/*            will be serialized (prtblock) to perform the actual     */
;/*            work. If we do not have access, an error is immediately */
;/*            returned.                                               */
;/*                                                                    */
;/* REMARKS:  This function is only valid if a monitor is registered.  */
;/*                                                                    */
;/* ENTRY POINT: PRTCHECK_PJT                                          */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINE:           verlockdata                                  */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtcheck_pjt near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [di].commonflags,MONREG1                ; IF MON REGISTERED
        jnz     prtcheck_pjt1                           ; THEN CONTINUE
        mov     es:[bx].PktStatus,REQDONE               ; SET RETURN CODE
        jmp     SHORT prtcheck_pjt2                     ; EXIT
prtcheck_pjt1:
        mov     cx,PJOBDBLEN                            ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtcheck_pjt2                           ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE
        call    prtblock                                ; SERIALIZE VALID REQ
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtcheck_pjt2:
        ret
EndProc prtcheck_pjt

BREAK <CHECK SET/RET HARDWARE TIMEOUT REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCHECK_TO                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Check Set/Ret Hardware Timeout Request.          */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is verify access        */
;/*            to the hardware timeout IOCtl request.  If the printer  */
;/*            device driver receives access, then the request will be */
;/*            serialized (prtblock) to perform the actual work.  If   */
;/*            we do not have access, an error is immediately returned.*/
;/*                                                                    */
;/* REMARKS:  The reason for having two routines to handle this request*/
;/*           is so the timeout value will not change in the middle of */
;/*           an output request.                                       */
;/*                                                                    */
;/* ENTRY POINT: PRTCHECK_TO                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINE:           verlockdata                                  */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtcheck_to near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     cx,TIMEOUTLEN                           ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtcheck_to1                            ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE
        call    prtblock                                ; SERIALIZE VALID REQ
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtcheck_to1:
        ret
EndProc prtcheck_to

BREAK <CHECK SET/RET DIRECT MODE ACCESS>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTCHECK_DM                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Check Set/Ret Direct Mode Access.                */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is verify access        */
;/*            to the direct mode access IOCtl request. If the printer */
;/*            device driver receives access, then the request will be */
;/*            serialized (prtblock) to perform the actual work.  If   */
;/*            we do not have access, an error is immediately returned.*/
;/*                                                                    */
;/* REMARKS:  The reason for having two routines to handle this request*/
;/*           is so the direct mode flag will not change in the middle */
;/*           of an output request.                                    */
;/*                                                                    */
;/* ENTRY POINT: PRTCHECK_DM                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtblock                                     */
;/*    ROUTINE:           verlockdata                                  */
;/*                       unlockdata                                   */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINE:                                                        */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtcheck_dm near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     cx,DIRECTMODELEN                        ; LENGTH OF DATA BUF
        call    verlockdata                             ; VERIFY ACCESS & LOCK
        jc      prtcheck_dm1                            ; IF ERROR, EXIT
        SaveReg <ax,cx>                                 ; SAVE LOCK HANDLE
        call    prtblock                                ; SERIALIZE VALID REQ
        RestoreReg <cx,ax>                              ; GET LOCK HANDLE
        call    unlockdata                              ; UNLOCK GIODATAPACK
prtcheck_dm1:
        ret
EndProc prtcheck_dm

BREAK <START GENERIC IOCTL ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTSTIOC                                         */
;/*                                                                    */
;/* DESCRIPTIVE NAME: START IOCTL                                      */
;/*                                                                    */
;/* FUNCTION:  DISPATCH THE APPROPRIATE IOCTL ROUTINE.                 */
;/*                                                                    */
;/* ENTRY POINT: PRTSTIOC                                              */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  see iopc_dispatch table                      */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtstioc near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     al,es:[bx].GIOFunction                  ; GET FUNCTION CODE
        and     ax,NOT IOCTLMASK                        ; PRODUCE INDEX
        mov     si,ax                                   ; BYTE INDEX
        sal     si,1                                    ; MAKE WORD INDEX
        call    WORD PTR iopc_dispatch[si]              ; CALL ROUTINE
        ret
EndProc prtstioc

BREAK <REGISTER A PRINTER DEVICE MONITOR>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTMONREG                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  PRINTER DD MONITOR REGISTER ROUTINE.            */
;/*                                                                    */
;/* FUNCTION:  THE FUNCTION OF THIS SUBROUTINE IS TO CREATE A MONITOR  */
;/*            CHAIN, IF THERE IS NO EXISTING MONITOR CHAIN, AND       */
;/*            REISTER THE SPECIFIED MONITOR IN THE NEWLY CREATED      */
;/*            MONITOR CHAIN OR PREVIOUSLY CREATED MONITOR CHAIN.      */
;/*                                                                    */
;/* NOTE:  MONITOR INDEX OF MONITOR REGISTER IOCTL                     */
;/*        = 1 MEANS REGISTER A DATA MONITOR                           */
;/*        = 2 MEANS REGISTER A CODE PAGE MONITOR                      */
;/*                                                                    */
;/* ENTRY POINT: PRTMONREG                                             */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:   ES:[BX].PktStatus = REQDONE                         */
;/*                                                                    */
;/* EXIT-ERROR :   ES:[BX].PktStatus = WRITEFAULT                      */
;/*                ES:[BX].PktStatus = INVALIDCOMMD                    */
;/*                                                                    */
;/* INTERNAL REFERENCES:  chainmonitor                                 */
;/*    ROUTINES:          registermonitor                              */
;/*                       devdone                                      */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtmonreg near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; GET PARMS ADDRESS
        mov     ax,es:[bx].monindex                     ; SAVE THE INDEX VALUE
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        cmp     ax,1                                    ; IF INDEX = 1
        je      monreg10                                ; PROCESS DATA MONITOR
        cmp     ax,2                                    ; IF INDEX = 2
        je      monreg60                                ; PROCESS CODEPG MONITOR
        mov     es:[bx].PktStatus,INVALIDPARM           ; SET INVALID PARAMETER
        jmp     monreg95                                ; EXIT

;*******************************************************************************
;*      PROCESS DATA MONITOR CHAIN                                             *
;*******************************************************************************
monreg10:
        test    [di].commonflags,MONCHAIN1              ; TEST DATA CHAIN
        jnz     monreg20                                ; JUMP IF ON
        mov     si,[di].frommonbuf_off                  ; DS:SI -> MON FINAL BUF
        mov     ax,[di].configbufsize                   ; GET MON BUF SIZE
        mov     [si].monfinalbufsize,ax                 ; SET SIZE ON REG CALL
        call    chainmonitor                            ; ELSE CREATE THE CHAIN
        jc      monreg90                                ; JUMP IF ERROR
        or      [di].commonflags,MONCHAIN1              ; SET DATA MONITOR REG'D
        mov     [di].monhandle,ax                       ; SAVE DATA MON HANDLE
monreg20:
        mov     ax,[di].monhandle                       ; MONITOR DATA HANDLE
        call    registermonitor                         ; REGISTER A MONITOR
        jc      monreg90                                ; IF ERROR, EXIT
        or      [di].commonflags,MONREG1                ; SET DATA MON REG'D
        or      [di].commonflags,INFINRETRY             ; TURN ON INFINRETRY
        jmp     SHORT monreg80                          ; SET RETCODE, EXIT

;*******************************************************************************
;*      PROCESS CODE PAGE MONITOR CHAIN                                        *
;*******************************************************************************
monreg60:
        test    [di].commonflags,MONCHAIN2              ; TEST CODE PAGE CHAIN
        jnz     monreg70                                ; JUMP IF ON
        mov     [di].moncpbufsize,SIZE cpfmonreq + FROMMONFIXEDLEN ; SET SIZE
        lea     si,[di].moncpbufsize                    ; MON RETURN BUF ADDRESS
        call    chainmonitor                            ; ELSE CREATE THE CHAIN
        jc      monreg90                                ; IF ERROR, EXIT
        or      [di].commonflags,MONCHAIN2              ; SET DATA MONITOR REG'D
        mov     [di].cpfhandle,ax                       ; MONITOR HANDLE
monreg70:
        mov     ax,[di].cpfhandle                       ; MONITOR CODE PG HANDLE
        call    registermonitor                         ; REGISTER A MONITOR
        jc      monreg90                                ; IF ERROR, EXIT
        or      [di].commonflags,MONREG2                ; SET CODE PG MON REG'D
monreg80:
        mov     es:[bx].PktStatus,REQDONE               ; RETURN NO ERRORS
        jmp     SHORT monreg95                          ; EXIT
monreg90:
        mov     es:[bx].PktStatus,WRITEFAULT            ; ASSUME ERROR CODE
monreg95:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtmonreg

BREAK <CHAIN MONITOR ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  CHAINMONITOR                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  CHAIN A MONITOR                                 */
;/*                                                                    */
;/* FUNCTION:  The function of this routine is to register the printer */
;/*            device drivers notification buffer and routine with the */
;/*            the monitor dispatcher.                                 */
;/*                                                                    */
;/* ENTRY POINT: CHAINMONITOR                                          */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            SI = MONITOR FINAL BUFFER ADDRESS                       */
;/*                                                                    */
;/* EXIT-NORMAL:  NC = Created new monitor chain                       */
;/*               AX = Monitor handle                                  */
;/*               SI = Monitor final buffer address                    */
;/*                                                                    */
;/* EXIT-ERROR :  CY = New monitor chain not created                   */
;/*               AX = Error code                                      */
;/*               SI = Monitor final buffer address                    */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  MonitorCreate                   */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure chainmonitor near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <bx,di,ds,es,dx>
        xor     ax,ax                                   ; CREATE NEW CHAIN
        xor     bh,bh                                   ; MAKE BH 0
        mov     bl,[di].deviceindex                     ; GET DEVICE INDEX
        sal     bx,1                                    ; WORD INDEX
        push    ds                                      ; DATA SEG ADDR
        pop     es                                      ; ES:SI -> BUFFER ADDR
        mov     di,monnotify_tbl[bx]                    ; OFFSET NOTIFY ROUTINE
        mov     dx,CSEG                                 ; RES CODE SEG ADDR
        mov     ds,dx                                   ; DS:DI -> NOTI RTN
        mov     dl,DevHlp_MonitorCreate                 ; MON CREATE FUNCTION
        call    DWORD PTR es:[device_help]              ; CALL DEVHLP
        RestoreReg <dx,es,ds,di,bx>
        ret
EndProc chainmonitor

BREAK <REGISTER MONITOR ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  REGISTERMONITOR                                  */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  REGISTER A MONITOR                              */
;/*                                                                    */
;/* FUNCTION:  The function of this routine is to register the caller's*/
;/*            monitor input and output buffers in the placement order */
;/*            with the monitor dispatcher.                            */
;/*                                                                    */
;/* ENTRY POINT: REGISTERMONITOR                                       */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            AX = HANDLE TO USE TO REGISTER A NEW MONITOR            */
;/*                                                                    */
;/* EXIT-NORMAL:  NC = Monitor registered                              */
;/*               AX = Handle used to register a new monitor           */
;/*                                                                    */
;/* EXIT-ERROR :  CY = Monitor not registered                          */
;/*               AX = Error code                                      */
;/*                                                                    */
;/* INTERNAL REFERENCES:  getpid                                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  VerifyAccess                    */
;/*    ROUTINES:                       Register                        */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure registermonitor near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx,cx,si,di>
        push    ax
        call    getpid                                  ; GET MONITOR PROC ID
        mov     cx,ax                                   ; GET MONITOR PROC ID
        les     bx,es:[bx].GIODataPack                  ; GET DATA BUFFER
        push    cx
        mov     ax,WORD PTR es:[bx].moninbuf+2          ; AX:DI->DATA BUF
        mov     di,WORD PTR es:[bx].moninbuf            ; AX:DI->DATA BUF
        mov     cx,offset moninbuf
        mov     dh,RACCESS                              ; READ ACCESS
        mov     dl,Devhlp_VerifyAccess                  ; VERIFY ACC FUNC
        call    DWORD PTR [device_help]                 ; DEVICE HELP
        pop     cx
        pop     ax
        jc      rmon0
        mov     dx,es:[bx].placement                    ; PLACEMENT FLAG
        mov     di,es:[bx].monoutbuf                    ; MONITOR OUTPUT BUFFER
        les     si,es:[bx].moninbuf                     ; MONITOR INPUT BUFFER
        mov     dh,dl                                   ; PLACEMENT FLAG
        mov     dl,DevHlp_Register                      ; REGISTER FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVHLP
rmon0:
        RestoreReg <di,si,cx,bx,es>
        ret
EndProc registermonitor

BREAK <GENERIC IOCTL SET/RETURN FRAME CONTROL ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_FC                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: IOCTL PRINTER FRAME CONTROL.                     */
;/*                                                                    */
;/* FUNCTION:   THE FUNCTION OF THIS SUBROUTINE WILL BE TO SET THE     */
;/*             PRINTER FRAME CONTROL WHICH CONSISTS OF THE NUMBER OF  */
;/*             CHARACTERS THAT CAN BE PRINTED ON ONE LINE AND THE     */
;/*             NUMBER OF LINES THAT CAN BE PRINTED IN ONE INCH.  VALID*/
;/*             CHARS/LINE ARE 80 AND 132 AND VALID LINES/INCH ARE 6 & */
;/*             8. THE USER WILL USE THE MODE COMMAND TO SET THE       */
;/*             PRINTER FRAME CONTROL WHICH WILL ISSUE AND IOCTL CALL  */
;/*             TO THE DEVICE DRIVER STRATEGY ENTRY POINT.  IF A SET   */
;/*             FRAME CONTROL COMMAND, THIS SUBROUTINE WILL TAKE THE   */
;/*             ALREADY VALIDATED FRAME CONTROL VALUES AND WILL FILL   */
;/*             IN THE NECESSARY ESCAPE CODES INTO THE BUFFER AND CALL */
;/*             THE ROUTINE TO SEND THEM TO THE PRINTER.  IF A MONITOR */
;/*             IS INSTALLED, THE BUFFER WILL BE SENT TO THE MONITOR   */
;/*             DISPATCHER TO SPOOL (SERIALIZE) THE REQUEST.  IF THE   */
;/*             REQUEST IS A RETURN FRAME CONTROL COMMAND, THE CURRENT */
;/*             FRAME CONTROL WILL BE RETURNED IN THE PARAMETER AREA   */
;/*             POINTED TO BY THE KERNEL REQUEST BLOCK.                */
;/*                                                                    */
;/* NOTE:  IOCTL DATA PACKET HAS BEEN VERIFIED AND LOCKED.             */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_FC                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*               ES:[BX].charsperline = VALUE                         */
;/*               ES:[BX].linesperinch = VALUE                         */
;/*               [DI].PRTFRMCTRL.CHARSPERLINE = NEW VALUE (IF SET CMD)*/
;/*               [DI].PRTFRMCTRL.LINESPERINCH = NEW VALUE (IF SET CMD)*/
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = WRITEFAULT or CHARIOINT          */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtbuftoreqpkt                               */
;/*    ROUTINES:          flushcpqueue                                 */
;/*                       flushcache                                   */
;/*                       monwrite                                     */
;/*                       devdone                                      */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_fc near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        cmp     es:[bx].GIOFunction,IOLW_FC             ; IF FUNC = SET FRMCTRL
        je      prtioctl_fc1                            ; THEN SET FRAME CTRL
        jmp     prtioctl_fc3                            ; ELSE RET FRAME CTRL
prtioctl_fc1:
        ; SAVE VALIDATED FRAME CONTROL VALUES

        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; IOCTL DATA AREA
        mov     ah,es:[bx].charsperline                 ; GET CHARS/LINE VALUE
        mov     [di].prtfrmctrl.charsperline,ah         ; SAVE CHARS/LINE VALUE
        mov     al,es:[bx].linesperinch                 ; GET LINES/INCH VALUE
        mov     [di].prtfrmctrl.linesperinch,al         ; SAVE LINES/INCH VALUE

        SaveReg <di>                                    ; SAVE REGISTERS
        cld                                             ; SET FORWARD DIRECTION
        mov     cx,FRAMECTRLMAX                         ; # OF FRAME CTRL COMB.
        push    ds                                      ; DATA SEGMENT ADDRESS
        pop     es                                      ; DATA SEGMENT ADDRESS
        mov     di,OFFSET frmctrlcomb                   ; OFF OF FRM. CTRL COMB.
        repnz   scasw                                   ; CHECK IF PARMS VALID
        mov     si,di                                   ; OFFSET OF COMB TO DI
        RestoreReg <di,bx,es>                           ; RESTORE REGISTERS
        dec     si                                      ; ADJUST TO START
        dec     si                                      ; ADJUST TO START
        sub     si,OFFSET frmctrlcomb                   ; CALC INDEX
        mov     ax,WORD PTR framectrldata[si]           ; GET FRM CTRL ESC CODES

        test    [di].commonflags,MONREG1                ; IF NO MONITOR CREATED
        jz      prtioctl_fc2                            ; SEND DATA TO DEVICE
        call    flushcpqueue                            ; FLUSH KERNEL CP REQS
        jc      prtioctl_fc4                            ; IF ERROR, EXIT
        mov     cx,es:[bx].GIOSFN                       ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH CACHE
        jc      prtioctl_fc4                            ; IF ERROR, EXIT

        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON BUF
        mov     [si].tomonbuf[0],al                     ; SET 1ST BYTE
        mov     [si].tomonbuf[1],ESCAPE                 ; SET 2ND BYTE = ESCAPE
        mov     [si].tomonbuf[2],ah                     ; SET 3RD BYTE
        mov     ax,es:[bx].GIOSFN                       ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLEAR                ; SET MONITOR WRITE FLAG
        mov     cx,FRMCTRLCNT + TOMONFIXEDLEN           ; SET COUNT FOR MONITOR
        mov     dh,MONWAIT                              ; BLOCK REQUEST
        call    monwrite                                ; GIVE DATA TO MONITOR
        jmp     SHORT prtioctl_fc4                      ; RETURN TO KERNEL
prtioctl_fc2:
        mov     si,[di].frommonbuf_off                  ; DS:SI -> FROM MON BUF
        mov     [si].frommonbuf[0],al                   ; SET 1ST BYTE
        mov     [si].frommonbuf[1],ESCAPE               ; SET 2ND BYTE = ESCAPE
        mov     [si].frommonbuf[2],ah                   ; SET 3RD BYTE
        mov     ax,es:[bx].GIOSFN                       ; GET SFN
        mov     [si].frommonsfn,ax                      ; SAVE SFN
        mov     [si].frommonflags,MONCLEAR              ; SET MONITOR WRITE FLAG
        mov     [si].monfinalbufsize,FRMCTRLCNT + FROMMONFIXEDLEN ; SAVE SIZE
        call    prtbuftoreqpkt                          ; SIMULATE MON DISP CALL
        mov     es:[bx].PktStatus,ax                    ; SAVE RETURN CODE
        jmp     SHORT prtioctl_fc4                      ; RETURN TO KERNEL
prtioctl_fc3:
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; VIRT. ADDR. DATA AREA
        mov     ah,[di].prtfrmctrl.charsperline         ; GET CHARS/LINE VALUE
        mov     es:[bx].charsperline,ah                 ; RET CHARS/LINE VALUE
        mov     ah,[di].prtfrmctrl.linesperinch         ; GET LINES/INCH VALUE
        mov     es:[bx].linesperinch,ah                 ; RET LINES/INCH VALUE
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
prtioctl_fc4:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtioctl_fc

BREAK <GENERIC IOCTL INITIALIZE DEVICE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_IN                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME: GENERIC IOCTL INITIALIZE THE PRINTER.            */
;/*                                                                    */
;/* FUNCTION: THE FUNCTION OF THIS SUBROUTINE IS TO SETUP AND CALL     */
;/*           THE INITIALIZATION ROUTINE WITH THE NECESSARY PARMS.     */
;/*                                                                    */
;/* NOTE:  IOCTL DATA PACKET HAS BEEN VERIFIED AND LOCKED.             */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_IN                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                  */
;/*            BX = VIRTUAL  OFFSET OF REQUEST BLOCK                   */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = WRITEFAULT or CHARIOINT          */
;/*                                                                    */
;/* INTERNAL REFERENCES:  prtreqdirect                                 */
;/*    ROUTINES:          initialprt                                   */
;/*                       prtreldirect                                 */
;/*                       flushcpqueue                                 */
;/*                       flushcache                                   */
;/*                       monwrite                                     */
;/*                       devdone                                      */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_in near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        test    [di].commonflags,MONREG1                ; IF MONITOR CREATED
        jnz     iocin1                                  ; GIVE DATA TO MONITOR

        call    prtreqdirect                            ; REQUEST PORT ACCESS
        jc      iocin2                                  ; IF UNUSUAL WAKEUP
        call    initialprt                              ; INITIALIZE THE DEVICE
        call    prtreldirect                            ; RELEASE PORT ACCESS
        jmp     SHORT iocin2                            ; DEVDONE SETS DONE BIT
iocin1:
        call    flushcpqueue                            ; FLUSH KERNEL CP REQS
        jc      iocin3                                  ; IF ERROR, EXIT
        mov     cx,es:[bx].GIOSFN                       ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH CACHE
        jc      iocin3                                  ; IF ERROR, EXIT

        mov     cx,initstringlen                        ; INIT STRING LENGTH
        SaveReg <di,cx,es>                              ; SAVE REGISTERS
        cld                                             ; SET FORWARD DIRECTION
        push    ds                                      ; DATA SEGMENT ADDRESS
        pop     es                                      ; DATA SEGMENT ADDRESS
        mov     si,OFFSET initstring                    ; SOURCE ADDRESS
        mov     di,[di].tomonbuf_off                    ; ES:DI -> TO MON PKT
        push    di                                      ; SAVE PERPRTAREA OFF
        lea     di,[di].tomonbuf                        ; ES:DI -> TO MON BUF
        rep     movsb                                   ; MOVE BYTES
        pop     si                                      ; DS:SI -> TO MON BUF
        RestoreReg <es,cx,di>                           ; RESTORE REGISTERS
        add     cx,TOMONFIXEDLEN                        ; FIXED SIZE OF MON REC
        mov     ax,es:[bx].GIOSFN                       ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLEAR                ; MONITOR WRITE FLAG
        mov     dh,MONTIMEOUT                           ; WAIT UNTIL TIMEOUT
        call    monwrite                                ; GIVE DATA TO MONITOR
        jc      iocin3                                  ; ERROR, EXIT
iocin2:
        mov     [di].prtfrmctrl.charsperline,CHARS80_LINE ; SET CPL TO DEFAULT
        mov     [di].prtfrmctrl.linesperinch,LINES6_INCH  ; SET LPI TO DEFAULT
iocin3:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtioctl_in

BREAK <CODE PAGE/FONT IOCTL>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_CPF                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Code Page/Font IOCTL Handler                     */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine will be to pass the     */
;/*            Code Page/Font requests to the monitor if one is        */
;/*            registered. These requests must be synchronized with    */
;/*            the monitor as it must return data and success or       */
;/*            failure information to the caller.                      */
;/*                                                                    */
;/*            Valid requests are:                                     */
;/*            1. Activate Code Page/Font                              */
;/*            2. Query Active Code Page/Font                          */
;/*            3. Verify Active Code Page/Font                         */
;/*                                                                    */
;/* NOTE:  IOCTL DATA PACKET HAS BEEN VERIFIED AND LOCKED.             */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_CPF                                          */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:  ES:[BX].PktStatus = REQDONE                          */
;/*                                                                    */
;/* EXIT-ERROR :  ES:[BX].PktStatus = WRITEFAULT or CHARIOINT          */
;/*                                                                    */
;/* INTERNAL REFERENCES:  flushcpqueue                                 */
;/*    ROUTINES:          flushcache                                   */
;/*                       monwrite                                     */
;/*                       block_cpf                                    */
;/*                       devdone                                      */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_cpf near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        call    flushcpqueue                            ; FLUSH KERNEL CP REQS
        jnc     prtioctl_cpf0                           ; IF NO ERROR, CONTINUE
        jmp     prtioctl_cpf4                           ; ELSE IF ERROR, EXIT
prtioctl_cpf0:
        mov     cx,es:[bx].GIOSFN                       ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH CACHE
        jnc     prtioctl_cpf10                          ; IF NO ERROR, CONTINUE
        jmp     prtioctl_cpf4                           ; ELSE, EXIT
prtioctl_cpf10:
        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON PKT
        mov     ax,es:[bx].GIOSFN                       ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLEAR                ; CLEAR THE FLAGS
        mov     BYTE PTR [si].tomonflags+1,MONCPFREQ    ; SET CODE PAGE REQUEST
        SaveReg <di>                                    ; SAVE PERPRTDATA PTR

        ;/***********************************************************/
        ;/*                                                         */
        ;/*              CLEAR FIRST PART OF MONBUFFER              */
        ;/*                                                         */
        ;/***********************************************************/

        lea     di,[si].tomonbuf                        ; DS:DI -> TO MON BUF
        SaveReg <es,di>                                 ; SAVE REGISTERS
        push    ds                                      ; SET UP ES TO BE
        pop     es                                      ; SAME AS DS
        mov     ax,0                                    ; SET AX = 0
        mov     cx,CPFMONREQLEN                         ; SET COUNT FIELD
        cld                                             ; SET FORWARD DIRECTION
        rep     stosw                                   ; CLEAR AREA
        RestoreReg <di,es>                              ; RESTORE REGISTERS

     .IF <es:[bx].GIOFunction EQ IOLR_QF>               ; CHECK FOR QUERY
        mov     [di].cpfcommnd,MONQRYCPF                ; SET QUERY COMMAND
     .ELSEIF <es:[bx].GIOFunction EQ IOLW_AF>           ; CHECK FOR ACTIVATE
        mov     [di].cpfcommnd,MONACTCPF                ; SET ACTIVATE COMMND
     .ELSE                                              ; ASSUME VERIFY
        mov     [di].cpfcommnd,MONVFYCPF                ; SET VERIFY COMMND
     .ENDIF

        ;/***********************************************************/
        ;/*                                                         */
        ;/*   PREPARE MONITOR BUFFER FOR ACTIVATECPF OR VERIFYCPF   */
        ;/*                                                         */
        ;/***********************************************************/

     .IF <es:[bx].GIOFunction NE IOLR_QF>               ; CHECK FOR NOT QUERY
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; SET IOCTL DATA @
        mov     ax,es:[bx].ioctlpage                    ; MOVE CODE PAGE & FONT
        mov     [di].cpfcodepg,ax                       ; DATA FROM REQ PACKET
        mov     ax,es:[bx].ioctlfont                    ; TO MON BUFFER FOR
        mov     [di].cpffont,ax                         ; VERIFY & ACTIVATE
        RestoreReg <bx,es>
     .ENDIF
        RestoreReg <di>                                 ; RESTORE DATA POINTER
        or      [di].commonflags,CPFINPROGRESS          ; SET THE INPROG FLAG
        mov     cx,SIZE cpfmonreq                       ; SET BYTE COUNT IN CX
        add     cx,TOMONFIXEDLEN                        ; ADD PACKET FIXED SIZE
        mov     dh,MONTIMEOUT                           ; BLOCK REQUEST
        call    monwrite                                ; SEND REQ TO SPOOLER
        jc      prtioctl_cpf1                           ; IF ERROR EXIT
        call    block_cpf                               ; BLOCK THIS THREAD
        jnc     prtioctl_cpf2                           ; IF NO ERROR CONTINUE
prtioctl_cpf1:
        and     [di].commonflags,NOT CPFINPROGRESS      ; CLEAR INPROG FLAG
        jmp     prtioctl_cpf4                           ; EXIT

        ;/***********************************************************/
        ;/*                                                         */
        ;/*                  RESUME OPERATION HERE                  */
        ;/*                                                         */
        ;/***********************************************************/

prtioctl_cpf2:
        SaveReg <di>                                    ; SAVE DATA POINTER
        lea     di,[di].moncpinbuf                      ; POINT TO BUF
        mov     ax,[di].cpfreturn                       ; SET RETURN CODE
        mov     es:[bx].PktStatus,ax                    ; IN PACKET AREA

        test    [di].cpfreturn,0ffffh                   ; TEST THE RETURN CODE
     .IF < NZ >                                         ; IF AN ERROR OCCURRED
        or      es:[bx].PktStatus,USERRETCODE           ; SET USER RETURN CODE
     .ELSE
        or      es:[bx].PktStatus,REQDONE               ; SET REQUEST DONE FLAG
     .ENDIF

     .IF <es:[bx].GIOFunction EQ IOLR_QF>               ; CHECK FOR QUERY
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,es:[bx].GIODataPack                  ; SET IOCTL DATA @
        mov     ax,[di].cpfcodepg                       ; MOVE CODE PAGE & FONT
        mov     es:[bx].ioctlpage,ax                    ; DATA FROM MON BUFFER
        mov     ax,[di].cpffont                         ; TO REQUEST PACKET TO
        mov     es:[bx].ioctlfont,ax                    ; RETURN QUERY INFO.
        RestoreReg <bx,es>
     .ENDIF
        RestoreReg <di>
prtioctl_cpf4:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtioctl_cpf

BREAK <CODE PAGE BLOCK>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  BLOCK_CPF                                        */
;/*                                                                    */
;/* DESCRIPTIVE NAME: Block Code Page/Font Request.                    */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine will be to block the    */
;/*            Code Page/Font request until an answer has been         */
;/*            received from the Code Page/Font Switcher. RESUME_CPF   */
;/*            will cause this thread to be started.                   */
;/*                                                                    */
;/* ENTRY POINT: BLOCK_CPF                                             */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   NC - NORMAL WAKEUP                                  */
;/*                                                                    */
;/* EXIT-ERROR :   CY - UNUSUAL WAKEUP - ABORT REQUEST                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcBlock                       */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure block_cpf near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
block_cpf1:
        cli
        test    [di].commonflags,CPFINPROGRESS          ; IF INPROG FLAG IS OFF
        jz      block_cpf2                              ; THEN RUN ALREADY DONE

        SaveReg <bx,di>                                 ; SAVE REGISTERS
        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     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
        RestoreReg <di,bx>                              ; RESTORE REGISTERS
        jc      block_cpf2                              ; UNUSUAL WAKEUP, EXIT
        jmp     SHORT block_cpf1                        ; MAKE SURE REQ DONE
block_cpf2:
        sti                                             ; ENABLE INTERRUPTS
        ret
EndProc block_cpf

BREAK <SET PRINT JOB TITLE REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_PJT                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Set Print Job Title Request.                    */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to format a print    */
;/*            job title monitor packet and devhlp_monwrite it down    */
;/*            the data chain (index=1) in order for the spooler to    */
;/*            be able to display a print job title in the queue for   */
;/*            non pm printing jobs.                                   */
;/*                                                                    */
;/* REMARKS:  This function is only valid if a monitor is registered.  */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_PJT                                          */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:  es:[bx].PktStatus = REQDONE                          */
;/*                                                                    */
;/* EXIT-ERROR :  es:[bx].PktStatus = INVALIDPARM if invalid datapkt   */
;/*                                                                    */
;/* INTERNAL REFERENCES:  flushcpqueue                                 */
;/*   ROUTINE:            flushcache                                   */
;/*                       monwrite                                     */
;/*                       devdone                                      */
;/*                                                                    */
;/* EXTERNAL REFERENCES:                                               */
;/*   ROUTINE:            DEVICE_HELP VerifyAccess                     */
;/*                       DEVICE_HELP LinToGDTSelector                 */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_pjt near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx,di>                              ; SAVE REGISTERS
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        les     bx,DWORD PTR dosvar                     ; GET LOCAL INFO SEG
        les     bx,DWORD PTR es:[bx]                    ; 
        cmp     es:[bx].LIS_ProcType,LIS_PT_REALMODE    ; IF PROCESS != RMODE
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        jne     prtioctl_pjt0                           ; THEN VERIFY ACCESS

        ; Convert V86 address to Linear Address

.386c
        les     bx,es:[bx].GIODataPack                  ; ES:BX -> DATA PACK
        movzx   edx,WORD PTR es:[bx].pjtitlesel         ; REAL MODE ADDR
        shl     edx,4                                   ; PARAGRAPH ALIGN
        movzx   eax,WORD PTR es:[bx].pjtitleoff         ; EAX = OFFSET, ADD
        add     edx,eax                                 ; EDX -> PRT JOB TITLE

        ; Map Linear Address to GDT selector

        mov     ax,[di].gdtuserbuf                      ; GET GDT SELECTOR
        movzx   ecx,WORD PTR es:[bx].pjtitlelen         ; LENGTH OF DATA BUF
        mov     ebx,edx                                 ; EBX = LINEAR ADDR
.286c
        mov     dl,DevHlp_LinToGDTSelector              ; MAP LIN TO GDT
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jc      prtioctl_pjt07                          ; IF ERROR, EXIT
        xor     di,di                                   ; CLEAR OFFSET
        jmp     SHORT prtioctl_pjt05                    ; AX:DI -> DATA BUF

        ; Verify Access to user data area

prtioctl_pjt0:
        les     bx,es:[bx].GIODataPack                  ; ES:BX -> DATA PACK
        mov     di,WORD PTR es:[bx].pjtitleoff          ; GET JOB TITLE PTR
        mov     ax,WORD PTR es:[bx].pjtitlesel          ; AX:DI -> TITLE BUF
        mov     cx,es:[bx].pjtitlelen                   ; LENGTH OF DATA BUF
prtioctl_pjt05:
        mov     dh,RACCESS                              ; NEED READ ACCESS
        mov     dl,Devhlp_VerifyAccess                  ; VERIFY ACCESS FUNC
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jnc     prtioctl_pjt1                           ; IF !ERROR, CONTINUE
prtioctl_pjt07:
        RestoreReg <di,bx,es>                           ; RESTORE REGISTERS
        mov     es:[bx].PktStatus,INVALIDPARM           ; ELSE RETURN ERROR
        jmp     SHORT prtioctl_pjt5                     ; EXIT
prtioctl_pjt1:
        cmp     cx,126                                  ; IF LEN <= 126
        jbe     prtioctl_pjt2                           ; THEN CONTINUE
        mov     cx,126                                  ; ELSE SET LEN = 126
prtioctl_pjt2:
        mov     si,di                                   ; GET SOURCE OFFSET
        pop     di                                      ; RESTORE REGISTER
        RestoreReg <bx,es>
        call    flushcpqueue                            ; FLUSH KERNEL CP REQS
        jc      prtioctl_pjt5                           ; IF ERROR, EXIT
        SaveReg <es,bx>
        SaveReg <cx,si>
        mov     cx,es:[bx].GIOSFN                       ; GET SFN OF REQUEST
        call    flushcache                              ; FLUSH CACHE
        RestoreReg <si,cx>
        jc      prtioctl_pjt5                           ; IF ERROR, EXIT
        SaveReg <di,ds>                                 ; SAVE REGISTERS
        push    ds
        pop     es
        mov     di,[di].tomonbuf_off                    ; ES:DI -> TO MON PKT
        push    di                                      ; SAVE TO MON PKT OFF
        lea     di,[di].tomonbuf                        ; ES:DI -> TO MON BUF
        mov     ds,ax                                   ; DS:SI -> PJTITLE BUF
        SaveReg <di,cx>                                 ; SAVE REGISTERS
        inc     di
        inc     di                                      ; POINT PASSED LENGTH
        cld                                             ; SET DIRECTION
        rep     movsb                                   ; MOVE BYTES
        RestoreReg <cx>                                 ; RESTORE LENGTH
        dec     di                                      ; POINT TO LAST BYTE
        cmp     BYTE PTR es:[di],0                      ; IF LAST WAS ASCIIZ
        je      prtioctl_pjt4                           ; THEN CONTINUE
        cmp     cx,126                                  ; IF BUF FULL/CX OKAY
        je      prtioctl_pjt3                           ; THEN JUST ASCIIZ IT
        inc     cx                                      ; ELSE ADD NULL TO CTR
        inc     di                                      ; POINT PASSED LAST
prtioctl_pjt3:
        mov     BYTE PTR es:[di],0                      ; MAKE STRING ASCIIZ

prtioctl_pjt4:
        RestoreReg <di>                                 ; RESTORE REGISTER
        mov     WORD PTR es:[di],cx                     ; INSERT LENGTH IN PKT
        pop     si                                      ; DS:SI -> TO MON PKT
        RestoreReg <ds,di>                              ; RESTORE REGISTER
        inc     cx                                      ; ADD TWO BYTES FOR
        inc     cx                                      ; LEN WORD PREPENDED
        add     cx,TOMONFIXEDLEN                        ; FIXED SIZE OF PKT
        pop     bx
        pop     es
        mov     ax,es:[bx].GIOSFN                       ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON PKT
        mov     [si].tomonflags,MONCLEAR                ; CLEAR THE FLAGS
        mov     BYTE PTR [si].tomonflags+1,MONPJOBTITLE ; MONITOR JOB TITLE
        mov     dh,MONTIMEOUT                           ; WAIT UNTIL TIMEOUT
        call    monwrite                                ; GIVE DATA TO MONITOR
prtioctl_pjt5:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtioctl_pjt

BREAK <SET/RET HARDWARE TIMEOUT REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_TO                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Set/Ret Hardware Timeout Request.               */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to set the hardware  */
;/*            timeout length or return the hardware timeout length    */
;/*            for a particular parallel port.                         */
;/*                                                                    */
;/* REMARKS:                                                           */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_TO                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  devdone                                      */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_to near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        cmp     es:[bx].GIOFunction,IOLW_TO             ; IF SET TIMEOUT VALUE
        les     bx,es:[bx].GIODataPack                  ; GET DATA PACKET ADDR
        je      prtioctl_to1                            ; THEN PROCESS SET TO

        ; RETURN USER-DEFINABLE HARDWARE TIMEOUT VALUE

        mov     ax,[di].timeoutmax                      ; GET CURRENT TIMEOUT
        mov     es:[bx].usertimeout,ax                  ; RETURN TIMEOUT VALUE
        jmp     SHORT prtioctl_to2

        ; SET USER-DEFINABLE HARDWARE TIMEOUT VALUE

prtioctl_to1:
        mov     ax,es:[bx].usertimeout                  ; GET TIMEOUT VALUE
        cli                                             ; DISABLE INTERRUPTS
        mov     [di].timeoutmax,ax                      ; SET TIMEOUT FOR PORT
        sti                                             ; ENABLE INTERRUPTS
prtioctl_to2:
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtioctl_to

BREAK <SET/RET DIRECT MODE ACCESS REQUEST>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  PRTIOCTL_DM                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  Set/Ret Direct Mode Access Request              */
;/*                                                                    */
;/* FUNCTION:  The function of this subroutine is to set the share     */
;/*            access flag for a particular parallel port.  With this  */
;/*            flag set, multiple physical and virtual device drivers  */
;/*            can access the parallel port hardware simultaneously.   */
;/*            The user performs the serialization.                    */
;/*                                                                    */
;/* REMARKS:                                                           */
;/*                                                                    */
;/* ENTRY POINT: PRTIOCTL_DM                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = Virtual segment of request block                   */
;/*            BX = Virtual offset of request block                    */
;/*            DI = Offset to appropriate printer data area            */
;/*                                                                    */
;/* EXIT-NORMAL:   N/A                                                 */
;/*                                                                    */
;/* EXIT-ERROR :   N/A                                                 */
;/*                                                                    */
;/* INTERNAL REFERENCES:  devdone                                      */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure prtioctl_dm near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <es,bx>                                 ; SAVE REGISTERS
        cmp     es:[bx].GIOFunction,IOLW_DM             ; IF SET DIRECT ACCESS
        les     bx,es:[bx].GIODataPack                  ; GET DATA PACKET ADDR
        je      SHORT prtioctl_dm1                      ; THEN PROCESS SET
                                                        ; ELSE RETURN VALUE
        ; RETURN DIRECT MODE ACCESS VALUE

        mov     es:[bx].useraccessflag,DISABLEDM        ; SET DIRECT MODE DISABLED
        test    [di].commonflags1,DIRMODEACCESS         ; IF DIRECT MODE !SET
        jz      SHORT prtioctl_dm4                      ; THEN ASSUMED CORRECTLY
        mov     es:[bx].useraccessflag,ENABLEDM         ; ELSE DIR MODE ENABLED
        jmp     SHORT prtioctl_dm4                      ; EXIT

        ; SET DIRECT MODE ACCESS

prtioctl_dm1:
        cmp     es:[bx].useraccessflag,ENABLEDM         ; IF NEED TO ENABLE
        je      SHORT prtioctl_dm2                      ; THEN ENABLE DIRECT
        cmp     es:[bx].useraccessflag,DISABLEDM        ; IF NEED TO DISABLE
        je      SHORT prtioctl_dm3                      ; THEN DISABLE DIRECT
        RestoreReg <bx,es>                              ; RESTORE REGISTERS
        mov     es:[bx].PktStatus,INVALIDCOMMD          ; SET ERROR CODE
        jmp     SHORT prtioctl_dm5                      ; RETURN TO CALLER

prtioctl_dm2:
        or      [di].commonflags1,DIRMODEACCESS         ; ENABLE DIRECT MODE
        jmp     SHORT prtioctl_dm4                      ; RETURN TO CALLER

prtioctl_dm3:
        and     [di].commonflags1,NOT DIRMODEACCESS     ; DISABLE DIRECT MODE

prtioctl_dm4:
        pop     bx                                      ; RESTORE REGISTERS
        pop     es                                      ; RESTORE REGISTERS
        mov     es:[bx].PktStatus,REQDONE               ; SET DONE BIT
prtioctl_dm5:
        call    devdone                                 ; ISSUE DEVICE DONE
        ret
EndProc prtioctl_dm

BREAK <VERIFY/ACCESS USER DATA BUFFER ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  VERLOCKDATA                                      */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  VERIFY ACCESS AND LOCK IOCTL DATA BUFFER        */
;/*                                                                    */
;/* FUNCTION:  The function of this routine is to verify access to     */
;/*            the user's data buffer passed to us in an ioctl request.*/
;/*            If access is ok, then the memory segment will be locked.*/
;/*                                                                    */
;/* ENTRY POINT: VERLOCKDATA                                           */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            CX = LENGTH OF AREA TO BE VERIFIED (DEFAULT)            */
;/*                                                                    */
;/* EXIT-NORMAL:  NC = Access verified                                 */
;/*               AX:CX = Lock handle                                  */
;/*                                                                    */
;/* EXIT-ERROR :  CY = Access denied                                   */
;/*               ES:[BX].PktStatus = INVALIDPARM                      */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  VerifyAccess                    */
;/*    ROUTINES:                       Lock                            */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure verlockdata near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <dx,di,es,bx>

        ; DETERMINE LENGTH OF BUFFER FOR ACCESS (IOCTL2?)

        mov     dx,es:[bx].GIODataLen                   ; GET IOCTL2 LENGTH
        or      dx,dx                                   ; IF ZERO, NOT SPECIFIED
        jz      verifydata1                             ; THEN USE DEFAULT IN CX
        cmp     cx,dx                                   ; IF DEFAULT >= IOCTL2
        jae     verifydata1                             ; THEN CODE REQS DEFAULT
        mov     cx,dx                                   ; ELSE USE IOCTL2
verifydata1:

        ; DETERMINE TYPE OF ACCESS (READ OR READWRITE)

        mov     dh,RWACCESS                             ; ASSUME WRITE ACCESS
        test    es:[bx].GIOFunction,IOFUNC_READ         ; IF RETURNING INFO
        jnz     verifydata2                             ; THEN ASSUMED CORRECT
        mov     dh,RACCESS                              ; ELSE READ ACCESS
verifydata2:

        ; VERIFY ACCESS TO DATA PACKET

        mov     di,WORD PTR es:[bx].GIODataPack         ; GET DATA BUFFER ADDR
        mov     ax,WORD PTR es:[bx].GIODataPack+2       ; AX:DI -> DATA BUFFER
        mov     dl,Devhlp_VerifyAccess                  ; VERIFY ACCESS FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jnc     verifydata4                             ; IF !ERROR, LOCK
verifydata3:
        pop     bx
        pop     es
        mov     es:[bx].PktStatus,INVALIDPARM           ; ELSE RETURN ERROR
        jmp     SHORT verifydata5                       ; EXIT

        ; LOCK MEMORY SEGMENT

verifydata4:
        mov     bh,SHORTTERM                            ; DURATION OF LOCK
        mov     bl,WAITFLAG                             ; BLOCK UNTIL LOCKED
        mov     dl,Devhlp_Lock                          ; LOCK MEMORY SEGMENT
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jc      verifydata3                             ; IF ERROR, EXIT
        mov     cx,bx
        RestoreReg <bx,es>
verifydata5:
        RestoreReg <di,dx>
        ret
EndProc verlockdata

BREAK <LOCK USER DATA BUFFER ROUTINE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  UNLOCKDATA                                       */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  UNLOCK USER IOCTL DATA BUFFER                   */
;/*                                                                    */
;/* FUNCTION:  The function of this routine is to unlock the user's    */
;/*            data buffer passed to us in an ioctl request.           */
;/*                                                                    */
;/* ENTRY POINT: UNLOCKDATA                                            */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            AX:CX = LOCK HANDLE                                     */
;/*                                                                    */
;/* EXIT-NORMAL:  NC = Segment unlocked                                */
;/*                                                                    */
;/* EXIT-ERROR :  CY = Segment not unlocked                            */
;/*                                                                    */
;/* INTERNAL REFERENCES:  NONE                                         */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  UnLock                          */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure unlockdata near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <bx,dx>
        mov     bx,cx                                   ; AX:BX = LOCK HANDLE
        mov     dl,Devhlp_Unlock                        ; UNLOCK MEMORY SEGMENT
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        RestoreReg <dx,bx>
        ret
EndProc unlockdata

BREAK <FLUSH KERNEL ACTIVATE CODE PAGE QUEUE>
;/********************** START OF SPECIFICATIONS ***********************/
;/*                                                                    */
;/* SUBROUTINE NAME:  FLUSHCPQUEUE                                     */
;/*                                                                    */
;/* DESCRIPTIVE NAME:  FLUSH KERNEL ACTIVATE CODE PAGE REQUEST QUEUE   */
;/*                                                                    */
;/* FUNCTION:  The function of this routine is issue monwrite calls    */
;/*            for all (open, close, and kernel activate code page)    */
;/*            requests in the queue.  It is unnecessary for this      */
;/*            thread to block and wait for the code page return info  */
;/*            from the monitor.  The queued requests were simulated   */
;/*            as completed successfully when they were orginally      */
;/*            issued, were queued so they would not cause a deadlock  */
;/*            when a monitor tried to issue a DosXXX call while the   */
;/*            thread had the kernel semaphore and potentially blocked */
;/*            in the monitor dispatcher.                              */
;/*                                                                    */
;/* ENTRY POINT: FLUSHCPQUEUE                                          */
;/*    LINKAGE : CALL NEAR                                             */
;/*                                                                    */
;/* INPUT:     ES = VIRTUAL SEGMENT OF REQUEST BLOCK                   */
;/*            BX = VIRTUAL OFFSET OF REQUEST BLOCK                    */
;/*            DI = OFFSET TO APPROPRIATE PERPRTDATA AREA              */
;/*            [DI].CPQUEUE = DWORD PTR TO START OF QUEUE              */
;/*                                                                    */
;/* EXIT-NORMAL:  NC                                                   */
;/*                                                                    */
;/* EXIT-ERROR :  CY                                                   */
;/*               ES:[BX].PktStatus = Error Code                       */
;/*                                                                    */
;/* INTERNAL REFERENCES:  monwrite                                     */
;/*    ROUTINES:                                                       */
;/*                                                                    */
;/* EXTERNAL REFERENCES:  DEVICE_HELP PullRequest                      */
;/*    ROUTINES:                      FreeReqPacket                    */
;/*                                   PushRequest                      */
;/*                                                                    */
;/*********************** END OF SPECIFICATIONS ************************/
Procedure flushcpqueue near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pusha                                           ; SAVE REGISTERS
        push    es
flushcpq1:
        lea     si,[di].cpqueue                         ; TOP OF QUEUE
        mov     dl,DevHlp_PullRequest                   ; GET KERNEL REQ PKT
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jnc     flushcpq10                              ; MORE REQ PKTS? YES
        jmp     flushcpq2                               ; END OF QUEUE, EXIT
flushcpq10:

        ; ISSUE OPEN REQUEST TO MONITOR

        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON BUF
        cmp     es:[bx].PktCmd,CMDOpen                  ; OPEN REQUEST
        jne     flushcpq11                              ; NO, CHECK OTHERS
        mov     ax,es:[bx].OCSFN                        ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONOPEN                 ; SET OPEN IN MON REC
        mov     cx,TOMONFIXEDLEN                        ; SET SIZE OF MON REC
        jmp     short flushcpq12                        ; ISSUE MON WRITE

        ; ISSUE KERNEL CODE PAGE REQUEST TO MONITOR - NO NEED TO WAIT FOR RC

flushcpq11:
        cmp     es:[bx].PktCmd,CMDGenIOCTL              ; GENERIC IOCTL REQUEST
        jne     flushcpq111                             ; NO, CHECK OTHERS
        mov     ax,es:[bx].GIOSFN                       ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLEAR                ; CLEAR THE FLAGS
        mov     BYTE PTR [si].tomonflags+1,MONCPFREQ + MONCPFINT17REQ ; NO RUN
        SaveReg <di>                                    ; SAVE PERPRTDATA PTR

        ; CLEAR CODE PAGE MONITOR BUFFER AREA

        lea     di,[si].tomonbuf                        ; DI -> TO MON BUF
        SaveReg <es,di>                                 ; SAVE REGISTERS
        push    ds                                      ; SET UP ES TO BE
        pop     es                                      ; SAME AS DS
        mov     ax,0                                    ; SET AX = 0
        mov     cx,CPFMONREQLEN                         ; SET COUNT FIELD
        cld                                             ; SET FORWARD DIRECT
        rep     stosw                                   ; CLEAR AREA
        RestoreReg <di,es>                              ; RESTORE REGISTERS

        ; SET ACTIVATE CODE PAGE MONITOR PACKET

        mov     [di].cpfcommnd,MONACTCPF                ; SET ACTIVATE COMMND
        mov     ax,word ptr es:[bx].GIODataPack         ; GET CODE PAGE
        mov     [di].cpfcodepg,ax                       ; SET CP IN MON REC
        mov     ax,word ptr es:[bx].GIODataPack+2       ; GET FONT
        mov     [di].cpffont,ax                         ; SET FONT IN MON REC
        RestoreReg <di>                                 ; RESTORE DATA POINTER
        mov     cx,SIZE cpfmonreq                       ; SET BYTE COUNT
        add     cx,TOMONFIXEDLEN                        ; ADD FIXED PKT SIZE
        jmp     SHORT flushcpq12                        ; ISSUE MON WRITE

        ; ISSUE CLOSE REQUEST TO MONITOR

flushcpq111:
        cmp     es:[bx].PktCmd,CMDClose                 ; CLOSE REQUEST
        jne     flushcpq121                             ; NO, IGNORE PACKET
        mov     ax,es:[bx].OCSFN                        ; GET SFN FROM REQ BLK
        mov     [si].tomonsfn,ax                        ; SET SFN IN MON REC
        mov     [si].tomonflags,MONCLOSE                ; SET CLOSE IN MON REC
        mov     cx,TOMONFIXEDLEN                        ; SET SIZE OF MON REC

        ; ISSUE MONWRITE

flushcpq12:
        mov     dh,MONTIMEOUT                           ; WAIT UNTIL TIMEOUT
        call    monwrite                                ; SEND REQ TO SPOOLER
        jc      flushcpq13                              ; JMP IF ERROR

flushcpq121:
        mov     dl,DevHlp_FreeReqPacket                 ; FREE ALLOC REQ PKT
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        jmp     flushcpq1                               ; REP UNTIL QUE EMPTY

flushcpq13:
        mov     ax,es:[bx].PktStatus                    ; GET ERROR CODE
        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON BUF
        mov     WORD PTR [si].tomonbuf,ax               ; SAVE ERROR CODE - TEMP
        lea     si,[di].cpqueue                         ; TOP OF QUEUE
        mov     dl,devhlp_PushRequest                   ; PUT BACK ON QUEUE
        call    DWORD PTR [device_help]                 ; CALL DEVICE HELP
        pop     es
        popa                                            ; RESTORE REGISTERS
        stc                                             ; SET CARRY FLAG - ERROR
        SaveReg <si>                                    ; SAVE SI REGISTER
        mov     si,[di].tomonbuf_off                    ; DS:SI -> TO MON BUF
        mov     ax,WORD PTR [si].tomonbuf               ; GET ERROR CODE - TEMP
        RestoreReg <si>                                 ; RESTORE SI REGISTER
        mov     es:[bx].PktStatus,ax                    ; SAVE ERROR CODE
        jmp     SHORT flushcpq3                         ; EXIT

flushcpq2:
        clc                                             ; CLEAR CARRY - NO ERROR
        pop     es
        popa                                            ; RESTORE REGISTERS
flushcpq3:
        ret
EndProc flushcpqueue

SWAPSEG ENDS
        END
