
; SCCSID = @(#)prtplpt.asm      6.9 91/08/27
;/**********************************************************************
;/*                                                                    *
;/*                       IBM/Microsoft Confidential                   *
;/*                                                                    *
;/*                 Copyright (c) IBM Corporation  1987, 1990          *
;/*                 Copyright (c) Microsoft Corp.  1987, 1990          *
;/*                           All Rights Reserved                      *
;/*                                                                    *
;/**********************************************************************
 TITLE PRINTDD - PRINTER DEVICE DRIVER IDC 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:
;       PLPTCMD_ENTRY  (VDD-PDD IDC)
;        VDMREGISTER
;        VDMDEREGISTER
;        PRTREQEXCLUSIVE,HYBRID
;         CHECKDIRECTACCESS
;        PRTRELEXCLUSIVE,HYBRID
;         FREEDIRECTACCESS
;        VDMRETPARBUFSIZE
;        PRTQUERYDENIEDACCESS,HYBRID
;       PRTREQDIRECT   (PRT worker)
;       PRTRELDIRECT   (PRT worker)
;       PRTPDD_ENTRY   (PDD-PDD IDC)
;***********************************************************************

        .XCREF
        .XLIST
        INCLUDE basemaca.inc            ; VARIOUS MACRO'S (BREAK, LJC, ETC.)
        INCLUDE osmaca.inc
        INCLUDE devsym.inc
        INCLUDE devhlp.inc              ; DEFINITION OF DEVICE HELP CALLS.
        .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   device_help:DWORD
        EXTRN   perprtarea:BYTE
        EXTRN   deinstallflg:BYTE
        PUBLIC  plptname

        EVEN
plptname        db      'LPT',0         ; DEVICE DRIVER NAME FOR DH_REGISTERPDD

plpttbl LABEL   WORD                            ; CALL TABLE VDD/PDD ROUTINES
        dw      OFFSET vdmregister              ; 0 FUNCTION
        dw      OFFSET vdmderegister            ; 1 FUNCTION
        dw      OFFSET prtreqexclusive          ; 2 FUNCTION
        dw      OFFSET prtrelexclusive          ; 3 FUNCTION
        dw      OFFSET vdmretparbufsize         ; 4 FUNCTION
PLPTTBLMAX EQU  ($ - plpttbl)/2-1               ; MAX ENTRIES - ZERO BASED

DSEG   ENDS

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

        EXTRN initialprt:NEAR
        EXTRN getpid:NEAR

BREAK <VDD-PDD IDC ENTRY POINT>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PLPTCMD_Entry                                     */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Printer Physical Device Driver IDC entry         */
;/*                    point and request router routine.                */
;/*                                                                     */
;/* FUNCTION:  This routine is the Printer Physical Device Driver IDC   */
;/*            entry point router/handler. IDC function requests are    */
;/*            routed to the appropriate worker routine. The address    */
;/*            of this routine is setup via the DevHelp RegisterPDD     */
;/*            call during initialization.                              */
;/*                                                                     */
;/* ENTRY POINT :  PLPTCMD_Entry                                        */
;/*    LINKAGE  :  CALL FAR                                             */
;/*                                                                     */
;/* INPUT:  On entry the stack is set-up as shown below:                */
;/*                                                                     */
;/*         TOS --> return address (4 words)                            */
;/*                 variable 2     (2 words)                            */
;/*                 variable 1     (2 words)                            */
;/*                 function code  (2 words)                            */
;/*                                                                     */
;/* Where: Variable 1 and 2 are specified in the worker routines.       */
;/*        BX:CX =  variable 1                                          */
;/*        DX:DI -> variable 2                                          */
;/*                                                                     */
;/* EXIT-NORMAL:  EAX = 0                                               */
;/*                                                                     */
;/* EXIT-ERROR:  EAX = error return code                                */
;/*                                                                     */
;/* EFFECTS:  NONE                                                      */
;/*                                                                     */
;/* INTERNAL REFERENCES:  plpttbl[]                                     */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure plptcmd_entry far
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

  ?abase = 8 + 2
  ArgVar var2 DWORD
  ArgVar var1 DWORD
  ArgVar func DWORD

        enterproc
        SaveReg <es,ds,bx,cx,dx,si,di>
        push    ds
        pop     es                                      ; ES = CALLER'S DS
        push    DSEG                                    ;%% SETUP DS
        pop     ds                                      ;%%
.386C
        xor     eax,eax                                 ; CLEAR EXTENDED AX
.286C
        mov     si,WORD PTR func                        ; GET FUNCTION CODE
        cmp     si,PLPTTBLMAX                           ; IF INVALID FUNC CODE
        ja      plptcmd_e1                              ; THEN EXIT, ERROR
        mov     cx,WORD PTR var1                        ; LOW WORD, VAR1
        mov     bx,WORD PTR var1+2                      ; HIGH WORD, VAR1
        mov     di,WORD PTR var2                        ; LOW WORD, VAR2
        mov     dx,WORD PTR var2+2                      ; HIGH WORD, VAR2
        shl     si,1                                    ; MAKE WORD INDEX
        call    WORD PTR plpttbl[si]                    ; PERFORM FUNCTION
        jmp     SHORT plptcmd_e2                        ; EXIT
plptcmd_e1:
        mov     ax,ERROR_I24_INVALID_PARAMETER          ; SET ERROR CODE
plptcmd_e2:
        RestoreReg <di,si,dx,cx,bx,ds,es>
        leaveproc
        db      66h                                     ; 32-BIT OVERRIDE
        ret     12                                      ; 32-BIT RETURN
EndProc plptcmd_entry

BREAK <REGISTER VLPT IDC ENTRY POINT ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  VDMRegister                                       */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Register VLPT IDC entry point address.           */
;/*                                                                     */
;/* FUNCTION:  This routine is the printer physical device driver       */
;/*            register VLPT worker routine.  It saves the 16:32        */
;/*            address of the VLPT IDC router in the printer device     */
;/*            driver's data segment.                                   */
;/*                                                                     */
;/* NOTE:  Currently, this interface is unidirectional, VLPT calls      */
;/*        the PLPT so this function in a nop.                          */
;/*                                                                     */
;/* ENTRY POINT :  VDMRegister                                          */
;/*    LINKAGE  :  CALL NEAR                                            */
;/*                                                                     */
;/* INPUT:  DS = data segment selector address                          */
;/*         SI = 16 bit Segment of the VLPT Entry Point                 */
;/*         DX:DI = 32 bit Offset of the VLPT Entry Point               */
;/*                                                                     */
;/* EXIT-NORMAL:  VLPT entry point address saved.                       */
;/*               EAX = 1                                               */
;/*                                                                     */
;/* EXIT-ERROR:  N/A                                                    */
;/*                                                                     */
;/* EFFECTS:  VLPT address is saved.                                    */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure vdmregister near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     ax,1                                    ; SET GOOD RETURN CODE
        ret
EndProc vdmregister

BREAK <DEREGISTER VLPT IDC ENTRY POINT ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  VDMDeRegister                                     */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Deregister VLPT IDC entry point address.         */
;/*                                                                     */
;/* FUNCTION:  This routine is the printer physical device driver       */
;/*            deregister VLPT worker routine.  It clears the 16:32     */
;/*            address of the VLPT IDC router in the printer device     */
;/*            driver's data segment.                                   */
;/*                                                                     */
;/* NOTE:  Currently, this interface is unidirectional, VLPT calls      */
;/*        the PLPT so this function in a nop.                          */
;/*                                                                     */
;/* ENTRY POINT :  VDMDeRegister                                        */
;/*    LINKAGE  :  CALL NEAR                                            */
;/*                                                                     */
;/* INPUT:  DS = data segment selector address                          */
;/*                                                                     */
;/* EXIT-NORMAL:  VLPT entry point address cleared.                     */
;/*               EAX = 1                                               */
;/*                                                                     */
;/* EXIT-ERROR:  N/A                                                    */
;/*                                                                     */
;/* EFFECTS:  VLPT address is cleared.                                  */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure vdmderegister near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        mov     ax,1                                    ; SET GOOD RETURN CODE
        ret
EndProc vdmderegister

BREAK <REQUEST DIRECT HARDWARE ACCESS ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PrtReqExclusive                                   */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Request Exclusive Parallel Port Usage.           */
;/*                                                                     */
;/* FUNCTION:  This routine is the physical parallel port device driver */
;/*            request exclusive parallel port usage worker routine.    */
;/*            It determines if a (physical or virtual) device driver   */
;/*            already has exclusive access of the port.  If no one has */
;/*            exclusive access to the parallel port, then exclusive    */
;/*            access is granted.  Exclusive access to the parallel port*/
;/*            remains in effect until an PrtRelExclusive call is made. */
;/*                                                                     */
;/* NOTE:  User can set "Share Access" checkbox in print object to      */
;/*        specify that user will perform serialization of access to    */
;/*        parallel port hardware.                                      */
;/*                                                                     */
;/* ENTRY POINT :  PrtReqExclusive                                      */
;/*    LINKAGE  :  CALL NEAR OR FAR                                     */
;/*                                                                     */
;/* INPUT:  ES = caller's ds                                            */
;/*         DS = data segment selector address                          */
;/*         BX = flags (Bit 0 = 1 block until exclusive is available)   */
;/*         CX = port id (0 = lpt1, 1 = lpt2, 2 = lpt3)                 */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0, Caller granted exclusive access.              */
;/*                                                                     */
;/* EXIT-ERROR:  AX = ERROR_I24_INVALID_PARAMETER if bad port id        */
;/*              AX = ERROR_I24_CHAR_CALL_INTERRUPTED                   */
;/*              AX = ERROR_I24_DEVICE_IN_USE                           */
;/*                                                                     */
;/* EFFECTS:  NONE                                                      */
;/*                                                                     */
;/* INTERNAL REFERENCES:  checkdirectaccess                             */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure prtreqexclusive,hybrid
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        cmp     cx,MAXPRINTERS                          ; IF PORT ID >= MAX
        jae     prtreqex_1                              ; EXIT ERROR

        imul    di,cx,SIZE printer_database             ; CALC OFF IN PERPRTDATA
        add     di,OFFSET perprtarea                    ; ADD START ADDRESS

        mov     al,[di].deviceflag                      ; GET DEVICE FLAG
        test    deinstallflg,al                         ; IF DEVICE DEINSTALLED
        jnz     prtreqex_1                              ; DON'T GIVE EXCLUSIVE

        call    checkdirectaccess                       ; REQUEST DIRECT ACCESS
        jmp     SHORT prtreqex_2                        ; EXIT
prtreqex_1:
        mov     ax,ERROR_I24_INVALID_PARAMETER          ; INVALID PORT PARM
prtreqex_2:
        ret
EndProc prtreqexclusive

BREAK <CHECK FOR DIRECT ACCESS ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  CheckDirectAccess                                 */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Grant direct access privilege when no one else   */
;/*                    has it.                                          */
;/*                                                                     */
;/* FUNCTION:  This routine will test to see if a physical or virtual   */
;/*            device driver has requested direct access to the parallel*/
;/*            port hardware and if so the caller can block until the   */
;/*            device driver with direct access releases it.            */
;/*                                                                     */
;/* NOTE:  User can set "Share Access" checkbox in print object to      */
;/*        specify that user will perform serialization of access to    */
;/*        parallel port hardware.                                      */
;/*                                                                     */
;/* ENTRY POINT :  checkdirectaccess                                    */
;/*    LINKAGE  :  CALL NEAR                                            */
;/*                                                                     */
;/* INPUT:  ES = caller's ds                                            */
;/*         BX = flags (Bit 0 = 1 block until exclusive is available)   */
;/*      DS:DI = address of appropriate perprtdata area                 */
;/*                                                                     */
;/* EXIT-NORMAL: NC = NO ERROR                                          */
;/*              AX = 0                                                 */
;/*                                                                     */
;/* EXIT-ERROR:  CY = ERROR                                             */
;/*              AX = ERROR_I24_CHAR_CALL_INTERRUPTED                   */
;/*              AX = ERROR_I24_DEVICE_IN_USE                           */
;/*                                                                     */
;/* EFFECTS:  DIRECTACCESS flag is set.                                 */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcBlock                        */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure checkdirectaccess near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        pusha                                           ; SAVE REGISTERS
checkdir1:
        cli                                             ; DISABLE INTERRUPTS
        test    [di].commonflags1,DIRMODEACCESS         ; IF SHARE ACCESS IS ON
        jnz     checkdir3                               ; ALL CAN ACCESS PORT

        test    [di].commonflags1,DIRECTACCESS          ; IF NO ONE HAS DIRECT
        jz      checkdir3                               ; THEN GIVE DIRECTACCESS

        ; PHYSICAL OR VIRTUAL DD HAS DIRECT ACCESS ON THIS PORT

        cmp     bx,1                                    ; WILLING TO BLOCK?
        jne     checkdir2                               ; NO, RETURN ERROR

        push    bx
        push    di

        inc     [di].waitcount                          ; INC NUMBER WAITING
        mov     ax,ds                                   ; SEL OF PRTPRTDATA AREA
        mov     bx,di                                   ; OFF OF PRTPRTDATA AREA
        mov     cx,BLOCKLOWVALUE                        ; -1 NEVER TIMEOUT
        mov     di,BLOCKHIVALUE                         ; -1 NEVER TIMEOUT
        mov     dh,BLOCKSLEEPINT                        ; SLEEP INTERRUPTIBLE
        mov     dl,DevHlp_ProcBlock                     ; BLOCK FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO BLOCK

        pop     di
        pop     bx
        pushf
        dec     [di].waitcount                          ; DEC NUMBER WAITING
        popf
        jnc     checkdir1                               ; JMP IF WAKEUP OK
        jz      checkdir1                               ; JMP IF TIMEOUT

        ; RETURN UNUSUAL WAKEUP ERROR

        popa                                            ; RESTORE REGISTERS
        mov     ax,ERROR_I24_CHAR_CALL_INTERRUPTED      ; SET ERROR RETURN CODE
        stc                                             ; SET CARRY FLAG
        jmp     SHORT checkdir4                         ; EXIT

        ; RETURN DEVICE IN USE ERROR

checkdir2:
        or      [di].commonflags1,DENIEDACCESS          ; SET DENIEDACCESS FLAG
        popa                                            ; RESTORE REGISTERS
        mov     ax,ERROR_I24_DEVICE_IN_USE              ; SET ERROR RETURN CODE
        stc                                             ; SET CARRY FLAG
        jmp     SHORT checkdir4                         ; EXIT

        ; SET TO DIRECT MODE

checkdir3:
        and     [di].commonflags1,NOT DENIEDACCESS      ; CLEAR DENIEDACCESS
        or      [di].commonflags1,DIRECTACCESS          ; SET CALLER TO DIRECT
        mov     [di].directid,es                        ; SAVE OWNER DIRECT MODE
        popa                                            ; RESTORE REGISTERS
        xor     ax,ax                                   ; SET GOOD RETURN CODE
        clc                                             ; CLEAR CARRY FLAG

        ; EXIT

checkdir4:
        sti                                             ; ENABLE INTERRUPTS
        ret
EndProc checkdirectaccess

BREAK <RELEASE DIRECT HARDWARE ACCESS ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PrtRelExclusive                                   */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Release Exclusive Parallel Port Usage.           */
;/*                                                                     */
;/* FUNCTION:  This routine is the physical parallel port device driver */
;/*            release exclusive parallel port usage worker routine.    */
;/*            It determines if a physical or virtual device driver has */
;/*            exclusive access to the port and releases it.  If a      */
;/*            device driver is blocked waiting for access, it will be  */
;/*            run so that it can obtain direct access priviledge to    */
;/*            the port.                                                */
;/*                                                                     */
;/* NOTE:  User can set "Share Access" checkbox in print object to      */
;/*        specify that user will perform serialization of access to    */
;/*        parallel port hardware.                                      */
;/*                                                                     */
;/* ENTRY POINT :  PrtRelExclusive                                      */
;/*    LINKAGE  :  CALL NEAR OR FAR                                     */
;/*                                                                     */
;/* INPUT:  ES = caller's ds                                            */
;/*         DS = data segment selector address                          */
;/*         CX = port id (0 = lpt1, 1 = lpt2, 2 = lpt3)                 */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0, Caller granted release of exclusive access.   */
;/*                                                                     */
;/* EXIT-ERROR:  AX = ERROR_I24_INVALID_PARAMETER if bad port id        */
;/*                                                                     */
;/* EFFECTS:  NONE                                                      */
;/*                                                                     */
;/* INTERNAL REFERENCES:  freedirectaccess                              */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure prtrelexclusive,hybrid
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        cmp     cx,MAXPRINTERS                          ; IF PORT ID >= MAX
        jae     prtrelex_1                              ; EXIT ERROR

        imul    di,cx,SIZE printer_database             ; CALC OFF IN PERPRTDATA
        add     di,OFFSET perprtarea                    ; ADD START ADDRESS

        call    freedirectaccess                        ; FREE DIRECT ACCESS
        jmp     SHORT prtrelex_2                        ; EXIT
prtrelex_1:
        mov     ax,ERROR_I24_INVALID_PARAMETER          ; INVALID PORT PARM
prtrelex_2:
        ret
EndProc prtrelexclusive

BREAK <FREE DIRECT ACCESS ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  FreeDirectAccess                                  */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Free direct access privilege so others can       */
;/*                    access the hardware.                             */
;/*                                                                     */
;/* FUNCTION:  This routine will run any threads blocked waiting for    */
;/*            direct access to the parallel port hardware.             */
;/*                                                                     */
;/* NOTE:  User can set "Share Access" checkbox in print object to      */
;/*        specify that user will perform serialization of access to    */
;/*        parallel port hardware.                                      */
;/*                                                                     */
;/* ENTRY POINT :  freedirectaccess                                     */
;/*    LINKAGE  :  CALL NEAR                                            */
;/*                                                                     */
;/* INPUT:  ES = caller's ds                                            */
;/*         DS:DI = address of appropriate perprtdata area              */
;/*                                                                     */
;/* EXIT-NORMAL: NC = NO ERROR                                          */
;/*              AX = 0                                                 */
;/*                                                                     */
;/* EXIT-ERROR:  CY = ERROR                                             */
;/*              AX = ERROR_I24_DEVICE_IN_USE                           */
;/*                                                                     */
;/* EFFECTS:  DIRECTACCESS flag is clear.                               */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  DEVICE_HELP  ProcRun                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure freedirectaccess near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        pusha                                           ; SAVE REGISTERS
        test    [di].commonflags1,DIRMODEACCESS         ; IF SHARE ACCESS = ON
        jnz     freedirect0                             ; THEN NO OWNER CHECK
        mov     ax,es
        cmp     [di].directid,ax                        ; IF OWNER != CURRENT
        jne     freedirect1                             ; ERROR, EXIT
freedirect0:
        and     [di].commonflags1,NOT DIRECTACCESS      ; CLR DIRECT ACCESS FLAG

        mov     ax,ds                                   ; SEL OF PRTPRTDATA AREA
        mov     bx,di                                   ; OFF OF PRTPRTDATA AREA
        mov     dl,DevHlp_ProcRun                       ; RUN FUNCTION
        call    DWORD PTR [device_help]                 ; START WAITING THREADS

        popa                                            ; RESTORE REGISTERS
        xor     ax,ax                                   ; SET RETURN CODE
        clc                                             ; CLEAR CARRY FLAG
        jmp     SHORT freedirect2                       ; EXIT
freedirect1:
        popa                                            ; RESTORE REGISTERS
        mov     ax,ERROR_I24_DEVICE_IN_USE              ; SET ERROR RETURN CODE
        stc                                             ; SET CARRY FLAG
freedirect2:
        ret
EndProc freedirectaccess

BREAK <RETURN PARALLEL BUFFER SIZE ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  VDMRetParBufSize                                  */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Return parallel buffer size routine.             */
;/*                                                                     */
;/* FUNCTION:  This routine is the printer physical device driver       */
;/*            return parallel port buffer size worker routine.         */
;/*            This allows the virtual device driver to maximize its    */
;/*            buffer to the size of the physical parallel port device  */
;/*            driver buffer size.                                      */
;/*                                                                     */
;/* ENTRY POINT :  VDMRetParBufSize                                     */
;/*    LINKAGE  :  CALL NEAR                                            */
;/*                                                                     */
;/* INPUT:  DS = data segment selector address                          */
;/*         CX = port id (0 = lpt1, 1 = lpt2, 2 = lpt3)                 */
;/*         DX:DI = SELECTOR:OFFSET return area                         */
;/*                                                                     */
;/* EXIT-NORMAL:  DX:DI -> contains parallel port buffer size.          */
;/*               EAX = 0                                               */
;/*                                                                     */
;/* EXIT-ERROR:  EAX = INVALIDPARM if bad port id                       */
;/*                                                                     */
;/* EFFECTS:                                                            */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure vdmretparbufsize near
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        cmp     cx,MAXPRINTERS                          ; IF PORT ID >= MAX
        jae     vdmretpar1                              ; EXIT ERROR

        push    di                                      ; SAVE REGISTER
        imul    di,cx,SIZE printer_database             ; CALC OFF IN PERPRTDATA
        add     di,OFFSET perprtarea                    ; ADD START ADDRESS
        mov     ax,[di].configbufsize                   ; GET MON BUFFER SIZE
        sub     ax,FROMMONFIXEDLEN                      ; SUBTRACT FIXED PART
        pop     di                                      ; RESTORE REGISTER

        mov     es,dx                                   ; ES:DI -> STRUCTURE
        mov     es:[di],ax                              ; RETURN PAR BUF SIZE

        xor     ax,ax                                   ; RETCODE = NO ERROR
        jmp     SHORT vdmretpar2
vdmretpar1:
        mov     ax,ERROR_I24_INVALID_PARAMETER          ; INVALID PORT PARM
vdmretpar2:
        ret
EndProc vdmretparbufsize

BREAK <QUERY DENIED ACCESS ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PrtQueryDeniedAccess                              */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Query Denied Access Routine.                     */
;/*                                                                     */
;/* FUNCTION:  This routine is the physical parallel port device driver */
;/*            query denied access routine.  It can be used by the      */
;/*            device driver that owns exclusive access to the parallel */
;/*            port to determine whether another device driver wants    */
;/*            exclusive access to the parallel port hardware. If       */
;/*            another device driver was denied access or is currently  */
;/*            waiting for access, this routine returns AX = FFFFh.     */
;/*            Other device drivers with queued requests can use this   */
;/*            routine to decide when to release exclusive access to    */
;/*            the parallel port.                                       */
;/*                                                                     */
;/* NOTE:  User can set "Share Access" checkbox in print object to      */
;/*        specify that user will perform serialization of access to    */
;/*        parallel port hardware.  When set, this routine always       */
;/*        returns zero (no caller denied access).                      */
;/*                                                                     */
;/* ENTRY POINT :  PrtQueryDeniedAccess                                 */
;/*    LINKAGE  :  CALL NEAR OR FAR                                     */
;/*                                                                     */
;/* INPUT:  ES = caller's ds                                            */
;/*         DS = data segment selector address                          */
;/*         CX = port id (0 = lpt1, 1 = lpt2, 2 = lpt3)                 */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0, No caller denied access or waiting for access.*/
;/*                                                                     */
;/* EXIT-ERROR:  AX = FFFFh, caller denied access or is waiting.        */
;/*                                                                     */
;/* EFFECTS:  NONE                                                      */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure prtquerydeniedaccess,hybrid
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        mov     ax,0ffffh                               ; ASSUME SOMEONE WAITING
        cmp     cx,MAXPRINTERS                          ; IF PORT ID >= MAX
        jae     prtqueryden1                            ; EXIT ERROR

        imul    di,cx,SIZE printer_database             ; CALC OFF IN PERPRTDATA
        add     di,OFFSET perprtarea                    ; ADD START ADDRESS

        cmp     [di].waitcount,0                        ; SOMEONE BLOCKED?
        jne     prtqueryden1                            ; YES
        test    [di].commonflags1,DENIEDACCESS          ; ANYONE DENIED?
        jnz     prtqueryden1                            ; YES
        sub     ax,ax                                   ; NO, CLEAR AX
prtqueryden1:
        ret
EndProc prtquerydeniedaccess

BREAK <REQUEST DIRECT ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PRTREQDIRECT                                      */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Request direct access to the parallel port.      */
;/*                                                                     */
;/* FUNCTION:  This routine is called by the parallel port device driver*/
;/*            to see if another physical device driver or a virtual    */
;/*            device driver has exclusive access to the parallel port. */
;/*            This routine will request that the caller's thread be    */
;/*            blocked until direct access to the parallel port can be  */
;/*            granted.                                                 */
;/*                                                                     */
;/* ENTRY POINT :  prtreqdirect                                         */
;/*    LINKAGE  :  CALL NEAR OR FAR                                     */
;/*                                                                     */
;/* INPUT:  ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                      */
;/*         BX = VIRTUAL  OFFSET OF REQUEST BLOCK                       */
;/*         DI = OFFSET TO APPROPRIATE PERPRTDATA AREA                  */
;/*                                                                     */
;/* EXIT-NORMAL: NC = NO ERROR                                          */
;/*                                                                     */
;/* EXIT-ERROR:  CY = ERROR                                             */
;/*              ES:[BX].PktStatus = STERR + STDON + error code         */
;/*                                                                     */
;/* EFFECTS:  PDDDIRACCESS                                              */
;/*                                                                     */
;/* INTERNAL REFERENCES:  checkdirectaccess                             */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure prtreqdirect,HYBRID
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        push    ax

        ; if have new request, and if the driver is configured to use the
        ; polling protocol and if someone was previously denied exclusive
        ; access, then block for 2 ticks so that the other driver has chance
        ; to obtain exclusive access. The other driver may be an ADD (parallel
        ; port attached CD-ROM drive), be executing at interrupt time (can not
        ; block), and can only request exclusive access each timer tick.

        test    [di].commonflags, USEPOLLING            ; DEV CONFIG FOR POLLING
        jz      prtreqdir0                              ; NO

        test    [di].commonflags1,DENIEDACCESS          ; DRIVER DENIED ACCESS?
        jz      prtreqdir0                              ; NO

        SaveReg <ax,bx,cx,dx,di>

        mov     ax,ds                                   ; SEL OF PRTPRTDATA AREA
        mov     bx,di                                   ; OFF OF PRTPRTDATA AREA
        mov     cx,64                                   ; 2 TICKS TIMEOUT
        mov     di,0                                    ; 2 TICKS TIMEOUT
        mov     dh,BLOCKSLEEPNOTINT                     ; SLEEP !INTERRUPTIBLE
        mov     dl,DevHlp_ProcBlock                     ; BLOCK FUNCTION
        call    DWORD PTR [device_help]                 ; CALL DEVHLP TO BLOCK

        RestoreReg <di,dx,cx,bx,ax>
prtreqdir0:
        push    es                                      ; SAVE REGISTER
        push    bx                                      ; SAVE REGISTER
        push    ds
        pop     es                                      ; ES = CALLER'S DS
        mov     bx,1                                    ; WAIT FOR ACCESS
        call    checkdirectaccess                       ; REQ EXCLUSIVE ACCESS
        pop     bx                                      ; RESTORE REGISTER
        pop     es                                      ; RESTORE REGISTER
        jc      prtreqdir1                              ; ERROR, EXIT
        or      [di].commonflags1,PDDDIRACCESS          ; TURN FLAG ON
        jmp     SHORT prtreqdir2                        ; EXIT

prtreqdir1:
        mov     es:[bx].PktStatus,ax                    ; SET ERROR CODE
        or      es:[bx].PktStatus,STERR + STDON         ; SET ERROR & DONE BIT
        stc                                             ; SET CARRY FLAG AGAIN
prtreqdir2:
        pop     ax
        ret
EndProc prtreqdirect

BREAK <RELEASE DIRECT ROUTINE>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PRTRELDIRECT                                      */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Release direct access to the parallel port.      */
;/*                                                                     */
;/* FUNCTION:  This routine is called by the parallel port device driver*/
;/*            to release direct access to the parallel port.           */
;/*                                                                     */
;/* ENTRY POINT :  prtreldirect                                         */
;/*    LINKAGE  :  CALL NEAR OR FAR                                     */
;/*                                                                     */
;/* INPUT:  ES = VIRTUAL  SEGMENT OF REQUEST BLOCK                      */
;/*         BX = VIRTUAL  OFFSET OF REQUEST BLOCK                       */
;/*         DI = OFFSET TO APPROPRIATE PERPRTDATA AREA                  */
;/*                                                                     */
;/* EXIT-NORMAL: NC = NO ERROR                                          */
;/*                                                                     */
;/* EXIT-ERROR:  CY = ERROR                                             */
;/*              ES:[BX].PktStatus = STERR + STDON + error code         */
;/*                                                                     */
;/* EFFECTS:  PDDDIRACCESS                                              */
;/*                                                                     */
;/* INTERNAL REFERENCES:  freedirectaccess                              */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure prtreldirect,HYBRID
        ASSUME  CS:SWAPSEG,DS:DSEG,ES:NOTHING,SS:NOTHING

        pushf
        cli
        push    ax
        push    es                                      ; SAVE REGISTER
        push    ds
        pop     es                                      ; ES = CALLER'S DS
        call    freedirectaccess                        ; REL EXCLUSIVE ACCESS
        pop     es                                      ; RESTORE REGISTER
        jc      prtreldir1                              ; ERROR, EXIT
        and     [di].commonflags1,NOT PDDDIRACCESS      ; TURN FLAG OFF
        jmp     SHORT prtreldir2                        ; EXIT

prtreldir1:
        mov     es:[bx].PktStatus,ax                    ; SET ERROR CODE
        or      es:[bx].PktStatus,STERR + STDON         ; SET ERROR & DONE BIT
        stc                                             ; SET CARRY FLAG AGAIN
prtreldir2:
        pop     ax
        sti
        popf
        ret
EndProc prtreldirect

SWAPSEG ENDS

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

BREAK <PDD-PDD IDC ENTRY POINT>
;/******************* START OF SPECIFICATIONS ***************************/
;/*                                                                     */
;/* SUBROUTINE NAME:  PRTPDD_Entry                                      */
;/*                                                                     */
;/* DESCRIPTIVE NAME:  Parallel Port Device Driver PDD-PDD IDC entry    */
;/*                    point and request router routine.                */
;/*                                                                     */
;/* FUNCTION:  This routine is the Parallel Port Device Driver PDD-PDD  */
;/*            IDC entry point router/handler. IDC function requests are*/
;/*            routed to the appropriate worker routine. The address    */
;/*            of this routine is returned to other device drivers via  */
;/*            the DevHelp AttachDD call.                               */
;/*                                                                     */
;/* ENTRY POINT :  PRTPDD_Entry                                         */
;/*    LINKAGE  :  CALL FAR                                             */
;/*                                                                     */
;/* INPUT:  On entry, the following registers must be setup.            */
;/*                                                                     */
;/*         AX = function code                                          */
;/*         BX = flags                                                  */
;/*         CX = port id (0, 1, or 2 for LPT1, LPT2, or LPT3)           */
;/*         DS = parallel port device driver data segment               */
;/*         ES = caller's DS                                            */
;/*                                                                     */
;/* Where: flags depends upon the function being called.                */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0                                                */
;/*                                                                     */
;/* EXIT-ERROR:  AX = error return code                                 */
;/*                                                                     */
;/* EFFECTS:  NONE                                                      */
;/*                                                                     */
;/* INTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/* EXTERNAL REFERENCES:  NONE                                          */
;/*    ROUTINES:                                                        */
;/*                                                                     */
;/******************* END  OF  SPECIFICATIONS ***************************/
Procedure prtpdd_entry far
        ASSUME  CS:CSEG,DS:DSEG,ES:NOTHING,SS:NOTHING
        SaveReg <bx,cx,dx,si,di,es>                     ; SAVE REGISTERS

        cmp     ax,0                                    ; IF ! FUNCTION 0
        jne     prtpdd_e0                               ; THEN TRY NEXT ONE
        CALLFAR prtreqexclusive                         ; CALL REQ EXCLUSIVE
        jmp     SHORT prtpdd_e2                         ; EXIT
prtpdd_e0:
        cmp     ax,1                                    ; IF ! FUNCTION 1
        jne     prtpdd_e1                               ; THEN TRY NEXT ONE
        CALLFAR prtrelexclusive                         ; CALL REQ EXCLUSIVE
        jmp     SHORT prtpdd_e2                         ; EXIT
prtpdd_e1:
        cmp     ax,2                                    ; IF ! FUNCTION 2
        jne     prtpdd_e20                              ; THEN TRY NEXT ONE
        CALLFAR prtquerydeniedaccess                    ; CALL QRY DENIED ACCESS
        jmp     SHORT prtpdd_e2                         ; EXIT
prtpdd_e20:
        mov     ax,ERROR_I24_INVALID_PARAMETER          ; SET ERROR CODE
prtpdd_e2:
        RestoreReg <es,di,si,dx,cx,bx>                  ; RESTORE REGISTERS
        ret
EndProc prtpdd_entry

CSEG    ENDS
        END
