;       SCCSID = @(#)vcomi14.asm	6.7 92/03/20

        Page    ,132
        NAME    VCOM
        TITLE   VCOM     - Virtual COM device driver
        SUBTTL  VCOMI14.ASM - VCOM Int 14h handler
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;;;;;;;;;;;;;;;;;;;;;;; START OF FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;
;SOURCE FILE NAME: VCOMI14.ASM
;
;DESCRIPTIVE NAME: VCOM Int 14h handler
;
;FUNCTION:
;       This file contains procedures that simulate the CBIOS Int 14h
;       functions.
;
;SUBROUTINES:
;       Int14h_Init
;       Int14h_Rx
;       Int14h_Tx
;       Int14h_Status
;       Int14h_xCtl
;       Int14h_xInit
;       Int14h_Wait
;       Int14h_Get_TimeOut
;       Int14h_Timeout_Proc
;
;INTERNAL REFERENCES:
;      Virt_ComIn
;      Virt_ComOut
;      Set_DLLDLM_Request
;      Set_MCR_Request
;      Set_LCR_Request
;      Get_VMSR
;      Check_PortOwner
;
;EXTERNAL REFERENCES:
;       VDHQuerySysValue
;       VDHWaitVIRRs
;       VDHQueryHookData
;       VDHArmTimerHook
;       VDHDisarmTimerHook
;
;;;;;;;;;;;;;;;;;;;;;;; END OF FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Jin Kim
;       Yoshihiko Nishida
;       Allen C. Wynn
;       (c) International Business Machines Corporation
;       January 1989
;
;Modification History
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        .386p

.xlist
include STRUC.INC
include VCOM.INC
include mvdm.inc
.list

include VDDSEG.INC
include VCOMDATA.INC

DefCode     EXPORT,SWAP,PASCAL            ;start CSWAP_TEXT segment
        DefFn  Int14h_Init                  ;Export definitions
        DefFn  Int14h_Rx
        DefFn  Int14h_Tx
        DefFn  Int14h_Status
        DefFn  Int14h_xCtl
        DefFn  Int14h_xInit
        DefFn  Int14h_Wait
        DefFn  Int14h_Get_TimeOut
EndCode                                ;End CSWAP_TEXT segment


DefCode     IMPORT,SWAP,PASCAL            ;start CSWAP_TEXT segment
        DefFn Virt_ComIn                    ;Imported fuctions
        DefFn Virt_ComOut
        DefFn Set_DLLDLM_Request
        DefFn Set_MCR_Request
        DefFn Set_LCR_Request
        DefFn Get_VMSR
        DefFn Check_PortOwner
        EXTRN Int14h_Main_Ret:NEAR        ;return point for Int14 procs
EndCode                                   ;End CSWAP_TEXT segment

DefCode     IMPORT,GLOBAL,PASCAL            ;start _TEXT segment
        DefFn VDHQuerySysValue
        DefFn VDHWaitVIRRs
        DefFn VDHQueryHookData
        DefFn VDHArmTimerHook
        DefFn VDHDisarmTimerHook
        DefFn Int14h_Timeout_Proc
EndCode                                   ;End _TEXT segment

DefCode    PRIVATE,SWAP,PASCAL            ;start CSWAP_TEXT segment
                                            ;actual code
;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_Init
;
;DESCRIPTIVE NAME: Int 14h (ah=0) virtualization service routine
;
;INPUT:  DL  = Port_ID
;        AL  = Parameters for Initialization
;        ESI -> Base address of PI for this port
;
;OUTPUT: AH = VLSR
;        AL = VMSR
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;       Variables in PI table:
;           VLCR, VDLL, VDLM,
;
;FUNCTION:
;       Set VDLL and VDLM according to Baud Rate.
;       Set VLCR according to parity, stop bits, and word length.
;       Set Interrupt enables all off
;
;CALLED BY:
;       VCOM_Int14h
;
;INTERNAL REFERENCES:
;       Set_DLLDLM_Request
;       Set_LCR_Request
;       Virt_ComOut
;       Get_VMSR
;
;EXTERNAL REFERENCES:
;       NONE
;
;
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_Init    proc    near

       mov     ah,al                      ;Put parameters in AH
       shr     ah,BAUDRATEPOSITION        ;Shift AH value to the right 5 times
                                          ; to get just BAUD rate in AH

       .if     <ah eq ZERO>               ;Was 110 Baud selected?
           mov     [esi].VDLL,DLL_110BAUD ;Special case DLL/DLM
           mov     [esi].VDLM,DLM_110BAUD ;Store values in VDLL and VDLM
       .else
           mov     cl,ah                  ;These DLM/DLL values are powers
           mov     bx,BASE_DLLDLM         ; of 2 apart, so just put in
           shr     bx,cl                  ; base rate and shift right
           mov     [esi].VDLL,bl          ;Store values in VDLL and VDLM
           mov     [esi].VDLM,bh
       .endif

       call    Set_DLLDLM_Request         ;Call to set DLL and DLL
                                          ; from VDLL and VDLM

       and     al,(WLSBITS+STBIT+PENBIT+EPSBIT) ;Strip off Baud Rate
       push    ax
       mov     ah,[esi].VLCR
       mov     [esi].VLCR,al      ;Put parity, stopbits, and
                                          ; word length into VLCR
       and     ax,DLAB_EXP                ; Exculde DLAB
       .if     <ah ne al>                 ; If change in LCR
               call    Set_LCR_Request    ;Call to set LCR from VLCR
       .endif
       pop     ax
       mov     cl,IER                     ;Call Virt_ComOut to set
       xor     al,al                      ;interrupt enables all off
       call    Virt_ComOut                ;(Same as BIOS)

       mov      ecx,LSR                   ;Call Virt_ComIn to get current
       call     Virt_ComIn                ;VLSR value
       mov      ah,al                     ;put LSR value in AH

       call    Get_VMSR                   ;call to set AL to current VMSR

       jmp    Int14h_Main_Ret             ; Return

Int14h_Init    endp




;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_Tx
;
;DESCRIPTIVE NAME: Int 14h (ah=1) virtualization service routine
;
;INPUT: DL  = Port_ID
;       AL  = Character to send
;       ESI -> Base address of PI for this port
;
;OUTPUT: AH = Current timeout bit status + VLSR
;        AL = Character  (Register is preserved)
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       NONE
;  Global Data:
;       Variables in PI table:
;           VLSR, VMSR, VMCR
;
;FUNCTION:
;       Transmit a character.
;
;CALLED BY:
;       VCOM_Int14h
;
;INTERNAL REFERENCES:
;       Set_MCR_Request    - Set VMCR.DTR and/or VMCR.RTS by notifying PCOM
;       Virt_ComOut        - Transmit a character
;       Int14h_Get_TimeOut - Get timeout value into PI
;       Int14h_Wait        - Delay
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_Tx      proc    near

       .if     <BIT [esi].VMCR nand (DTR)> or  ;if DTR is not set or
       .if     <BIT [esi].VMCR nand (RTS)>     ;if RTS is not set,

           mov     ah,[esi].VMCR
           mov     al,ah
           or      al,(DTR+RTS)

           .if     <al ne ah>                  ; if change in MCR
                   mov     [esi].VMCR,al       ;    then set both
                   call    Set_MCR_Request     ;
           .endif
       .endif

        push    eax
        push    ecx
        mov     ecx,LSR                 ;Get current LSR (and clear interrupt)
        call    Virt_ComIn              ;
        mov     ecx,MSR                 ;Get current MSR (and clear interrupt)
        call    Virt_ComIn              ;
        pop     ecx
        pop     eax

       .if     <BIT [esi].VMSR nand (DSR+CTS)> or;if VMSR.DSR and CTS and
       .if     <BIT [esi].VLSR nand THRE>        ;VLSR.THRE are not set
            call    Int14h_Get_TimeOut           ;Get Timeout value into PI
            mov     ah,INT14TX                   ;Set callerid
            mov     [esi].Wait_AX,ax
            mov     [esi].Wait_DX,dx
            pop     ebx
            push    ebx
            call    Int14h_Wait                  ; Delay
            jmp    Int14h_Main_Ret           ; Return
        .endif

        mov     bl,al                      ;save char to send
        mov      ecx,LSR                   ;Call Virt_ComIn to get current
        call     Virt_ComIn                ;VLSR value
        mov      ah,al                     ;put LSR value in AH

        mov     ecx,THR                         ;Move to ECX Reg_Id THR
        mov     al,bl                           ;get character to send (back)
                                                ;Save register destroyed by
        push    eax                             ; Virt_ComOut
        call    Virt_ComOut                     ;Other values are already there
        pop     eax                             ;Restore register
                                                ; (we only care about EAX)

        jmp    Int14h_Main_Ret             ; Return

Int14h_Tx      endp




;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_Rx
;
;DESCRIPTIVE NAME: Int 14h (ah=2) virtualization service routine
;
;INPUT:  DL  = Port_ID
;        ESI -> Base address of PI for this port
;
;OUTPUT: AH = Current timeout bit status + VLSR
;        AL = Character received
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       NONE
;  Global Data:
;       Variables in PI table:
;           VLSR, VMSR, VMCR, VRBR
;
;FUNCTION:
;       Receive a character.
;
;CALLED BY:
;       VCOM_Int14h
;
;INTERNAL REFERENCES:
;       Set_MCR_Request    - Set VMCR.DTR by notifying PCOM
;       Virt_ComIn         - Receive a character
;       Int14h_Get_TimeOut - Get timeout value into PI
;       Int14h_Wait        - Delay
;
;
;EXTERNAL REFERENCES:
;       NONE
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_Rx      proc    near

       .if     <BIT [esi].VMCR nand DTR> ;If VMCR.DTR is not set
           mov     ah,[esi].VMCR
           mov     al,ah
           or      al,DTR
           .if     <al ne ah>                  ; if change in MCR
                 mov     [esi].VMCR,al         ; then set it.
                 call    Set_MCR_Request
           .endif
       .endif

        push    ecx
        mov     ecx,LSR                 ;Get current LSR (and clear interrupt
        call    Virt_ComIn              ; as well as do Virt_Get_Byte)
        mov     ecx,MSR                 ;Get current MSR (and clear interrupt
        call    Virt_ComIn              ; as well as do Virt_Get_Byte)
        pop     ecx

       .if     <BIT [esi].VMSR nand DSR> or     ;If VMSR.DSR is not set
       .if     <BIT [esi].VLSR nand DR>         ; or VLSR.DR is not set
            call    Int14h_Get_TimeOut           ;Get Timeout value into PI
            mov     ah,INT14RX                   ;Set callerid
            mov     [esi].Wait_AX,ax
            mov     [esi].Wait_DX,dx
            pop     ebx
            push    ebx
            call    Int14h_Wait             ; Delay
            jmp    Int14h_Main_Ret          ; Return
        .endif

       mov      ecx,LSR                   ;Call Virt_ComIn to get current
       call     Virt_ComIn                ;VLSR value
       mov      ah,al                     ;put LSR value in AH

        mov     ecx,RBR             ;Move to ECX Reg_Id RBR
        push    ebx                 ;Save Regs destroyed by
        push    eax                 ;   Virt_ComIn
        call    Virt_ComIn          ;other values are already set
                                    ;Virt_ComIn returns char in AL
        mov     bl,al               ;Save character_in in BL
        pop     eax                 ;Restore AH (EAX)
        mov     al,bl               ;Put character_in in AL
        pop     ebx                 ;Restore EBX
        jmp    Int14h_Main_Ret             ; Return

Int14h_Rx      endp




;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_Status
;
;DESCRIPTIVE NAME: Int 14h (ah=3) virtualization service routine
;
;INPUT:  DL  = Port_ID
;        ESI -> Base address of PI for this port
;
;OUTPUT: AH = VLSR
;        AL = VMSR
;
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;       Variables in PI table:
;           VLSR, VMSR
;
;FUNCTION:
;       Get Modem and Line Status.
;
;CALLED BY:
;       VCOM_Int14h
;       Get_VMSR
;
;INTERNAL REFERENCES:
;       NONE
;
;EXTERNAL REFERENCES:
;       NONE
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_Status  proc    near

       mov      ecx,LSR                   ;Call Virt_ComIn to get current
       call     Virt_ComIn                ;VLSR value
       mov      ah,al                     ;put LSR value in AH
       call    Get_VMSR                ;Put VMSR in AH

       jmp    Int14h_Main_Ret             ; Return

Int14h_Status  endp




;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_xInit
;
;DESCRIPTIVE NAME: Int 14h (ah=4) virtualization service routine
;
;INPUT:  DL  = Port_ID
;        AL  = Break
;        BH  = Parity
;        BL  = Stop Bit
;        CH  = Word Length
;        CL  = Baud Rate
;        ESI -> Base address of PI for this port
;
;OUTPUT:
;        AH = VLSR
;        AL = VMSR
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;       Variables in PI table:
;           VLSR, VMSR, VDLL, VDLM, VLCR
;
;FUNCTION:
;       Extended COM port initialization.
;
;CALLED BY:
;       VCOM_Int14h
;
;INTERNAL REFERENCES:
;       Set_LCR_Request
;       Set_DLLDLM_Request
;       Virt_ComOut
;       Get_VMSR
;
;EXTERNAL REFERENCES:
;       NONE
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_xInit   proc    near

       .if   <al g MAX_XINITBREAK> or  ;If break value is out of range or
       .if   <bh g MAX_XINITPARITY> or ;If parity value is out of range or
       .if   <bl g MAX_XINITSTOPB> or  ;If stop bit is out of range or
       .if   <ch g MAX_XINITWORDL> or  ;If word length is out of range or
       .if   <cl g MAX_XINITBAUD>      ;If Baud Rate is illegal,
           jmp  XINITFAIL              ; then fail
       .endif

       shl     al,BREAKBIT_SHIFT       ;Put Break bit in position for LCR
       shl     bl,STBIT_SHIFT          ;Put Stop bits in position for LCR

       or      al,bl                   ;Put Stop Bits and Word Length into
       or      al,ch                   ; register with Break bit

       .if     <bh ne ZERO>            ;If a parity was requested,
           dec     bh                  ;Change to LCR format
           shl     bh,PARITY_SHIFT     ;Put parity bits in LCR position
           or      al,bh               ;Put Stick/Even bits into register
           or      al,PENBIT           ;Put Parity Enable bit into register
       .endif                          ;  with other bits
       push    ax
       mov     ah,[esi].VLCR
       mov     [esi].VLCR,al           ;Put parameters into VLCR  al = VLCR
       and     ax,DLAB_EXP             ; Exclude DLAB bit
       .if     <al ne ah>              ;If change in LCR
               call    Set_LCR_Request ;Call to set LCR from VLCR
       .endif
       pop     ax                      ;Now get BAUD RATE

       .if     <cl eq ZERO>               ;Was 110 BAUD selected?
           mov     [esi].VDLL,DLL_110BAUD ;Special case DLL/DLM
           mov     [esi].VDLM,DLM_110BAUD ;Store values in VDLL and VDLM
       .else
           mov     bx,BASE_DLLDLM      ; values are 2 apart, so just put
           shr     bx,cl               ; in base rate and shift right
           mov     [esi].VDLL,bl       ;Store values in VDLL and VDLM
           mov     [esi].VDLM,bh       ;
       .endif

       call    Set_DLLDLM_Request      ;Call to set DLL and DLL
                                       ; from VDLL and VDLM

       mov     cl,IER                  ;Call Virt_ComOut to set
       xor     al,al                   ;interrupt enables all off
       call    Virt_ComOut             ;(Same as BIOS)

       mov      ecx,LSR                   ;Call Virt_ComIn to get current
       call     Virt_ComIn                ;VLSR value
       mov      ah,al                     ;put LSR value in AH
       call    Get_VMSR                ;Call to set AL to current VMSR

XINITFAIL:
       jmp    Int14h_Main_Ret             ; Return

Int14h_xInit   endp




;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_xCtl
;
;DESCRIPTIVE NAME: Int 14h (ah=5) virtualization service routine
;
;INPUT:  DL  = Port_ID
;        AL  = 0 (Read MCR) or AL = 1 (Write MCR)
;        BL  = MCR data when INPUT : AL = 1
;        ESI -> Base address of PI for this port
;
;OUTPUT: BL = MCR when INPUT : AL = 0
;        AH = VLSR
;        AL = VMSR
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;       Variables in PI table:
;           VLSR, VMSR, VMCR
;
;FUNCTION:
;       Extended COM Port Control.
;
;CALLED BY:
;       VCOM_Int14h
;
;INTERNAL REFERENCES:
;       Set_MCR_Request
;       Get_VMSR
;
;EXTERNAL REFERENCES:
;       NONE
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_xCtl    proc    near

       .if     <al eq XCTL_READ>       ;If function is read (al=0), then
           mov     bl,[esi].VMCR       ;    set BL to VMCR
       .elseif <al eq XCTL_WRITE>      ;If function is write (al=1), then
           and     bl,(DTR+RTS+OUT2)   ;   Give only bits we support in MCR
           .if     <bl ne [esi].VMCR>          ; if changes in MCR
                   mov     [esi].VMCR,bl       ;   Move value to VMCR
                   call    Set_MCR_Request     ;   Call to set MCR
           .endif
       .else                           ;If illegal value, then
            jmp    Int14h_Main_Ret     ; Return
       .endif

       mov      ecx,LSR                   ;Call Virt_ComIn to get current
       call     Virt_ComIn                ;VLSR value
       mov      ah,al                     ;put LSR value in AH
       call    Get_VMSR                ;Call to set AL to current VMSR
       jmp    Int14h_Main_Ret             ; Return

Int14h_xCtl    endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_Wait
;
;DESCRIPTIVE NAME: Int 14h Wait for Status
;
;INPUT:
;        ESI  -> Base address of PI for this port
;
;OUTPUT:
;       Success:  AH = VLSR
;                 AL = Character received for Rx (preserved otherwise)
;       TimeOut:  AH = 80h  (Timeout)
;                 Al = Preserved
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;        iClients_DX
;  Global Data:
;        Variables in PI
;           Wait_TimeOut
;           Wait_AX
;           Wait_DX
;
;FUNCTION:
;       Delay for time indicated in 40:0 RS232 timeout value
;
;CALLED BY:
;       Int14h_Rx
;       Int14h_Tx
;       VCOM_Int14h_ReturnProc
;
;INTERNAL REFERENCES:
;       NONE
;
;EXTERNAL REFERENCES:
;       NONE
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


Int14h_Wait    proc    near
        push    edx
        push    ecx
        push    ebx
begin:
        mov     ebx,[esi].Wait_TimeOut
        mov     ax,[esi].Wait_AX

        mov     cl, ah                      ;put caller id in cl
        mov     ah,00h                      ;Value for timeout
        push    eax                         ;(Will be changed if success)

        push    ecx

;At this point, CL  = callerid
;               EBX = System seconds at end of delay

        mov     eax,VDHGSV_SECONDS1970

        mov     edx,CURRENT_VDM
        CallFn VDHQuerySysValue,<edx, eax>;   ;if current seconds <

        mov     dx,[esi].Wait_DX

        mov     [esi].Wait_DX,dx        ;Get current dx for Virt_ComIn
        push    eax
        mov     ecx,LSR                 ;Get current LSR (and clear interrupt
        call    Virt_ComIn              ; as well as do Virt_Get_Byte)
        mov     ecx,MSR                 ;Get current MSR (and clear interrupt
        call    Virt_ComIn              ; as well as do Virt_Get_Byte)
        pop     eax

        pop     ecx

        .if <eax nb ebx>                         ; If no more time is left,
            pop     eax
            mov     ah,80h                       ;set timeout in eax
            push    eax
            sti
        .else near
            cli
            .if     <cl eq INT14RX> and
            .if     <BIT [esi].VMSR and DSR> and ;If VMSR.DSR is set
            .if     <BIT [esi].VLSR and DR>      ; and VLSR.DR is set
                   pop     eax

                   mov     ecx,LSR            ;Call Virt_ComIn to get current
                   call    Virt_ComIn         ;VLSR value
                   mov     ah,al              ;put LSR value in AH

                   push    eax
                   mov     ecx,RBR             ;Move to ECX Reg_Id RBR
                   call    Virt_ComIn          ;other values are already set
                                               ;Virt_ComIn returns char in AL
                   mov     bl,al               ;Save character_in in BL
                   pop     eax                 ;Restore AH (EAX)
                   mov     al,bl               ;Put character_in in AL
                   push    eax                 ;Push EAX back on stack

            .elseif <cl eq INT14TX> and          ;cl eq INT14TX
            .if <BIT [esi].VMSR and (DSR+CTS)> and ; if VMSR.DSR and CTS and
            .if <BIT [esi].VLSR and THRE>        ; VLSR.THRE are set
                   pop     eax

                   mov     bl,al                 ;save char to send
                   mov     ecx,LSR               ;Call Virt_ComIn to get current
                   call    Virt_ComIn            ;VLSR value
                   mov     ah,al                 ;put LSR value in AH

                   mov     al,bl                 ;get back char to send
                   mov     ecx,THR               ;Move to ECX Reg_Id THR
                   push    eax
                   call    Virt_ComOut           ;Call Virt_ComOut
            .else near                           ;we didn't timeout, and we
                or     [esi].flgStatus, SLEEPING
                sti
                push   esi
                push   eax
                push   ebx

                CallFn VDHQueryHookData, <[hHook_Timeout]>

                mov    ebx,ihVDM
                mov    [eax],ebx

                xor    eax,eax
                mov    ax, iClients_DX              ;get DX passed by user
                lea    ebx,VDMBase.rb_abCOMtimeout  ;Get base address of 40:0 area
                add    bx,ax                        ;point to correct slot
                mov    al,[ebx]                     ;get timeout value in AL

                .if     <al eq 0>                   ;If infinite retry, then
                    mov     eax, 00004000h          ;  use this retry value
                .else                               ;otherwise
                    inc     al                      ;  0-based, so add 1
                    inc     al                      ;  ignore 1/100, so add 1 to
                                                    ;  make sure it lasts long enough
                    and     eax,0ffh                ;  clear out rest of EAX
                .endif
                mov    edx,1000
                mul    eax

                CallFn VDHArmTimerHook, <[hHook_Timeout], \
                                         eax,VDH_TIMER_GLOBAL_CONTEXT>

                pop    ebx
                pop    eax
                pop    esi

                CallFn VDHQueryHookData, <[hhookInt14ReturnHook]>
                mov     [eax],esi
                CallFn VDHWaitVIRRs, <[hhookInt14ReturnHook]>
                                                 ;couldn't transmit or receive
                                                 ;so wait for next interrupt.
                push   eax
                and    [esi].flgStatus, NOT SLEEPING
                CallFn VDHDisarmTimerHook, <[hHook_Timeout]>
                pop    eax

                test   eax,TRUE                  ;if VDHWakeVIRRs was issued
                .if <z>                          ;yes

                   pop    eax
                   jmp    begin

                .else                            ;no

                   mov    iInt14h_Complete, INTERRUPTED

                .endif                      ;Don't do VDHPopInt, so we return
            .endif
            sti
        .endif

        pop     eax
        pop     ebx
        pop     ecx
        pop     edx
        ret
Int14h_Wait    endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: Int14h_Get_TimeOut
;
;DESCRIPTIVE NAME: Decide timeout value for Int14
;
;INPUT:
;        ESI -> Base address of PI for this port
;
;OUTPUT:
;       Wait_TimeOut (in PI) is set
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;        iClients_DX
;        Variables in PI (Port_Info_Tab
;           Wait_TimeOut
;
;  Global Data:
;        NONE
;
;FUNCTION:
;       Figure timeout value to be used by Tx or Rx
;
;CALLED BY:
;       Int14h_Rx
;       Int14h_Tx
;
;INTERNAL REFERENCES:
;       NONE
;
;EXTERNAL REFERENCES:
;       VDHQuerySysVal
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

Int14h_Get_TimeOut proc    near
        push    eax
        push    ebx
        push    ecx

        mov     ax, iClients_DX             ;get DX passed by user
        lea     ebx,VDMBase.rb_abCOMtimeout ;Get base address of 40:0 area
        add     bx,ax                       ;point to correct slot
        mov     al,[ebx]                    ;get timeout value in AL

        .if     <al eq 0>                   ;If infinite retry, then
            mov     eax, 00004000h          ;  use this retry value
        .else                               ;otherwise
            inc     al                      ;  0-based, so add 1
            inc     al                      ;  ignore 1/100, so add 1 to
                                            ;  make sure it lasts long enough
            and     eax,0ffh                ;  clear out rest of EAX
        .endif

        mov     ebx,eax                     ;put delay time in EBX

;               EBX = delay time (seconds)

        mov     eax,VDHGSV_SECONDS1970
        mov     ecx,CURRENT_VDM
        CallFn VDHQuerySysValue,<ecx, eax>;
        add     ebx,eax

;               EBX = System seconds at end of delay

        mov     [esi].Wait_TimeOut,ebx

        pop     ecx
        pop     ebx
        pop     eax
        ret
Int14h_Get_TimeOut endp


EndCode                                 ;end CSWAP_TEXT segment
        END
