;       SCCSID = @(#)vcom.asm   6.13 92/03/20

        Page    ,132
        NAME    VCOM
        TITLE   VCOM     - Virtual COM device driver
        SUBTTL  VCOM.ASM - Entry points for VCOM
; ****************************************************************************
; *                                                                          *
; *                       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: VCOM.ASM
;
;DESCRIPTIVE NAME: VCOM Entry Points for VDMM, 8086EM, and PCOM
;
;FUNCTION:
;       This file contains procedures that are the entry points
;       for the VDM manager, the 8088 Emulator, and the physical COM
;       device drivers.
;
;       This is the Virtual Asyncronous Device Driver for OS/2 running
;       on 80386 based machines.
;
;
;NOTES:
;       Dependencies: PCOM must be present.
;       Restrictions: Currently only supports COM1, COM2, and COM3 (PS/2).
;
;SUBROUTINES:
;       VCOM_PortIn
;       VCOM_PortOut
;       VCOM_Int14h
;       VCOM_Int66h
;       VCOM_PCOMNotify
;       VCOM_VDMCreation
;       VCOM_VDMTermination
;       VCOM_Int14h_ReturnProc
;       VCOM_Int2fHandler                                                @95743
;       VCOM_VPMBegin                                                    @95743
;
;EXTERNAL REFERENCES:
;       VDHInstallIntHook
;       VDHInstallIOHook
;       VDHRemoveIOHook
;       VDHFreeHook
;       VDHCloseVIRQ
;       VDHPopInt
;       VDHPopInt
;       VDHArmVPMBPHook                                                  @95743
;       VDHGetVPMIntVector                                               @95743
;       VDHSetVPMIntVector                                               @95743
;       VCOM_VxdServiceRouter                                            @95743
;
;;;;;;;;;;;;;;;;;;;;;;; END OF FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Jin Kim
;       Yoshihiko Nishida
;       Allen C. Wynn
;       (c) International Business Machines Corporation
;       January 1989
;
;Modification History
;
;   01/18/93  R206 p060491      Bill Madden     Use VDHRegisterAPI, not int 66
;   03/29/93  @59629            J.W. Krier      Add receive buffer flush DosProperty
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        .386p

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

include VDDSEG.INC
include VCOMDATA.INC

DefData IMPORT,SWAPINST,C               ;Start SWAP_INST segment
        _DWORD flVdmStatus
EndData                                 ;End SWAP_INST segment

DefData IMPORT,GLOBAL,C                                                 ;60491
ULONG   TKSSBase                                                        ;60491
EndData                                                                 ;60491

DefCode EXPORT,SWAP,PASCAL              ;Start CSWAP_TEXT segment
                                        ;Export delcarations (publics)
        public Int14h_Main_Ret          ;return point for Int14 procs
        DefFn  VCOM_VDMCreation
        DefFn  VCOM_VDMTermination
        DefFn  VCOM_PDBDestroy
        DefFn  VCOM_PDBChange
        DefFn  VCOM_VDMForeground       ;@59629
        DefFn  VCOM_VDMRxBufferFlush    ;@59629
        DefFn  VCOM_Rx_Flush            ;@59629
        DefFn  VCOM_Int14h
        DefFn  VCOM_Int66h
        DefFn  VCOM_PortIn
        DefFn  VCOM_PortOut
        DefFn  VCOM_Int14h_ReturnProc
        DefFn  VCOM_Hold_Res            ;CP20D1390
        DefFn  VCOM_HW_COM              ;
        DefFn  VCOM_COM_SELECT          ;
        DefFn  VCOM_Int2fHandler        ;@95743
        DefFn  VCOM_VPMBegin            ;@95743
EndCode                                 ;end CSWAP_TEXT segment
                                        ;Export delcarations (publics)

DefCode EXPORT,GLOBAL,PASCAL            ;Start _TEXT segment
        DefFn  VCOM_PCOMNotify
EndCode                                 ;end _TEXT segment

DefCode IMPORT,SWAP,PASCAL              ;Start CSWAP_TEXT segment
        DefFn   Virt_ComIn
        DefFn   Virt_ComOut
        DefFn   Get_PortId_Register
        DefFn   Check_PortOwner
        DefFn   Int14h_Wait
        DefFn   Close_Request
EndCode                                 ;end CSWAP_TEXT segment
                                        ;Import declarations

DefCode IMPORT,GLOBAL,PASCAL            ;Start _TEXT segment
        DefFn   Virt_HWInt
        DefFn   VDHInstallIOHook       ;Import declarations
        DefFn   VDHInstallIntHook
        DefFn   VDHRemoveIOHook
        DefFn   VDHCloseVIRQ
        DefFn   VDHPopInt
        DefFn   VDHSetFlags
        DefFn   VDHAllocHook
        DefFn   VDHCreateSem
        DefFn   VDHPostEventSem
        DefFn   VDHResetEventSem
        DefFn   VDHQuerySem
        DefFn   VDHDestroySem
        DefFn   VDHQueryProperty        ;CP20D1390
        DefFn   VDHFreeMem
        DefFn   VDHFreeHook
        DefFn   VDHArmContextHook       ;@59629
        DefFn   VDHQueryHookData        ;@59629
        DefFn   VDHQueryLin
        DefFn   VDHRegisterAPI                                          ;60491
        DefFn   VDHPopStack                                             ;60491
        DefFn   VDHArmVPMBPHook         ;@95743                                            ;60491
        DefFn   VDHGetVPMIntVector      ;@95743                                            ;60491
        DefFn   VDHSetVPMIntVector      ;@95743                                            ;60491
        DefFn   VCOM_VxDServiceRouter   ;@95743                                            ;60491
        DefFn   Int14h_Timeout_Proc     ;CP20B726262                              00117  INSERT(NEW)  00119
EndCode                                 ;end _TEXT segment


DefCode PRIVATE,SWAP,PASCAL           ;Start CSWAP_TEXT segment
                                        ;Actual code
;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_PortIn
;
;DESCRIPTIVE NAME: VCOM Port "In" instruction Trap entry point
;
;INPUT:
;       EDX = Port address ( 03F8h - 03FFh, 02F8h - 02FFh, 3220h - 3227h )
;
;OUTPUT:
;       AL = data read
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;
;FUNCTION:
;       This routine calls Get_PortId_Register to get the port id,
;       and UART register id.
;       Then Check_PortOwner is called to validate the port ownership.
;       If every thing is OK, then calls Virt_ComIn routine.
;
;CALLED BY:
;       8086EM
;
;INTERNAL REFERENCES:
;       Virt_ComIn
;       Get_PortId_Register
;       Check_PortOwner
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_PortIn     proc    near
        push    ebx                     ;Save registers that we are not
        push    esi                     ; allowed to change
        push    edi                     ;

        mov     ah, VPORTIN             ;Identify myself, and get
        call    Get_PortId_Register     ;  port id and register id
        .if     nc                      ;Port addr is out of range?
            call    Check_PortOwner
            .if     nc                  ;Everything is O.K.
                call    Virt_ComIn
            .endif
        .endif
        pop     edi                     ;Restore registers that we are not
        pop     esi                     ; allowed to change
        pop     ebx                     ;
        ret
VCOM_PortIn     endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_PortOut
;
;DESCRIPTIVE NAME: VCOM Port "Out" instruction Trap entry point
;
;INPUT:
;       EDX = Port address ( 03F8h - 03FFh, 02F8h - 02FFh, 3220h - 3227h )
;       AL  = data to write
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;
;FUNCTION:
;       This routine calls Get_PortId_Register to get the port id,
;       and UART register id.
;       Then Check_PortOwner is called to validate the port ownership.
;       If every thing is OK, then calls Virt_ComOut routine.
;
;CALLED BY:
;       8086EM
;
;INTERNAL REFERENCES:
;       Virt_ComOut
;       Get_PortId_Register
;       Check_PortOwner
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_PortOut    proc    near
        push    ebx                     ;Save registers that we are not
        push    esi                     ; allowed to change
        push    edi                     ;

        mov     ah, VPORTOUT            ;Identify myself, and get
        call    Get_PortId_Register     ;  port id and register id
        .if     nc                      ;Port addr is out of range?
            call    Check_PortOwner
            .if     nc                  ;Everything is O.K.
                call    Virt_ComOut
            .endif
        .endif
        pop     edi                     ;Restore registers that we are not
        pop     esi                     ; allowed to change
        pop     ebx                     ;
        ret
VCOM_PortOut    endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_Int66h
;
;DESCRIPTIVE NAME: VCOM Int 66h instruction Trap entry point
;
;INPUT
;       pcrf -> Base address of Client Register Frame
;OUTPUT:
;       Carry bit is cleared (if interrupt is serviced)
;       Carry bit is set (if not serviced)
;
; Within the Client Register Frame, the Client registers give the function
; and the parameters for the INT66h call.
;
;   Function = Reenable all ports for this VDM
;              INPUT from Client Register Frame
;                     AH = 1 (Extended Communication port control)
;                     AH = 2 (Extended Communication port control:Get IRQ)
;                     DS:SI -> "VCOM"
;              OUTPUT to Client Register Frame
;                     NONE
;                     AL = IRQ if INPUT AH = 2
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;    iflgignore
;
;  Global Data:
;
;FUNCTION:
;       get ax from CRF
;       if our function AND
;       if CRF(DS:SI)-> VCOM then
;         iflgignore = 0
;         Pop return address from client stack (VDHPopStack)
;         CLC
;       else
;         STC
;       return
;
;CALLED BY:
;       8086EM
;
;INTERNAL REFERENCES:
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

Procedure VCOM_Int66h,near                                              ;60491
ArgVar pRefData,PBYTE                                                   ;60491
ArgVar pcrf,PCRF                                                        ;60491
LocalVar vpretaddr,DWORD                                                ;60491

        EnterProc                                                       ;60491

        push    ebx                     ; Save registers that we are not
        push    esi                     ;  allowed to change
        push    edi                     ;

        mov     ebx,pcrf                ; EBX = pointer to client regs

;60491  test _flVdmStatus,VDM_STATUS_VPM_APP
;60491  jz   not_protect_mode_app

        ; protect mode app

;60491  test _flVdmStatus,VDM_STATUS_VPM_EXEC
;60491  jz   not_in_protect_mode

        ; in protect mode

;60491  movzx   esi,[ebx].crf_ds        ; make (crf) DS:SI into pointer
;60491  jmp     short get_pointer

not_in_protect_mode:
;60491  movzx   esi,[ebx].crf_altds     ; make (crf) altDS:SI into pointer
get_pointer:
;60491  shl     esi,16                  ;
;60491  mov     edi,[ebx].crf_esi       ; ESI is F16PVOID
;60491  mov     si,di
;60491  CallFn  VDHQueryLin <esi>
;60491  mov     esi,eax
;60491  jmp     got_pointer

not_protect_mode_app:
;60491  movzx   esi,[ebx].crf_ds        ; make (crf) DS:SI into pointer
;60491  shl     esi,4                   ;
;60491  add     esi,[ebx].crf_esi       ;

got_pointer:
;60491  mov     esi,[esi]               ; Use pointer to get 4 bytes

;60491  .if <esi eq 'MOCV'>             ; if this is for VCOM

        mov     eax,[ebx].crf_eax       ; Get AX value
        .if <ah eq 1>                   ; Is this our re-enable?
          mov     iflgIgnore, 0         ; re-enable com ports
          clc                           ; Clear carry bit (Consume interrupt)
        .elseif <ah eq 2>               ; Is this a query for a COM port?
          lea   esi, PI                 ; ESI -> PI for COM1
          movzx eax,al                  ; eax = port number
          mov   dl,size Port_Info_Tab   ; dl = structure size
          mul   dl                      ; ax = structure offset for this port
          add   esi,eax                 ; esi = linear address of port struct
          movzx eax,[esi].Port_Addr     ; get starting port address ...
          mov   [ebx].crf_eax,eax       ; ... into user's EAX
          movzx eax,[esi].IRQ_Level     ; get IRQ level ...
          mov   [ebx].crf_edx,eax       ; ... into user's EDX
          clc                           ; Clear carry bit (Consume interrupt)
        .elseif <ah eq 3>               ; Is this a Close for a COM port?
          lea   esi,PI                  ; ESI -> PI for COM1
          movzx eax,al                  ; eax = port number
          mov   edx,eax                 ; edx =  "    "
          mov   cl,size Port_Info_Tab   ; cl = structure sixe
          mul   cl                      ; ax = structure offset for this port
          add   esi,eax                 ; esi = linear address of port struct
          mov   eax,ihVDM               ; eax = hvdm
          .if <eax eq [esi].hVDM_PI>    ; If this port is owned by this VDM,
            call Close_Request          ; close the port.(edx=port_id)
          .endif
;60491      clc                         ; Clear carry bit (Consume interrupt)
;60491    .else
;60491      stc                         ; Chain to NEXT
        .endif

;60491  .else
;60491    stc                           ; Chain to NEXT
;60491  .endif

;60491  .if nc
;60491    CallFn  VDHPopInt,<>          ; We're finished, don't return
        SSToDS  eax,vpretaddr           ; (EAX) = addr of vpretaddr     ;60491
        CallFn  VDHPopStack, <4, eax>                                   ;60491
        or      eax,eax
        .if nz
          or      eax, eax
          jz      short end_int66h
          mov     eax,vpretaddr
          mov     word ptr [ebx].crf_eip,ax
          shr     eax,16
          mov     [ebx].crf_cs,ax
        .endif

end_int66h:
        pop     edi                     ; Restore registers that we are not
        pop     esi                     ;  allowed to change
        pop     ebx                     ;
        ExitProc
;60491  ret                             ; Return

EndProc VCOM_Int66h                                                     ;60491


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_Int14h
;
;DESCRIPTIVE NAME: VCOM Int 14h instruction Trap entry point
;
;INPUT
;       EBX -> Base address of Client Register Frame
;OUTPUT:
;       Carry bit is cleared (interrupt is serviced)
;
; Within the Client Register Frame, the Client registers give the function
; and the parameters for the INT14h call.  The INT14h output parameters
; are returned in the Client Register Frame.
;
;   Function = Initialize Port
;              INPUT from Client Register Frame
;                     AH = 0 (Init function)
;                     AL = parameter for initialization
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AH = LSR
;                     AL = MSR
;
;   Function = Send a Character
;              INPUT from Client Register Frame
;                     AH = 1 (Send the character)
;                     AL = character
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AH = Time out + LSR error status
;                     AL = character (this register is preserved)
;
;   Function = Receive a Character
;              INPUT from Client Register Frame
;                     AH = 2 (Receive a character)
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AL = character
;                     AH = Time out + LSR error status
;
;   Function = Get port status
;              INPUT from Client Register Frame
;                     AH = 3 (Get the status)
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AH = LSR
;                     AL = MSR
;
;   Function = Extended Initialize
;              INPUT from Client Register Frame
;                     AH = 4 (Extended Init)
;                     AL = break
;                     BH = parity
;                     BL = stop bit
;                     CH = word length
;                     CL = baud rate
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AH = LSR
;                     AL = MSR
;
;   Function = Extended port control (Read modem control register)
;              INPUT from Client Register Frame
;                     AH = 5 (Extended Communication port control)
;                     AL = 0 (Read modem control register)
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AH = LSR
;                     AL = MSR
;                     BL = MCR
;
;   Function = Extended port control (Write modem control register)
;              INPUT from Client Register Frame
;                     AH = 5 (Extended Communication port control)
;                     AL = 1 (Write modem control register)
;                     BL = MCR data
;                     DX = RS-232-C Communications line to use (0,1,2,3)
;                          corresponding to the acutal port base address
;                          at 40:00
;              OUTPUT to Client Register Frame
;                     AH = LSR
;                     AL = MSR
;
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;      Int14_Jump_Tab
;      PI (Port Information Table)
;
;FUNCTION:
;       Get the requested port number
;       If the requested port is a valid COM port, then
;           Set ESI -> Base address of PI for the COM port
;       Check that the requested COM port exists
;       Check_PortOwner routine is called to validate the port ownership.
;       If a collision occured and the user selected ignore, return to caller
;       Get input parameters from Client Register Frame
;       Jump to the individual INT14h function handler routine
;       Save the output in Client Register Frame
;       Set carry bit
;
;CALLED BY:
;       8086EM
;
;INTERNAL REFERENCES:
;       Check_PortOwner
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_Int14h     proc    near
        push    ebx                     ;Save registers that we are not
        push    esi                     ; allowed to change
        push    edi                     ;

        mov     edi,ebx                 ;Save pntr to Client Register Frame

        mov     eax,[edi].crf_eax       ;Get AX value

        .if     <ah a INT14XCTL>        ;If requested function is out of range
            jmp CleanUp                 ; then exit
        .endif

        mov     edx,[edi].crf_edx       ;Get Requested Port Number
        and     edx,0FFFFh              ;Clear out all but DX

        mov     iInt14h_Complete, COMPLETED
                                        ;Default is do VDHPopint on return

        .if  <dx a MAXBIOSPORT>         ;if DX value is invalid
             jmp CleanUp                ; then just return
        .endif
        mov     iClients_DX, dx         ;save DX passed by user
                                        ; (for use with INT14h_Delay)
        lea     ebx,VDMBase.rb_awCOM    ;Get base address of 40:0 area

        add     ebx,edx                 ;make EBX point to the 40:0 slot
        add     ebx,edx                 ;that we want (WORD, so add twice)

        mov     ax,[ebx]                ;get the port address from 40:0

        .if     <ax eq 0>               ;if address is zero, then
            jmp CleanUp                 ;  just return
        .endif

        lea     esi,PI                  ;Get base address of PI

        .for edx = 0 to (MAXNUMPORT-1) by 1;for each slot in PI,
            .if <ax eq  [esi].Port_Addr>   ;if 40:0 address is same as in PI,
                .leave                     ;  the we found the correct port
            .endif                         ; (DX and ESI are set up correctly)
            add  esi,size Port_Info_Tab    ;otherwise, get next PI slot
        .next   edx                        ;and try again (DX is incremented)

        .if <ax ne [esi].Port_Addr>     ;If 40:0 address is not same as PI,
            jmp CleanUp                 ; then we don't support the port
        .endif                          ; in 40:0 area or we fell out of the
                                        ; loop above (off end of PI)
        call    Check_PortOwner         ;Call Check_PortOwner to
                                        ;validate the port ownership

        jc short CleanUp                ;If Carry is set, then
                                        ;/* There was a collision and the  */
                                        ;/* user chose ignore or terminate */
                                        ;/* Or we are in the IGNORE state  */
                                        ;   Jump down to CLEANUP: label

        mov     eax,[edi].crf_eax       ;Move Client Register Frame values
        mov     ecx,[edi].crf_ecx       ;for AX, CX, and BX to registers
        mov     ebx,[edi].crf_ebx       ;

        mov     iSaveInt14Cmd, ah   ;Save command
        push    edi
        mov     di,ax
        shr     di,8
        and     edi,0fh
        jmp     Int14_Jump_Tab[edi*4]    ;Jump to correct routine


               ;CP20 B722294 Move CleanUp so that client registers are not
               ;changed if error is found.
CleanUp:                            ;label to jump to in case of error
        CallFn  VDHPopInt,<>        ;We're finished, don't return
        clc                         ;Clear carry bit (Consume interrupt)
        jmp     I14h_x              ;    Don't chain to CBIOS



public Int14h_Main_Ret
Int14h_Main_Ret:

        pop     edi


        .if     <iInt14h_Complete eq COMPLETED>
                                            ;If we were not interrupted,
            .if <iSaveInt14Cmd eq INT14XCTL>;If requested function was XCTL
                and     ebx,0FFh            ;Clear out EBX except for BL
                mov     [edi].crf_ebx,ebx   ;Put EBX in CRF_EBX
            .endif

            and     eax,0FFFFh          ;Clear out EAX except for AX
           mov     [edi].crf_eax,eax   ;Put EAX in Client Register Frame
           jmp     CleanUp                 ; Temp Hack!!!!!!!!!!!
        .else
            mov     ebx,[edi].crf_eflag
            or      ebx,F_INTERRUPT

            CallFn  VDHSetFlags, <ebx>
;           stc                         ;Chain to CBIOS for hardware
            clc                         ;Clear carry bit (Consume interrupt)
                                        ;interrupt simulation (reflection)
        .endif


I14h_x:
        pop     edi                     ;Restore registers that we are not
        pop     esi                     ; allowed to change
        pop     ebx                     ;
        ret                             ;Return

VCOM_Int14h    endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_VDMCreation
;
;DESCRIPTIVE NAME: VDM Creation Event handler entry point
;
;INPUT:
;       hVDM
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       ipdbCurrent
;       ihComSem
;       iCreateSemDone
;  Global Data:
;       PI (Port_Info_Tab)
;       off_VCOM_Int14h
;       IOHook
;
;FUNCTION:
;
;        ~ Save hVDM in Instance data area
;        ~ Set hooks for I/O port trapping ( VDHInstallIOHook )
;        ~ Set hooks for INT 14h ( VDHInstallIntHook )
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;       Event_Success (Label in VCOM_VDMTermination)
;       VCOM_VDMTermination
;
;EXTERNAL REFERENCES:
;       VDHInstallIntHook
;       VDHInstallIOHook
;       VDHCreateSem
;       VDHResetEventSem
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_VDMCreation        proc    near           ;

        push    ebp                            ; Save registers for VDMM
        mov     ebp, esp                       ; This adds 16 bytes to
        push    ebx                            ; the (32 bit) stack
        push    edi                            ; , 4 bytes for return
        push    esi                            ;   address
                                               ;
        mov     eax, [ebp+8]                   ; Get hVDM from stack
                                               ; (see above)
        mov     ihVDM, eax                     ; Save as instance data
        mov     ipdbCurrent,INVALID_PDB        ; invalidate the PDB, we'll get
                                               ;     called at VCOM_PDBChange
        lea     esi,PI                         ; let esi->PI
        xor     ecx,ecx                        ; set ecx = 0
        .repeat                                ; Repeat for all three ports
            push    ecx                        ; Save ECX
            .if <[esi].Port_Addr ne 0>         ; If PI's Port_addr != 0
                                               ; Hook this IO port
                lea eax,IOHook                 ; IOHook parameter packet
                movzx  ecx,[esi].Port_Addr     ; Number of ports to hook
                CallFn VDHInstallIOHook,     \
                       <ihVDM, ecx, 8, eax,  \
                        VDH_ASM_HOOK+VDHIIH_ALWAYS_TRAP>
                .if <eax eq VDH_FAILURE>       ; If fails
                    pop     ecx                ;    Restore ECX
                    jmp     Create_Fail        ;    Jump to Create_Fail
                .endif
            .endif

            add esi,size Port_Info_Tab             ; Advance to next PI
            pop     ecx                            ; Restore ECX
            inc     ecx                            ; increase the count
            mov     iIOHooksDone,cl                ; Save number of successes
        .until <ecx g (MAXNUMPORT-1)>              ; Repeat for all three PIs


        ;begin @59629

        and     iDOSProp, not (COM_FLUSH_Rx+COM_FLUSH_BACKGROUND) ; default no
        mov     ecx, OFFSET FLAT:szPropRxFlush   ;
        CallFn  VDHQueryProperty       <ecx>     ;Query Rx buffer flush property
        or      eax,eax                          ; see if error
        jz      end_check_RxFlush

        mov     cl, [eax]                        ; get first character of
        cmp     cl, FLUSH_ALL                    ; property string
        jnz     check_Rx
        or      iDOSProp, (COM_FLUSH_Rx+COM_FLUSH_BACKGROUND) ; set on, so set the flag
        jmp     short end_check_RxFlush

  check_Rx:
        cmp     cl, FLUSH_Rx                     ;
        jnz     check_Background
        or      iDOSProp, COM_FLUSH_Rx           ; on, so set the flag
        jmp     short end_check_RxFlush

  check_Background:
        cmp     cl, FLUSH_BACKGROUND             ;
        jnz     end_check_RxFlush
        or      iDOSProp, COM_FLUSH_BACKGROUND   ; set on, so set the flag
  end_check_RxFlush:


        ;end @59629

        mov     ecx, OFFSET FLAT:szPropHardwareCOM   ;
        CallFn  VDHQueryProperty       <ecx>     ;Query Hard COM property
        cmp     eax,0                            ;
        je      set_HW_COM_off                   ;
                                                 ;
        or      iDOSProp, HW_COM                 ;If the DOS property is ON,
        jmp     SHORT no_hook_int14              ;
                                                 ;
set_HW_COM_off:                                  ;Otherwise,
        and     iDOSProp, NOT HW_COM             ;Turn off the flag
        mov     eax, offset FLAT:VCOM_Int14h       ;hook Int14h to VCOM_Int14h
        CallFn  VDHInstallIntHook,<ihVDM,14h,eax,VDH_ASM_HOOK>

        CallFn  VDHAllocHook, <VDH_WAITVIRRS_HOOK, \
                               offset FLAT:VCOM_Int14h_ReturnProc, 4>
        mov     [hhookInt14ReturnHook],eax
        or      eax,eax
        jz       Create_Fail

no_hook_int14:                                   ;

        mov     eax,VDH_EVENTSEM
        CallFn  VDHCreateSem,<offset FLAT:ihComSem,eax>
        or      eax,eax
        jz       Create_Fail
        mov     iCreateSemDone,1

        mov     eax,ihComSem
        CallFn  VDHResetEventSem,<eax>
        or      eax,eax
        jz      Create_Fail

        push    eax                              ;CP20D1390----------
        mov     ecx, OFFSET FLAT:szPropHoldRes   ;
        CallFn  VDHQueryProperty       <ecx>     ;Query Hold COM Resource property
        cmp     eax,0                            ;
        je      set_Hold_Res_off                 ;
                                                 ;
        or      iDOSProp, HOLD_RESOURCE          ;If the DOS property is ON,
        jmp     SHORT successful_end             ;set the flag
                                                 ;
set_Hold_Res_off:                                ;Otherwise,
        and     iDOSProp, NOT HOLD_RESOURCE      ;Turn off the flag
                                                 ;
successful_end:                                  ;-------------------
        or      iDOSProp, COM_SELECT_ALL         ;Clear up selct bits

        mov     ecx, OFFSET FLAT:szPropCOMSelect ;
        CallFn  VDHQueryProperty       <ecx>     ;Query Hard COM property
        mov     cl,[eax+3]
        cmp     cl,ALL                           ;
        je      successful_end2                  ;
        and     iDOSProp, NOT COM_SELECT_ALL     ;Clear up selct bits

        cmp     cl,ONE
        jne     try_com2

        or      iDOSProp, COM_SELECT_1           ;If the COM1 is selected,
        jmp     SHORT successful_end2            ;

try_com2:
        cmp     cl,TWO
        jne     try_com3
        or      iDOSProp, COM_SELECT_2           ;If the COM2 is selected,
        jmp     SHORT successful_end2            ;

try_com3:
        cmp     cl,THREE
        jne     try_com4
        or      iDOSProp, COM_SELECT_3           ;If the COM3 is selected,
        jmp     SHORT successful_end2            ;

try_com4:
        cmp     cl,FOUR
        jne     try_none
        or      iDOSProp, COM_SELECT_4           ;If the COM4 is selected,

try_none:
        cmp     cl,NONE
        jne     successful_end2
        and     iDOSProp, NOT COM_SELECT_ALL     ;Clear up selct bits

successful_end2:                                 ;-------------------
        CallFn  VDHAllocHook, <VDH_TIMER_HOOK, \
                               offset FLAT:Int14h_Timeout_Proc, 4>
        mov     [hHook_Timeout],eax
        pop     eax

        mov     eax, offset FLAT:VCOM_Int66h   ;hook Int66h to VCOM_Int66h
;60491  CallFn  VDHInstallIntHook,<ihVDM,66h,eax,VDH_ASM_HOOK>
        CallFn  VDHRegisterAPI,<offset FLAT:szVCOM,eax,eax>

        CallFn  VDHQueryProperty,<offset FLAT:szVMBoot>
        mov     ebx,eax
        .if <ebx ne 0>
          mov     al,[ebx]
          .if <al ne 0>                   ; if this is a VMBOOT session
            mov     iflgIgnore,0fh        ; turn on ignore bits for 4 ports
          .endif
          CallFn  VDHFreeMem,<ebx>      ; queryproperty allocates a string
        .endif

        CallFn  VDHAllocHook, <VDH_BP_HOOK, \
                               offset FLAT:VCOM_Int2fHandler, 0>      ;@95743
        mov [hhookInt2fBPHook], eax    ;save hook handle              ;@95743

        CallFn  VDHAllocHook, <VDH_BP_HOOK, \
                               offset FLAT:VCOM_VxDServiceRouter, 0>  ;@95743
        mov [hhookVxDServiceBPHook], eax ;save hook handle            ;@95743

        jmp     Event_Success                    ; Jump to Successful return


Create_Fail     LABEL     near
        mov     eax,ihVDM
        push    eax                              ;We failed on creation, so
        call    VCOM_VDMTermination              ;clean up and

        mov     eax,VDH_FAILURE                  ;return an error
        jmp     Event_Ret

VCOM_VDMCreation        endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_VDMTermination
;
;DESCRIPTIVE NAME: VDM Termination Event handler entry point
;
;INPUT:
;       hVDM
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       iCreateSemDone
;       ihComSem
;       iSemState
;  Global Data:
;       PI (Port_Info_Tab)
;       off_VCOM_Int14h
;       IOHook
;
;FUNCTION:
;
;        ~ Remove I/O port Hooks
;        ~ If any COM port was opened for this VDM, Call Close_Request to
;          close COM port(s)
;        ~ Remove Interrupt  Hooks
;
;
;CALLED BY:
;       VDMM at Task time
;       VCOM_VDMCreation at creation time if creation fails
;
;INTERNAL REFERENCES:
;       Close_Request
;
;EXTERNAL REFERENCES:
;       VDHRemoveIOHook
;       VDHPostEventSem
;       VDHQuerySem
;       VDHDestroySem
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_VDMTermination     proc    near             ;
        push    ebp
        push    ebx                              ; Save registers for VDMM
        push    edi
        push    esi

        pushf                                    ;Don't want interrupts
        cli                                      ;while we clean up
        .if <iIOHooksDone ne 0>
           lea     esi,PI

           xor     ecx,ecx
           .repeat
               .if <[esi].Port_Addr ne 0>            ; Disable IO Hook
                   .if <BIT iDOSProp and HW_COM>
                   .else
                       push    ecx
                       lea eax,IOHook                    ; IOHook parameter packet
                       movzx  ecx,[esi].Port_Addr        ; Port address to unhook
                       CallFn VDHRemoveIOHook,<ihVDM,ecx,8,eax>
                       pop     ecx
                   .endif
                   mov     eax,ihVDM
                   .if <eax eq [esi].hVDM_PI>        ; If this port is own by
                       mov  edx,ecx                  ; termination VDM, close
                       call Close_Request            ; the port.(edx=port_id)
                   .endif
               .endif
               add     esi,size Port_Info_Tab  ; Advance to next PI
               inc     ecx                     ; Next Port id
           .until <cl ge (iIOHooksDone)>       ; Repeat for all IOHooks Done
                                               ; (Should be all PI's except in
                                               ;  case of error in creation)
        .endif

        .if <iCreateSemDone ne 0>                 ;Did we create a semaphore?
           mov     eax,ihComSem
           CallFn  VDHQuerySem,<eax, offset FLAT:iSemState>
           .if <iSemState.vss_fOwned ne 0>        ;If sema4 is owned,
               mov     eax,ihComSem               ; then clear it
               CallFn  VDHPostEventSem,<eax>      ; Clear Semaphore
           .endif
           mov     eax,ihComSem
           CallFn  VDHDestroySem,<eax>            ; Release system resource
        .endif


        .if <hhookInt2fBPHook ne 0>               ; if we had a 2F hook...
               CallFn VDHFreeHook,<hhookInt2fBPHook>
        .endif
        .if <hhookVxDServiceBPHook ne 0>          ; if we had a VxD hook...
               CallFn VDHFreeHook,<hhookVxDServiceBPHook>
        .endif

        popf

Event_Success LABEL     near
        mov     eax,VDH_SUCCESS

Event_Ret:
        pop     esi
        pop     edi
        pop     ebx
        pop     ebp
        ret     4                        ; Clear hVDM parameter from the stack

VCOM_VDMTermination     endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_PDBDestroy
;
;DESCRIPTIVE NAME: VDM Application termination  Event handler entry point
;
;INPUT:
;       hVDM  - VDM handle
;       vPDB  - v86 segment of PDB
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       iflgIgnore
;  Global Data:
;       PI (Port_Info_Tab)
;
;FUNCTION:
;
;        ~ If any COM port was opened for this VDM, Call Close_Request to
;          close COM port(s)
;        ~ Reset data in Instance data area
;
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;       Close_Request
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_PDBDestroy         proc    near
        push    ebp
        mov     ebp,esp
        push    eax
        push    ebx                              ; Save registers for VDMM
        push    ecx
        push    esi

        mov     ax,[ebp+8]                       ; put PDB in eax
        .if <eax ne INVALID_PDB>                 ; if it's a valid PDB, do stuff

           test    iDOSProp, HOLD_RESOURCE       ;CP20D1390 If Hold Res property
          .if <z>                                ;is off, continue closing

             lea     esi,PI                      ; let esi->PI
             xor     ecx,ecx                     ; set ecx = 0
             .repeat                             ; Repeat for all three ports
                push    ecx                      ; save ecx
                   .if <ax eq [esi].pdb_PI>      ; If PDB matches,
                      mov     ebx,ihVDM          ;    and
                      .if <ebx eq [esi].hVDM_PI> ; If hVDM matches
                         mov  edx,ecx            ;  close the port
                         call Close_Request      ;  (edx=port_id)
                      .endif
                   .endif

                add esi,size Port_Info_Tab       ; Advance to next PI
                pop     ecx                      ; Restore ECX
                inc     ecx                      ; increase the count
             .until <ecx g (MAXNUMPORT-1)>       ; Repeat for all three PIs

             mov  iflgIgnore,0                   ; Reset iflgIgnore

          .endif
        .endif
        pop     esi
        pop     ecx
        pop     ebx
        pop     eax
        pop     ebp
        ret     8                        ; Clear parameters from the stack
VCOM_PDBDestroy         endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_VDMForeground                            ;@59629
;
;DESCRIPTIVE NAME: VDM Application Foreground Event handler entry point
;
;INPUT:
;       hVDM  - VDM handle
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;
;FUNCTION:
;
;        ~ Allocate a context hook and arm it for the VDM coming to the
;          foreground.
;        ~ The context hook is to determine if the Rx buffers should
;          be discarded or not.
;
;CALLED AT:
;       Task time
;
;INTERNAL REFERENCES:
;
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


VCOM_VDMForeground      proc    near

        push    ebp
        mov     ebp,esp

        push    eax
        push    ebx                              ; Save registers for VDMM
        push    ecx
        push    esi





        CallFn  VDHAllocHook, <VDH_CONTEXT_HOOK, \
                               offset FLAT:VCOM_VDMRxBufferFlush, 4>
        mov     ebx, eax                       ; save handle to hook

        ; get the address of the data

        CallFn  VDHQueryHookData, <eax>        ; get address of ref data


        ; store handle in reference data       ; system halt if error

        mov     [eax], ebx                     ; save handle in ref data


        ; Arm the context hook for the VDM coming into the foreground

        mov     eax, [bp+8]                    ; get hVDM
        CallFn  VDHArmContextHook, <ebx, eax>

        pop     esi
        pop     ecx
        pop     ebx
        pop     eax

        pop     ebp

        ret     4                        ; Clear parameters from the stack

VCOM_VDMForeground      endp


;start @95743
;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_VPMBegin
;
;DESCRIPTIVE NAME: VDM Application Protect Mode Begin Event handler
;
;INPUT:
;       hVDM  - VDM handle
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;
;FUNCTION:
;        Arm the break point hook for the INT 2Fh handler
;        Hook INT 2Fh
;
;CALLED AT:
;       Task time
;
;INTERNAL REFERENCES:
;
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************
VCOM_VPMBegin     proc    near

        push    ebp
        mov     ebp, esp

        push    eax
        push    ecx
        push    edx

        movzx   eax, [fpfnInt2fHandler.Segmt32]   ; Q: is BP addr empty?
        or      eax, [fpfnInt2fHandler.Offst32]
        .if <eax eq ZERO>
           mov   eax, [hhookInt2fBPHook]          ; Y: Arm the hook to
           CallFn VDHArmVPMBPHook eax             ;    get the BP addr
           mov [fpfnInt2fHandler.Offst32], eax    ;    returned in DX:EAX
           mov [fpfnInt2fHandler.Segmt32], dx
        .endif

        lea    eax, fpfnOldInt2f                  ; get the old INT 2F handler
        CallFn VDHGetVPMIntVector <2Fh, eax>

        movzx  edx, [fpfnInt2fHandler.Segmt32]    ; replace it with ours
        mov    eax, [fpfnInt2fHandler.Offst32]
        CallFn VDHSetVPMIntVector <2Fh, edx, eax>

        pop     edx
        pop     ecx
        pop     eax
        pop     ebp
        ret     4                        ; Clear parameters from the stack

VCOM_VPMBegin    endp
;end @95743


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_VDMRxBufferFlush                         ;@59629
;
;DESCRIPTIVE NAME: Flush the Rx buffers if property is set
;
;INPUT:
;       pRefData on stack
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;
;FUNCTION:
;
;          If the Flush buffer at switch to foreground property is set
;          AND there is data in the Rx buffer, flush the Rx buffer
;
;CALLED AT:
;       VDM task time (this is a context hook)
;
;INTERNAL REFERENCES:
;
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************


VCOM_VDMRxBufferFlush   proc    near

        push    ebp
        mov     ebp,esp

        push    eax
        push    ebx                              ; Save registers for VDMM
        push    ecx
        push    esi
        push    edx




        mov     eax, [ebp+12]                  ; Get pref data from stack
        mov     eax, [eax]                     ; get handle to this hook
        CallFn  VDHFreeHook, <eax>             ; free this hook



        .if <BIT iDOSProp and COM_FLUSH_BACKGROUND>

             lea     esi,PI                      ; let esi->PI
             xor     ecx,ecx                     ; set ecx = 0
             .repeat                             ; Repeat for all three ports
                 push    ecx
                 mov     edx, ecx                ; set com port id (0-3)

                 .if    <BIT [esi].flgRxOp and RXINT_REQD> or ;RXINT requested
                 .if    <BIT [esi].flgRxOp and MORE_TO_COME>  ;more in buffer
                     or     [esi].VLSR, DR       ; preset DataReady
                 .endif

                 .while <BIT [esi].VLSR and DR>
                     mov ecx,RBR                 ; set register
                     call Virt_ComIn
                 .endwhile

                 add esi,size Port_Info_Tab      ; Advance to next PI
                 pop     ecx                     ; Restore ECX
                 inc     ecx                     ; increase the count
             .until <ecx g (MAXNUMPORT-1)>       ; Repeat for all three PIs

        .endif

        pop     edx
        pop     esi
        pop     ecx
        pop     ebx
        pop     eax

        pop     ebp

        ret     8                        ; Clear parameters from the stack

VCOM_VDMRxBufferFlush   endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_PDBChange
;
;DESCRIPTIVE NAME: VDM Application change Event handler entry point
;                  (App may shell to COMMAND.COM and return)
;
;INPUT:
;       hVDM  - VDM handle
;       vPDB  - v86 segment of PDB
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       ipdbCurrent
;  Global Data:
;       PI (Port_Info_Tab)
;
;FUNCTION:
;
;        ~ Change ipdbCurrent to new PDB
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;
;EXTERNAL REFERENCES:
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_PDBChange          proc    near
        push    ebp
        mov     ebp,esp
        push    eax
        mov     ax,[ebp+8]
        mov     ipdbCurrent,ax
        pop     eax
        pop     ebp
        ret     8                        ; Clear parameters from the stack
VCOM_PDBChange          endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_Hold_Res
;
;DESCRIPTIVE NAME: VCOM Hold Resource DOS Property Handler
;
;INPUT:
;       hVDM  - VDM handle
;       vPDB  - v86 segment of PDB
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       ipdbCurrent
;  Global Data:
;       PI (Port_Info_Tab)
;
;FUNCTION:
;
;        ~ Change ipdbCurrent to new PDB
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;
;EXTERNAL REFERENCES:
;
;NOTE: CP20D1390
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_Hold_Res             proc    near
        push    ebp
        mov     ebp,esp

        cmp     DWORD PTR [ebp+8], 0
        je      SHORT no_hold_res

        or      iDOSProp,HOLD_RESOURCE
        jmp     SHORT end_prop_check

no_hold_res:

        and     iDOSProp,NOT HOLD_RESOURCE

end_prop_check:

        leave
        ret     16                       ; Clear parameters from the stack
        nop
VCOM_Hold_Res             endp




;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_Rx_Flush
;
;DESCRIPTIVE NAME: VCOM Rx Buffer Flush DOS Property Handler
;
;INPUT:
;       hVDM  - VDM handle
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;
;  Global Data:
;
;
;FUNCTION:
;
;
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;
;EXTERNAL REFERENCES:
;
;NOTE: CP20D1390
;
;********************** END OF SPECIFICATIONS *********************************


VCOM_Rx_Flush             proc    near
        push    ebp
        mov     ebp,esp

        leave
        ret     16                       ; Clear parameters from the stack
        nop
VCOM_Rx_Flush             endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_HW_COM
;
;DESCRIPTIVE NAME: VCOM Hardware COM Direct Access Handler
;
;INPUT:
;       hVDM  - VDM handle
;       vPDB  - v86 segment of PDB
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       ipdbCurrent
;  Global Data:
;       PI (Port_Info_Tab)
;
;FUNCTION:
;
;        ~ Change ipdbCurrent to new PDB
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;
;EXTERNAL REFERENCES:
;
;NOTE: CP20D1390
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_HW_COM               proc    near
        push    ebp
        mov     ebp,esp

        cmp     DWORD PTR [ebp+8], 0
        je      SHORT no_com_select

        or      iDOSProp,COM_SELECT_ALL
        jmp     SHORT end_select_prop_check

no_com_select:

        or      iDOSProp,COM_SELECT_ALL

end_select_prop_check:

        leave
        ret     16                       ; Clear parameters from the stack
        nop
VCOM_HW_COM     endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_COM_SELECT
;
;DESCRIPTIVE NAME: VCOM Select COM Port
;
;INPUT:
;       hVDM  - VDM handle
;       vPDB  - v86 segment of PDB
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;       ihVDM
;       ipdbCurrent
;  Global Data:
;       PI (Port_Info_Tab)
;
;FUNCTION:
;
;        ~ Change ipdbCurrent to new PDB
;
;CALLED BY:
;       VDMM at Task time
;
;INTERNAL REFERENCES:
;
;EXTERNAL REFERENCES:
;
;NOTE: CP20D1390
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_COM_SELECT               proc    near
        push    ebp
        mov     ebp,esp

        cmp     DWORD PTR [ebp+8], 0
        je      SHORT no_hold_res

        or      iDOSProp,HW_COM
        jmp     SHORT end_hw_prop_check

no_hw_com:

        and     iDOSProp,NOT HW_COM

end_hw_prop_check:

        leave
        ret     16                       ; Clear parameters from the stack
        nop
VCOM_COM_SELECT endp



;@95743 start
;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_Int2fHandler
;
;DESCRIPTIVE NAME: Int 2fh handler
;
;INPUT: (on stack)
;        ulData  -> Base address BP hook reference data
;        pcrf    -> Base address of Client Register Frame
;
;
;OUTPUT:
;       address of service router table in ES:DI
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;        NONE
;  Global Data:
;        NONE
;
;FUNCTION:
;       Check for AX = 1684h and BX = device id of Windows 3.11 virtual
;           comm device driver
;       If registers match up return the address of the VxD service router
;       If not, chain to the next INT 2F handler
;
;CALLED BY:
;
;
;INTERNAL REFERENCES:
;
;
;EXTERNAL REFERENCES:
;       NONE
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_Int2fHandler  proc    near
        push    ebp
        mov     ebp,esp

        mov     ebx, [ebp+8]                ;Pointer to Client Register Frame
        mov     eax, [ebx].crf_eax                      ; INT 2F function
        shl     eax, 16
        mov     ax, word ptr [ebx].crf_ebx              ; device id
        .if <eax eq VCOM_VXD_MAGIC>
            movzx   eax, [fpfnVxDServiceRouter.Segmt32] ; Q: do we have the
            or      eax, [fpfnVxDServiceRouter.Offst32] ;    router addr?

VCOM_VxD_query label near
public VCOM_VxD_query

            .if <eax eq ZERO>
               mov   eax, [hhookVxDServiceBPHook]       ; No
               CallFn VDHArmVPMBPHook eax               ; arm the hook to
               mov [fpfnVxDServiceRouter.Offst32], eax  ; get it in DX:EAX
               mov [fpfnVxDServiceRouter.Segmt32], dx
            .endif

            mov   ax, [fpfnVxDServiceRouter.Segmt32]    ; return router
            mov   [ebx].crf_es, ax                      ;  to client in
            mov   eax, [fpfnVxDServiceRouter.Offst32]   ;  ES:DI
            mov   [ebx].crf_edi, eax
            CallFn  VDHPopInt,<>                        ; don't chain
        .else
           mov   ax, [fpfnOldInt2f.Segmt32]             ; chain to next
           mov   [ebx].crf_cs, ax                       ;  handler
           mov   eax, [fpfnOldInt2f.Offst32]
           mov   [ebx].crf_eip, eax
        .endif

        pop     ebp
        ret     8                                       ; clean up.
VCOM_Int2fHandler  endp

;@95743 end

;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_Int14h_ReturnProc
;
;DESCRIPTIVE NAME: Int 14h Return Hook handler
;
;INPUT: (on stack)
;        ulData  -> Base address of PI for this port
;        pcrf    -> Base address of Client Register Frame
;
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;        NONE
;  Global Data:
;        NONE
;
;FUNCTION:
;       Set up variables/stack when called for return hook
;       Call Int14h_Wait to complete original call (or set up another
;           return hook)
;       Put return value in client's CRF.
;
;CALLED BY:
;       8086EM
;
;INTERNAL REFERENCES:
;       Int14h_Wait
;
;EXTERNAL REFERENCES:
;       NONE
;
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_Int14h_ReturnProc  proc    near
        push    ebp
        mov     ebp,esp
        push    esi
        push    ebx

        mov  iInt14h_Complete, COMPLETED ;Default is do VDHPopint on return

        mov     ebx,[ebp].ss_pcrf           ;Pointer to Client Register Frame
        mov     esi,[ebp].ss_ppi
        mov     esi,[esi]                   ;Pointer to correct PI

        push    ebx

        call    Int14h_Wait                 ;call to continue wait for status

        pop     ebx

        .if     <iInt14h_Complete eq COMPLETED>
            and     eax,0FFFFh              ;Clear out EAX except for AX
            mov     [ebx].crf_eax,eax       ;Put EAX in Client Register Frame
            CallFn  VDHPopInt,<>            ;We're finished, don't return
        .endif

        pop     ebx
        pop     esi
        pop     ebp
        clc
                                            ;Don't chain interrupts
        ret     8                           ;We have to clean up.
VCOM_Int14h_ReturnProc  endp

EndCode                                 ;end CSWAP_TEXT segment
;============================================================================
;============================================================================
;     Interrupt time code follows.  It cannot be swapped.
;============================================================================

DefCode PRIVATE,GLOBAL,PASCAL           ;Start _TEXT segment

;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_PCOMNotify
;
;DESCRIPTIVE NAME: VCOM's Entry point for notifications from PCOM
;
;INPUT:
;       AH = function
;               VCOM_RXInt_Notify = 4; Rx interrupt
;               VCOM_TXInt_Notify = 2; Tx interrupt
;               VCOM_MSInt_Notify = 0; MS interrupt
;       DL = Port number ( 0 = com1, 1 = com2, 2 = com3 )
;       BL  =  contents of MSR excepts for delta bits, if MSINT.
;              LSR error bits (or 0) if RXINT.
;
;OUTPUT:
;       NONE
;
;RELATED DATA OBJECTS:
;  Instance Data per VDM:
;
;  Global Data:
;       Variables in PI table:
;          hVDM
;
;FUNCTION:
;       This routine handles the notifications from PCOM,
;       only when the port has been opened.
;
;CALLED BY:
;       PCOM at Interrupt time
;
;INTERNAL REFERENCES:
;       Virt_HWInt
;EXTERNAL REFERENCES:
;       NONE
;NOTE:
;
;********************** END OF SPECIFICATIONS *********************************

VCOM_PCOMNotify proc    far


        push    ds                              ;save PCOM's DS register
        push    es                              ;save PCOM's ES register
        pushad

        mov     cx, SEG FLAT:_DATA              ;get our data segment
        mov     DS,cx
        mov     ES,cx

        assume  ds:FLAT,es:FLAT

        .if     <dl ae MAXNUMPORT>              ;validate dl parameter
            jmp VPNotify_Exit                   ;
        .endif                                  ;

        lea     esi,PI                          ;get the base addr of PI

        .for    bh = 1 to dl by 1               ;Point to correct PI entry
            add     esi, size Port_Info_Tab     ;
        .next bh                                ;

        .if     <[esi].hVDM_PI ne -1>           ;Has the port an owner yet?
            call    Virt_HWInt                  ;Ok. Handles it
        .endif

VPNotify_Exit:
        popad
        pop     es                              ;restore PCOM's ES register
        pop     ds                              ;restore PCOM's DS register
        assume ds:nothing,es:nothing

        ret                                     ;match what's on stack
VCOM_PCOMNotify endp

EndCode                                 ;end _TEXT segment
        END
