;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;SKIP_SETCOM     equ     1
;SKIP_CTX        equ     1
;SKIP_TRMCOM     equ     1
;SKIP_STACOM     equ     1
;SKIP_EXTFN      equ     1
;SKIP_FLUSH      equ     1
;SKIP_CEVT       equ     1
;SKIP_CEVTGET    equ     1
;SKIP_SETMSR     equ     1
;SKIP_WRITESTG   equ     1
;SKIP_READSTG    equ     1
;SKIP_ENABLENOT  equ     1

DEBUGINT3       macro
;       int     3
                endm

        Page    ,132
        NAME    VCOM
        TITLE   VCOM        - Virtual COM device driver
        SUBTTL  VCOMVXD.ASM - VxD Services
; ****************************************************************************
; *                                                                          *
; *                                                                          *
; *                                                                          *
; ****************************************************************************

;;;;;;;;;;;;;;;;;;;;;;; START OF FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;
;SOURCE FILE NAME: VCOMVXD.ASM
;
;DESCRIPTIVE NAME: VCOM VxD Services for         3.11
;
;FUNCTION:
;       This file contains procedures that are called by protected mode
;       programs running in a VDM.  A PM program can execute an INT 2Fh
;       with AX = 1684h and BX = 002Bh expecting an address to be returned
;       in ES:DI.  It can then make calls to this address with a function
;       number in AX.  This VDD answers the 2F/1684/002B with the address
;       of the router procedure below.  The router procedure examines the
;       function number in AX and jumps to the correct service procedure.
;
;NOTES:
;       Dependencies: PCOM must be present.
;       Restrictions: Currently only supports COM1, COM2, and COM3 (PS/2).
;
;SUBROUTINES:
;
;     VCOM_OpenCom
;     VCOM_SetCom
;     VCOM_Setup
;     VCOM_ctx
;     VCOM_TrmCom
;     VCOM_StaCom
;     VCOM_ExtFn
;     VCOM_Flush
;     VCOM_cevt
;     VCOM_cevtGet
;     VCOM_SetMSRShadow
;     VCOM_WriteString
;     VCOM_ReadString
;     VCOM_EnableNotify
;
;
;EXTERNAL REFERENCES:
;
;;;;;;;;;;;;;;;;;;;;;;; END OF FILE SPECIFICATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       Robert A. Rose & Bob Russin
;       (c) International Business Machines Corporation
;       September 1994
;
;Modification History
;
;   09/16/94  @95743               Bob Russin      Entire file added for @95743
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
STRICT  equ     1

        .386p

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

include VDDSEG.INC
include VCOMDATA.INC

;***    DCB - Device Control Block
;
DefStruc ,dcb_s
        CHAR    dcb_id
        USHORT  dcb_baudrate
        CHAR    dcb_bytesize
        CHAR    dcb_parity
        CHAR    dcb_stopbits
        USHORT  dcb_rlstimeout
        USHORT  dcb_ctstimeout
        USHORT  dcb_dsrtimeout
        CHAR    dcb_bitmask1
        CHAR    dcb_bitmask2
        CHAR    dcb_xonchar
        CHAR    dcb_xoffchar
        USHORT  dcb_xonlim
        USHORT  dcb_xofflim
        CHAR    dcb_pechar
        CHAR    dcb_eofchar
        CHAR    dcb_evtchar
        USHORT  dcb_txdelay
EndStruc DCB

;***
;*** dcb_bitmask1 - Bits in DCB bitmask1
;***
fBinary         equ     01h             ;Binary mode
fRtsDisable     equ     02h             ;Don't assert RTS at init time
fParity         equ     04h             ;Enable parity checking
fOutxCtsFlow    equ     08h             ;CTS handshaking on output
fOutxDsrFlow    equ     10h             ;DSR handshaking on output
fDummy1         equ     20h             ;reserved
fDummy2         equ     40h             ;reserved
fDtrDisable     equ     80h             ;Don't Assert DTR at init time

;***
;*** dcb_bitmask2 - Bits in DCB bitmask2
;***
fOutX           equ     01h             ;Enable output XON/XOFF
fInX            equ     02h             ;Enable input XON/XOFF
fPeChar         equ     04h             ;Enable parity error replacement
fNull           equ     08h             ;Enable NULL stripping
fChEvt          equ     10h             ;Enable Rx character event
fDtrflow        equ     20h             ;DTR handshake on input
fRtsflow        equ     40h             ;RTS handshake on input
fDummy3         equ     80h             ;reserved

DefStruc ,cms_s
        CHAR    COMS_BitMask1
        USHORT  COMS_cbInQue    ;count of characters in Rx Queue
        USHORT  COMS_cbOutQue   ;count of characters in Tx Queue
EndStruc COMSTAT

;***
;*** COMS_BitMask1 - Bits in COMSTAT bitmask1
;***
fCtsHold        equ     01h             ;Transmit is on CTS hold
fDsrHold        equ     02h             ;Transmit is on DSR hold
fRlsdHold       equ     04h             ;Transmit is on RLSD hold
fXoffHold       equ     08h             ;Received handshake
fXoffSent       equ     10h             ;Issued handshake
fEof            equ     20h             ;End of File character found
fTxim           equ     40h             ;Character being transmitted

MAGIC_1 equ     7523h
MAGIC_2 equ     98deh

;**     Hardware clock speed
;
; clock = 115200 = 1C200h
;
CLOCK_RATEHI    EQU     1               ; MSW of clock rate
CLOCK_RATELO    EQU     0C200h          ; LSW of clock rate

CBR_110         equ     0FF10h          ;Baud rate indexes
CBR_300         equ     0FF11h
CBR_600         equ     0FF12h
CBR_1200        equ     0FF13h
CBR_2400        equ     0FF14h
CBR_4800        equ     0FF15h
CBR_9600        equ     0FF16h
CBR_14400       equ     0FF17h
CBR_19200       equ     0FF18h
CBR_38400       equ     0FF1Bh
CBR_56000       equ     0FF1Fh
CBR_128000      equ     0FF23h
CBR_256000      equ     0FF27h


; Event Mask Bits
EV_RXCHAR       equ     0001h   ;Enable detct of any character received
EV_RXFLAG       equ     0002h   ;Enable detct of special event character
EV_TXEMPTY      equ     0004h   ;Enable detct of last char in xmit queue is sent
EV_CTS          equ     0008h   ;Enable detct of the CTS signal
EV_DSR          equ     0010h   ;Enable detct of the DSR signal
EV_RLSD         equ     0020h   ;Enable detct of the receive-line-signal-detect (RLSD) signal
EV_BREAK        equ     0040h   ;Enable detct of a BREAK signal
EV_ERR          equ     0080h   ;Enable detct of errors (frame,overrun,parity)
EV_RING         equ     0100h   ;Enable detct of ring indicator
EV_PERR         equ     0200h   ;Enable detct of print errs (DNS,IOE,LOOP,PTO)

DefCode     IMPORT,SWAP,PASCAL              ;Start SWAP_TEXT segment
        DefFn   PDDProc_Handler             ;Import definitions
        DefFn   PDDProc_IOCTL_Handler
        DefFn   VDHPopVPMFarRet
        DefFn   Open_Request
        DefFn   Close_Request
        DefFn   Set_MCR_Request
        DefFn   Get_MCR_Request
        DefFn   Set_LCR_Request
        DefFn   Get_LCR_Request
        DefFn   Virt_Clear_IIR
        DefFn   Virt_ComIn
        DefFn   Virt_ComOut
EndCode

DefCode EXPORT,SWAP,PASCAL              ;Start CSWAP_TEXT segment
        DefFn  VCOM_VxDServiceRouter
EndCode                                 ;end CSWAP_TEXT segment


DefCode PRIVATE,SWAP,PASCAL           ;Start CSWAP_TEXT segment

;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_VxDServiceRouter
;
;DESCRIPTIVE NAME:         3.11 VxD Services Router
;
;INPUT: (on stack)
;        ulData  -> Base address BP hook reference data
;        pcrf    -> Base address of Client Register Frame
;
;
;OUTPUT:
;        CY flag
;
;FUNCTION:
;       Check for valid service number in client's AX
;       If AX in range, service the request otherwise set CY in
;          client's eflags and return
;
;********************** END OF SPECIFICATIONS *********************************
VCOM_VxDServiceRouter  proc    near
        assume ds:nothing,es:nothing
        push    ebp
        mov     ebp,esp

        mov     ebx, [ebp+8]                ; Pointer to Client Register Frame
        movzx   esi, word ptr [ebx].crf_eax

        .if <esi ge VCOM_VXD_MIN_SVC> and
        .if <esi le VCOM_VXD_MAX_SVC>
           push    ds                           ;VDHPopVPMFarRet is dependent
           push    es                           ;  on DS and ES *both* == FLAT
           call    VCOM_VxD_Service_Table[esi*4]
           pop     es
           pop     ds
        .else
           or      [ebx].crf_eflag, 1
        .endif
        CallFn  VDHPopVPMFarRet
        cmp     ax,0                    ;check for VDHPopVPMFarRet errors
        jne     srok
        int     3                       ;bugbug - put fault code here
srok:
        pop     ebp
        ret     8                           ;We have to clean up.
VCOM_VxDServiceRouter  endp

;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_OpenCom
;
;DESCRIPTIVE NAME:
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;       BX=Port ID number (0=COM1  1=COM2  2=COM3  3=COM4)
;
;VDM Frame Exit:
;    DX:AX=Handle for future calls
;                                                                        RAROSE
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_OpenCom
VCOM_OpenCom           proc    near
        DEBUGINT3
        mov     eax,[ebx].crf_ebx
        cmp     eax,3
        jge     ocbad

        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   edx,word ptr [ebx].crf_ebx
        mov     cx,1                    ; don't do that IRQ thingy...
        call    Open_Request
        cmp     ah,0
        jnz     ocbad

        xor     edx,edx                     ; high order of port always 0
        movzx   eax,word ptr [ebx].crf_ebx  ; concoct a handle based on COMx ID
        xor     dx,MAGIC_1
        xor     ax,MAGIC_2
        mov     word ptr [ebx].crf_eax,ax
        mov     word ptr [ebx].crf_edx,dx
ocbye:
        ret
ocbad:  mov     word ptr [ebx].crf_eax,-1
        mov     word ptr [ebx].crf_edx,-1
        jmp short ocbye
VCOM_OpenCom           endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_SetCom
;
;DESCRIPTIVE NAME: Set COM port parameters
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;      EBX=Handle from Open call
;    ES:DX=pDCB
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;                                                                        RAROSE
; N.B.:
;    Not all information from the DCB is used.  Timeouts, for example, don't
;    make a whole lot of sense when PCOM is actually running the show.  Also
;    things like Binary/Cooked and NULL stripping are done here in VCOM
;    instead of in PCOM.
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_SetCom
VCOM_SetCom            proc    near
        DEBUGINT3
ifndef SKIP_SETCOM
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      scbad
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
        push    dx

        lea     esi, PI                 ; ESI -> PI for COM1
        mov     eax,edx                 ; 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

        mov     es,word ptr [ebx].crf_es
        movzx   edi,word ptr [ebx].crf_edx      ;ES:EDI=DCB structure

        mov     cx,es:[edi].dcb_baudrate        ;Configure Baud Rate
        cmp     ch,0FFh                         ;actual or index?
        jne     actual

        movzx   ecx,cl                          ;convert index to divisor
        cmp     ecx,10h
        jl      bdbad
        sub     ecx,10h
        cmp     ecx,17h
        jg      bdbad
        mov     cx,word ptr BaudTbl[ecx*2]
        jcxz    bdbad
        jmp short stbau

actual:
;
; 1. Set up baud rate.  Actual baud rate in CX
;
        mov     dx,CLOCK_RATEHI         ;convert baudrate to divisor
        mov     ax,CLOCK_RATELO         ; (dx:ax) = clock rate
        div     cx                      ; (ax) = divisor = clock / baud
                                        ; (dx) = remainder
        mov     cx,ax                   ; (cx) = divisor
stbau:  mov     ax,SETDLLDLM            ;set the baud rate
        pop     dx                      ;get port number back
        call    PDDProc_Handler

;
; 2. Set up Word length, Parity and Stop bits
;
        push    ebx
        push    edi
        mov     al,es:[edi].dcb_bytesize        ;Configure byte size
        mov     [esi].Ioctl_Parm_Pkt.Data_Bits_Parm,al
        mov     al,es:[edi].dcb_parity          ;Configure parity
        mov     [esi].Ioctl_Parm_Pkt.Parity_Parm,al
        mov     al,es:[edi].dcb_stopbits        ;Configure Stop Bits
        mov     [esi].Ioctl_Parm_Pkt.Stop_Bits_Parm,al
        mov     ax,SETLCR
        call    PDDProc_IOCTL_Handler
        pop     edi
        pop     ebx

;
; 3. Set up our copies of XON/XOFF, Parity-Replace, NULL-strip, etc.
;
        push    es                      ;swap ds,es
        push    ds
        pop     es
        pop     ds
        mov     esi,edi
        mov     edi,offset FLAT:PDCD
        mov     ecx,25
        rep movsb
        push    es                      ;swap ds,es back
        push    ds
        pop     es
        pop     ds
endif
        mov     word ptr [ebx].crf_eax,0
        ret
bdbad:  pop     dx
scbad:  mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_SetCom            endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:   VCOM_Setup
;
;DESCRIPTIVE NAME:  Configure COM port buffers
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;    SS:SP+0 =handle from Open Call
;    SS:SP+4 =ptr to base of receive queue
;    SS:SP+8 =size of rcv queue
;    SS:SP+10=ptr to base of transmit queue
;    SS:SP+14=size of transmit queue
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;                                                                        RAROSE
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_Setup
VCOM_Setup             proc    near
        DEBUGINT3
;
; Tell Windows... A-OK!  (We don't use their buffers anyways!)
;
        mov     word ptr [ebx].crf_eax,0

        ret
VCOM_Setup             endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_ctx
;
;DESCRIPTIVE NAME:  Out-of-band Character Transmission
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CL=Character to send immediately
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_ctx
VCOM_ctx               proc    near
        DEBUGINT3
ifndef SKIP_CTX
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      ctxbad
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number

        push    bx
        mov     bx,word ptr [ebx].crf_ecx
        mov     ax,PUTBYTE                      ;DL=port BL=char
        call    PDDProc_Handler                 ;BUG     this could be optimized
        pop     bx
endif
        mov     word ptr [ebx].crf_eax,0
        ret
ctxbad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_ctx               endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_TrmCom
;
;DESCRIPTIVE NAME: Close COM port
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;                                                                        RAROSE
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_TrmCom
VCOM_TrmCom            proc    near
        DEBUGINT3
ifndef SKIP_TRMCOM
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      tcbad
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
        cmp     edx,3
        jge     tcok

        push    dx
        movzx   eax,dx
        lea     esi,PI                  ;figure offset to proper PI struct
        mov     cx,size Port_Info_Tab
        mul     cx
        add     esi,eax
        pop     dx

        xor     eax,eax
        mov     offset FLAT:EventPtr[edx*4],eax                ;stop updates...
        mov     offset FLAT:VCOM_VXD_MSRshadow[edx*4],eax      ;stop updates...

        call    Close_Request
endif
tcok:   mov     word ptr [ebx].crf_eax,0
        ret
tcbad:  mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_TrmCom            endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_StaCom
;
;DESCRIPTIVE NAME: Get port status
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;      ES:DX=pointer to status buffer
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;                                                                        RAROSE
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_StaCom
VCOM_StaCom            proc    near
        DEBUGINT3
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      stabad
ifndef SKIP_STACOM
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number

        push    es
        mov     ax,word ptr [ebx].crf_es
        cmp     ax,0
        jz      stabde                          ; ES can't be 0! (crazy app!)
        mov     es,ax
        movzx   edi,word ptr [ebx].crf_edx      ; es:edi=buffer for status
        push    ebx

        lea     esi, PI                 ; ESI -> PI for COM1
        mov     eax,edx                 ; eax = port number
        mov     cl,size Port_Info_Tab   ; dl = structure size
        mul     cl                      ; ax = structure offset for this port
        add     esi,eax                 ; esi = linear address of port struct

        mov     ecx,6                   ; Get MSR
        call    Virt_ComIn
        xor     bx,bx
        mov     bl,al
        shr     bx,4                    ;BL=_ _ _ _ DCD RI DSR CTS
        test    bx,8
        jz      @F
        or      bx,4                    ;BL=_ _ _ _ DCD DCD DSR CTS
@@:     and     bx,7
        or      bl,PSTAT.COMS_BitMask1
        mov     es:[di],bl
        inc     di

        or      [esi].flgRxOp, NO_RXINT_REQD  ;Do a real read....
        mov     ecx,5
        call    Virt_ComIn
        mov     al,[esi].VLSR
        xor     bx,bx
        test    al,1                    ;check RD bit...
        jz      @F
        mov     bl,0Fh                  ;RD bit set, so say we've got data

@@:     mov     es:[di],bx
        inc     di
        inc     di
        mov     bx,0
        test    al,60h                  ;Transmitter Empty?
        jnz     @F
        mov     bx,07FFFh
@@:     mov     es:[di],bx
        call    UpdateEvents
        pop     ebx
stabde: pop     es
endif
        mov     word ptr [ebx].crf_eax,0
        ret
stabad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_StaCom            endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_ExtFn
;
;DESCRIPTIVE NAME: Extended Functions
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=Function number (12=set break  13=clear break)
;             1=XOFF received
;             2=XON received
;             3=set RTS
;             4=clear RTS
;             5=set DTR
;             6=clear DTR
;             7=reset printer                            (do nothing for com)
;             8=get max number of supported lpt ports    (handled by comm.drv)
;             9=get max number of supported com ports    (handled by comm.drv)
;            10=get base port address and IRQ            (handled by comm.drv)
;            11=                                         (no spec)
;            12=set break
;            13=clear break
;
;VDM Frame Exit:
;      EAX=Return value (or)
;    DX:AX=Return value
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_ExtFn
VCOM_ExtFn             proc    near
        DEBUGINT3
ifndef SKIP_EXTFN
        assume DS:FLAT
        mov     eax,[ebx].crf_ebx
        cmp     eax,-1
        je      VCOM_ExtFn_UnSupported
        xor     eax,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number

        mov     edx,eax                 ;Port_ID
        lea     esi,PI                  ;figure offset to proper PI struct
        mov     cx,size Port_Info_Tab
        mul     cx
        add     esi,eax                 ;ESI -> PI struct

        movzx   edi, word ptr [ebx].crf_ecx     ;function number
        cmp     edi, 13
        ja      VCOM_ExtFn_UnSupported
        jmp     VCOM_ExtFn_Table[edi*4]

public VCOM_ExtFn_SETXOFF
VCOM_ExtFn_SETXOFF:
        or      PSTAT.COMS_BitMask1, fXoffHold
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_SETXON
VCOM_ExtFn_SETXON:
        and     PSTAT.COMS_BitMask1, 0FFh-fXoffHold
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_SETRTS
VCOM_ExtFn_SETRTS:
        call    Get_MCR_Request
        or      [esi].VMCR, RTS
        call    Set_MCR_Request
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_CLRRTS
VCOM_ExtFn_CLRRTS:
        call    Get_MCR_Request
        and     [esi].VMCR, not RTS
        call    Set_MCR_Request
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_SETDTR
VCOM_ExtFn_SETDTR:
        call    Get_MCR_Request
        or      [esi].VMCR, DTR
        call    Set_MCR_Request
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_CLRDTR
VCOM_ExtFn_CLRDTR:
        call    Get_MCR_Request
        and     [esi].VMCR, not DTR
        call    Set_MCR_Request
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_SETBRK
VCOM_ExtFn_SETBRK:
        call    Get_LCR_Request
        or      [esi].VLCR, BREAKBIT
        call    Set_LCR_Request
        jmp     VCOM_ExtFn_Return

public VCOM_ExtFn_CLRBRK
VCOM_ExtFn_CLRBRK:
        call    Get_LCR_Request
        and     [esi].VLCR, not BREAKBIT
        call    Set_LCR_Request
endif

public VCOM_ExtFn_Return
VCOM_ExtFn_Return:
        mov     [ebx].crf_eax, 0
        mov     word ptr [ebx].crf_edx, 0
        ret

public VCOM_ExtFn_UnSupported
VCOM_ExtFn_UnSupported:
        mov     [ebx].crf_eax, -1
        mov     word ptr [ebx].crf_edx, 0ffffh
        ret
VCOM_ExtFn             endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_Flush
;
;DESCRIPTIVE NAME: Flush the specified queue
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=queue to flush (0=transmit, 1=receive)
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;
;********************** END OF SPECIFICATIONS *********************************
FLUSH_RX        equ   1

        public  VCOM_Flush
VCOM_Flush             proc    near
        DEBUGINT3
ifndef SKIP_FLUSH
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      flubad
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number

        cmp     word ptr [ebx].crf_ecx, 1         ; which queue are we
        jg      flubad                            ; flushing? CX = 1 is Rx
        jne     fluTx                             ;           CX = 0 is Tx
fluRx:
        mov     ax, GETBYTE                    ; dl = Port_ID already.
        call    PDDProc_Handler
        test    cl, 1                          ; more to come?
        jz      flugood
        jmp     short fluRx
fluTx:
        ;nop for now
flugood:
endif
        mov     word ptr [ebx].crf_eax,0
        ret

flubad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_Flush             endp


;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_cevt
;
;DESCRIPTIVE NAME: Set event mask and Bitmask shadow
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=event mask to set
;      ES:DX=far pointer to event mask shadow
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_cevt
VCOM_cevt              proc    near
        DEBUGINT3
        mov     eax,[ebx].crf_ebx
        cmp     eax,-1
        je      cevbad
ifndef SKIP_CEVT
        xor     eax,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number

        mov     cx,word ptr [ebx].crf_edx       ;save pointer
        mov     offset FLAT:EventPtr[eax*4],cx
        mov     cx,word ptr [ebx].crf_es
        mov     offset FLAT:EventPtr[eax*4+2],cx

        mov     cx,word ptr [ebx].crf_ecx
        mov     offset FLAT:EventMask[eax*2],cx
        and     offset FLAT:Events[eax*4],cx    ;update current mask
endif
        mov     word ptr [ebx].crf_eax,0
        ret
cevbad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_cevt              endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_cevtGet
;
;DESCRIPTIVE NAME:  Return accumulated mask, and clear some events
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=mask of bits to clear
;      ES:DX=DWORD to put bitmask into
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_cevtGet
VCOM_cevtGet           proc    near
        DEBUGINT3
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      gtcbad
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
ifndef SKIP_CEVTGET
        push    es
        mov     ax,word ptr [ebx].crf_es
        mov     es,ax
        movzx   edi,word ptr [ebx].crf_edx
        mov     eax,offset FLAT:Events[edx*4]
        stosd                                   ;update client EVENT shadow
        movzx   ecx,word ptr [ebx].crf_ecx
        and     eax,ecx
        mov     offset FLAT:Events[edx*4],eax
        pop     es
endif
        mov     word ptr [ebx].crf_eax,0
        ret
gtcbad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_cevtGet           endp



;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_SetMSRShadow
;
;DESCRIPTIVE NAME: Give location to shadow MSR value into
;                     (To Application this value is READ ONLY)
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;      ES:DX=BYTE pointer to MSR shadow buffer
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_SetMSRShadow
VCOM_SetMSRShadow      proc    near
        DEBUGINT3
        assume  ds:FLAT
        mov     edx,[ebx].crf_ebx
        cmp     edx,-1
        je      msrbad
        xor     edx,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
ifndef SKIP_SETMSR
        mov     ax,word ptr [ebx].crf_edx
        mov     word ptr VCOM_VXD_MSRshadow[edx*4],ax
        mov     ax,word ptr [ebx].crf_es
        mov     word ptr VCOM_VXD_MSRshadow[edx*4+2],ax
endif
        mov     word ptr [ebx].crf_eax,0
        ret
msrbad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_SetMSRShadow      endp


ifdef OLDWRITESTRING
;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_WriteString
;
;DESCRIPTIVE NAME: Send a stream of characters out
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=count of characters
;      ES:DX=buffer to send
;         SI=character to send if CX == 1
;
;VDM Frame Exit:
;       AX=Number of characters written
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_WriteString
VCOM_WriteString       proc    near
        DEBUGINT3
        mov     eax,[ebx].crf_ebx
        cmp     eax,-1
        je      wstbad
        xor     eax,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
ifndef SKIP_WRITESTG
        mov     dx,ax                           ;setup port number for later

        movzx   ecx,word ptr [ebx].crf_ecx
        cmp     ecx,1
        jne     wsstg
        push    ebx
        mov     bx,word ptr [ebx].crf_esi
        jmp short wsone
wsstg:  mov     ax,word ptr [ebx].crf_es
        mov     es,ax
        movzx   edi,word ptr [ebx].crf_edx
        push    ebx
wsnxt:  mov     bl,es:[edi]
        inc     edi
wsone:
        push    ecx
        push    edi
        mov     ax,PUTBYTE                      ;DL=port BL=char
        call    PDDProc_Handler                 ;BUG     this could be optimized
        test    cl,1                            ;more room?
        pop     edi
        pop     ecx
        jz      wsdun
        loop    wsnxt
        inc     cx
wsdun:  dec     cx
        pop     ebx
        mov     ax,word ptr [ebx].crf_ecx
        sub     ax,cx
        mov     word ptr [ebx].crf_eax,ax
        ret
endif
wstbad: mov     word ptr [ebx].crf_eax,0
        ret
VCOM_WriteString       endp
else
;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_WriteString
;
;DESCRIPTIVE NAME: Send a stream of characters out
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=count of characters
;      ES:DX=buffer to send
;         SI=character to send if CX == 1
;
;VDM Frame Exit:
;       AX=Number of characters written
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_WriteString
VCOM_WriteString       proc    near
        DEBUGINT3
        mov     eax,[ebx].crf_ebx
        cmp     eax,-1
        je      wstbad
        push    ebp
        xor     eax,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
ifndef SKIP_WRITESTG
        mov     edx,eax                         ;setup port number for later
        lea     esi, PI                 ; ESI -> PI for COM1
        mov     cl,size Port_Info_Tab   ; dl = structure size
        mul     cl                      ; ax = structure offset for this port
        add     esi,eax                 ; esi = linear address of port struct
        movzx   ecx,word ptr [ebx].crf_ecx     ; count

        mov     ebp,0                   ;retry count
        cmp     ecx,1
        jne     wsstg
        push    ebx
        mov     ax,word ptr [ebx].crf_esi
        jmp short wsone

wsstg:  mov     ax,word ptr [ebx].crf_es
        mov     es,ax
        movzx   edi,word ptr [ebx].crf_edx
        push    ebx

wsnxt:  mov     al,es:[edi]                     ;Char to send in AL
        inc     edi
wsone:
        push    ecx
        push    eax
wsrtr:  or      [esi].flgRxOp, NO_RXINT_REQD  ;Do a real read....
        mov     ecx,LSR
        call    Virt_ComIn
        test    al,60h
        jz      wsfull
        pop     eax
        pop     ecx

        push    edi
        push    ecx
        mov     ecx,THR                         ;Write to Data Register
        call    Virt_ComOut                     ;ESI=PI, EDX=port#,
        pop     ecx
        pop     edi
        xor     ebp,ebp                         ;clear retry count
        loop    wsnxt
wsdun:
        pop     ebx
        pop     ebp
        mov     ax,word ptr [ebx].crf_ecx
        sub     ax,cx
        mov     word ptr [ebx].crf_eax,ax
        ret
wsfull: inc     ebp
        cmp     ebp,07FFFFFFFh
        jne     wsrtr
        pop     eax
        pop     ecx
        jmp short wsdun
endif
wstbad: mov     word ptr [ebx].crf_eax,0
        ret
VCOM_WriteString       endp
endif

;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME:  VCOM_ReadString
;
;DESCRIPTIVE NAME: Read a stream from port
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=Count to read
;      SI:DX=Buffer to store into
;      ES:DI=ULONG pointer for number of bytes read
;
;VDM Frame Exit:
;       AX=Number of characters read (0=error)
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_ReadString
VCOM_ReadString        proc    near
        DEBUGINT3
        pushfd                                  ; PDD disables ints
        mov     eax,[ebx].crf_ebx
        cmp     eax,-1
        je      rstbad
        xor     eax,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number
ifndef SKIP_READSTG
        mov     edx,eax                         ; Port_ID

        push    es
        mov     ax, word ptr [ebx].crf_esi     ; buffer to read into set to
        mov     es, ax                         ; ES:DI
        movzx   edi,word ptr [ebx].crf_edx

        push    edx
        lea     esi, PI                 ; ESI -> PI for COM1
        mov     eax,edx                 ; eax = port number
        mov     cl,size Port_Info_Tab   ; dl = structure size
        mul     cl                      ; ax = structure offset for this port
        add     esi,eax                 ; esi = linear address of port struct
        movzx   ecx,word ptr [ebx].crf_ecx     ; count
        pop     edx
rstloop:
        push    ecx
        mov     ecx,5
        call    Virt_ComIn
        test    al,1
        jz      rsnod

        mov     ecx,8                           ;Get data register
        call    Virt_ComIn                      ;ESI=PI, EDX=port#,

        call    vcom_procrcv                   ; do pipeline stuff
        call    UpdateEvents                   ; update flaggies

        cmp     ah,0FFh
        je      baddat                         ; skip this invalid data
        stosb
        pop     ecx
        loop    rstloop
        jmp short rstout
baddat: pop     ecx                     ;bad data received
        jmp short rstloop
rsnod:  pop     ecx
rstout: mov     ax, word ptr [ebx].crf_es      ; return number read at the
        mov     es, ax                         ;    ptr in the client's ES:DI
        mov     di, word ptr [ebx].crf_edi

        movzx   eax, word ptr [ebx].crf_ecx    ; count
        sub     ax, cx
        mov     dword ptr es:[di], eax
        pop     es
        mov     word ptr [ebx].crf_eax, ax     ; return bytes read in AX
endif
rstbye:
        popfd                                  ; turn ints back on
        ret

rstbad: mov     word ptr [ebx].crf_eax,0
        jmp     short rstbye
VCOM_ReadString        endp

;
; PROCESS A RECEIVED CHARACTER
;      Take a raw received character and process it:
;          1. Parity Replacement
;          2. NULL stripping
;          3. XON/XOFF detection
;          4. Event Detection
;          5. EOF detection
;          6. other event flags
;
; Input
;     AL=character
;    EDX=port number
;    ESI=port info structure
;
; Output
;     AL=character
;     AH=flag to use character (FF=ignore)
;     Events implicitly updated
;
vcom_procrcv    proc    near
        push    cx

        mov     ah,[esi].VLSR
        xor     cx,cx
        test    ah,04h                          ;parity error?
        jz      pcnull
        test    PDCD.dcb_bitmask2,fPeChar
        jz      pcnull
        mov     al,PDCD.dcb_pechar
pcnull: cmp     al,0                            ;null stripping?
        jnz     pcxon
        test    PDCD.dcb_bitmask2,fNull
        jz      pcxon
        mov     ah,-1
        jmp     pcdun
pcxon:  cmp     al,PDCD.dcb_xonchar             ;XON/XOFF flow control
        jnz     pcxoff
        test    PDCD.dcb_bitmask2,fOutX
        jz      pcxoff
        and     PSTAT.COMS_BitMask1, 0FFh-fXoffHold     ;Start output
        jmp     pcevnt
pcxoff: cmp     al,PDCD.dcb_xoffchar
        jnz     pcevnt
        test    PDCD.dcb_bitmask2,fInX
        jz      pcevnt
        or      PSTAT.COMS_BitMask1,fXoffHold           ;Stop output
pcevnt: cmp     al,PDCD.dcb_evtchar
        jnz     pceof
        or      cx,EV_RXFLAG
pceof:  cmp     al,PDCD.dcb_eofchar
        jnz     pcnnul
        test    PDCD.dcb_bitmask1,fBinary
        jnz     pcnnul
        or      PSTAT.COMS_BitMask1,fEof                ;note EOF received
pcnnul: or      cx,EV_RXCHAR                            ;we have at least 1 char
        test    ah,10h                                  ;break received?
        jz      pcnbrk
        or      cx,EV_BREAK
pcnbrk: test    ah,0Eh                                  ;line error?
        jz      pcdun
        or      cx,EV_ERR
pcdun:
        or      Events[edx*4],cx                ;update events
        pop     cx
        ret
vcom_procrcv    endp

;
; ESI = pointer VCOM info structure
; EDX = port number (0-3)
;
;
UpdateEvents    proc
        push    ax
        push    cx
        mov     cx,word ptr Events[edx*4]
        mov     al,[esi].VLSR
        test    al,10h                  ;BREAK?
        jz      @F
        or      cx,EV_BREAK
@@:     test    al,20h                  ;THRE?
        jz      @F
        or      cx,EV_TXEMPTY
@@:     test    al,01h                  ;DR?
        jz      @F
        or      cx,EV_RXCHAR
@@:     test    al,0Eh                  ;Errors?
        jz      @F
        or      cx,EV_ERR
@@:     mov     al,[esi].VMSR
        test    al,10h                  ;CTS?
        jz      @F
        or      cx,EV_CTS
@@:     test    al,10h                  ;DSR?
        jz      @F
        or      cx,EV_DSR
@@:     test    al,10h                  ;RI?
        jz      @F
        or      cx,EV_RING
@@:     test    al,10h                  ;RLSD? (better known as Carrier Detect)
        jz      @F
        or      cx,EV_RLSD
@@:     mov     word ptr Events[edx*4],cx

        push    edi                     ;update user value if needed...
        mov     edi,EventPtr[edx*4]
        cmp     edi,0
        jz      @F
        push    es
        mov     es,EventPtr[edx*4+2]
        mov     es:[di],cx
        pop     es
@@:     mov     edi,VCOM_VXD_MSRshadow[edx*4]   ;update user value if needed...
        cmp     edi,0
        jz      @F
        push    es
        mov     es,VCOM_VXD_MSRshadow[edx*4+2]
        mov     cl,[esi].VMSR
        mov     es:[di],cl

        pop     es
@@:     pop     edi
        pop     cx
        pop     ax
        ret
UpdateEvents    endp

;********************** START OF SPECIFICATIONS ******************************
;SUBROUTINE NAME: VCOM_EnableNotify
;
;DESCRIPTIVE NAME: Setup a callback function on events
;
;INPUT: (on stack)
;  +0    ebp     -> from entry code
;  +4    retcseip-> return address
;  +8    pcrf    -> Base address of Client Register Frame
;  +C    ulData  -> Base address BP hook reference data
;
;VDM Frame Entry:
;        EBX=handle from Open Call
;         CX=hwnd (ClientRefData=Windows window handle)
;         DX=receive threshold trigger
;         SI=transmit threshold trigger
;        EDI=16:16 address of notify function to call
;
;VDM Frame Exit:
;       AX=Error code (0 for success, bit 15 set on error)
;
;********************** END OF SPECIFICATIONS *********************************
        public  VCOM_EnableNotify
VCOM_EnableNotify      proc    near
        DEBUGINT3
        mov     eax,[ebx].crf_ebx
        cmp     eax,-1
        je      enabad
        xor     eax,(MAGIC_1 SHL 16)+MAGIC_2    ;convert cookie to port number

        int 3           ;BUG     Unsupported function currently

        mov     word ptr [ebx].crf_eax,0
        ret
enabad: mov     word ptr [ebx].crf_eax,0FFFFh
        ret
VCOM_EnableNotify      endp


EndCode                                 ;end CSWAP_TEXT segment
        END
