summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/wow16/drivers')
-rw-r--r--private/mvdm/wow16/drivers/comm/bimodint.inc95
-rw-r--r--private/mvdm/wow16/drivers/comm/ccom.asm616
-rw-r--r--private/mvdm/wow16/drivers/comm/comdev.h243
-rw-r--r--private/mvdm/wow16/drivers/comm/comdev.inc103
-rw-r--r--private/mvdm/wow16/drivers/comm/comdevi.h28
-rw-r--r--private/mvdm/wow16/drivers/comm/comm.def42
-rw-r--r--private/mvdm/wow16/drivers/comm/comm.rc4
-rw-r--r--private/mvdm/wow16/drivers/comm/comm.rcv12
-rw-r--r--private/mvdm/wow16/drivers/comm/commmsg.asm51
-rw-r--r--private/mvdm/wow16/drivers/comm/ddkmake47
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmcom.asm1947
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmcom.inc265
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmcom1.asm1556
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmint.asm1374
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmlpt.asm412
-rw-r--r--private/mvdm/wow16/drivers/comm/ibmsetup.asm2878
-rw-r--r--private/mvdm/wow16/drivers/comm/ins8250.inc78
-rw-r--r--private/mvdm/wow16/drivers/comm/makefile127
-rw-r--r--private/mvdm/wow16/drivers/display/config.asm64
-rw-r--r--private/mvdm/wow16/drivers/display/display.asm88
-rw-r--r--private/mvdm/wow16/drivers/display/display.def17
-rw-r--r--private/mvdm/wow16/drivers/display/display.rc8
-rw-r--r--private/mvdm/wow16/drivers/display/display.rcv12
-rw-r--r--private/mvdm/wow16/drivers/display/makefile121
-rw-r--r--private/mvdm/wow16/drivers/keyboard/kbd.def118
-rw-r--r--private/mvdm/wow16/drivers/keyboard/kbdlocal.asm301
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.asm155
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.def30
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.rc4
-rw-r--r--private/mvdm/wow16/drivers/keyboard/keyboard.rcv12
-rw-r--r--private/mvdm/wow16/drivers/keyboard/makefile114
-rw-r--r--private/mvdm/wow16/drivers/mouse/makefile110
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.asm224
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.def16
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.rc4
-rw-r--r--private/mvdm/wow16/drivers/mouse/mouse.rcv12
-rw-r--r--private/mvdm/wow16/drivers/sound/makefile109
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.asm88
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.def27
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.rc4
-rw-r--r--private/mvdm/wow16/drivers/sound/sound.rcv12
41 files changed, 11528 insertions, 0 deletions
diff --git a/private/mvdm/wow16/drivers/comm/bimodint.inc b/private/mvdm/wow16/drivers/comm/bimodint.inc
new file mode 100644
index 000000000..e579440bb
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/bimodint.inc
@@ -0,0 +1,95 @@
+;******************************************************************************
+;
+; (C) Copyright MICROSOFT Corp., 1990
+;
+; Title: BIMODINT.INC - Bimodal Interrupt Handler Equates and Structures
+;
+; Version: 1.00
+;
+; Date: 14-Nov-1990
+;
+; Author: RAL
+;
+;------------------------------------------------------------------------------
+;
+; Change log:
+;
+; DATE REV DESCRIPTION
+; ----------- --- -----------------------------------------------------------
+; 14-Nov-1990 RAL Original
+;
+;==============================================================================
+
+Bimodal_Int_Struc STRUC
+BIS_IRQ_Number dw ?
+BIS_VM_ID dw 0
+BIS_Next dd ?
+BIS_Reserved1 dd ?
+BIS_Reserved2 dd ?
+BIS_Reserved3 dd ?
+BIS_Reserved4 dd ?
+BIS_Flags dd 0
+BIS_Mode dw 0
+BIS_Entry dw ?
+BIS_Control_Proc dw ?
+ dw ?
+BIS_User_Mode_API dd ?
+BIS_Super_Mode_API dd ?
+BIS_User_Mode_CS dw ?
+BIS_User_Mode_DS dw ?
+BIS_Super_Mode_CS dw ?
+BIS_Super_Mode_DS dw ?
+BIS_Descriptor_Count dw ?
+Bimodal_Int_Struc ENDS
+
+BIS_Sel_Table equ word ptr (SIZE Bimodal_Int_Struc)
+
+
+EBIS_Sel_Struc STRUC
+EBIS_User_Mode_Sel dw ?
+ dw ?
+EBIS_Super_Mode_Sel dw ?
+EBIS_Sel_Struc ENDS
+
+
+.errnz BIS_Super_Mode_API-BIS_User_Mode_API-4
+.errnz BIS_Super_Mode_CS-BIS_User_Mode_CS-4
+.errnz BIS_Super_Mode_DS-BIS_User_Mode_DS-4
+.errnz EBIS_Super_Mode_Sel-EBIS_User_Mode_Sel-4
+
+
+VPICD_API_Get_Ver EQU 0000h
+VPICD_Install_Handler EQU 0001h
+VPICD_Remove_Handler EQU 0002h
+VPICD_Call_At_Ring0 EQU 0003h
+
+
+BIH_API_EOI EQU 0000h
+BIH_API_Mask EQU 0001h
+BIH_API_Unmask EQU 0002h
+BIH_API_Get_Mask EQU 0003h
+BIH_API_Get_IRR EQU 0004h
+BIH_API_Get_ISR EQU 0005h
+BIH_API_Call_Back EQU 0006h
+
+
+Declare_PM_BIS MACRO IRQn,CtrlP,ISRoff,APIoff,ISRcs,ISRds
+LOCAL strt
+strt label byte
+ dw IRQn ; BIS_IRQ_Number
+ dw 0 ; BIS_VM_ID
+ dd 6 DUP(0) ; BIS_Next/BIS_Reserved1-BIS_Reserved4/BIS_Flags
+ dw 0 ; BIS_Mode
+ dw ISRoff ; BIS_Entry
+ dw CtrlP ; BIS_Control_Proc
+ dw 0 ; filler
+ dw APIoff ; BIS_User_Mode_API
+ dw ISRcs
+ dd 0 ; BIS_Super_Mode_API
+ dw ISRcs ; BIS_User_Mode_CS
+ dw ISRds ; BIS_User_Mode_DS
+ dw 0 ; BIS_Super_Mode_CS
+ dw 0 ; BIS_Super_Mode_DS
+ dw 0 ; BIS_Descriptor_Count
+.errnz $-strt - (SIZE Bimodal_Int_Struc)
+ENDM
diff --git a/private/mvdm/wow16/drivers/comm/ccom.asm b/private/mvdm/wow16/drivers/comm/ccom.asm
new file mode 100644
index 000000000..31dbc94fd
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ccom.asm
@@ -0,0 +1,616 @@
+page,132
+
+;---------------------------Module-Header-------------------------------;
+; Module Name: CCOM.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; History
+;
+; 041786 Fixed RECCOM to return be able to return nulls
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ibmcom.inc
+.list
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+;=========================================================================
+;
+; Communications Device Driver - C language interface module.
+; This module provides an interface layer between programs written
+; in C, and the low-level OEM specific communications drivers.
+;
+;=========================================================================
+
+ externNP $CLRBRK
+ externNP $DCBPTR
+ externNP $EVT
+ externNP $EVTGET
+ externNP $EXTCOM
+ externNP $FLUSH
+ externNP $INICOM
+ externNP $RECCOM
+ externNP $RECSTR
+ externNP $SETBRK
+ externNP $SETCOM
+ externNP $SETQUE
+ externNP $SNDCOM
+ externNP $SNDIMM
+ externNP $STACOM
+ externNP $TRMCOM
+ externNP $SNDCOMSTR
+ externNP $ENANOTIFY
+
+ externNP GetDEB
+
+;=========================================================================
+;
+; ushort inicom(pdcb)
+; dcb far *pdcb;
+;
+; returns - 0 if no errors occured
+; - Error Code (which is reset)
+;
+; Inicom is a one-time called routine to initialize. This is meant
+; to be called when a process starts, or determines that it will use
+; communications. Operating parameters are also passed on to setcom(),
+; below.
+;
+; Fields within the dcb (including device id) should be set up prior to
+; calling inicom.
+;
+; As a true device driver, this routine is to be called when the device
+; driver is loaded at system start-up time. The dcb reflects the
+; default operating parameters.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc inicom,<PUBLIC,FAR>
+ parmD pdcb
+
+cBegin
+ les bx,pdcb
+ assumes es,nothing
+
+ call $INICOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort setcom(pdcb)
+; dcb far *pdcb;
+;
+; returns - 0 if no errors occured
+; - Error Code (reset)
+;
+; Set/alter communications operating parameters. This is a non-destructive
+; alteration of operating mode. Queues and interrupts are not affected.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc setcom,<PUBLIC,FAR>
+ parmD pdcb
+
+cBegin
+ les bx,pdcb ;get pointer to dcb
+ assumes es,nothing
+
+ call $SETCOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; void setque(cid,pqdb)
+; char cid;
+; qdb far *pqdb;
+;
+; Init the locations of the receive and transmit queues that are to be
+; used to buffer incomming and outgoing characters.
+;
+; This may be called at any time by a process to use a different set
+; of queues. Characters (transmit and/or receive) may be lost if the
+; queues are changed when not empty. This allows dynamic allocation
+; of variable sized queues. Under DOS 4.0, the queues must be locked in
+; memory.
+;
+; As a true device driver, the queues would be allocated at boot time,
+; and must also be locked under DOS 4.0.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc setque,<PUBLIC,FAR>
+ parmB cid
+ parmD pqdb
+
+cBegin
+ mov ah,cid
+ les bx,pqdb ;pointer to qdb
+ assumes es,nothing
+
+ call $SETQUE
+cEnd
+
+page
+
+;=========================================================================
+;
+; short reccom(cid)
+; char cid;
+;
+; Returns - character.
+; - -1 if error
+; - -2 if no character available
+;
+; Read a byte. Extracts a byte from the receive data queue. Returns
+; immediately.
+;=========================================================================
+
+
+assumes ds,Data
+assumes es,nothing
+
+cProc reccom,<PUBLIC,FAR>
+ parmB cid
+
+cBegin
+ mov ah,cid ;Id Into AH
+
+ call $RECCOM ;Get char, error, or no data
+ mov cx,ax ;Save data
+ mov ah,0 ;Assume valid data
+ jnz reccom5 ;Data is valid
+ mov ax,-2 ;Assume no data available
+ jcxz reccom5 ;No data available
+ inc ax ;Show error (-1)
+
+reccom5:
+cEnd
+
+page
+
+;=========================================================================
+;
+; short ReadCommString(cid, buf, cnt)
+; char cid;
+; LPSTR buf;
+; int cnt;
+;
+; Returns - ax = # of bytes read
+; - 0 if no character available or error
+;
+; Read string. Extracts bytes from the receive data queue. Returns
+; immediately.
+;=========================================================================
+
+
+assumes ds,Data
+assumes es,nothing
+
+cProc ReadCommString,<PUBLIC,FAR>
+ parmB cid
+ parmD buf
+ parmW cnt
+
+cBegin
+ mov ah,cid ;Id Into AH
+ les di, buf
+ mov cx, cnt
+
+ call $RECSTR ;Get char, error, or no data
+ jnz short recstr5 ; jmp if no error
+ xor ax, ax
+recstr5:
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort sndcom(cid,ch)
+; char cid;
+; char ch;
+;
+; Returns - 0 if no errors
+; - Error Code (Not removed, i.e. stacom will return this error
+; unless another occurs before the next call to stacom.)
+;
+; Transmit a byte. Places a byte into the transmit queue. Negative return
+; indicates error.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc sndcom,<PUBLIC,FAR>
+ parmB cid
+ parmB chr
+
+cBegin
+ mov ah,cid
+ mov al,chr
+
+ call $SNDCOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort ctx(cid,ch)
+; char cid;
+; char ch;
+;
+; Returns - 0 if no errors
+; - -1 if character could not be sent.
+;
+; Transmit a byte "immediately". Places a byte into the transmit queue.
+; or other buffer such that it is the next character picked up for
+; transmission. Negative return indicates error.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc ctx,<PUBLIC,FAR>
+ parmB cid
+ parmB chr
+
+cBegin
+ mov ah,cid
+ mov al,chr
+
+ call $SNDIMM
+cEnd
+
+page
+
+;=========================================================================
+;
+; void trmcom(cid)
+; char cid;
+;
+; Terminate communications on a particular channel. Flushes the
+; buffers (waits for completion), and shuts down the comm device.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc trmcom,<PUBLIC,FAR>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $TRMCOM ;and go for it
+cEnd
+page
+
+;=========================================================================
+;
+; ushort stacom(cid,pstat)
+; char cid;
+; stat far *pstat;
+;
+; Returns - 0 if no errors
+; - Error Code
+; - status structure updated.
+;
+; Get device status. Returns device status and input queue status.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc stacom,<PUBLIC,FAR>,<si,di>
+ parmB cid
+ parmD pstat
+
+cBegin
+ mov ah,cid
+ les bx,pstat
+ assumes es,nothing
+
+ call $STACOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; dword cextfcn(cid,fcn)
+; char cid;
+; short fcn;
+;
+; Perform extended functions.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cextfcn,<PUBLIC,FAR>
+ parmB cid
+ parmW fcn
+
+cBegin
+ mov ah,cid
+ mov bx,fcn
+
+ call $EXTCOM
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort cflush(cid,q)
+; ushort cid;
+; ushort q;
+;
+; Queue flush. empties the specified queue. q=0 means transmit queue,
+; 1 indicates receive queue.
+;
+; Returns - 0 or -1.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cflush,<PUBLIC,FAR>,<si,di>
+ parmB cid
+ parmB q
+
+cBegin
+ mov ah,cid
+ mov bh,q
+
+ call $FLUSH
+cEnd
+
+page
+
+;=========================================================================
+;
+; ushort far *cevt(cid,evtmask)
+; ushort cid;
+; ushort evtmask;
+;
+; Returns the location of a word which in which certain bits will be set
+; when particular events occur. The event mask passed defines which bits
+; are to be enabled. The event byte is used primarily for speed in
+; determining if certain events have occurred. Returns 0 on success, -1
+; for an illegal handle.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cevt,<PUBLIC,FAR>
+ parmB cid
+ parmW evt_mask
+
+cBegin
+ mov ah,cid
+ mov bx,evt_mask
+
+ call $EVT ;Set the event
+cEnd
+
+page
+
+;=========================================================================
+;
+; short cevtGet(cid, evtmask)
+; ushort cid;
+; ushort evtmask;
+;
+; The event byte set up by cevt, above, is returned. This routine must be
+; used to read the event byte in order to prevent loss of an event
+; occurance. Those bits set in the event mask passed are then cleared in
+; the event byte.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cevtGet,<PUBLIC,FAR>
+ parmB cid
+ parmW evt_mask
+
+cBegin
+ mov ah,cid
+ mov bx,evt_mask
+
+ call $EVTGET
+cEnd
+
+page
+
+;=========================================================================
+;
+; short csetbrk(cid)
+; ushort cid;
+;
+; Suspends character transmission, and places the transmission line in
+; a break state until cclrbrk is called. Returns 0 on success, -1 if
+; illegal handle.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc csetbrk,<PUBLIC,FAR>,<si,di>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $SETBRK
+cEnd
+
+page
+
+;=========================================================================
+;
+; short cclrbrk(cid)
+; ushort cid;
+;
+; Restores the line to a non-breaking state, and restarts character
+; transmission. Returns 0 on success, -1 if illegal handle.
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc cclrbrk,<PUBLIC,FAR>,<si,di>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $CLRBRK
+cEnd
+
+page
+
+;=========================================================================
+;
+; dcb far *getdcb(cid)
+; ushort cid;
+;
+; Returns a pointer to the dcb associated with the given id.
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc getdcb,<PUBLIC,FAR>,<si,di>
+ parmB cid
+
+cBegin
+ mov ah,cid
+
+ call $DCBPTR
+cEnd
+
+;=========================================================================
+;
+; int CommWriteString(cid, lpstring, count)
+; ushort cid;
+; LPSTR lpstring;
+; int count;
+;
+; Returns # of bytes sent
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc CommWriteString, <FAR, PUBLIC>, <si, di>
+
+ parmB cid
+ parmD lpstring
+ parmW count
+
+cBegin
+
+ xor ax, ax
+ mov cx, count
+ jcxz short cws_exit
+ mov ah, cid
+ les di, lpstring
+ call $SNDCOMSTR
+cws_exit:
+cEnd
+page
+
+;=========================================================================
+;
+; bool EnableNotification(cid, hWnd, recv_trigger, send_trigger)
+; ushort cid;
+; WORD hWnd; /* 0, to disable notification */
+; int recv_trigger;
+; int send_trigger;
+;
+; Returns # of bytes sent
+;
+;=========================================================================
+
+assumes ds,Data
+assumes es,nothing
+
+cProc EnableNotification, <FAR, PUBLIC>, <si, di>
+
+ parmB cid
+ parmW _hWnd
+ parmW recvT
+ parmW sendT
+
+cBegin
+
+ mov ah, [cid]
+ mov bx, [_hWnd]
+ mov cx, [recvT]
+ mov dx, [sendT]
+ call $ENANOTIFY
+cEnd
+page
+
+;-----------------------------------------------------------------------;
+; WEP
+;
+;
+; Entry:
+;
+; Returns:
+;
+; Registers Destroyed:
+;
+; History:
+; Sat 13-Jan-1990 18:33:48 -by- David N. Weise [davidw]
+; Wrote it!
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc WEP,<PUBLIC,FAR>
+cBegin nogen
+ nop ; You don't want to know why.
+ mov ax,1
+ ret 2
+cEnd nogen
+
+sEnd Code
+
+end
+
diff --git a/private/mvdm/wow16/drivers/comm/comdev.h b/private/mvdm/wow16/drivers/comm/comdev.h
new file mode 100644
index 000000000..a913cffa3
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comdev.h
@@ -0,0 +1,243 @@
+/*************************************************************************
+**
+** Miscelaneous definitions.
+*/
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+
+#define NULL 0
+#define FALSE 0
+#define TRUE 1
+
+#define LPTx 0x80 /* Mask to indicate cid is for LPT device */ /*081985*/
+#define LPTxMask 0x7F /* Mask to get cid for LPT device */ /*081985*/
+
+#define PIOMAX 3 /* Max number of LPTx devices in high level */ /*081985*/
+#define CDEVMAX 10 /* Max number of COMx devices in high level */
+#define DEVMAX 13 /* Max number of devices in high level */ /*081985*/
+
+/*************************************************************************
+**
+** device control block.
+** This block of information defines the functional parameters of the
+** communications software and hardware.
+**
+** Fields in the DCB are defined as follows:
+**
+** Id - Comm device ID, set by the device driver.
+** BaudRate - Baud rate at which operating.
+** ByteSize - Number of bits per transmitted/received byte. (4-8)
+** Received data is also masked off to this size.
+** Parity - Transmitt/Receive Parity. (0,1,2,3,4) = (None, Odd,
+** Even, Mark, Space)
+** StopBits - Number of stop bits. (0,1,2) = (1, 1.5, 2)
+** RlsTimeout - Amount of time, in milleseconds, to wait for RLSD to
+** become high. RLSD, Receive Line Signal Detect is also
+** known as CD, Carrier Detect. RLSD flow control can be
+** achieved by specifying infinite timeout.
+** CtsTimeout - Amount of time, in milleseconds, to wait for CTS,
+** Clear To Send, to become high. CTS flow control can
+** be achieved by specifying infinite timeout.
+** DsrTimeout - Amount of time, in milleseconds, to wait for DSR,
+** Data Set Ready, to become high. DSR flow control can
+** be acheived by specifying infinite timeout.
+** fBinary - Binary Mode flag. In non-binary mode, EofChar is
+** recognized and remembered as end of data.
+** fRtsDisable - Disable RTS flag. If set, Request To Send is NOT
+** used, and remains low. Normally, RTS is asserted when
+** the device is openned, and dropped when closed.
+** fParity - Enable Parity Checking. Parity errors are not
+** reported when 0.
+** fOutxCtsFlow - enable output xon/xoff(hardware) using cts
+** fOutxDsrFlow - enable output xon/xoff(hardware) using dsr
+** fOutX - Indicates that X-ON/X-OFF flow control is to be used
+** during transmission. The transmitter will halt if
+** an X-OFF character is received, and will start again
+** when an X-ON character is received.
+** fInX - Indicates that X-ON/X-OFF flow control is to be used
+** during reception. An X-OFF character will be
+** transmitted when the receive queue comes within 10
+** characters of being full, after which an X-ON will be
+** transmitted when the queue comes with 10 characters
+** of being empty.
+** fPeChar - Indicates that characters received with parity errors
+** are to be replaced with the character specified in
+** PeChar, below.
+** fNull - Indicates that received NULL characters are to be
+** discarded.
+** fChEvt - Indicates that the reception of EvtChar is to be
+** flagged as an event by cevt.
+** fDtrFlow - Indicates that the DTR signal is to be used for
+** receive flow control. (cextfcn can be used to set and
+** clear DTR, overriding this definition).
+** fRtsFlow - Indicates that the RTS signal is to be used for
+** receive flow control. (cextfcn can be used to set and
+** clear RTS, overriding this definition).
+** XonChar - X-ON character for both transmit and receive
+** XoffChar - X-OFF character for both transmit and receive
+** XonLim - When the number of characters in the receive queue
+** drops below this value, then an X-ON character is
+** sent, if enabled, and DTR is set, if enabled.
+** XoffLim - When the number of characters in the receive queue
+** exceeds this value, then an X-OFF character is sent,
+** if enabled, and DTR is dropped, if enabled.
+** PeChar - Parity Error replacement character.
+** EvtChar - Character which triggers an event flag.
+** EofChar - Character which specifies end of input.
+** TxDelay - Specifies the minimum amount of time that must pass
+** between transmission of characters.
+**
+** Timeouts are in milleseconds. 0 means ignore the signal. 0xffff means
+** infinite timeout.
+**
+*************************************************************************/
+typedef struct {
+ char Id; /* Internal Device ID */
+ ushort BaudRate; /* Baudrate at which runing */
+ char ByteSize; /* Number of bits/byte, 4-8 */
+ char Parity; /* 0,1,2,3,4 = None,Odd,Even,Mark,Sp*/
+ char StopBits; /* 0,1,2 = 1, 1.5, 2 */
+ ushort RlsTimeout; /* Timeout for RLSD to be set */
+ ushort CtsTimeout; /* Timeout for CTS to be set */
+ ushort DsrTimeout; /* Timeout for DSR to be set */
+
+ uchar fBinary: 1; /* CTRL-Z as EOF flag */
+ uchar fRtsDisable:1; /* Suppress RTS */
+ uchar fParity: 1; /* Enable parity check */
+ uchar fOutxCtsFlow: 1; /* Enable output xon/xoff with cts */
+ uchar fOutxDsrFlow: 1; /* Enable output xon/xoff with dsr */
+ uchar fDummy: 3;
+
+ uchar fOutX: 1; /* Enable output X-ON/X-OFF */
+ uchar fInX: 1; /* Enable input X-ON/X-OFF */
+ uchar fPeChar: 1; /* Enable Parity Err Replacement */
+ uchar fNull: 1; /* Enable Null stripping */
+ uchar fChEvt: 1; /* Enable Rx character event. */
+ uchar fDtrflow: 1; /* Enable DTR flow control */
+ uchar fRtsflow: 1; /* Enable RTS flow control */
+ uchar fDummy2: 1;
+
+ char XonChar; /* Tx and Rx X-ON character */
+ char XoffChar; /* Tx and Rx X-OFF character */
+ ushort XonLim; /* Transmit X-ON threshold */
+ ushort XoffLim; /* Transmit X-OFF threshold */
+ char PeChar; /* Parity error replacement char */
+ char EofChar; /* End of Input character */
+ char EvtChar; /* Recieved Event character */
+ ushort TxDelay; /* Amount of time between chars */
+ } DCB;
+
+/*************************************************************************
+**
+** COMSTAT
+** Status record returned by GetCommError
+**
+*************************************************************************/
+typedef struct {
+ uchar fCtsHold: 1; /* Transmit is on CTS hold */
+ uchar fDsrHold: 1; /* Transmit is on DSR hold */
+ uchar fRlsdHold: 1; /* Transmit is on RLSD hold */
+ uchar fXoffHold: 1; /* Transmit is on X-Off hold */
+ uchar fXoffSent: 1; /* Recieve in X-Off or DTR hold */
+ uchar fEof: 1; /* End of file character found */
+ uchar fTxim: 1; /* Character being transmitted */
+ uchar fPerr:1; /* Printer error */ /*081985*/
+ ushort cbInQue; /* count of characters in Rx Que*/
+ ushort cbOutQue; /* count of characters in Tx Que*/
+ } COMSTAT;
+
+/*************************************************************************
+**
+** DCB field definitions.
+**
+*************************************************************************/
+#define NOPARITY 0
+#define ODDPARITY 1
+#define EVENPARITY 2
+#define MARKPARITY 3
+#define SPACEPARITY 4
+
+#define ONESTOPBIT 0
+#define ONE5STOPBITS 1
+#define TWOSTOPBITS 2
+
+#define IGNORE 0 /* Ignore signal */
+#define INFINITE 0xffff /* Infinite timeout */
+
+/*************************************************************************
+**
+** Comm Device Driver Error Bits.
+**
+*************************************************************************/
+#define CE_RXOVER 0x0001 /* Receive Queue overflow */
+#define CE_OVERRUN 0x0002 /* Receive Overrun Error */
+#define CE_RXPARITY 0x0004 /* Receive Parity Error */
+#define CE_FRAME 0x0008 /* Receive Framing error */
+#define CE_CTSTO 0x0020 /* CTS Timeout */
+#define CE_DSRTO 0x0040 /* DSR Timeout */
+#define CE_RLSDTO 0x0080 /* RLSD Timeout */
+#define CE_PTO 0x0100 /* LPTx Timeout */ /*081985*/
+#define CE_IOE 0x0200 /* LPTx I/O Error */ /*081985*/
+#define CE_DNS 0x0400 /* LPTx Device not selected */ /*081985*/
+#define CE_OOP 0x0800 /* LPTx Out-Of-Paper */ /*081985*/
+#define CE_MODE 0x8000 /* Requested mode unsupported */
+
+/*************************************************************************
+**
+** Initialization Error Codes
+**
+*************************************************************************/
+#define IE_BADID -1 /* Invalid or unsupported id */
+#define IE_OPEN -2 /* Device Already Open */
+#define IE_NOPEN -3 /* Device Not Open */
+#define IE_MEMORY -4 /* Unable to allocate queues */
+#define IE_DEFAULT -5 /* Error in default parameters */
+#define IE_HARDWARE -10 /* Hardware Not Present */
+#define IE_BYTESIZE -11 /* Illegal Byte Size */
+#define IE_BAUDRATE -12 /* Unsupported BaudRate */
+/*************************************************************************
+**
+** Event mask definitions. Used by SetCommEventMask and GetCommEventMask
+**
+** RXCHAR - Set when any character is received and placed in the input
+** queue.
+** RXFLAG - Set when a particular character, as defined in the dcb, is
+** received and placed in the input queue.
+** TXEMPTY - Set when the last character in the transmit queue is
+** transmitted.
+** CTS - Set when the CTS signal changes state.
+** DSR - Set when the DSR signal changes state.
+** RLSD - Set when the RLSD signal changes state.
+** BREAK - Set when a break is detected on input.
+** ERR - Set when a line status error occurs.
+**
+*************************************************************************/
+#define EV_RXCHAR 0x0001 /* Any Character received */
+#define EV_RXFLAG 0x0002 /* Received certain character */
+#define EV_TXEMPTY 0x0004 /* Transmitt Queue Empty */
+#define EV_CTS 0x0008 /* CTS changed state */
+#define EV_DSR 0x0010 /* DSR changed state */
+#define EV_RLSD 0x0020 /* RLSD changed state */
+#define EV_BREAK 0x0040 /* BREAK received */
+#define EV_ERR 0x0080 /* Line Status Error Occurred */
+#define EV_RING 0x0100 /* Ring signal detected */
+#define EV_PERR 0x0200 /* LPTx error occured */ /*081985*/
+
+/*************************************************************************
+**
+** Extended Functions
+**
+** SETXOFF - Causes transmit to behave as if an X-OFF character had
+** been received. Valid only if transmit X-ON/X-OFF specified
+** in the dcb.
+** SETXON - Causes transmit to behave as if an X-ON character had
+** been received. Valid only if transmit X-ON/X-OFF specified
+** in the dcb.
+*************************************************************************/
+#define SETXOFF 1 /* Set X-Off for output control */
+#define SETXON 2 /* Set X-ON for output control */
+#define SETRTS 3 /* Set RTS high */
+#define CLRRTS 4 /* Set RTS low */
+#define SETDTR 5 /* Set DTR high */
+#define CLRDTR 6 /* Set DTR low */
+#define RESETDEV 7 /* Reset device if possible */ /*081985*/
diff --git a/private/mvdm/wow16/drivers/comm/comdev.inc b/private/mvdm/wow16/drivers/comm/comdev.inc
new file mode 100644
index 000000000..1238c6b62
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comdev.inc
@@ -0,0 +1,103 @@
+;=========================================================================
+; Communications Device Driver Definitions - September, 1985
+;=========================================================================
+
+.xcref
+
+WIN31 = 1
+; remove unneeded things in Windows.inc
+NOGDICAPMASKS = 1
+NOVK = 1
+NOWH = 1
+NOMST = 1
+NORASTOPS = 1
+NOMETAFILE = 1
+NOMDI = 1
+NOWINMESSAGES = 1
+NOSYSMETRICS = 1
+NOCOLOR = 1
+include windows.inc
+
+DCBSize equ SIZE DCB
+DCB_Flags equ byte ptr DCB_BitMask1
+DCB_Flags2 equ byte ptr DCB_BitMask2
+
+LPTx equ 10000000b ;Flags an ID as being an LPT port
+
+
+; DCB_BitMask1 (DCB_Flags) equates
+
+fBinary equ 00000001b ;Binary mode
+fRTSDisable equ 00000010b ;Disable RTS
+fParity equ 00000100b ;Perform Parity Checking
+fOutXCTSFlow equ 00001000b ;Output handshaking using CTS
+fOutXDSRFlow equ 00010000b ;Output handshaking using DSR
+fEnqAck equ 00100000b ;ENQ/ACK software handshaking [rkh] ...
+fEtxAck equ 01000000b ;ETX/ACK software handshaking
+fDTRDisable equ 10000000b ;Disable DTR
+
+
+; DCB_BitMask2 (DCB_Flags2) equates
+
+fOutX equ 00000001b ;Output X-ON/X-OFF
+fInX equ 00000010b ;Input X-ON/X-OFF
+fPErrChar equ 00000100b ;Parity Error Replacement char active
+fNullStrip equ 00001000b ;Null Stripping
+fCharEvent equ 00010000b ;Character event
+fDTRFlow equ 00100000b ;Input handshaking using DTR
+fRTSFlow equ 01000000b ;Input handshaking using RTS
+; equ 10000000b
+
+
+; Values for RLSTimeout, CTSTimeout, DSRTimeout
+
+Ignore equ 0
+Infinite equ 0FFFFh
+
+
+; COMS_BitMask1 equates
+
+fCTSHold equ 00000001b ;Tx is on CTS hold
+fDSRHold equ 00000010b ;Tx is on DSR hold
+fRLSDHold equ 00000100b ;Tx is on RLSD hold
+fXOFFHold equ 00001000b ;Received an X-OFF
+fXOFFSent equ 00010000b ;Sent an X-OFF
+fEOF equ 00100000b ;Received defined EOF character
+fTxImmed equ 01000000b ;There's a char to transmit immediate
+; equ 10000000b
+
+
+
+; Event mask definitions. Used by SetCommEventMask and GetCommEventMask
+;
+; RXCHAR - Set when any character is received and placed in the input
+; queue.
+; RXFLAG - Set when a particular character, as defined in the DCB,
+; is received and placed in the input queue.
+; TXEMPTY - Set when the last character in the transmit queue is
+; transmitted.
+; CTS - Set when the CTS signal changes state.
+; DSR - Set when the DSR signal changes state.
+; RLSD - Set when the RLSD signal changes state.
+; BREAK - Set when a break is detected on input.
+; RING - Set when Ring Indicator is detected
+; ERR - Set when a line status error occurs.
+
+
+;=========================================================================
+;
+; qdb
+; Queue definition block. Passed to setqueue, defines the location and
+; size of the transmit and receive circular queue's used for interrupt
+; transmit and recieve processing.
+;
+;=========================================================================
+
+QDB struc
+ QueueRxAddr dd ? ;Pointer to RX Queue, Offset
+ QueueRxSize dw ? ;Size of RX Queue in bytes
+ QueueTxAddr dd ? ;Pointer to TX Queue, Offset
+ QueueTxSize dw ? ;Size of TX Queue in bytes
+QDB ends
+
+.cref
diff --git a/private/mvdm/wow16/drivers/comm/comdevi.h b/private/mvdm/wow16/drivers/comm/comdevi.h
new file mode 100644
index 000000000..f640125c2
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comdevi.h
@@ -0,0 +1,28 @@
+/*************************************************************************
+**
+** qdb
+** que definition block.
+**
+*************************************************************************/
+typedef struct {
+ char far *pqRx; /* pointer to rx queue */
+ short cbqRx; /* size of RX Queue in bytes */
+ char far *pqTx; /* Pointer to TX Queue */
+ short cbqTx; /* Size of TX Queue in bytes */
+ } qdb;
+
+ushort far pascal inicom(DCB far *);
+ushort far pascal setcom(DCB far *);
+void far pascal setque();
+int far pascal reccom();
+ushort far pascal sndcom();
+ushort far pascal ctx();
+short far pascal trmcom();
+ushort far pascal stacom();
+ushort far pascal cextfcn();
+ushort far pascal cflush();
+ushort far *far pascal cevt();
+ushort far pascal cevtGet();
+int far pascal csetbrk();
+int far pascal cclrbrk();
+DCB far *far pascal getdcb();
diff --git a/private/mvdm/wow16/drivers/comm/comm.def b/private/mvdm/wow16/drivers/comm/comm.def
new file mode 100644
index 000000000..99b887da8
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comm.def
@@ -0,0 +1,42 @@
+LIBRARY COMM
+
+DESCRIPTION 'Windows Communications Driver'
+
+EXETYPE WINDOWS
+STUB '..\..\bin\WINSTUB.EXE'
+
+DATA PRELOAD FIXED SINGLE
+
+SEGMENTS
+ _INIT PRELOAD MOVEABLE DISCARDABLE SHARED
+ _TEXT MOVEABLE DISCARDABLE SHARED
+ _INTERRUPT PRELOAD FIXED SHARED
+
+
+EXPORTS
+ inicom @1
+ setcom @2
+ setque @3
+ reccom @4
+ sndcom @5
+ ctx @6
+ trmcom @7
+ stacom @8
+ cextfcn @9
+ cflush @10
+ cevt @11
+ cevtGet @12
+ csetbrk @13
+ cclrbrk @14
+ getdcb @15
+; mapdevname @16 ;Reserved for mapping dev to cid
+ SuspendOpenCommPorts @17 ;for 286 winoldaps only
+ ReactivateOpenCommPorts @18 ;for 286 winoldaps only
+ CommWriteString @19 ; for fast lpt output
+ ReadCommString @20 ; for fast input
+ EnableNotification @100
+ WEP
+
+IMPORTS
+ CreateSystemTimer = SYSTEM.2
+ GetSystemMsecCount = SYSTEM.6
diff --git a/private/mvdm/wow16/drivers/comm/comm.rc b/private/mvdm/wow16/drivers/comm/comm.rc
new file mode 100644
index 000000000..fabcbab37
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comm.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* COMM.RC */
+/********************************************************************/
+#include "comm.rcv"
diff --git a/private/mvdm/wow16/drivers/comm/comm.rcv b/private/mvdm/wow16/drivers/comm/comm.rcv
new file mode 100644
index 000000000..ea8edd8c4
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/comm.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* COMM.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_COMM
+#define VER_FILEDESCRIPTION_STR "Windows COMM Driver"
+#define VER_INTERNALNAME_STR "COMM"
+#define VER_ORIGINALFILENAME_STR "COMM.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/comm/commmsg.asm b/private/mvdm/wow16/drivers/comm/commmsg.asm
new file mode 100644
index 000000000..8980166dc
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/commmsg.asm
@@ -0,0 +1,51 @@
+.xlist
+include cmacros.inc
+.list
+
+
+sBegin Data
+
+PUBLIC szMessage, pLPTByte
+PUBLIC szCOMMessage, pCOMByte
+PUBLIC _szTitle
+
+szMessage db 'The LPT'
+pLPTByte db '?'
+ db ' port is currently assigned to a DOS application. Do you '
+ db 'want to reassign the port to Windows?',0
+szCOMMessage db 'The COM'
+pCOMByte db '?'
+ db ' port is currently assigned to a DOS application. Do you '
+ db 'want to reassign the port to Windows?',0
+_szTitle db 'Device Conflict',0
+
+PUBLIC lpCommBase, CommBaseX
+lpCommBase db 'COM'
+CommBaseX db ?
+ db 'BASE', 0
+
+PUBLIC lpCommIrq, CommIrqX
+lpCommIrq db 'COM'
+CommIrqX db ?
+ db 'IRQ', 0
+
+PUBLIC lpCommFifo, CommFifoX
+lpCommFifo db 'COM'
+CommFifoX db ?
+ db 'FIFO', 0
+
+PUBLIC lpCommDSR, CommDSRx
+lpCommDSR db 'COM'
+CommDSRx db ?
+ db 'FORCEDSR', 0
+
+PUBLIC lpCommSection, lpSYSTEMINI
+
+lpCommSection db '386ENH', 0
+lpSYSTEMINI db 'SYSTEM.INI', 0
+
+ ALIGN 2
+
+sEnd Data
+
+End
diff --git a/private/mvdm/wow16/drivers/comm/ddkmake b/private/mvdm/wow16/drivers/comm/ddkmake
new file mode 100644
index 000000000..f148215e4
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ddkmake
@@ -0,0 +1,47 @@
+# International mods
+# NOTE: LANG is a external macros set by international
+!IFNDEF LANG
+RES_DIR=.\messages\usa
+!ELSE
+RES_DIR=.\messages\$(LANG)
+!ENDIF
+
+#
+# Standard command line definitions
+#
+OPT= /W2 #NOP the options feature
+as=masm
+MASMOBJ=$(as) $(OPT)
+#
+# DOS 3.x inference rules
+#
+.asm.obj:
+ $(MASMOBJ) $*.asm;
+
+.asm.lst:
+ $(as) $(OPT) /l $*.asm;
+
+comm: comm.drv
+
+ccom.obj ccom.lst: ccom.asm ibmcom.inc comdev.inc
+
+ibmsetup.obj ibmsetup.lst: ibmsetup.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmcom.obj: ibmcom.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmint.obj: ibmint.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmlpt.obj: ibmlpt.asm ibmcom.inc comdev.inc
+
+commmsg.obj: $(RES_DIR)\commmsg.asm
+ $(MASMOBJ) $(RES_DIR)\commmsg.asm, commmsg.obj;
+
+comm.drv: iclean ccom.obj ibmsetup.obj ibmcom.obj ibmint.obj ibmlpt.obj commmsg.obj \
+ comm.def comm.rc comm.rcv
+ link ccom+ibmsetup+ibmcom+ibmint+ibmlpt+commmsg,comm.drv,comm.map/map,libw /NOD /AL:16,comm.def
+ rc comm.rc comm.drv
+ mapsym comm
+
+iclean:
+ del comm.drv
+ del commmsg.obj
diff --git a/private/mvdm/wow16/drivers/comm/ibmcom.asm b/private/mvdm/wow16/drivers/comm/ibmcom.asm
new file mode 100644
index 000000000..653726cf1
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmcom.asm
@@ -0,0 +1,1947 @@
+page,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMCOM.ASM
+;
+; !!!
+;
+; Created: Fri 06-Feb-1987 10:45:12
+; Author: Walt Moore [waltm]
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; General Description:
+;
+; History:
+;
+; ***************************************************************
+; Tue Dec 19 1989 09:32:15 -by- Amit Chatterjee [amitc]
+; ---------------------------------------------------------------
+; Modified the 'InitAPort' routine called from 'ReactivateOpenCommPort'.
+; If the out queue for a port has characters to send out then we must
+; restart the trasmission process by faking a comm interrupt on that
+; port.
+; ***************************************************************
+; Tue Nov 21 1989 09:46:50 -by- Amit Chatterjee [amitc]
+; ---------------------------------------------------------------
+; The base port addresses in the COMM1,COMM2,COMM3,COMM4 structures
+; are being zeroed out when the corresponding comm port is closed.
+; This is because the 'ReactivateOpenCommPort' function looks at it
+; and if the port address is not zero decides that comm ports are
+; open.
+; ***************************************************************
+; Tue Nov 14 1989 18:42:00 ADDED TWO EXPORTED FUNCTIONS
+; ---------------------------------------------------------------
+; Added two exported functions 'SuspendOpenCommPorts' and
+; 'ReactivateOpenCommPorts' for 286 winoldap support. The first one simply
+; releases the comm int vects and installs the originall one, the second one
+; hooks back the comm driver comm vectors and then reads the receive buffer,
+; the status and the IIR registers of all the available comm ports to
+; remove pending interrupts. It also reprograms the PIC to enable interrupts
+; on all open comm channels.
+; ---------------------------------------------------------------
+; -by- Amit Chatterjee [amitc]
+; ***************************************************************
+; Tue Aug 30 198? 12:52:00 MAJOR FIX TO HANDLE 8250B
+; ---------------------------------------------------------------
+;
+; 8250B has the following peculiar charactersistic
+; . The very first time (after reset) the Tx Holding Empty
+; interrupt is enabled, an immediate interrupt is generated
+;
+; . After the first time, switching the Tx Holding Empty
+; interrupt enable bit from disabled to enabled will NOT
+; generate an immediate interrupt (unlike in 8250)
+; Because of this the KICKTX routine fails to set the transmit cycle
+; on if the machine has a 8250B
+;
+; This has been taken care as follows:
+; . For the very first byte that is being transmitted, KICKTX
+; is used to generate the first Tx Holding Empty interrupt
+; . Subsequently, whenever we find that the transmit buffer
+; is empty, we use a SOFTWARE INT (either INT 0Bh, or INT 0Ch)
+; to force the first character out, once this is done the
+; Tx Holding Empty interrupt will be generated once the buffer
+; really is empty
+; . Now we no longer disable the Tx Holding Empty interrupt
+; in the Xmit ISR to ensure that even m/cs with 8250, use
+; the software int to kick the tx interrupt on after the
+; first time.
+; . The software interrupt is also forced whenever an X-ON
+; character is received.
+;
+; The code that implements the above logic is marked out with a line
+; asterixes.
+; ------------------------------------------------------------------
+; -by- Amit Chatterjee [amitc]
+; ******************************************************************
+;
+; 062587 HSFlag and Evtmask in DoLPT. These fields do not exist
+; for LPT type devices. The code which manipulated them
+; was removed
+;
+; KickTx from $SndCom - interrupts were not disabled when
+; calling KickTx.
+;
+; $SetCom - added CLD at the start
+;
+; $SetQue - movsw ==> stosw
+;
+; 111285 Changed the Timeout from 7 to 30 seconds.
+;
+; 110885 Forgot to set EV_RxChar event when a character
+; was received.
+;
+; 102985 INS8250, INS8250B bug with enabling interrupts.
+; Setting ACE_ETBEI in the Interrupt Enable Register
+; will cause an immediate interrupt regardless of
+; whether the transmitter register is empty or not.
+; The first interrupt MAY also be missed.
+;
+; The first case is not a problem since we only enable
+; interrupts if the transmitter register is empty. The
+; second problem was showing up on Microsoft System Cards
+; in PC-XTs. The first interrupt was missed after a cold
+; boot. National claims the fix is to write the register
+; twice, which SEEMS to work...
+;
+; Added timeout code to $TRMCOM. If the number of
+; characters in the output queue doesn't decrease
+; in "Timeout" seconds, then the port will be closed
+; anyway. Also flushed the input queue and added a
+; discard-input flag for the data available interrupt
+; code to discard any input received while terminating
+; a port. $TRMCOM will return an error code if it
+; discarded any output data.
+;
+; Removed infinite timeout test in MSRWait routine.
+; Still bad, but it will timeout around 65 seconds
+; instead of never.
+;
+; 102785 LPT initialization code was jumping to InitCom90,
+; which was setting EFlags[si] to null. Well, LPTs
+; don't have an EFlags field, so the null was getting
+; stuffed over the LSB of BIOSPortLoc of the next LPT
+; device.
+;
+; 101185 Save interrupt vector when opening a comm port
+; and restore it when closing. Would you believe
+; there are actually programs that assume the
+; vector points to a non-specific 8259 ACK and
+; an IRET!
+;
+; 100985 Added MS-NET support to gain exclusive control
+; of an LPT port if DOS 3.x and not running in as
+; a server, receiver, or messenger. Required to
+; keep another application, such as command.com
+; from closing the stream or mixing their output
+; with ours.
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;-----------------------------------------------------------------------;
+
+title IBMCom - IBM PC, PC-XT, PC-AT, PS/2 Communications Interface
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ins8250.inc
+include ibmcom.inc
+include vint.inc
+.list
+
+externNP GetDEB
+externNP DoLPT
+externNP StringToLPT
+externNP FindCOMPort
+externNP StealPort
+
+
+sBegin Data
+
+externB $MachineID
+
+sEnd Data
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $RECCOM - Receive Characters From Device
+;
+; Read Byte From RS232 Input Queue If Data Is Ready
+;
+; LPT ports will return with an indication that no characters are
+; available.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; 'Z' clear if data available
+; AL = byte
+; Error Returns:
+; 'Z' Set if error or no data
+; AX = error code
+; AX = 0 if no data
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $RECCOM
+$RECCOM proc near
+
+ push si ;Once again, save some registers
+ push di
+ call GetDEB ;Get DEB pointer in SI
+ jc RecCom10 ;Invalid Port [rkh] ...
+ jns RecCom20 ;COM port
+ jmp RecCom95 ;LPT port, return no characters
+
+RecCom10:
+ jmp RecCom100 ; Invalid Port
+
+; Before removing any charcters from the input queue, check to see
+; if XON needs to be issued. If it needs to be issued, set the
+; flag that will force it and arm transmit interrupts.
+
+RecCom20:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom32 ; No
+ test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
+ jnz RecCom21 ; No Enq recvd & no lines dropped
+ jmp RecCom60 ; No Enq recvd & no lines dropped
+RecCom21:
+ jmp short RecCom34
+
+RecCom32:
+ test HSFlag[si],HSSent ;Handshake sent?
+ jnz RecCom33 ; No XOFF sent & no lines dropped
+ jmp RecCom60 ; No XOFF sent & no lines dropped
+RecCom33:
+
+RecCom34:
+ mov ax,QInCount[si] ;Get current count of input chars
+ cmp ax,[si.DCB_XonLim] ;See if at XOn limit
+ ja RecCom60 ;Not at XOn limit yet
+
+; If any hardware lines are down, then raise them. Then see
+; about sending XON.
+
+ mov dx,Port[si] ;Get the port
+ mov ah,HHSLines[si] ;Get hardware lines mask
+ call DOCLI ;Handle this as a critical section
+ mov cl,HSFlag[si] ;Get handshaking flags
+ or ah,ah ;Any hardware lines to play with?
+ jz RecCom40 ; No
+ add dl,ACE_MCR ;--> Modem control register
+ in al,dx
+ or al,ah ;Turn on the hardware bits
+ iodelay
+ out dx,al
+ and cl,NOT HHSDropped ;Show hardware lines back up
+
+RecCom40:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom47 ; No
+ test cl,EnqReceived ;Did we receive Enq?
+ jz RecCom55 ; No
+ and cl,NOT EnqReceived
+ jmp short RecCom50
+
+RecCom47:
+ test cl,XOffSent ;Did we send XOFF?
+ jz RecCom55 ; No
+ and cl,NOT XOffSent ;Remove XOFF sent flag
+
+RecCom50:
+ or cl,XOnPending ;Show XON or ACK must be sent
+ call KickTx ;Kick xmit if needed
+
+RecCom55:
+ mov HSFlag[si],cl ;Store handshake flag
+ call DOSTI ;Can allow interrupts now
+
+; Now we can get down to the business at hand, and remove a character
+; from the receive queue. If a communications error exists, we return
+; that, and nothing else.
+
+RecCom60:
+ xor ax,ax
+ or ax,ComErr[si] ;Any Errors?
+ jnz RecCom100 ; Yes, return the error code
+ or ax,QInCount[si] ;Get current input char count
+ jz RecCom90 ;No characters in the queue
+ les di,QInAddr[si] ;Get queue pointer
+ assumes es,nothing
+
+ mov bx,QInGet[si] ;Also get the index to head
+ mov al,es:[bx][di] ;Finally, get byte from queue
+ inc bx ;Update queue index
+ cmp bx,QInSize[si] ;See if time for wrap-around
+ jc RecCom70 ;Jump if no wrap
+ xor bx,bx ;wrap by zeroing the index
+
+RecCom70:
+ mov QInGet[si],bx ;Save new head pointer
+ dec QInCount[si] ;Dec # of bytes in queue
+
+ mov cx, [si.QinCount]
+ cmp cx, [si.RecvTrigger] ;Q: have we read below trigger?
+ jae RecCom80 ; N:
+ and [si.NotifyFlagsHI], NOT CN_RECEIVE ; allow timeout notify again
+RecCom80:
+ or sp,sp ;Reset PSW.Z
+ pop di
+ pop si
+ ret
+
+; No characters in the input queue. Check to see if EOF
+; was received, and return it if it was. Otherwise show
+; no characters.
+
+RecCom90:
+ test [si.DCB_Flags],fBinary ;Are we doing binary stuff?
+ jnz RecCom95 ; Yes, show no characters
+ mov al,[si.DCB_EofChar] ;Assume EOF
+ test EFlags[si],fEOF ;Has end of file char been received?
+ jnz RecCom80 ; Yes, show end of file
+
+RecCom95:
+ xor ax,ax ;Show no more characters
+
+; Return with 'Z' to show error or no characters
+
+RecCom100:
+ xor cx,cx ;Set PSW.Z
+ pop di
+ pop si
+ ret
+
+$RECCOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $RECSTR - Receive Characters From Device
+;
+; Read Byte From RS232 Input Queue If Data Is Ready
+;
+; LPT ports will return with an indication that no characters are
+; available.
+;
+; Entry:
+; AH = Device ID
+; ES:DI -> receive buffer
+; CX max bytes to read
+; Returns:
+; 'Z' clear if data available
+; AX = # of bytes read
+; Error Returns:
+; 'Z' Set if error or no data
+; AX = error code
+; AX = 0 if no data
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $RECSTR
+$RECSTR proc near
+
+ push si ;Once again, save some registers
+ push di
+ call GetDEB ;Get DEB pointer in SI
+ jc RecStr10 ;Invalid Port [rkh] ...
+ jns RecStr20 ;COM port
+ jmp RecStr95 ;LPT port, return no characters
+
+RecStr10:
+ jmp RecStr100 ; Invalid Port
+RecStr15:
+ jmp RecStr90
+
+RecStr20:
+ xor ax,ax
+ or ax,ComErr[si] ;Any Errors?
+ jnz RecStr10 ; Yes, return the error code
+ or ax,QInCount[si] ;Get current input char count
+ jz RecStr15 ;No characters in the queue
+
+ cmp cx, ax ;Q: more chars available than can read?
+ jbe short RecStr30 ; N:
+ mov cx, ax ; Y: adjust # of chars to read
+RecStr30:
+ push cx
+ mov dx, QInSize[si]
+ mov ax, QInGet[si]
+ sub dx, ax ; dx = # of bytes before end of buf
+ cmp dx, cx ;Q: more avail than can read?
+ jbe short RecStr40 ; N:
+ mov dx, cx ; Y: adjust avail count
+RecStr40:
+ xchg cx, dx ; cx = # of bytes for 1st copy
+ sub dx, cx ; dx = # of bytes for 2nd copy
+
+ push ds
+ push si
+ lds bx, QInAddr[si]
+ mov si, bx
+ add si, ax ; ds:si -> first char in buffer
+ cld
+ rep movsb ; do first copy
+ mov cx, dx
+ jcxz short RecStr50 ; jump if no 2nd copy needed
+ mov si, bx ; ds:si -> start of buffer
+ rep movsb ; do 2nd copy
+RecStr50:
+ sub si, bx ; si = new QInGet
+ mov bx, si
+ pop si
+ pop ds
+ pop cx
+ call DOCLI
+ mov QInGet[si], bx ; update QInGet
+ sub QInCount[si], cx ; update count
+ mov ax, QInCount[si]
+ call DOSTI
+
+ cmp ax, [si.RecvTrigger] ;Q: have we read below trigger?
+ jae @F ; N:
+ and [si.NotifyFlagsHI], NOT CN_RECEIVE ; allow timeout notify again
+@@:
+
+; Check to see if XON needs to be issued. If it needs to be issued, set the
+; flag that will force it and arm transmit interrupts.
+
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz @F ; No
+ test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
+ jnz RecStr58 ; No Enq recvd & no lines dropped
+ jmp RecStr80 ; No Enq recvd & no lines dropped
+RecStr58:
+ jmp short RecStr60
+
+@@:
+ test HSFlag[si],HSSent ;Handshake sent?
+ jnz RecStr59 ; No XOFF sent & no lines dropped
+ jmp RecStr80 ; No XOFF sent & no lines dropped
+RecStr59:
+
+RecStr60:
+ ;ax = current count of input chars
+ cmp ax,[si.DCB_XonLim] ;See if at XOn limit
+ ja RecStr80 ;Not at XOn limit yet
+
+;; int 1
+; If any hardware lines are down, then raise them. Then see
+; about sending XON.
+
+ mov dx,Port[si] ;Get the port
+ mov ah,HHSLines[si] ;Get hardware lines mask
+ push cx
+ call DOCLI ;Handle this as a critical section
+ mov cl,HSFlag[si] ;Get handshaking flags
+ or ah,ah ;Any hardware lines to play with?
+ jz @F ; No
+ add dl,ACE_MCR ;--> Modem control register
+ in al,dx
+ or al,ah ;Turn on the hardware bits
+ iodelay
+ out dx,al
+ and cl,NOT HHSDropped ;Show hardware lines back up
+
+@@:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz @F ; No
+ test cl,EnqReceived ;Did we receive Enq?
+ jz RecStr70 ; No
+ and cl,NOT EnqReceived
+ jmp short RecStr65
+
+@@:
+ test cl,XOffSent ;Did we send XOFF?
+ jz RecStr70 ; No
+ and cl,NOT XOffSent ;Remove XOFF sent flag
+
+RecStr65:
+ or cl,XOnPending ;Show XON or ACK must be sent
+ call KickTx ;Kick xmit if needed
+
+RecStr70:
+ mov HSFlag[si],cl ;Store handshake flag
+ call DOSTI ;Can allow interrupts now
+ pop cx
+
+RecStr80:
+ mov ax, cx
+ or sp,sp ;Reset PSW.Z
+ pop di
+ pop si
+ ret
+
+; No characters in the input queue. Check to see if EOF
+; was received, and return it if it was. Otherwise show
+; no characters.
+
+RecStr90:
+ test [si.DCB_Flags],fBinary ;Are we doing binary stuff?
+ jnz RecStr95 ; Yes, show no characters
+ mov al,[si.DCB_EofChar] ;Assume EOF
+ test EFlags[si],fEOF ;Has end of file char been received?
+ jnz RecStr80 ; Yes, show end of file
+
+RecStr95:
+ xor ax,ax ;Show no more characters
+
+; Return with 'Z' to show error or no characters
+
+RecStr100:
+ xor cx,cx ;Set PSW.Z
+ pop di
+ pop si
+ ret
+
+$RECSTR endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SNDIMM - Send A Character Immediately
+;
+; This routine either sends a character to the port immediately,
+; or places the character in a special location which is used by
+; the next transmit interrupt to transmit the character prior to
+; those in the normal transmit queue.
+;
+; For LPT ports, the character is always sent immediately.
+;
+; Entry:
+; AH = Device ID
+; AL = Character
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = 8000H if Bad ID
+; AX = 4000H if couldn't send because another character
+; transmitted "immediately" is waiting to be sent
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $SNDIMM
+$SNDIMM proc near
+
+ push si
+ call GetDEB ;Get pointer to the DEB
+ jc SendImm20 ;Bad ID, return an error
+ jns SendImm10 ;Its a COM port
+
+
+; For LPT ports, call DoLPT to do the dirty work. If DoLPT
+; returns an error code, map it to 4000h.
+
+ xor ch,ch ;Show xmit character
+ call DoLPT ;Do the work here
+ or ax,ax ;Error occur?
+ jz SendImm20 ; No, show all is OK
+ mov ax,4000h ; Yes, return 4000h
+ jmp short SendImm20
+
+SendImm10:
+ mov dl, al
+ mov ax,4000h ;In case we cannot send
+ test EFlags[si],fTxImmed ;Another char waiting "immediately"?
+ jnz SendImm20 ; Yes, return error
+ mov ah,dl ;Set char for TXI
+ call DOCLI ;TXI is critical section code
+ call TXI ;Set character to tx immediately
+ call DOSTI
+ xor ax,ax ;Show all is OK
+
+SendImm20:
+ pop si
+ ret
+
+$SNDIMM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SNDCOM - Send Byte To Port
+;
+; The given byte is sent to the passed port if possible.
+; If the output queue is full, an error will be returned.
+;
+; Entry:
+; AH = Device ID
+; AL = Character
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = error code
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SNDCOM
+$SNDCOM proc near
+
+ push si
+ push di
+ call GetDEB ;--> DEB
+ jc SendCom40 ;Invalid ID
+ jns SendCom20 ;Its a COM port
+
+; Handle the transmission of a LPT character. The ROM BIOS int 17
+; call will be made to do the transmission. The port address will
+; be restored during the call, then zeroed out upon return.
+
+SendCom10:
+ xor ch,ch ;Show xmit character
+ call DoLPT ;Do the work here
+ jmp short SendCom40 ;Return the status to caller
+
+; Send a character to a COM port. Return an error if control
+; line timeout occurs or there is no room in the output queue.
+
+SendCom20:
+ push ax ;Save character
+
+ call MSRWait ;See if lines are correct for output
+ pop ax ;Restore char
+ jnz SendCom60 ;Timeout occured, return error
+ mov cx,QOutSize[si] ;See if queue is full
+ cmp cx,QOutCount[si]
+ jle SendCom50 ;There is no room in the queue
+ les di,QOutAddr[si] ;--> output queue
+ assumes es,nothing
+
+ mov bx,QOutPut[si] ;Get index into queue
+ mov es:[bx][di],al ;Store the byte
+ inc bx ;Update index
+ cmp bx,cx ;Wrap time?
+ jc SendCom30 ; No
+ xor bx,bx ;Wrap-around is a new zero pointer
+
+SendCom30:
+
+ call DOCLI
+ mov QOutPut[si],bx ;Store updated pointer
+ mov ax,QOutCount[si] ; get the count
+ inc ax ; have the updated value in AX for test later
+ mov QOutCount[si],ax ;Update queue population
+ call KickTx ;Make sure xmit interrupt is armed
+ call DOSTI
+
+ xor ax,ax ;Show no error (that we know of)
+
+;****************************************************************************
+
+SendCom40:
+ pop di
+ pop si
+ ret
+
+SendCom50:
+ or by ComErr+1[si],HIGH CE_TXFULL
+ .errnz LOW CE_TXFULL
+
+SendCom60:
+ mov ax,ComErr[si] ;Return error code to caller
+ jmp short SendCom40
+
+$SNDCOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SNDCOMSTR - Send buffer To Port
+;
+; The given buffer is sent to the passed port if possible.
+; Once the output queue is detected as being full, a CE_TXFULL error
+; will be indicated and AX will be returned as the # of chars actually
+; queued.
+;
+; Entry:
+; DS:SI --> DEB
+; ES:DI --> buffer
+; Returns:
+; AX = # of bytes queued
+; Registers Destroyed:
+; AX,BX,CX,DX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SNDCOMSTR
+$SNDCOMSTR proc near
+
+ push cx ; save count
+ call GetDEB
+ jc cws_error ; jump if id invalid
+ jns cws_comm ; jump if COM port
+
+ call StringToLPT
+ pop cx ; discard saved count, ax = # transfered
+ jmp short cws_exit
+
+cws_error:
+ pop ax
+ sub ax, cx ; ax = # transfered
+cws_exit:
+ ret
+
+cws_comm:
+ call MSRWait ;See if lines are correct for output
+ pop cx
+ push cx
+ jnz cws_error ;Timeout occured, return error
+
+ mov dx, QOutSize[si] ;See if queue is full
+ sub dx, QOutCount[si] ; dx = # of chars free in queue
+ jg scs_loop
+ jmp scs_full ;There is no room in the queue
+
+scs_loop:
+ push cx ; save count left to send
+ cmp cx, dx ;Q: room for buffer in queue?
+ jbe @f ; Y:
+ mov cx, dx ; N: adjust size to send
+@@:
+ push cx ; save # of chars which will be copied
+ push si
+ push ds
+ push di
+ push es
+ les bx,QOutAddr[si] ;--> output queue
+ assumes es,nothing
+
+ mov dx, QOutSize[si]
+ mov di, QOutPut[si] ;Get index into queue
+ sub dx, di ; dx = # of free chars before end of queue
+ cmp dx, cx
+ jbe @f
+ mov dx, cx
+@@:
+ xchg cx, dx ; cx = # of chars for 1st copy
+ sub dx, cx ; dx = # of chars for 2nd copy
+ pop ds
+ pop si ; ds:si -> src buffer
+ assumes ds,nothing
+ add di, bx ; es:di -> current pos in queue
+ cld
+ rep movsb ; copy first section
+ mov cx, dx
+ jcxz @F
+ mov di, bx ; circle back to start of queue
+ rep movsb ; copy 2nd section
+@@:
+ sub di, bx ; di last index into queue
+ mov dx, di
+ mov di, si ; last location in src buffer
+ mov si, ds
+ mov es, si ; es:di -> last loc in src buf
+ pop ds
+ pop si ; ds:si -> ComDEB
+ assumes ds,data
+ pop bx ; # of chars copied
+ call DOCLI
+ mov QOutPut[si], dx ;new index into queue
+ add QOutCount[si], bx
+ call KickTx
+ call DOSTI
+ pop cx
+ sub cx, bx ; # of chars left to send
+ jnz scs_full_2 ; jump if none
+scs_exit:
+ pop ax
+ sub ax, cx ; ax = # transfered
+ ret
+
+scs_full:
+ call DOCLI
+ call KickTx
+ call DOSTI
+scs_full_2:
+ or by ComErr+1[si],HIGH CE_TXFULL
+ .errnz LOW CE_TXFULL
+ jmp scs_exit
+
+$SNDCOMSTR endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $FLUSH - Flush The Input and Output Queues
+;
+; This is a hard initialization of the transmit and receive queue's,
+; which immediately empties the given queue.
+;
+; LPT ports will just return the device error word
+;
+; Entry:
+; AH = Device ID
+; BH = Queue # to clear (0=Tx, 1=Rx)
+; Returns:
+; AX = Device Error Word. (Not reset)
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $FLUSH
+$FLUSH proc near
+
+ push si
+ push di
+ call GetDEB ;si --> DEB
+ jc Flush40 ;Invalid ID
+ js Flush30 ;LPT port, return any error
+
+ mov cx,QOutCount-QInCount ;# of bytes to zero
+ lea di,QInCount[si] ;--> receive queue data
+ or bh,bh ;Transmit queue?
+ jnz Flush10 ; No, input queue
+ add di,cx ; Yes, --> xmit queue data
+
+Flush10:
+ cld
+ push ds
+ pop es
+ assumes es,nothing
+
+ xor al,al
+ call DOCLI ;Time to worry about critical sections
+ rep stosb
+ call DOSTI
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+
+ or bh,bh ;Rx queue?
+ jz Flush30 ; No, xmit queue
+
+
+; If the queue to be cleared is the receive queue, any
+; hardware handshake must be cleared to prevent a possible
+; deadlock situation. Since we just zeroed the queue count,
+; a quick call to $RecCom should do wonders to clear any
+; receive handshake (i.e. send XON if needed).
+
+Flush20:
+ call $RECCOM ;Take care of handshakes here
+
+Flush30:
+ mov ax,ComErr[si] ;And return the error word.
+
+Flush40:
+ pop di
+ pop si
+ ret
+
+$FLUSH endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; TXI - Transmit A Character Immediately
+;
+; Set up a character to be transmitted "immediately".
+; by placing the character in a location that guarantees
+; it to be the next character transmitted.
+;
+; The check to see if the immediate character can be placed has
+; already been made prior to entry.
+;
+; Interrupts must be disabled before entering this code
+;
+; Entry:
+; AH = Character
+; DS:SI --> DEB
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; L,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public TXI ;Public for debugging
+TXI proc near
+
+; call DOCLI ;Must be done by caller!
+ or EFlags[si],fTxImmed ;Show char to xmit
+ mov ImmedChar[si],ah ;Set character to transmit next
+; jmp short KickTx ;Kick Xmit just in case
+ errn$ KickTx
+
+TXI endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; KickTx - Kick Transmitter
+;
+; "Kick" the transmitter interrupt routine into operation.
+; If the Transmitter Holding Register isn't empty, then
+; nothing needs to be done. If it is empty, then the xmit
+; interrupt needs to enabled in the IER.
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public KickTx ;Public for debugging
+KickTx proc near
+
+; call DOCLI ;Done by caller
+ test [si.VCDflags], 1 ;Q: we still own port?
+ jnz can_we_steal ; N:
+
+enable_int:
+ mov dx,Port[si] ;Get device I/O address
+ add dl,ACE_IER ;--> Interrupt enable register
+ in al,dx ;Get current IER state
+ test al,ACE_ETBEI ;Interrupt already enabled?
+ jnz KickTx10 ; Yes, don't reenable it
+ or al,ACE_ETBEI ; No, enable it
+ out dx,al
+ iodelay ;8250, 8250-B bug requires
+ out dx,al ; writting register twice
+
+KickTx10:
+; call DOSTI ;Done by caller
+ ret
+
+can_we_steal:
+ call StealPort ; call VCD to see if we can steal
+ ; the port back
+ jnc short enable_int ; jump, if we got it
+;
+; flush out queue
+;
+ xor ax, ax
+ mov [si.QOutCount], ax
+ mov [si.QOutMod], ax
+ mov ax, [si.QOutGet]
+ mov [si.QOutPut], ax
+ jmp short KickTx10 ; N:
+
+KickTx endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; MSRWait - Modem Status Register Wait
+;
+; This routine checks the modem status register for CTS, DSR,
+; and/or RLSD signals. If a timeout occurs while checking,
+; the appropriate error code will be returned.
+;
+; This routine will not check for any signal with a corresponding
+; time out value of 0 (ignore line).
+;
+; Entry:
+; SI --> DEB
+; Returns:
+; AL = error code
+; ComErr[si] updated
+; 'Z' set if no timeout
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public MSRWait ;Public for debugging
+
+MSRWait proc near
+
+ push di
+
+MSRRestart:
+ xor di,di ;Init Timer
+
+MSRWait10:
+ mov cx,11 ;Init Delay counter (used on non-ATs)
+
+MSRWait20:
+ xor dh,dh ;Init error accumulator
+ mov al,MSRShadow[si] ;Get Modem Status
+ and al,MSRMask[si] ;Only leave bits of interest
+ xor al,MSRMask[si] ;0 = line high
+ jz MSRWait90 ;All lines of interest are high
+ mov ah,al ;ah has 1 bits for down lines
+
+ shl ah,1 ;Line Signal Detect low?
+ jnc MSRWait30 ; No, it's high
+ .errnz ACE_RLSD-10000000b
+ cmp di,[si.DCB_RlsTimeout] ;RLSD timeout yet?
+ jb MSRWait30 ; No
+ or dh,CE_RLSDTO ;Show modem status timeout
+
+MSRWait30:
+ shl ah,1 ;Data Set Ready low?
+ shl ah,1
+ .errnz ACE_DSR-00100000b
+ jnc MSRWait40 ; No, it's high
+ cmp di,[si.DCB_DsrTimeout] ;DSR timeout yet?
+ jb MSRWait40 ; No
+ or dh,CE_DSRTO ;Show data set ready timeout
+
+MSRWait40:
+ shl ah,1 ;CTS low?
+ jnc MSRWait50 ; No, it's high
+ .errnz ACE_CTS-00010000b
+ cmp di,[si.DCB_CtsTimeout] ;CTS timeout yet?
+ jb MSRWait50 ; No
+ or dh,CE_CTSTO ;Show clear to send timeout
+
+MSRWait50:
+ or dh,dh ;Any timeout occur?
+ jnz MSRWait80 ; Yes
+
+ cmp [$MachineID],0FCh ;Is this a PC-AT? [rkh debug for PS/2]
+ je MSRWait60 ; Yes, use ROM function
+ loop MSRWait20 ; No, continue until timeout
+ jmp short MSRWait70 ;Should have taken about a millisecond
+
+MSRWait60:
+ push bx ;Special SALMON ROM routine to delay
+ push di
+ xor cx,cx ;Number of Microseconds to delay
+ mov dx,1000 ; in CX:DX
+ mov ah,86h
+ int 15h ;Wait 1 millisecond
+ pop di
+ pop bx
+
+MSRWait70:
+ inc di ;Timer +1
+ jmp short MSRWait10 ;Until Timeout or Good status
+
+MSRWait80:
+ xor ah,ah
+ mov al,dh
+ or by ComErr[si],al ;Return updated status
+ .errnz HIGH CE_CTSTO
+ .errnz HIGH CE_DSRTO
+ .errnz HIGH CE_RLSDTO
+
+MSRWait90:
+ or al,al ;Set 'Z' if no timeout
+ pop di
+ ret
+
+MSRWait endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVT - Set Event Mask
+;
+; Set up event word and mask. Returns a pointer to a word in which
+; certain bits, as enabled by the mask, will be set when certain
+; events occur.
+;
+; Entry:
+; AH = Device ID
+; BX = Event enable mask
+; Returns:
+; DX:AX --> event word.
+; Error Returns:
+; AX = 0 if error
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVT
+$EVT proc near
+
+ push si
+ xor dx,dx ;In case of error
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx ;Finish setting error return value
+ jc Evt10 ;Illegal id, return error
+ js Evt10 ;LPTx, return error
+ mov EvtMask[si],bx ;Save the new event mask
+ lea ax,EvtWord[si] ;Get address of event word
+ mov dx,ds ; into dx:ax
+
+Evt10:
+ pop si
+ ret
+
+$EVT endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVTGET - Get Event Word
+;
+; Return and clear fields in the event word. This routine MUST be used
+; by applications to read the event word, as it is the ONLY way they
+; can be assured that an event is not lost between reading the flags
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; BX = Event clear mask
+; Returns:
+; AX = event word
+; Error Returns:
+; None
+; Registers Preserved:
+; AX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; BX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVTGET
+$EVTGET proc near
+
+ push si
+ call GetDEB
+ mov ah,0 ;In case of error (AL already 0)
+ jc EvtGet10 ;Illegal ID
+ js EvtGet10 ;Illegal ID
+ call DOCLI ;No interrupts allowed
+ mov ax,EvtWord[si] ;Get the current event word
+ not bx ;Convert mask for our purposes
+ and bx,ax ;Clear events that user wants us to
+ mov EvtWord[si],bx ;And save those results
+ call DOSTI ;Magic over
+
+EvtGet10:
+ pop si
+ ret
+
+$EVTGET endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $STACOM - Return Status Information
+;
+; Returns the number of bytes in both queues.
+;
+; LPT ports will show both queues empty.
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; ES:BX = Pointer to status structure to be updated.
+; = Null if not to update
+; Returns:
+; AX = comm error word
+; Status Structure Updated.
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $STACOM
+$STACOM proc near
+
+ push si
+ call GetDEB ;Get DEB pointer in SI
+ jc StaCom30 ;Invalid ID
+ mov cx,es ;Is the pointer NULL?
+ or cx,bx
+ jz StaCom25 ; Yes, just return error code
+ xor cx,cx
+ xor dx,dx
+ or ah,ah ;Set 'S' if LPT port
+ mov ax,cx ;For LPTs, everything is zero
+ js StaCom20 ;LPT port
+
+; Need to get the status for a com port. Since not all the
+; status is contained within EFlags, it has to be assembled.
+; Also note that currently there is no way to specify RLSD
+; as a handshaking line, so fRLSDHold is always returned false.
+
+ mov al,MSRShadow[si] ;Get state of hardware lines
+ and al,OutHHSLines[si] ;Mask off required bits
+ xor al,OutHHSLines[si] ;1 = line low
+ mov cl,4 ;Align bits
+ shr al,cl ;al = fCTSHold + fDSRHold
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+ .errnz fCTSHold-00000001b
+ .errnz fDSRHold-00000010b
+
+ mov ah,HSFlag[si] ;Get fXOffHold+fXOffSent
+ and ah,XOffReceived+XOffSent
+ or al,ah
+
+ .errnz XOffReceived-fXOFFHold
+ .errnz XOffSent-fXOFFSent
+
+ mov ah,EFlags[si] ;Get fEOF+fTxImmed
+ and ah,fEOF+fTxImmed
+ or al,ah
+
+ mov cx,QInCount[si] ;Get input queue count
+ mov dx,QOutCount[si] ;Get tx queue count
+
+StaCom20:
+ mov es:[bx.COMS_BitMask1],al
+ mov es:[bx.COMS_cbInQue],cx
+ mov es:[bx.COMS_cbOutQue],dx
+
+StaCom25:
+ xor ax,ax ;Return old com error
+ xchg ax,ComErr[si] ; and clear it out
+
+StaCom30:
+ pop si
+ ret
+
+$STACOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SetBrk - Set Break
+;
+; Clamp the Tx data line low. Does not wait for the
+; transmitter holding register and shift registers to empty.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $SETBRK
+$SETBRK proc near
+
+ mov cx,0FF00h+ACE_SB ;Will be setting break
+ jmp short ClrBrk10
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+$SETBRK endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $CLRBRK - Clear Break
+;
+; Release any BREAK clamp on the Tx data line.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $CLRBRK
+$CLRBRK proc near
+
+ mov cx,(NOT ACE_SB) SHL 8
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+ClrBrk10:
+ push si
+ call GetDEB ;Get DEB address
+ jc ClrBrk30 ;Invalid ID
+ js ClrBrk20 ;Ignored for LPT ports
+ call DOCLI
+ and HSFlag[si],ch ;Set or clear the BreakSet bit
+ or HSFlag[si],cl
+
+; ch = mask to remove bits in the Line Control Register
+; cl = mask to turn bits on in the Line Control Register
+
+ mov dx,Port[si] ;Get comm device base I/O port
+ add dl,ACE_LCR ;Point at the Line Control Regieter
+ in al,dx ;Get old line control value
+ and al,ch ;Turn off desired bits
+ or al,cl ;Turn on desired bits
+ iodelay
+ out dx,al ;Output New LCR.
+ call DOSTI
+
+ClrBrk20:
+ mov ax,ComErr[si] ;Return Status Word
+
+ClrBrk30:
+ pop si
+ ret
+
+$CLRBRK endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EXTCOM - Extended Comm Functions
+;
+; A number of extended functions are routed through this entry point.
+;
+; Functions currently implemented:
+;
+; 0: Ignored
+; 1: SETXOFF - Exactly as if X-OFF character has been received.
+; 2: SETXON - Exactly as if X-ON character has been received.
+; 3: SETRTS - Set the RTS signal
+; 4: CLRRTS - Clear the RTS signal
+; 5: SETDTR - Set the DTR signal
+; 6: CLRDTR - Clear the DTR signal
+; 7: RESET - Yank on reset line if available (LPT devices)
+;
+; Entry:
+; AH = Device ID
+; BL = Function Code
+; (0-127 are MS-defined, 128-255 are OEM defined)
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+
+; Dispatch table for the extended functions
+
+ExtTab dw ExtComDummy ;Function 0: Never Mind
+ dw ExtCom_FN1 ;1: Set X-Off
+ dw ExtCom_FN2 ;2: Clear X-Off
+ dw ExtCom_FN3 ;3: Set RTS
+ dw ExtCom_FN4 ;4: Clear RTS
+ dw ExtCom_FN5 ;5: Set DSR
+ dw ExtCom_FN6 ;6: Clear DSR
+ dw ExtCom_FN7 ;7: Reset printer
+ dw ExtCom_FN8 ;8: Get Max LPT Port
+ dw ExtCom_FN9 ;9: Get Max COM Port
+ dw ExtCom_FN10 ;10: Get COM Port Base & IRQ
+ dw ExtCom_FN10 ;11: Get COM Port Base & IRQ
+%OUT fix this for bld 32 -- GetBaseIRQ is now 10
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EXTCOM
+$EXTCOM proc near
+
+ push si
+ push di
+ call GetDEB ;Get DEB pointer
+ jc ExtCom40 ;Invalid ID, return error
+ mov dx,Port[si] ; get port address
+ jns ExtCom10 ;Its a COM port
+ cmp bl,7 ;RESET extended function?
+ jne ExtCom30 ; No, return error word
+ jmp short ExtCom20 ; Yes, invoke the function
+
+ExtCom10:
+ cmp bl,11 ;Last fcn supported
+ ja ExtCom30 ;Not an implemented function.
+
+ExtCom20:
+ xor bh,bh
+ add bx,bx ;Shift for the call
+ call DOCLI ;Consider as critical sections
+ call ExtTab[bx] ; and perform the function
+ call DOSTI
+ jc ExtCom40 ; jump if sub returns data in DX:AX
+
+ExtCom30:
+ mov ax,ComErr[si] ;Return standard error word
+ xor dx, dx
+
+ExtCom40:
+ pop di
+ pop si
+
+ ret
+
+$EXTCOM endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN1 - Extended Function Set X-Off
+;
+; Analagous to receiving an X-OFF character. Bufferred transmision of
+; characters is halted until an X-ON character is received, or until
+; we fake that with a Clear X-Off call.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN1
+ExtCom_FN1 proc near
+
+ or HSFlag[si],XOffReceived
+ExtComDummy:
+ clc
+ ret
+
+ExtCom_FN1 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN2 - Extended Function Clear X-Off
+;
+; Analagous to receiving an X-ON character. Buffered
+; transmission of characters is restarted.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN2
+ExtCom_FN2 proc near
+
+ and HSFlag[si],NOT XOffReceived
+ call KickTx ;Kick transmitter interrupts on
+ clc
+ ret
+
+ExtCom_FN2 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN3 - Extended Function Set RTS
+;
+; Set the RTS signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN3
+ExtCom_FN3 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ or al,ACE_RTS ;Set RTS
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN3 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN4 - Extended Function Clear RTS
+;
+; Set the RTS signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN4
+ExtCom_FN4 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ and al,NOT ACE_RTS ;Clear RTS
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN4 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN5 - Extended Function Set DTR
+;
+; Set the DTR signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN5
+ExtCom_FN5 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ or al,ACE_DTR ;Set DTR
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN5 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN6 - Extended Function Clear DTR
+;
+; Set the DTR signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN6
+ExtCom_FN6 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ in al,dx ;Get current settings
+ and al,NOT ACE_DTR ;Clear DTR
+ iodelay
+ out dx,al ;And update
+ clc
+ ret
+
+ExtCom_FN6 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN7 - Extended Function Reset Printer
+;
+; Assert the RESET line on an LPT port
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN7
+ExtCom_FN7 proc near
+
+ call DOSTI ;Not called at interrupt time
+ mov ch,1 ;ROM BIOS Reset Port
+ call DoLPT ;Perform the function
+ clc
+ ret
+
+ExtCom_FN7 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN8 - Get Num Ports
+;
+; Entry:
+; Returns:
+; AX = Max LPT port id
+; DX = 0
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN8
+ExtCom_FN8 proc near
+
+ mov ax, MAXLPT + LPTx
+ xor dx, dx
+ stc
+ ret
+
+ExtCom_FN8 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN9 - Get Max COM Port
+;
+; Entry:
+; Returns:
+; AX = Max COM port id
+; DX = 0
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN9
+ExtCom_FN9 proc near
+
+ mov ax, MAXCOM
+ xor dx, dx
+ stc
+ ret
+
+ExtCom_FN9 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN10 - Get COM Port Bas & IRQ
+;
+; Entry:
+; AH = com id
+; DS:SI -> DEB
+; Returns:
+; AX = base
+; DX = irq
+; Error Returns:
+; None
+; Registers Preserved:
+; DS
+; Registers Destroyed:
+; AX,BX,CX,DX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN10
+ExtCom_FN10 proc near
+
+ call FindCOMPort
+ stc
+ ret
+
+ExtCom_FN10 endp
+page
+
+
+ifdef DEBUG
+ public RecCom40, RecCom50, RecCom60, RecCom70, RecCom80
+ public RecCom90, RecCom95, RecCom100
+ public SendImm10, SendImm20,
+ public SendCom10, SendCom20, SendCom30, SendCom40, SendCom50, SendCom60
+ public Flush10, Flush20, Flush30, Flush40
+ public KickTx10
+ public Evt10
+ public EvtGet10
+ public StaCom20, StaCom25, StaCom30
+ public ClrBrk10, ClrBrk20, ClrBrk30
+ public ExtCom10, ExtCom20, ExtCom30, ExtCom40, ExtComDummy
+ public MSRRestart, MSRWait10, MSRWait20, MSRWait30, MSRWait40
+ public MSRWait50, MSRWait60, MSRWait70, MSRWait80, MSRWait90
+endif
+
+
+DOSTI proc near
+ FSTI
+ ret
+DOSTI endp
+
+DOCLI proc near
+ FCLI
+ ret
+DOCLI endp
+
+
+sEnd code
+End
diff --git a/private/mvdm/wow16/drivers/comm/ibmcom.inc b/private/mvdm/wow16/drivers/comm/ibmcom.inc
new file mode 100644
index 000000000..cdf4608c1
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmcom.inc
@@ -0,0 +1,265 @@
+DEBUG equ 1
+
+No_DOSX_Bimodal_Services = 1
+IFDEF No_DOSX_Bimodal_Services
+%OUT generating code to handle ints without Bimodal Interrupt Services for DOSX
+ENDIF
+
+wo equ word ptr
+by equ byte ptr
+
+MAXLPT equ 2 ;3 LPTs supported (LPT1,2,3)
+MAXCOM equ 3 ;4 COMs supported (COM1,2,3,4)
+
+RS232B equ 0h ;RS232 Card(s) I/O addr 40:Save area.
+LPTB equ 8h ;LPT Card(s) I/O addr 40:Save area.
+
+IRQ3 equ 0bh ; Int vector for Com card @ 2xxh
+IRQ4 equ 0ch ; Int vector for Com card @ 3xxh
+
+INTA0 equ 20h ;X'20' 8259 Interrupt Control Port
+INTA1 equ 21h ;X'21' 8259 Interrupt Mask Port
+EOI equ 20h ;X'20' 8259 End-of-Interrupt ack
+
+Open equ 0201h ;Int 2F open request
+Close equ 0202h ;Int 2F close request
+Lock2F equ 0203h ;Int 2F lock request
+Unlock2F equ 0204h ;Int 2F unlock request
+
+
+; COMDEB - Communications Device Equipment Block.
+;
+; This is essentially a superset of the DCB used outside of this
+; module. The DCB is contained within the DEB as the first fields.
+; The fields which follow are data and status fields which
+; are unique to this implementation.
+;
+; AltQInAddr and AltQOutAddr are alternate queue pointers which are used when
+; in "supervisor" mode. Supervisor mode is a processor mode other than the
+; one which Windows normally runs in. In standard mode Windows, supervisor
+; mode is REAL mode. In enhanced mode Windows, supervisor mode is RING 0
+; protected mode. For more details see comments in IBMINT.ASM.
+
+ComDEB struc ;RS232 Data Equip Block
+
+ ComDCB db ((DCBSize+1) and 0FFFEh) DUP (0)
+
+ ComErr dw 0 ;Non-zero if I/O error
+ Port dw 0 ;Base I/O Address
+ NotifyHandle dw 0
+ NotifyFlags dw 0
+ RecvTrigger dw -1 ; char count threshold for calling
+ SendTrigger dw 0 ; char count threshold for calling
+
+; The following fields are specific to com ports only
+
+ IRQhook dw 0 ; ptr to IRQ_Hook_Struc
+ NextDEB dw 0 ; ptr to next DEB that is sharing IRQ
+ XOffPoint dw 0 ;Q count where XOff is sent
+ EvtMask dw 0 ;Mask of events to check for
+ EvtWord dw 0 ;Event flags
+ QInAddr dd 0 ;Address of the queue
+ AltQInAddr dd 0 ; Addr of queue in "supervisor" mode
+ QInSize dw 0 ;Length of queue in bytes
+ QOutAddr dd 0 ;Address of the queue
+ AltQOutAddr dd 0 ; Addr of queue in "supervisor" mode
+ QOutSize dw 0 ;Length of queue in bytes
+ QInCount dw 0 ;Number of bytes currently in queue
+ QInGet dw 0 ;Offset into queue to get bytes from
+ QInPut dw 0 ;Offset into queue to put bytes in
+ QOutCount dw 0 ;Number of bytes currently in queue
+ QOutGet dw 0 ;Offset into queue to get bytes from
+ QOutPut dw 0 ;Offset into queue to put bytes in
+ EFlags db 0 ;Extended flags
+ MSRShadow db 0 ;Modem Status Register Shadow
+ ErrorMask db 0 ;Default error-checking mask
+ RxMask db 0 ;Character mask
+ ImmedChar db 0 ;Char to be transmitted immediately
+ HSFlag db 0 ;Handshake flag
+ HHSLines db 0 ;8250 DTR/RTS bits for handshaking
+ OutHHSLines db 0 ;Lines that must be high to output
+ MSRMask db 0 ;Mask of Modem Lines to check
+ MSRInfinite db 0 ;Mask of MSR lines that must be high
+ IntVecNum db 0 ;Interrupt vector number
+ LSRShadow db 0 ;Line Status Register shadow
+ QOutMod dw 0 ;characters sent mod xOnLim ENQ/ETX [rkh]
+ VCD_data dd 0
+ VCDflags db 0
+ MiscFlags db 0 ;still more flags
+ComDEB ends
+
+.errnz (SIZE ComDEB) and 1
+
+.errnz MSRShadow - EvtWord - 35
+; In 3.0 MSRShadow had this relationship to EvtWord and major COM apps all
+; use this offset of 35 to get to MSRShadow so that they can determine the
+; current status of the Modem Status bits. We need to maintain this offset
+; so that these apps will continue to run.
+
+
+; The LptDEB is identical to the ComDEB structure, except
+; all the COM port specific stuff has been removed (which
+; convientiently was stored at the end so offsets would
+; be correct). This allows the code to act indifferently
+; when accessing the strucutres for things like the port.
+
+LptDEB struc
+ xComDCB db ((DCBSize+1) AND 0FFFEh) dup (0)
+ xComErr dw 0 ;Non-zero if I/O error
+ xPort dw 0 ;Base I/O Address
+ xNotifyHandle dw 0
+ xNotifyFlags dw 0
+ xRecvTrigger dw -1 ; char count threshold for calling
+ xSendTrigger dw 0 ; char count threshold for calling
+
+ BIOSPortLoc dw 0 ;Offset to port location (i.e. 40:0)
+LptDEB ends
+
+ .errnz xComDCB-ComDCB
+ .errnz xComErr-ComErr
+ .errnz xPort-Port
+
+ .errnz xNotifyHandle-NotifyHandle
+ .errnz xNotifyFlags-NotifyFlags
+ .errnz xRecvTrigger-RecvTrigger
+ .errnz xSendTrigger-SendTrigger
+
+
+; flag equates in EFlags
+fUseDSR equ 00000001b ; set, if DSR is significant
+fNoFIFO equ 00000010b ; set, if no FIFO on port
+fFIFOchkd equ 00000100b ; set, if FIFO has been checked
+fFIFOpre equ 00001000b ; FIFO enabled when port opened
+;fEOF equ 00100000b ; defined in comdev.inc
+;fTxImmed equ 01000000b ; defined in comdev.inc
+
+fEFlagsMask equ fUseDSR OR fFIFOpre OR fFIFOchkd OR fNoFIFO ; flags which shouldn't be cleared
+
+.errnz fEFlagsMask AND (fEOF OR fTxImmed) ;can't overlap with either of the bits
+ ; that are folded into COMS_BitMask1
+
+
+; Values for NotifyFlags
+;
+CN_RecvSent equ CN_RECEIVE SHL 8
+CN_TransSent equ CN_TRANSMIT SHL 8
+
+CN_Idle equ 10000000b
+CN_Notify equ 01000000b
+
+NotifyFlagsLO equ byte ptr NotifyFlags
+NotifyFlagsHI equ byte ptr NotifyFlags+1
+
+; Values for the handshake flag
+;
+; BreakSet - True if break was set - stops transmission
+; XOffSent - True if we have sent the XOff character
+; XOffPending - True if XOff character needs to be sent
+; XOnPending - True if XOn character needs to be sent
+; HHSDown - True if host dropped required hardware lines
+; HHSDropped - True if we dropped our hardware handshake lines
+; XOffReceived - True if XOff received from host
+; HSPending - Mask to return non-zero if XOn or Xoff must be sent
+; HSReceived - Mask to return non-zero if handshake has been
+; received from host stopping transmission
+; CannotXmit - Mask to return non-zero if any condition
+; exists which prevents us from tranmitting.
+; HSSent - Mask to return non-zero if we sent a handshake
+
+
+XOffPending equ 00000001b ;XOff needs to be sent
+EnqPending equ 00000001b ;Enq needs to be sent [rkh]
+EtxPending equ 00000001b ;Etx needs to be sent
+
+HHSDropped equ 00000010b ;Our hardware handshake lines are down
+
+XOnPending equ 00000100b ;XOn needs to be sent
+AckPending equ 00000100b ;Ack needs to be sent (ENQ/ACK & ETX/ACK)
+
+XOffReceived equ 00001000b ;XOff character received
+EnqSent equ 00001000b ;Enq has been sent
+EtxSent equ 00001000b ;Etx has been sent
+
+XOffSent equ 00010000b ;XOff has been sent
+EnqReceived equ 00010000b ;Enq character received (ENQ/ACK)
+EtxReceived equ 00010000b ;Etx character received (ETX/ACK)
+
+HHSDown equ 00100000b ;Host hardware handshake lines are down
+
+BreakSet equ 01000000b ;Break has been set
+
+HHSAlwaysDown equ 10000000b ;set if host handshake lines were never
+ ; detected high
+
+HSPending equ XOffPending+XOnPending
+HSReceived equ XOffReceived+HHSDown
+HSSent equ XOffSent+HHSDropped
+CannotXmit equ HSPending+HSReceived+BreakSet
+
+; values for MiscFlags
+
+Discard equ 00000001b ;Discard recevied data
+
+
+iodelay macro ;;macro to insure that an instruction
+ jmp $+2 ;; fetch occurs between IN and/or OUT
+ jmp $+2 ;; instructions on the PC-AT machine
+endm
+
+
+TimeoutError equ -2 ;Timeout error code for $TRMCOM
+Timeout equ 30 ;30 second timeout
+
+DELAY_TIME equ 200 ;Delay at least 200 milliseconds
+
+
+; Status bits returned from the BIOS for LPT ports
+
+PS_NotBusy equ 10000000b ;Printer not busy
+PS_Ack equ 01000000b ;Data acknowledged
+PS_PaperOut equ 00100000b ;Out of paper
+PS_Select equ 00010000b ;Device is selected
+PS_IOError equ 00001000b ;IO error
+PS_Timeout equ 00000001b ;Timeout occured
+
+
+; status bit defines for LPT
+
+L_BITS equ 0F8h ; the status bits we want
+L_BITS_INVERT equ 048h ; must invert to match BIOS
+L_DEVBUSY equ 080h ; device busy bit
+L_TIMEOUT equ 001h ; timeout bit
+
+; control bit defines for LPT
+
+L_NORMAL equ 00Ch ; normal state: selected, no reset
+L_RESET equ 008h ; reset state
+L_STROBE equ 00Dh ; tell printer we have char
+
+
+IRQ_Hook_Struc struc
+IRQn db 0
+HookCnt db 0
+OldMask db 0
+VecN db 0FFh
+HandlerOff dw 0
+First_DEB dw 0
+OldIntVec dd 0
+IFDEF No_DOSX_Bimodal_Services
+RM_OldIntVec dd 0
+RM_HandlerOff dw 0
+ENDIF
+IRQ_Hook_Struc ends
+
+
+IFDEF No_DOSX_Bimodal_Services
+include int31.inc
+
+Get_RM_IntVector equ (Int31_Int_Serv SHL 8) + Int_Get_Real_Vec
+Set_RM_IntVector equ (Int31_Int_Serv SHL 8) + Int_Set_Real_Vec
+ENDIF
+
+;
+; flag bits for VCDflags
+;
+fCOM_ignore_ints equ 00000001b
diff --git a/private/mvdm/wow16/drivers/comm/ibmcom1.asm b/private/mvdm/wow16/drivers/comm/ibmcom1.asm
new file mode 100644
index 000000000..0998e258c
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmcom1.asm
@@ -0,0 +1,1556 @@
+page
+
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMCOM1.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+;----------------------------Private-Routine----------------------------;
+;
+; DoLPT - Do Function To LPT port
+;
+; The given function (output or reset) is performed to the
+; passed LPT port.
+;
+; Before a character is sent, a check is made to see if the device
+; will be able to accept the character. If it can, then the character
+; will be sent. If not, then an error will be returned. If the
+; printer is selected and busy and no error, then the code returned
+; will be CE_TXFULL and the handshake bits will be set in HSFlag
+; to simulate that a handshake was received.
+;
+; If the BIOS ROM code is examined, you will note that they wait for
+; the busy character from the last charcater to be cleared before
+; they strobe in the current character. This can take a long time
+; on the standard EPSON class printer (1 mSec to greater than
+; 300 mSec if the last character actually caused printing).
+;
+; Because of this, several status read retrys will be made before
+; declaring that the device is actually busy. If only one status
+; read is performed, the spooler will yeild, take a while to get
+; back here, and things will be really slow. What difference does
+; it really make if we or the BIOS does the delay, at least we can
+; break out of it at some point when it seems hopeless.
+;
+; The OKIHACK: Okidata reports a 50 ns. 2.2 volt pulse on the paper
+; out signal on the trailing edge of the Busy signal. If we see this
+; glitch then we report paper out. So we try to get the status twice...
+; if it changes between the two tries we keep getting the status.
+; Silly hardware people.
+;
+; Entry:
+; AH = cid
+; AL = character to output
+; CH = Function request. 0 = Output, 1 = Initialize, 2 = Status
+; DS:SI -> DEB for the port
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+
+ assumes ds,Data
+ assumes es,nothing
+
+include vint.inc
+
+externFP OutputDebugString
+
+dbmsg macro msg
+.286
+push cs
+push offset $ + 3 + 5 + 2 ; push + far call + short jump
+call OutputDebugString
+jmp short @F
+ db msg,13,10,0
+@@:
+endm
+
+iodelay macro
+ jmp $+2
+ jmp $+2
+endm
+
+ public DoLPT ;Publics for debugging
+ public LPT_Reset
+ public LPT_Outchar
+ public LPT_Strobe
+ public LPT_GetStatus
+ public DoLPT40
+
+; status bit defines
+
+L_BITS equ 0F8h ; the status bits we want
+L_BITS_INVERT equ 048h ; must invert to match BIOS
+L_DEVBUSY equ 080h ; device busy bit
+L_TIMEOUT equ 001h ; timeout bit
+
+; control bit defines
+
+L_NORMAL equ 00Ch ; normal state: selected, no reset
+L_RESET equ 008h ; reset state
+L_STROBE equ 00Dh ; tell printer we have char
+
+DoLPT proc near
+
+ mov dx,Port[si] ;Get port address
+
+; DX = port address
+; CH = operation: 0 = write, 1 = init, 2 = status
+; AL = character
+
+ or ch, ch
+ jz LPT_OutChar
+ cmp ch, 1
+ jz LPT_Reset
+ jmp LPT_GetStatus
+ ret
+
+LPT_Reset:
+
+ inc dx
+ inc dx
+ mov al, L_RESET
+ iodelay
+ out dx, al
+
+ push dx
+
+ cCall GetSystemMsecCount
+ mov bx, ax
+
+LPT_ResetDelay:
+ push bx
+ cCall GetSystemMsecCount
+ pop bx
+ sub ax, bx
+ cmp ax, 300 ; 1/3 sec as good as any
+ jbe LPT_ResetDelay
+
+ pop dx
+
+ mov al, L_NORMAL
+ iodelay
+ iodelay
+ out dx, al
+ dec dx
+ dec dx
+ jmp LPT_GetStatus
+
+LPT_OutChar:
+ push ax ; save character to be written
+
+ ; first check to see if printer is ready for us
+ push di
+
+ push dx
+ call GetSystemMSecCount
+ mov di, ax
+ pop dx
+
+LPT_WaitReady:
+
+ inc dx ; point to status port
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ xchg al, ah
+
+ifndef NOOKIHACK
+ iodelay
+ in al, dx
+
+ dec dx
+
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah ; did any bits change?
+ jnz LPT_WaitReady
+else
+ dec dx
+endif
+
+
+ test ah, PS_PaperOut or PS_IOError
+ jnz LPT_PrinterNotReady
+ test ah, PS_Select
+ jz LPT_PrinterNotReady
+ test ah, PS_NotBusy
+ jnz LPT_PrinterReady
+
+ push ax
+ push dx
+ call GetSystemMSecCount
+ pop dx
+ pop bx
+ sub ax, di
+ cmp ax, 300 ; 1/3 sec timeout
+
+ jbe LPT_WaitReady
+
+; The device seems to be selected and powered up, but is just
+; busy (some printers seem to show selected but busy when they
+; are taken offline). Show that the transmit queue is full and
+; that the hold handshakes are set. This is so the windows
+; spooler will retry (and do yields so that other apps may run).
+
+
+ or ComErr[si],CE_TXFULL ;Show queue full
+ mov ah,bh
+ or ah, L_TIMEOUT
+
+LPT_PrinterNotReady:
+
+ pop di
+ pop cx ; throw away character
+ jmp LPT_ReturnStatus
+
+LPT_PrinterReady:
+ pop di ; get di back
+ pop ax ; get character back
+
+ iodelay
+ out dx, al ; write character to port
+
+ inc dx ; access status port
+
+LPT_Strobe:
+ inc dx ; control port
+ mov al, L_STROBE ; set strobe high
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; ...
+
+ mov al, L_NORMAL ;
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; set strobe low
+
+ sub dx, 2 ; point back to port base
+
+ ; FALL THRU
+
+LPT_GetStatus:
+ inc dx ; point to status port
+LPT_GS1:
+ iodelay
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ mov ah, al
+
+ifndef NOOKIHACK
+ in al, dx
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah
+ jnz LPT_GS1 ; if they changed try again...
+endif
+
+LPT_ReturnStatus:
+
+ assumes ds,Data
+ and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256
+ shr ah,1
+ adc ah,al ;Get back Timeout bit
+ xor ah,HIGH CE_DNS ;Invert selected bit
+ .errnz LOW CE_DNS
+ or by ComErr+1[si],ah ;Save comm error
+ ret
+
+ .errnz CE_PTO-0200h
+ .errnz CE_IOE-0400h
+ .errnz CE_DNS-0800h
+ .errnz CE_OOP-1000h
+
+DoLPT40:
+ assumes ds,Data
+ or ComErr[si],CE_TXFULL ;Show queue full
+ ret
+
+DoLPT endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; TXI - Transmit A Character Immediately
+;
+; Set up a character to be transmitted "immediately".
+; by placing the character in a location that guarantees
+; it to be the next character transmitted.
+;
+; The check to see if the immediate character can be placed has
+; already been made prior to entry.
+;
+; Interrupts must be disabled before entering this code
+;
+; Entry:
+; AH = Character
+; DS:SI --> DEB
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AL,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public TXI ;Public for debugging
+TXI proc near
+
+; FCLI ;Must be done by caller!
+ or EFlags[si],fTxImmed ;Show char to xmit
+ mov ImmedChar[si],ah ;Set character to transmit next
+; jmp short KickTx ;Kick Xmit just in case
+ errn$ KickTx
+
+TXI endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; KickTx - Kick Transmitter
+;
+; "Kick" the transmitter interrupt routine into operation.
+; If the Transmitter Holding Register isn't empty, then
+; nothing needs to be done. If it is empty, then the xmit
+; interrupt needs to enabled in the IER.
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public KickTx ;Public for debugging
+KickTx proc near
+
+; FCLI ;Done by caller
+ mov dx,Port[si] ;Get device I/O address
+ add dl,ACE_LSR ;Point at the line status reg
+ pin al,dx ;And get it
+ and al,ACE_THRE ;Check transmitter holding reg status
+ jz KickTx10 ;Busy, interrupt will hit soon enough
+
+ sub dl,ACE_LSR-ACE_IER ;--> Interrupt enable register
+ pin al,dx ;Get current IER state
+ test al,ACE_THREI ;Interrupt already enabled?
+ jnz KickTx10 ; Yes, don't reenable it
+ or al,ACE_THREI ; No, enable it
+ pout dx,al
+ pause ;8250, 8250-B bug requires
+ pout dx,al ; writting register twice
+
+KickTx10:
+; FSTI ;Done by caller
+ ret
+
+KickTx endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetDEB - Get Pointer To Device's DEB
+;
+; Returns a pointer to appropriate DEB, based on device number.
+;
+; Entry:
+; AH = cid
+; Returns:
+; 'C' clear
+; 'S' set if LPT device
+; DS:SI --> DEB is valid cid
+; AH = cid
+; Error Returns:
+; 'C' set if error (cid is invalid)
+; AX = 8000h
+; Registers Preserved:
+; BX,CX,DX,DI,DS,ES
+; Registers Destroyed:
+; AX,SI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public GetDEB ;Public for debugging
+GetDEB proc near
+
+ cmp ah,LPTx+MAXLPT ;Within range?
+ ja GetDEB30 ;No, return invalid ID
+ mov si,DataOFFSET LPT3 ;Assume LPT3
+ je GetDEB10 ;It's LPT3
+ cmp ah,MAXCOM ;Is cid within range for a com port?
+ ja GetDEB20 ; No, check for a LPT port 1 and 2
+ mov si,DataOFFSET Comm4 ;Assume COM4 [rkh] ...
+ je GetDEB10 ;It was COM4
+ mov si,DataOFFSET Comm3 ;Assume COM3
+ cmp ah,MAXCOM-1 ;Is cid within range for a com port?
+ je GetDEB10 ;It was COM3
+ mov si,DataOFFSET Comm2 ;Assume COM2
+ cmp ah,MAXCOM-2 ;Is cid within range for a com port?
+ je GetDEB10 ;It was COM2
+ mov si,DataOFFSET Comm1 ;It was COM1
+
+GetDEB10:
+ or ah,ah ;Set 'S' if LPT, clear 'C'
+ ret
+ .errnz LPTx-10000000b
+
+GetDEB20:
+ mov si,DataOFFSET LPT1 ;Assume LPT1
+ cmp ah,LPTx
+ je GetDEB10 ;Its LPT1
+ mov si,DataOFFSET LPT2 ;Assume LPT2
+ ja GetDEB10 ;Its LPT2
+
+GetDEB30:
+ mov ax,8000h ;Set error code
+ stc ;Set 'C' to show error
+ ret
+
+GetDEB endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SETQUE - Set up Queue Pointers
+;
+; Sets pointers to Receive and Transmit Queues, as provided by the
+; caller, and initializes those queues to be empty.
+;
+; Queues must be set before $INICOM is called!
+;
+; Entry:
+; AH = Device ID
+; ES:BX --> Queue Definition Block
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; BX,DX,SI,DI,DS
+; Registers Destroyed:
+; AX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SETQUE
+$SETQUE proc near
+
+ push si ;These will be used
+ push di
+ call GetDEB ;Get DEB
+ jc SetQue10 ;Invalid, ignore the call
+ js SetQue10 ;Ignore call for LPT ports
+ push ds ;Set ds:si --> QDB
+ push es ;Set es:di --> to ComDCB.QInAddr
+ pop ds
+ assumes ds,nothing
+ pop es
+ assumes es,Data
+ lea di,QInAddr[si]
+ mov si,bx
+ mov cx,(SIZE QDB)/2
+ .errnz (SIZE QDB) AND 1
+ xor ax,ax ;Will do some zero filling
+ cld
+ FCLI ;No one else can play with queues
+ rep movsw
+ mov cl,(EFlags-QInCount)/2
+ .errnz (EFlags-QInCount) AND 0FE01h
+ rep stosw
+ FSTI
+ push es ;Restore the data segment
+ pop ds
+ assumes ds,Data
+ assumes es,nothing
+
+SetQue10:
+ pop di ;Restore saved registers
+ pop si
+ ret
+
+; The above code made a few assumptions about how memory
+; was allocated within the structures:
+
+ .errnz (QueueRxSize-QueueRxAddr)-(QInSize-QInAddr)
+ .errnz (QueueTxAddr-QueueRxSize)-(QOutAddr-QInSize)
+ .errnz (QueueTxSize-QueueTxAddr)-(QOutSize-QOutAddr)
+
+ .errnz QueueRxSize-QueueRxAddr-4
+ .errnz QueueTxAddr-QueueRxSize-2
+ .errnz QueueTxSize-QueueTxAddr-4
+
+ .errnz QInSize-QInAddr-4
+ .errnz QOutAddr-QInSize-2
+ .errnz QOutSize-QOutAddr-4
+
+ .errnz QInCount-QOutSize-2
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+ .errnz EFlags-QOutPut-2 ;First non-queue item
+
+$SETQUE endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVT - Set Event Mask
+;
+; Set up event word and mask. Returns a pointer to a word in which
+; certain bits, as enabled by the mask, will be set when certain
+; events occur.
+;
+; Entry:
+; AH = Device ID
+; BX = Event enable mask
+; Returns:
+; DX:AX --> event word.
+; Error Returns:
+; AX = 0 if error
+; Registers Preserved:
+; BX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVT
+$EVT proc near
+
+ push si
+ xor dx,dx ;In case of error
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx ;Finish setting error return value
+ jc Evt10 ;Illegal id, return error
+ js Evt10 ;LPTx, return error
+ mov EvtMask[si],bx ;Save the new event mask
+ lea ax,EvtWord[si] ;Get address of event word
+ mov dx,ds ; into dx:ax
+
+Evt10:
+ pop si
+ ret
+
+$EVT endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EVTGET - Get Event Word
+;
+; Return and clear fields in the event word. This routine MUST be used
+; by applications to read the event word, as it is the ONLY way they
+; can be assured that an event is not lost between reading the flags
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; BX = Event clear mask
+; Returns:
+; AX = event word
+; Error Returns:
+; None
+; Registers Preserved:
+; AX,CX,SI,DI,DS,ES
+; Registers Destroyed:
+; BX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EVTGET
+$EVTGET proc near
+
+ push si
+ call GetDEB
+ mov ah,0 ;In case of error (AL already 0)
+ jc EvtGet10 ;Illegal ID
+ js EvtGet10 ;Illegal ID
+ FCLI ;No interrupts allowed
+ mov ax,EvtWord[si] ;Get the current event word
+ not bx ;Convert mask for our purposes
+ and bx,ax ;Clear events that user wants us to
+ mov EvtWord[si],bx ;And save those results
+ FSTI ;Magic over
+
+EvtGet10:
+ pop si
+ ret
+
+$EVTGET endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $STACOM - Return Status Information
+;
+; Returns the number of bytes in both queues.
+;
+; LPT ports will show both queues empty.
+; and resetting some.
+;
+; Entry:
+; AH = Device ID
+; ES:BX = Pointer to status structure to be updated.
+; = Null if not to update
+; Returns:
+; AX = comm error word
+; Status Structure Updated.
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $STACOM
+$STACOM proc near
+
+ push si
+ call GetDEB ;Get DEB pointer in SI
+ jc StaCom30 ;Invalid ID
+ mov cx,es ;Is the pointer NULL?
+ or cx,bx
+ jz StaCom25 ; Yes, just return error code
+ xor cx,cx
+ xor dx,dx
+ or ah,ah ;Set 'S' if LPT port
+ mov ax,cx ;For LPTs, everything is zero
+ js StaCom20 ;LPT port
+
+; Need to get the status for a com port. Since not all the
+; status is contained within EFlags, it has to be assembled.
+; Also note that currently there is no way to specify RLSD
+; as a handshaking line, so fRLSDHold is always returned false.
+
+ mov al,MSRShadow[si] ;Get state of hardware lines
+ and al,OutHHSLines[si] ;Mask off required bits
+ xor al,OutHHSLines[si] ;1 = line low
+ mov cl,4 ;Align bits
+ shr al,cl ;al = fCTSHold + fDSRHold
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+ .errnz fCTSHold-00000001b
+ .errnz fDSRHold-00000010b
+
+ mov ah,HSFlag[si] ;Get fXOffHold+fXOffSent
+ and ah,XOffReceived+XOffSent
+ or al,ah
+
+ .errnz XOffReceived-fXOFFHold
+ .errnz XOffSent-fXOFFSent
+
+ mov ah,EFlags[si] ;Get fEOF+fTxImmed
+ and ah,fEOF+fTxImmed
+ or al,ah
+
+ mov cx,QInCount[si] ;Get input queue count
+ mov dx,QOutCount[si] ;Get tx queue count
+
+StaCom20:
+ mov es:StatFlags[bx],al
+ mov es:StatRxCount[bx],cx
+ mov es:StatTxCount[bx],dx
+
+StaCom25:
+ xor ax,ax ;Return old com error
+ xchg ax,ComErr[si] ; and clear it out
+
+StaCom30:
+ pop si
+ ret
+
+$STACOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SetBrk - Set Break
+;
+; Clamp the Tx data line low. Does not wait for the
+; transmitter holding register and shift registers to empty.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $SETBRK
+$SETBRK proc near
+
+ mov cx,0FF00h+ACE_SB ;Will be setting break
+ jmp short ClrBrk10
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+$SETBRK endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $CLRBRK - Clear Break
+;
+; Release any BREAK clamp on the Tx data line.
+;
+; LPT ports will just return the comm error word
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS,ES
+; Registers Destroyed:
+; AX,BX,CX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $CLRBRK
+$CLRBRK proc near
+
+ mov cx,(NOT ACE_SB) SHL 8
+ .errnz BreakSet-ACE_SB ;Must be same bits
+
+ClrBrk10:
+ push si
+ call GetDEB ;Get DEB address
+ jc ClrBrk30 ;Invalid ID
+ js ClrBrk20 ;Ignored for LPT ports
+ FCLI
+ and HSFlag[si],ch ;Set or clear the BreakSet bit
+ or HSFlag[si],cl
+
+; ch = mask to remove bits in the Line Control Register
+; cl = mask to turn bits on in the Line Control Register
+
+ mov dx,Port[si] ;Get comm device base I/O port
+ add dl,ACE_LCR ;Point at the Line Control Regieter
+ pin al,dx ;Get old line control value
+ and al,ch ;Turn off desired bits
+ or al,cl ;Turn on desired bits
+ pause
+ pout dx,al ;Output New LCR.
+ FSTI
+
+ClrBrk20:
+ mov ax,ComErr[si] ;Return Status Word
+
+ClrBrk30:
+ pop si
+ ret
+
+$CLRBRK endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $EXTCOM - Extended Comm Functions
+;
+; A number of extended functions are routed through this entry point.
+;
+; Functions currently implemented:
+;
+; 0: Ignored
+; 1: SETXOFF - Exactly as if X-OFF character has been received.
+; 2: SETXON - Exactly as if X-ON character has been received.
+; 3: SETRTS - Set the RTS signal
+; 4: CLRRTS - Clear the RTS signal
+; 5: SETDTR - Set the DTR signal
+; 6: CLRDTR - Clear the DTR signal
+; 7: RESET - Yank on reset line if available (LPT devices)
+;
+; Entry:
+; AH = Device ID
+; BL = Function Code
+; (0-127 are MS-defined, 128-255 are OEM defined)
+; Returns:
+; AX = comm error word
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+
+; Dispatch table for the extended functions
+
+ExtTab dw ExtComDummy ;Function 0: Never Mind
+ dw ExtCom_FN1 ;1: Set X-Off
+ dw ExtCom_FN2 ;2: Clear X-Off
+ dw ExtCom_FN3 ;3: Set RTS
+ dw ExtCom_FN4 ;4: Clear RTS
+ dw ExtCom_FN5 ;5: Set DSR
+ dw ExtCom_FN6 ;6: Clear DSR
+ dw ExtCom_FN7 ;7: Reset printer
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $EXTCOM
+$EXTCOM proc near
+
+ push si
+ call GetDEB ;Get DEB pointer
+ jc ExtCom40 ;Invalid ID, return error
+ mov dx,Port[si] ; get port address
+ jns ExtCom10 ;Its a COM port
+ cmp bl,7 ;RESET extended function?
+ jne ExtCom30 ; No, return error word
+ jmp short ExtCom20 ; Yes, invoke the function
+
+ExtCom10:
+ cmp bl,7 ;Last fcn supported +1
+ jnc ExtCom30 ;Not an implemented function.
+
+ExtCom20:
+ xor bh,bh
+ add bx,bx ;Shift for the call
+ FCLI ;Consider as critical sections
+ call ExtTab[bx] ; and perform the function
+ FSTI
+
+ExtCom30:
+ mov ax,ComErr[si] ;Return standard error word
+
+ExtCom40:
+ pop si
+
+ExtComDummy:
+ ret
+
+$EXTCOM endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN1 - Extended Function Set X-Off
+;
+; Analagous to receiving an X-OFF character. Bufferred transmision of
+; characters is halted until an X-ON character is received, or until
+; we fake that with a Clear X-Off call.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN1
+ExtCom_FN1 proc near
+
+ or HSFlag[si],XOffReceived
+ ret
+
+ExtCom_FN1 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN2 - Extended Function Clear X-Off
+;
+; Analagous to receiving an X-ON character. Buffered
+; transmission of characters is restarted.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN2
+ExtCom_FN2 proc near
+
+ and HSFlag[si],NOT XOffReceived
+ jmp KickTx ;Kick transmitter interrupts on
+
+ExtCom_FN2 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN3 - Extended Function Set RTS
+;
+; Set the RTS signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN3
+ExtCom_FN3 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ or al,ACE_RTS ;Set RTS
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN3 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN4 - Extended Function Clear RTS
+;
+; Set the RTS signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public ExtCom_FN4
+ExtCom_FN4 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ and al,NOT ACE_RTS ;Clear RTS
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN4 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN5 - Extended Function Set DTR
+;
+; Set the DTR signal active.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN5
+ExtCom_FN5 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ or al,ACE_DTR ;Set DTR
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN5 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN6 - Extended Function Clear DTR
+;
+; Set the DTR signal inactive.
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN6
+ExtCom_FN6 proc near
+
+ add dl,ACE_MCR ;Point at Modem Control Register
+ pin al,dx ;Get current settings
+ and al,NOT ACE_DTR ;Clear DTR
+ pause
+ pout dx,al ;And update
+ ret
+
+ExtCom_FN6 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ExtCom_FN7 - Extended Function Reset Printer
+;
+; Assert the RESET line on an LPT port
+;
+; Entry:
+; interrupts disabled
+; dx = port base address
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public ExtCom_FN7
+ExtCom_FN7 proc near
+
+ FSTI ;Not called at interrupt time
+ mov ch,1 ;ROM BIOS Reset Port
+ call DoLPT ;Perform the function
+ ret
+
+ExtCom_FN7 endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $DCBPtr - Return Pointer To DCB
+;
+; Returns a long pointer to the DCB for the requested device.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; DX:AX = pointer to DCB.
+; Error Returns:
+; DX:AX = 0
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; BX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $DCBPTR
+$DCBPTR proc near
+
+ push si
+ xor dx,dx
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx
+ jc DCBPtr10 ;Jump if invalid device
+ mov ax,si ;else return value here
+ mov dx,ds
+
+DCBPtr10:
+ pop si
+ ret
+
+$DCBPTR endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $RECCOM - Receive Characters From Device
+;
+; Read Byte From RS232 Input Queue If Data Is Ready
+;
+; LPT ports will return with an indication that no characters are
+; available.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; 'Z' clear if data available
+; AL = byte
+; Error Returns:
+; 'Z' Set if error or no data
+; AX = error code
+; AX = 0 if no data
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $RECCOM
+$RECCOM proc near
+
+ push si ;Once again, save some registers
+ push di
+ call GetDEB ;Get DEB pointer in SI
+ jc RecCom10 ;Invalid Port [rkh] ...
+ js RecCom20 ;LPT port, return no characters
+ jmp short RecCom30
+
+RecCom10:
+ jmp RecCom100 ; Invalid Port
+
+RecCom20:
+ jmp RecCom95 ;LPT port, return no characters
+
+; Before removing any charcters from the input queue, check to see
+; if XON needs to be issued. If it needs to be issued, set the
+; flag that will force it and arm transmit interrupts.
+
+RecCom30:
+ test Flags[si],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom32 ; No
+ test HSFlag[si],EnqReceived+HHSDropped ;Enq recvd or lines dropped?
+ jz RecCom60 ; No Enq recvd & no lines dropped
+ jmp short RecCom34
+
+RecCom32:
+ test HSFlag[si],HSSent ;Handshake sent?
+ jz RecCom60 ; No XOFF sent & no lines dropped
+
+RecCom34:
+ mov ax,QInCount[si] ;Get current count of input chars
+ cmp ax,XONLim[si] ;See if at XOn limit
+ ja RecCom60 ;Not at XOn limit yet
+
+; If any hardware lines are down, then raise them. Then see
+; about sending XON.
+
+ mov dx,Port[si] ;Get the port
+ mov ah,HHSLines[si] ;Get hardware lines mask
+ FCLI ;Handle this as a critical section
+ mov cl,HSFlag[si] ;Get handshaking flags
+ or ah,ah ;Any hardware lines to play with?
+ jz RecCom40 ; No
+ add dl,ACE_MCR ;--> Modem control register
+ pin al,dx
+ or al,ah ;Turn on the hardware bits
+ pause
+ pout dx,al
+ and cl,NOT HHSDropped ;Show hardware lines back up
+
+RecCom40:
+ test Flags[si],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz RecCom47 ; No
+ test cl,EnqReceived ;Did we receive Enq?
+ jz RecCom55 ; No
+ and cl,NOT EnqReceived
+ jmp short RecCom50
+
+RecCom47:
+ test cl,XOffSent ;Did we send XOFF?
+ jz RecCom55 ; No
+ and cl,NOT XOffSent ;Remove XOFF sent flag
+
+RecCom50:
+ or cl,XOnPending ;Show XON or ACK must be sent
+ call KickTx ;Kick xmit if needed
+
+RecCom55:
+ mov HSFlag[si],cl ;Store handshake flag
+ FSTI ;Can allow interrupts now
+
+; Now we can get down to the business at hand, and remove a character
+; from the receive queue. If a communications error exists, we return
+; that, and nothing else.
+
+RecCom60:
+ xor ax,ax
+ or ax,ComErr[si] ;Any Errors?
+ jnz RecCom100 ; Yes, return the error code
+ or ax,QInCount[si] ;Get current input char count
+ jz RecCom90 ;No characters in the queue
+ les di,QInAddr[si] ;Get queue pointer
+ assumes es,nothing
+
+ mov bx,QInGet[si] ;Also get the index to head
+ mov al,es:[bx][di] ;Finally, get byte from queue
+ inc bx ;Update queue index
+ cmp bx,QInSize[si] ;See if time for wrap-around
+ jc RecCom70 ;Jump if no wrap
+ xor bx,bx ;wrap by zeroing the index
+
+RecCom70:
+ mov QInGet[si],bx ;Save new head pointer
+ dec QInCount[si] ;Dec # of bytes in queue
+
+RecCom80:
+ or sp,sp ;Reset PSW.Z
+ pop di
+ pop si
+ ret
+
+; No characters in the input queue. Check to see if EOF
+; was received, and return it if it was. Otherwise show
+; no characters.
+
+RecCom90:
+ test Flags[si],fBinary ;Are we doing binary stuff?
+ jnz RecCom95 ; Yes, show no characters
+ mov al,EOFChar[si] ;Assume EOF
+ test EFlags[si],fEOF ;Has end of file char been received?
+ jnz RecCom80 ; Yes, show end of file
+
+RecCom95:
+ xor ax,ax ;Show no more characters
+
+; Return with 'Z' to show error or no characters
+
+RecCom100:
+ xor cx,cx ;Set PSW.Z
+ pop di
+ pop si
+ ret
+
+$RECCOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $FLUSH - Flush The Input and Output Queues
+;
+; This is a hard initialization of the transmit and receive queue's,
+; which immediately empties the given queue.
+;
+; LPT ports will just return the device error word
+;
+; Entry:
+; AH = Device ID
+; BH = Queue # to clear (0=Tx, 1=Rx)
+; Returns:
+; AX = Device Error Word. (Not reset)
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $FLUSH
+$FLUSH proc near
+
+ push si
+ push di
+ call GetDEB ;si --> DEB
+ jc Flush40 ;Invalid ID
+ js Flush30 ;LPT port, return any error
+
+ mov cx,QOutCount-QInCount ;# of bytes to zero
+ lea di,QInCount[si] ;--> receive queue data
+ or bh,bh ;Transmit queue?
+ jnz Flush10 ; No, input queue
+ add di,cx ; Yes, --> xmit queue data
+
+Flush10:
+ cld
+ push ds
+ pop es
+ assumes es,nothing
+
+ xor al,al
+ FCLI ;Time to worry about critical sections
+ rep stosb
+ FSTI
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+
+ or bh,bh ;Rx queue?
+ jz Flush30 ; No, xmit queue
+
+
+; If the queue to be cleared is the receive queue, any
+; hardware handshake must be cleared to prevent a possible
+; deadlock situation. Since we just zeroed the queue count,
+; a quick call to $RecCom should do wonders to clear any
+; receive handshake (i.e. send XON if needed).
+
+Flush20:
+ call $RECCOM ;Take care of handshakes here
+
+Flush30:
+ mov ax,ComErr[si] ;And return the error word.
+
+Flush40:
+ pop di
+ pop si
+ ret
+
+$FLUSH endp
+
+ifdef DEBUG
+ public KickTx10
+ public GetDEB10
+ public GetDEB20
+ public GetDEB30
+ public SetQue10
+ public Evt10
+ public EvtGet10
+ public StaCom20
+ public StaCom25
+ public StaCom30
+ public ClrBrk10
+ public ClrBrk20
+ public ClrBrk30
+ public ExtCom10
+ public ExtCom20
+ public ExtCom30
+ public ExtCom40
+ public ExtComDummy
+ public DCBPtr10
+ public RecCom30
+ public RecCom40
+ public RecCom50
+ public RecCom60
+ public RecCom70
+ public RecCom80
+ public RecCom90
+ public RecCom95
+ public RecCom100
+ public Flush10
+ public Flush20
+ public Flush30
+ public Flush40
+endif
diff --git a/private/mvdm/wow16/drivers/comm/ibmint.asm b/private/mvdm/wow16/drivers/comm/ibmint.asm
new file mode 100644
index 000000000..d902841f2
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmint.asm
@@ -0,0 +1,1374 @@
+page,132
+;---------------------------Module-Header-------------------------------
+; Module Name: IBMINT.ASM
+;
+; Created: Fri 06-Feb-1987 10:45:12
+; Author: Walt Moore [waltm]
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved
+;
+; General Description:
+; This file contains the interrupt time routines for the
+; IBM Windows communications driver.
+;
+; The interrupt code is preloaded and fixed.
+;
+; History:
+;
+; **********************************************************************
+; Tue Dec 19 1989 09:35:15 -by- Amit Chatterjee [amitc]
+; ----------------------------------------------------------------------
+; Added a far entry point 'FakeCOMIntFar' so that the routine 'FakeCOMInt'
+; could be called from the 'InitAPort' routine in IBMCOM.ASM
+;
+; 26.Nov.90 richp
+;
+; Changed interrupt routines to use new VPICD services for bi-modal/multi-
+; modal interrupt handling. They now work in straight real mode for real
+; mode Windows, but can also handle interrupts in real mode or protected
+; mode for standard mode Windows, and handle interrupts in RING 0 protected
+; mode for enhanced mode Windows, even when the Windows VM is not currently
+; executing.
+;
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;-----------------------------------------------------------------------;
+
+subttl Communications Hardware Interrupt Service Routines
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ibmcom.inc
+include ins8250.inc
+include BIMODINT.INC
+include vint.inc
+.list
+
+externFP GetSystemMsecCount
+
+externW COMptrs
+externW activeCOMs
+
+externD lpPostMessage
+
+sBegin Data
+
+PUBLIC IRQhooks
+IRQhooks label byte
+DefineIRQhook MACRO num
+IFDEF No_DOSX_Bimodal_Services
+IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num,,,, \
+ IntCodeOFFSET DEF_RM_COM_INT_&num>
+ELSE
+IRQhook&num IRQ_Hook_Struc <,,,,IntCodeOFFSET DEF_COM_INT_&num>
+ENDIF
+ENDM
+??portnum = 1
+REPT MAXCOM+1
+ DefineIRQhook %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE DefineIRQhook
+
+EXTRN VCD_int_callback:fword
+
+sEnd data
+
+createSeg _INTERRUPT,IntCode,word,public,CODE
+sBegin IntCode
+assumes cs,IntCode
+
+page
+
+IFDEF No_DOSX_Bimodal_Services
+public RM_IntDataSeg
+RM_IntDataSeg dw 0
+ ; this variable is written into by a routine in inicom
+ ; if the 286 DOS extender is present. This variable
+ ; contains the SEGMENT value of the data selector "_DATA"
+ ; so that the real mode interrupt handler may use the
+ ; data segment, and not it's selector !
+
+PUBLIC RM_CallBack
+RM_CallBack dd 0
+ENDIF
+
+
+Control proc far
+ ret
+Control endp
+
+
+IFDEF No_DOSX_Bimodal_Services
+DEF_RM_Handler proc far
+ push es
+ push di
+ push ax
+ mov es, cs:[RM_IntDataSeg]
+ mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
+ add di, SIZE ComDEB ; ES:DI -> BIS
+ mov es:[di.BIS_Mode], 4
+ push cs
+ call NEAR PTR COMHandler
+ mov es:[di.BIS_Mode], 0
+ pop ax
+ pop di ; ES:DI -> IRQ_Hook_Struc
+ jc short DEF_RM_chain
+ pop es
+ pop di
+ add sp, 4
+ iret
+
+DEF_RM_chain:
+ call DOCLI
+ push bp
+ mov bp, sp ;stack frame:
+ ; bp+8 -> OldInt CS
+ ; bp+6 -> OldInt IP
+ ; bp+4 -> di
+ ; bp+2 -> es
+ ; bp+0 -> bp
+ les di, es:[di.RM_OldIntVec]
+ mov [bp+6], di
+ mov [bp+8], es
+ pop bp
+ pop es
+ pop di
+ ret ; far ret to OldInt handler
+DEF_RM_Handler endp
+ENDIF ;No_DOSX_Bimodal_Services
+
+
+Define_DEF_COM_INT MACRO num
+IFDEF No_DOSX_Bimodal_Services
+PUBLIC DEF_RM_COM_INT_&num
+DEF_RM_COM_INT_&num proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook&num
+ jmp DEF_RM_Handler
+DEF_RM_COM_INT_&num endp
+ENDIF
+PUBLIC DEF_COM_INT_&num
+DEF_COM_INT_&num proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook&num
+ jmp DEF_Handler
+DEF_COM_INT_&num endp
+ENDM
+
+??portnum = 2
+REPT MAXCOM
+ Define_DEF_COM_INT %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE Define_DEF_COM_INT
+
+IFDEF No_DOSX_Bimodal_Services
+PUBLIC DEF_RM_COM_INT_1
+DEF_RM_COM_INT_1 proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook1
+ jmp DEF_RM_Handler
+DEF_RM_COM_INT_1 endp
+ENDIF
+
+PUBLIC DEF_COM_INT_1
+DEF_COM_INT_1 proc far
+ sub sp, 4
+ push di
+ mov di, DataOFFSET IRQhook1
+IF2
+.errnz $ - OFFSET DEF_Handler
+ENDIF
+DEF_COM_INT_1 endp
+
+DEF_Handler proc far
+ push es
+ push di
+ push ax
+ mov ax, _DATA
+ mov es, ax
+ mov di, es:[di.First_DEB] ; ES:DI -> ComDEB
+ add di, SIZE ComDEB ; ES:DI -> BIS
+ push cs
+ call NEAR PTR COMHandler
+ pop ax
+ pop di ; ES:DI -> IRQ_Hook_Struc
+ jc short DEF_chain
+ pop es
+ pop di
+ add sp, 4
+ iret
+
+DEF_chain:
+ call DOCLI
+ push bp
+ mov bp, sp ;stack frame:
+ ; bp+8 -> OldInt CS
+ ; bp+6 -> OldInt IP
+ ; bp+4 -> di
+ ; bp+2 -> es
+ ; bp+0 -> bp
+ les di, es:[di.OldIntVec]
+ mov [bp+6], di
+ mov [bp+8], es
+ pop bp
+ pop es
+ pop di
+ ret ; far ret to OldInt handler
+DEF_Handler endp
+
+;------------------------------------------------------------------------------
+;
+; ENTER: ES:DI -> BIS
+;
+; EXIT: Carry set, if IRQ not handled by any com ports
+;
+COMHandler proc far
+ push ds
+ push si
+ push ax
+ push bx
+ mov si, es
+ mov ds, si
+ mov bh, -1
+ch_chk_all:
+ lea si, [di-SIZE ComDEB] ;ds:si -> ComDEB
+ mov si, [si.IRQhook]
+ mov si, [si.First_DEB]
+ mov bl, -1
+ch_next_com:
+ inc bl ; first time bl = 0
+ xor ax, ax
+ xchg ax, [di.BIS_Mode]
+ lea di, [si+SIZE ComDEB]
+ mov [di.BIS_Mode], ax
+ call CommInt
+ and al, 80h
+ or bl, al
+
+ mov si, [si.NextDEB]
+ or si, si
+ jnz ch_next_com
+
+ test bl, 7Fh ;Q: more than 1 com port?
+ jnz short ch_shared ; Y: check if handled
+ or bl, bl ;Q: int handled by port?
+ stc
+ jns ch_exit ; N:
+
+ch_eoi:
+ xor ax, ax
+.errnz BIH_API_EOI
+ xor bx, bx
+ xchg bx, es:[di.BIS_Mode]
+ call es:[bx][di.BIS_User_Mode_API]
+ lea si, [di-SIZE ComDEB] ; ds:si -> ComDEB
+ mov si, [si.IRQhook]
+ mov al, [si.OldMask]
+ shr al, 1 ; shift bit 0 into Carry (0, if unmasked
+ cmc ; -1, if originally masked)
+
+ch_exit:
+ pop bx
+ pop ax
+ pop si
+ pop ds
+ ret
+
+ch_shared:
+ inc bh ; count loop
+ or bl, bl ;Q: int handled by any port?
+ js ch_chk_all ; Y: check all ports again
+ or bh, bh ;Q: first time thru loop?
+ stc
+ jz ch_exit ; Y: int wasn't for a COM port, so
+ ; chain to next IRQ handler
+ jmp ch_eoi
+
+COMHandler endp
+
+
+IFDEF No_DOSX_Bimodal_Services
+
+PUBLIC Entry_From_RM
+Entry_From_RM proc far
+
+;
+; Simulate the far ret
+;
+ cld
+ lodsw
+ mov es:[di.RealMode_IP], ax
+ lodsw
+ mov es:[di.RealMode_CS], ax
+ add es:[di.RealMode_SP], 4
+
+ push es
+ push di
+.286
+;
+; Push far addr of Ret_To_IRET to cleanup stack and return to DPMI host
+;
+ push cs
+ push IntCodeOFFSET Ret_To_IRET
+;
+; Push far addr of proc to call, so we can do a far ret to it
+;
+ push es:[di.RealMode_CX] ; segment of callback
+ push es:[di.RealMode_DX] ; offset of callback
+ mov di, es:[di.RealMode_DI]
+ ret ; far ret to cx:dx
+ ; called proc will do a far ret
+Ret_To_IRET: ; <- to here
+ pop di
+ pop es
+ iret
+.8086
+
+Entry_From_RM endp
+
+PUBLIC RM_APIHandler
+RM_APIHandler proc far
+ cmp ax, BIH_API_Call_Back
+ jne APIHandler
+ call cs:[RM_CallBack]
+ ret
+RM_APIHandler endp
+
+ENDIF
+
+;------------------------------------------------------------------------------
+;
+; ENTER: ES:DI -> BIS
+;
+APIHandler proc far
+
+ or ax, ax
+ jnz short api_not_EOI
+.errnz BIH_API_EOI
+ mov ax, es:[di.BIS_IRQ_Number]
+ cmp al,8 ;Q: slave IRQ?
+ mov al,EOI
+ jb short api_master ; N:
+ out 0A0h,al ; Y: EOI slave
+api_master:
+ out INTA0,al ; EOI master
+ ret
+
+api_not_EOI:
+ cmp ax, BIH_API_Call_Back
+ jae short api_callme
+ push dx
+ push cx
+ mov dx, INTA1
+ mov cx, es:[di.BIS_IRQ_Number]
+ cmp cl, 8 ;Q: 2nd PIC?
+ jb @f ; N:
+ mov dx, 0A1h ; Y: dx = mask port
+ sub cl, 8
+@@:
+ cmp al, BIH_API_Get_Mask ;Q: get IRQ mask?
+ jae api_get_mask ; Y:
+ mov ah, al
+ mov ch, 1
+ shl ch, cl ; ch = mask byte
+ pushf
+ call DOCLI
+ in al, dx ; get current PIC mask state
+ cmp ah, BIH_API_Mask ;Q: mask IRQ?
+ jne @f ; N:
+ or al, ch ; Y: set IRQ's bit
+ jmp short api_mask_exit
+@@:
+ not ch ; N: clear IRQ's bit to unmask
+ and al, ch
+api_mask_exit:
+ out dx, al
+ pop ax
+ test ah, 2 ;Q: ints were enabled?
+ jz @f ; N:
+ call DOSTI
+@@:
+ pop cx
+ pop dx
+ ret
+
+api_get_mask:
+ in al, dx ; get current PIC mask state
+ inc cl
+ shr al, cl ; move IRQ's bit into carry
+ ; Carry set, if IRQ masked
+ pop cx
+ pop dx
+ ret
+
+api_callme:
+ push cx
+ push dx
+ ret ; far ret to call back, which will
+ ; do a far ret to our caller
+APIHandler endp
+
+
+;--------------------------Fake a Hardware Interrupt----------------------;
+; FakeCOMInt
+;
+; This routine fakes a hardware interrupt to IRQ3 or IRQ4
+; to clear out characters pending in the buffer
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+;
+; Registers Destroyed:
+; AX,DX,FLAGS
+; History: glenn steffler 5/17/89
+;-----------------------------------------------------------------------;
+
+FakeCOMInt proc near
+
+ ; call DOCLI ;Done by caller
+;
+; WARNING: jumping into the middle of CommInt, so the stack must be set
+; properly.
+;
+ push dx
+ push bx
+ push cx
+ push di
+ push es
+ push EvtWord[si]
+ mov dx,Port[si] ;Get device I/O address
+ add dl, ACE_IIDR
+ push dx
+ jmp FakeXmitEmpty ;Process the fake interrupt, DS:SI is
+ ; already pointing to proper DEB
+;
+; FakeXmitEmpty falls in XmitEmpty which jumps back into CommInt. When CommInt
+; determines that no interrupt is pending, then it will near return back to
+; FakeCOMIntFar which can far ret back to its caller.
+;
+FakeCOMInt endp
+
+public FakeCOMIntFar
+FakeCOMIntFar proc far
+
+ call FakeCOMInt
+ ret
+
+FakeCOMIntFar endp
+
+;--------------------------Interrupt Handler----------------------------
+;
+; CommInt - Interrupt handler for com ports
+;
+; Interrupt handlers for PC com ports. This is the communications
+; interrupt service routine for RS232 communications. When an RS232
+; event occurs the interrupt vectors here. This routine determines
+; who the caller was and services the appropriate interrupt. The
+; interrupts are prioritized in the following order:
+;
+; 1. line status interrupt
+; 2. read data available interrupt
+; 3. transmit buffer empty interrupt
+; 4. modem service interrupt
+;
+; This routine continues to service until all interrupts have been
+; satisfied.
+;
+; Entry:
+; DS:SI --> DEB
+; INTERRUPTS DISABLED!
+; Returns:
+; AL = 0, if not handled, -1, if handled
+;
+;-----------------------------------------------------------------------
+
+assumes ds,Data
+assumes es,nothing
+
+; Dispatch table for interrupt types
+
+SrvTab label word
+ dw OFFSET ModemStatus ;[0] Modem Status Interrupt
+ dw OFFSET XmitEmpty ;[2] Tx Holding Reg. Interrupt
+ dw OFFSET DataAvail ;[4] Rx Data Available Interrupt
+ ; or [C] if 16550 & 16550A
+ dw OFFSET LineStat ;[6] Reciever Line Status Interrupt
+
+
+ public CommInt
+
+CommInt proc near
+
+ xor al, al
+ cmp word ptr [VCD_int_callback+4], 0
+ je short @F ; jump if no callback (not 3.1 VCD)
+ test [si.VCDflags], fCOM_ignore_ints ;Q: we still own port?
+ jnz IntLoop40 ; N: ignore the int
+.386
+ push esi
+ mov esi, [si.VCD_data]
+ call [VCD_int_callback]
+ pop esi
+.8086
+@@:
+
+ push dx
+ mov dx,Port[si] ;Get comm I/O port
+ add dl,ACE_IIDR ;--> Interrupt ID Register
+ in al, dx
+ test al, 1 ;Q: interrupt pending?
+ jnz short IntLoop30 ; N:
+
+ push bx
+ push cx
+ push di
+ push es
+ mov cx, EvtWord[si]
+ push cx
+ jmp short IntLoop10
+
+InterruptLoop_ChkTx:
+ cmp QOutCount[si],0 ;Output queue empty?
+ je short InterruptLoop ; Y: don't chk tx
+ pop dx
+ push dx
+ dec dx ; to IER
+.errnz ACE_IIDR - ACE_IER - 1
+ in al, dx
+ and al,NOT ACE_ETBEI ; disable it
+ iodelay
+ out dx, al
+ or al, ACE_ETBEI ; enable it again
+ iodelay
+ out dx, al
+ iodelay
+ out dx, al
+
+InterruptLoop:
+ pop dx ;Get ID reg I/O address
+
+ in al,dx ;Get Interrupt Id
+ test al,1 ;Interrupt need servicing?
+ jnz IntLoop20 ;No, all done
+
+IntLoop10:
+ and ax, 07h
+ mov di,ax
+ push dx ;Save Id register
+ jmp SrvTab[di] ;Service the Interrupt
+
+IntLoop20:
+ mov ax,EvtMask[si] ;Mask the event word to only the
+ and ax, EvtWord[si] ; user specified bits
+ mov EvtWord[si], ax
+ pop bx
+ test [si.NotifyFlagsHI], CN_Notify
+ jz short ci_exit
+ not bx
+ and ax, bx ; bits set in ax are new events
+ jnz short ci_new_events
+
+ci_exit:
+ pop es
+ assumes es,nothing
+
+ pop di
+ pop cx
+ pop bx
+ xor al, al
+
+IntLoop30:
+ pop dx
+ and al, 1
+ dec al ; 0->-1, 1->0
+IntLoop40:
+ ret
+
+ci_new_events:
+ mov ax, CN_EVENT
+ call notify_owner
+ jmp ci_exit
+
+CommInt endp
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; LineStat - Line Status Interrupt Handler
+;
+; Break detection is handled and set in the event word if
+; enabled. Other errors (overrun, parity, framing) are
+; saved for the data available interrupt.
+;
+; This routine used to fall into DataAvail for the bulk of its processing.
+; This is no longer the case... A very popular internal modem seems to
+; operate differently than a real 8250 when parity errors occur. Falling
+; into the DataAvail handler on a parity error caused the same character
+; to be received twice. Having this routine save the LSR status, and
+; return to InterruptLoop fixes the problem, and still works on real COMM
+; ports. The extra overhead isn't a big deal since this routine is only
+; entered when there is an exception like a parity error.
+;
+; This routine is jumped to, and will perform a jump back into
+; the dispatch loop.
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+
+; assumes ds,Data
+assumes es,nothing
+
+public LineStat ;Public for debugging
+LineStat proc near
+
+ or by EvtWord[si],EV_Err ;Show line status error
+
+ add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
+ in al,dx
+ test al,ACE_PE+ACE_FE+ACE_OR ;Parity, Framing, Overrun error?
+ jz @f
+
+ mov LSRShadow[si],al ;yes, save status for DataAvail
+@@:
+ test al,ACE_BI ;Break detect?
+ jz InterruptLoop_ChkTx ;Not break detect interrupt
+
+ or by EvtWord[si],EV_Break ;Show break
+
+ jmp short InterruptLoop_ChkTx
+
+LineStat endp
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; DataAvail - Data Available Interrupt Handler
+;
+; The available character is read and stored in the input queue.
+; If the queue has reached the point that a handshake is needed,
+; one is issued (if enabled). EOF detection, Line Status errors,
+; and lots of other stuff is checked.
+;
+; This routine is jumped to, and will perform a jump back into
+; the dispatch loop.
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+; assumes ds,Data
+assumes es,nothing
+
+public DataAvail ;public for debugging
+DataAvail proc near
+
+ sub dl,ACE_IIDR-ACE_RBR ;--> receiver buffer register
+ in al,dx ;Read received character
+
+ and [si.NotifyFlagsHI], NOT CN_Idle ; flag as not idle
+
+ mov ah,LSRShadow[si] ;what did the last Line Status intrpt
+ mov bh,ah ; have to say?
+ or ah,ah
+ jz @f
+
+ and ah,ErrorMask[si] ;there was an error, record it
+ or by ComErr[si],ah
+ mov LSRShadow[si],0
+ .errnz ACE_OR-CE_OVERRUN ;Must be the same bits
+ .errnz ACE_PE-CE_RXPARITY
+ .errnz ACE_FE-CE_FRAME
+ .errnz ACE_BI-CE_BREAK
+@@:
+
+; Regardless of the character received, flag the event in case
+; the user wants to see it.
+
+ or by EvtWord[si],EV_RxChar ;Show a character received
+ .errnz HIGH EV_RxChar
+
+; Check the input queue, and see if there is room for another
+; character. If not, or if the end of file character has already
+; been received, then go declare overflow.
+
+DataAvail00:
+
+ mov cx,QInCount[si] ;Get queue count (used later too)
+ cmp cx,QInSize[si] ;Is queue full?
+ jge DataAvail20 ; Yes, comm overrun
+ test EFlags[si],fEOF ;Has end of file been received?
+ jnz DataAvail20 ; Yes - treat as overflow
+
+; Test to see if there was a parity error, and replace
+; the character with the parity character if so
+
+ test bh,ACE_PE ;Parity error
+ jz DataAvail25 ; No
+ test [si.DCB_Flags2],fPErrChar ;Parity error replacement character?
+ jz DataAvail25 ; No
+ mov al,[si.DCB_PEChar] ; Yes, get parity replacement char
+
+; Skip all other processing except event checking and the queing
+; of the parity error replacement character
+
+ jmp short DataAvail80 ;Skip all but event check, queing
+
+DataAvail20:
+ or by ComErr[si],CE_RXOVER ;Show queue overrun
+ jmp short DataAvail50
+
+; See if we need to strip null characters, and skip
+; queueing if this is one. Also remove any parity bits.
+
+DataAvail25:
+ and al,RxMask[si] ;Remove any parity bits
+ jnz DataAvail30 ;Not a Null character
+ test [si.DCB_Flags2],fNullStrip ;Are we stripping received nulls?
+ jnz DataAvail50 ; Yes, put char in the bit bucket
+
+; Check to see if we need to check for EOF characters, and if so
+; see if this character is it.
+
+DataAvail30:
+ test [si.DCB_Flags],fBinary ;Is this binary stuff?
+ jnz DataAvail60 ; Yes, skip EOF check
+ cmp al,[si.DCB_EOFChar] ;Is this the EOF character?
+ jnz DataAvail60 ; No, see about queing the charcter
+ or EFlags[si],fEOF ;Set end of file flag
+DataAvail50:
+ jmp DataAvail140 ;Skip the queing process
+
+; If output XOn/XOff is enabled, see if the character just received
+; is either an XOn or XOff character. If it is, then set or
+; clear the XOffReceived flag as appropriate.
+
+DataAvail60:
+ test [si.DCB_Flags2],fOutX ;Output handshaking?
+ jz DataAvail80 ; No
+ cmp al,[si.DCB_XoffChar] ;Is this an X-Off character?
+ jnz DataAvail70 ; No, see about XOn or Ack
+ or HSFlag[si],XOffReceived ;Show XOff received, ENQ or ETX [rkh]
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz DataAvail50 ; No
+ cmp cx,[si.DCB_XonLim] ;See if at XOn limit
+ ja DataAvail50 ; No
+ and HSFlag[si],NOT XOffReceived ;Show ENQ or ETX not received
+ and HSFlag[si], NOT XOnPending+XOffSent
+ mov al, [si.DCB_XonChar]
+ call OutHandshakingChar
+ jmp DataAvail50 ;Done
+
+DataAvail70:
+ cmp al,[si.DCB_XonChar] ;Is this an XOn character?
+ jnz DataAvail80 ; No, just a normal character
+ and HSFlag[si],NOT XOffReceived
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jz DataAvail75 ; No - jump to FakeXmitEmpty to get
+ ; transmitting going again
+ and HSFlag[si],NOT EnqSent
+
+DataAvail75:
+ jmp FakeXmitEmpty ;Restart transmit
+
+; Now see if this is a character for which we need to set an event as
+; having occured. If it is, then set the appropriate event flag
+
+
+DataAvail80:
+ cmp al,[si.DCB_EVTChar] ;Is it the event generating character?
+ jne DataAvail90 ; No
+ or by EvtWord[si],EV_RxFlag ;Show received specific character
+
+; Finally, a valid character that we want to keep, and we have
+; room in the queue. Place the character in the queue.
+; If the discard flag is set, then discard the character
+
+DataAvail90:
+ test MiscFlags[si], Discard ;Discarding characters ?
+ jnz DataAvail50 ; Yes
+
+ lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
+ mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
+ les di,QInAddr[si][bx] ;Get queue base pointer from either
+ assumes es,nothing ; QInAddr or AltQInAddr
+
+ mov bx,QInPut[si] ;Get index into queue
+ mov es:[bx][di],al ;Store the character
+ inc bx ;Update queue index
+ cmp bx,QInSize[si] ;See if time for wrap-around
+ jc DataAvail100 ;Not time to wrap
+ xor bx,bx ;Wrap-around is a new zero pointer
+
+DataAvail100:
+ mov QInPut[si],bx ;Store updated pointer
+ inc cx ;And update queue population
+ mov QInCount[si],cx
+
+; If flow control has been enabled, see if we are within the
+; limit that requires us to halt the host's transmissions
+
+ cmp cx,XOffPoint[si] ;Time to see about XOff?
+ jc DataAvail120 ; Not yet
+ test HSFlag[si],HSSent ;Handshake already sent?
+ jnz DataAvail120 ; Yes, don't send it again
+
+ mov ah,HHSLines[si] ;Should hardware lines be dropped?
+ or ah,ah ; (i.e. do we have HW HS enabled?)
+ jz DataAvail110 ; No
+ add dl,ACE_MCR ; Yes
+ in al,dx ;Clear the necessary bits
+ not ah
+ and al,ah
+ or HSFlag[si],HHSDropped ;Show lines have been dropped
+ out dx,al ; and drop the lines
+ sub dl,ACE_MCR
+
+DataAvail110:
+ test [si.DCB_Flags2],fInX ;Input Xon/XOff handshaking
+ jz DataAvail120 ; No
+ or HSFlag[si], XOffSent
+ mov al, [si.DCB_XoffChar]
+ call OutHandshakingChar
+
+DataAvail120:
+ cmp cx, [si.RecvTrigger] ;Q: time to call owner's callback?
+ jb short DataAvail130 ; N:
+
+ test [si.NotifyFlagsHI], CN_RECEIVE
+ jnz short DataAvail140 ; jump if notify already sent and
+ ; data in buffer hasn't dropped
+ ; below threshold
+ mov ax, IntCodeOFFSET DataAvail140
+ push ax
+ mov ax, CN_RECEIVE
+%OUT probably should just set a flag and notify after EOI
+ jmp notify_owner
+
+DataAvail130:
+ and [si.NotifyFlagsHI], NOT CN_RECEIVE
+
+DataAvail140:
+ pop dx
+ push dx
+ add dl, ACE_LSR-ACE_IIDR
+ in al, dx
+ test al, ACE_DR ;Q: more data available?
+ jz @F ; N:
+ sub dl, ACE_LSR ; Y: go read it
+ in al, dx ;Read available character
+ jmp DataAvail00
+@@:
+ jmp InterruptLoop_ChkTx
+
+DataAvail endp
+
+
+OutHandshakingChar proc near
+
+ add dl, ACE_LSR
+ mov ah, al
+@@:
+ in al, dx
+ test al, ACE_THRE
+ jz @B
+ sub dl, ACE_LSR
+ mov al, ah
+ out dx, al
+ ret
+
+OutHandshakingChar endp
+
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; XmitEmpty - Transmitter Register Empty
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+; assumes ds,Data
+assumes es,nothing
+
+public FakeXmitEmpty
+FakeXmitEmpty:
+ pop dx
+ push dx
+
+; "Kick" the transmitter interrupt routine into operation.
+
+ dec dl
+.errnz ACE_IIDR - ACE_IER-1
+ in al,dx ;Get current IER state
+ test al,ACE_ETBEI ;Interrupt already enabled?
+ jnz @F ; Yes, don't reenable it
+ or al,ACE_ETBEI ; No, enable it
+ out dx,al
+ iodelay ;8250, 8250-B bug requires
+ out dx,al ; writting register twice
+@@:
+ add dl,ACE_LSR-ACE_IER ;--> Line Status Register
+ iodelay
+ in al,dx ;Is xmit really empty?
+ sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
+ test al,ACE_THRE
+ jnz short XmitEmpty5 ; Y: send next char
+ jmp InterruptLoop ; N: return to processing loop
+
+public XmitEmpty
+XmitEmpty proc near
+
+ add dl,ACE_LSR-ACE_IIDR ;--> Line Status Register
+ in al,dx ;Is xmit really empty?
+ sub dl,ACE_LSR-ACE_THR ;--> Transmitter Holding Register
+ test al,ACE_THRE
+ jz Xmit_jumpto90 ;Transmitter not empty, cannot send
+
+; If the hardware handshake lines are down, then XOff/XOn cannot
+; be sent. If they are up and XOff/XOn has been received, still
+; allow us to transmit an XOff/XOn character. It will make
+; a dead lock situation less possible (even though there are
+; some which could happen that cannot be handled).
+
+XmitEmpty5:
+ mov ah,HSFlag[si] ;Get handshaking flag
+ test ah,HHSDown+BreakSet ;Hardware lines down or break set?
+ jnz Xmit_jumpto100 ; Yes, cannot transmit
+
+; Give priority to any handshake character waiting to be
+; sent. If there are none, then check to see if there is
+; an "immediate" character to be sent. If not, try the queue.
+
+XmitEmpty10:
+ test [si.DCB_Flags],fEnqAck+fEtxAck ;Enq or Etx Ack?
+ jnz XmitEmpty40 ; Yes
+
+XmitEmpty15:
+ test ah,HSPending ;XOff or XOn pending
+ jz XmitEmpty40 ; No
+
+XmitEmpty20:
+ and ah,NOT XOnPending+XOffSent
+ mov al,[si.DCB_XonChar] ;Get XOn character
+
+XmitEmpty30:
+ mov HSFlag[si],ah ;Save updated handshake flag
+ jmp XmitEmpty110 ;Go output the character
+
+Xmit_jumpto90:
+ jmp XmitEmpty90
+
+; If any of the lines which were specified for a timeout are low, then
+; don't send any characters. Note that by putting the check here,
+; XOff and Xon can still be sent even though the lines might be low.
+
+; Also test to see if a software handshake was received. If so,
+; then transmission cannot continue. By delaying the software check
+; to here, XOn/XOff can still be issued even though the host told
+; us to stop transmission.
+
+XmitEmpty40:
+ test ah,CannotXmit ;Anything preventing transmission?
+ jz XmitEmpty45 ; No
+Xmit_jumpto100:
+ jmp XmitEmpty100 ; Yes, disarm and exit
+
+; If a character has been placed in the single character "transmit
+; immediately" buffer, clear that flag and pick up that character
+; without affecting the transmitt queue.
+
+XmitEmpty45:
+ test EFlags[si],fTxImmed ;Character to xmit immediately?
+ jz XmitEmpty515 ; No, try the queue
+ and EFlags[si],NOT fTxImmed ;Clear xmit immediate flag
+ mov al,ImmedChar[si] ;Get char to xmit
+ jmp XmitEmpty110 ;Transmit the character
+
+XmitEmpty515:
+ mov cx,QOutCount[si] ;Output queue empty?
+ jcxz Xmit_jumpto90 ; Yes, go set an event
+
+ test [si.DCB_Flags],fEtxAck ;Etx Ack?
+ jz XmitEmpty55 ; No
+ mov cx,QOutMod[si] ;Get number bytes sent since last ETX
+ cmp cx,[si.DCB_XonLim] ;At Etx limit yet?
+ jne XmitEmpty51 ; No, inc counter
+ mov QOutMod[si],0 ; Yes, zero counter
+ or HSFlag[si],EtxSent ;Show ETX sent
+ jmp short XE_sendXOFF
+
+XmitEmpty51:
+ inc cx ; Update counter
+ mov QOutMod[si],cx ; Save counter
+ jmp short XmitEmpty59 ; Send queue character
+
+XmitEmpty55:
+ test [si.DCB_Flags],fEnqAck ;Enq Ack?
+ jz XmitEmpty59 ; No, send queue character
+ mov cx,QOutMod[si] ;Get number bytes sent since last ENQ
+ or cx,cx ;At the front again?
+ jnz XmitEmpty56 ; No, inc counter
+ mov QOutMod[si],1 ; Yes, send ENQ
+ or HSFlag[si],EnqSent ;Show ENQ sent
+XE_sendXOFF:
+ mov al,[si.DCB_XoffChar]
+ jmp short XmitEmpty110 ;Go output the character
+
+XmitEmpty56:
+ inc cx ;Update counter
+ cmp cx,[si.DCB_XonLim] ;At end of our out buffer len?
+ jne XmitEmpty58 ; No
+ xor cx,cx ;Show at front again.
+
+XmitEmpty58:
+ mov QOutMod[si],cx ;Save counter
+
+XmitEmpty59:
+ lea bx, [si+SIZE ComDEB] ; DS:BX -> BIS
+ mov bx, [bx.BIS_Mode] ; mode will be either 0 or 4
+ les di,QOutAddr[si][bx] ;Get queue base pointer from either
+ assumes es,nothing ; QOutAddr or AltQOutAddr
+
+ mov bx,QOutGet[si] ;Get pointer into queue
+ mov al,es:[bx][di] ;Get the character
+
+ inc bx ;Update queue pointer
+ cmp bx,QOutSize[si] ;See if time for wrap-around
+ jc XmitEmpty60 ;Not time for wrap
+ xor bx,bx ;Wrap by zeroing the index
+
+XmitEmpty60:
+ mov QOutGet[si],bx ;Save queue index
+ mov cx,QOutCount[si] ;Output queue empty?
+ dec cx ;Dec # of bytes in queue
+ mov QOutCount[si],cx ; and save new population
+
+ out dx,al ;Send char
+
+ cmp cx, [si.SendTrigger] ;Q: time to call owner's callback?
+ jae short XmitEmpty70 ; N:
+
+ test [si.NotifyFlagsHI], CN_TRANSMIT
+ jnz short XmitEmpty80 ; jump if notify already sent and
+ ; data in buffer hasn't raised
+ ; above threshold
+ mov ax, IntCodeOFFSET XmitEmpty80
+ push ax
+ mov ax, CN_TRANSMIT
+ jmp short notify_owner
+
+XmitEmpty70:
+ and [si.NotifyFlagsHI], NOT CN_TRANSMIT
+
+XmitEmpty80:
+%OUT check fNoFIFO in EFlags[si] to determine if we can queue more output
+ jmp InterruptLoop
+
+
+; No more characters to transmit. Flag this as an event.
+
+XmitEmpty90:
+ or by EvtWord[si],EV_TxEmpty
+
+; Cannot continue transmitting (for any of a number of reasons).
+; Disable the transmit interrupt. When it's time resume, the
+; transmit interrupt will be reenabled, which will generate an
+; interrupt.
+
+XmitEmpty100:
+ inc dx ;--> Interrupt Enable Register
+ .errnz ACE_IER-ACE_THR-1
+ in al,dx ;I don't know why it has to be read
+ and al,NOT ACE_ETBEI ; first, but it works this way
+XmitEmpty110:
+ out dx,al
+ jmp InterruptLoop
+
+XmitEmpty endp
+
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; ModemStatus - Modem Status Interrupt Handler
+;
+; Entry:
+; DS:SI --> DEB
+; DX = Port.IIDR
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DI,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+
+; assumes ds,Data
+assumes es,nothing
+
+public ModemStatus ;Public for debugging
+ModemStatus proc near
+
+; Get the modem status value and shadow it for MSRWait.
+
+ add dl,ACE_MSR-ACE_IIDR ;--> Modem Status Register
+ in al,dx
+ mov MSRShadow[si],al ;Save MSR data for others
+ mov ch,al ;Save a local copy
+
+; Create the event mask for the delta signals
+
+ mov ah,al ;Just a lot of shifting
+ shr ax,1
+ shr ax,1
+ shr ah,1
+ mov cl,3
+ shr ax,cl
+ and ax,EV_CTS+EV_DSR+EV_RLSD+EV_Ring
+ or EvtWord[si],ax
+
+ mov ah,ch ;[rkh]...
+ shr ah,1
+ shr ah,1
+ and ax,EV_CTSS+EV_DSRS
+ or EvtWord[si],ax
+
+ mov ah,ch
+ mov cl,3
+ shr ah,cl
+ and ax,EV_RLSD
+ or EvtWord[si],ax
+
+ mov ah,ch
+ mov cl,3
+ shl ah,cl
+ and ax,EV_RingTe
+ or EvtWord[si],ax
+
+ .errnz EV_CTS-0000000000001000b
+ .errnz EV_DSR-0000000000010000b
+ .errnz EV_RLSD-0000000000100000b
+ .errnz EV_Ring-0000000100000000b
+
+ .errnz EV_CTSS-0000010000000000b ;[rkh]
+ .errnz EV_DSRS-0000100000000000b
+ .errnz EV_RLSDS-0001000000000000b
+ .errnz EV_RingTe-0010000000000000b
+
+ .errnz ACE_DCTS-00000001b
+ .errnz ACE_DDSR-00000010b
+ .errnz ACE_DRLSD-00001000b
+ .errnz ACE_RI-01000000b
+
+ .errnz ACE_TERI-00000100b ;[rkh]
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+ .errnz ACE_RLSD-10000000b
+
+ModemStatus10:
+ mov al,OutHHSLines[si] ;Get output hardware handshake lines
+ or al,al ;Any lines that must be set?
+ jz ModemStatus40 ;No hardware handshake on output
+ and ch,al ;Mask bits of interest
+ cmp ch,al ;Lines set for Xmit?
+ je ModemStatus20 ; Yes
+ or HSFlag[si],HHSDown ;Show hardware lines have dropped
+ModemStatus30:
+ jmp InterruptLoop
+
+ModemStatus40:
+ jmp InterruptLoop_ChkTx
+
+; Lines are set for xmit. Kick an xmit interrupt if needed
+
+ModemStatus20:
+ and HSFlag[si],NOT (HHSDown OR HHSAlwaysDown)
+ ;Show hardware lines back up
+ mov cx,QOutCount[si] ;Output queue empty?
+ jcxz ModemStatus30 ; Yes, return to InterruptLoop
+ jmp FakeXmitEmpty ;Restart transmit
+
+ModemStatus endp
+
+page
+
+;------------------------------------------------------------------------------
+;
+; ENTER: AX = message #
+; DS:SI -> DEB
+notify_owner proc near
+
+ or [si.NotifyFlags], ax
+ lea di, [si+SIZE ComDEB]
+ mov ax, ds
+ mov es, ax
+ mov ax, BIH_API_Call_Back ; call immediate, or in protected mode
+ mov bx, 1 ; force SYS VM, if enhanced mode
+ mov cx, _INTERRUPT
+ mov dx, IntCodeOFFSET callback_event
+%OUT use equate
+ push ds
+ push si
+ mov si, 1 ; low priority boost
+ push bp
+ mov bp, es:[di.BIS_Mode]
+ call es:[bp][di.BIS_User_Mode_API]
+ pop bp
+ pop si
+ pop ds
+ ret
+
+notify_owner endp
+
+;------------------------------------------------------------------------------
+;
+; ENTER: ES:DI -> BIS
+;
+callback_event proc far
+ lea si, [di-SIZE ComDEB]
+ mov ax, es
+ mov ds, ax
+ mov ax, [si.NotifyHandle]
+ push ax ; push hWnd
+ mov ax, WM_COMMNOTIFY
+ push ax ; push wMsg
+ xor ax, ax
+ mov al, [si.DCB_Id]
+ push ax ; push wParam = ComID
+ xor al, al
+ push ax ; push high word of lParam
+ xchg al, [si.NotifyFlagsLO]
+ or [si.NotifyFlagsHI], al
+ push ax ; push low word of lParam = event flags
+ call [lpPostMessage]
+ ret
+callback_event endp
+
+
+PUBLIC TimerProc
+TimerProc proc far
+
+ push ds
+ mov ax, _DATA
+ mov ds, ax
+ assumes ds,data
+
+ mov ax, [activeCOMs]
+ or ax, ax
+ jz short tp_nonactive
+ push si
+ mov si, DataOFFSET COMptrs
+ mov cx, MAXCOM+1
+tp_lp:
+ push si
+ mov si, [si] ; si -> ComDEB
+ shr ax, 1
+ jnc tp_lpend
+
+ cmp [si.RecvTrigger], -1 ;Q: owner wants notification?
+ je short tp_lpend ; N: skip notify
+ cmp [si.QInCount], 0 ;Q: anything in input queue?
+ je short tp_lpend ; N: skip notify
+ test [si.NotifyFlagsHI], CN_RECEIVE ;Q: timeout notify already given?
+ jnz short tp_lpend ; N: skip notify
+
+ xor [si.NotifyFlagsHI], CN_Idle ;Q: first timer call?
+ js short tp_lpend ; Y: skip notify
+
+ push ax
+ push cx
+ mov ax, CN_RECEIVE ; N: notify owner
+ call notify_owner
+ pop cx
+ pop ax
+
+tp_lpend:
+ pop si
+ inc si ; inc to ptr to next ComDEB
+ inc si
+ or ax, ax
+ loopnz tp_lp
+ pop si
+
+tp_nonactive:
+ pop ds
+ assumes ds,nothing
+ ret
+
+TimerProc endp
+page
+
+ifdef DEBUG
+ public Control, DEF_Handler, COMHandler, APIHandler
+ public InterruptLoop, IntLoop10, IntLoop20
+ public DataAvail25, DataAvail30, DataAvail50
+ public DataAvail60, DataAvail70, DataAvail80, DataAvail90
+ public DataAvail100, DataAvail110, DataAvail120
+ public DataAvail130, DataAvail140, OutHandshakingChar
+ public XmitEmpty10, XmitEmpty20, XmitEmpty30, XmitEmpty40
+ public XmitEmpty59, XmitEmpty60
+ public XmitEmpty90, XmitEmpty100, XmitEmpty110
+ public ModemStatus10, ModemStatus20, ModemStatus30
+ public notify_owner, callback_event
+endif
+
+DOSTI proc near
+ FSTI
+ ret
+DOSTI endp
+
+DOCLI proc near
+ FCLI
+ ret
+DOCLI endp
+
+
+
+sEnd IntCode
+end
diff --git a/private/mvdm/wow16/drivers/comm/ibmlpt.asm b/private/mvdm/wow16/drivers/comm/ibmlpt.asm
new file mode 100644
index 000000000..c47e101cc
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmlpt.asm
@@ -0,0 +1,412 @@
+page,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMLPT.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; General Description:
+;
+; History:
+;
+;-----------------------------------------------------------------------;
+
+title IBMLpt - IBM PC, PC-XT, PC-AT, PS/2 Parallel Communications Interface
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ins8250.inc
+include ibmcom.inc
+.list
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+externFP GetSystemMsecCount
+
+externA __0040H
+
+;----------------------------Private-Routine----------------------------;
+;
+; DoLPT - Do Function To LPT port
+;
+; The given function (output or reset) is performed to the
+; passed LPT port.
+;
+; Before a character is sent, a check is made to see if the device
+; will be able to accept the character. If it can, then the character
+; will be sent. If not, then an error will be returned. If the
+; printer is selected and busy and no error, then the code returned
+; will be CE_TXFULL and the handshake bits will be set in HSFlag
+; to simulate that a handshake was received.
+;
+; If the BIOS ROM code is examined, you will note that they wait for
+; the busy character from the last charcater to be cleared before
+; they strobe in the current character. This can take a long time
+; on the standard EPSON class printer (1 mSec to greater than
+; 300 mSec if the last character actually caused printing).
+;
+; Because of this, several status read retrys will be made before
+; declaring that the device is actually busy. If only one status
+; read is performed, the spooler will yeild, take a while to get
+; back here, and things will be really slow. What difference does
+; it really make if we or the BIOS does the delay, at least we can
+; break out of it at some point when it seems hopeless.
+;
+; The OKIHACK: Okidata reports a 50 ns. 2.2 volt pulse on the paper
+; out signal on the trailing edge of the Busy signal. If we see this
+; glitch then we report paper out. So we try to get the status twice...
+; if it changes between the two tries we keep getting the status.
+; Silly hardware people.
+;
+; Entry:
+; AH = cid
+; AL = character to output
+; CH = Function request. 0 = Output, 1 = Initialize, 2 = Status
+; DS:SI -> DEB for the port
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; SI,DI
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public DoLPT
+DoLPT proc near
+
+ mov dx,Port[si] ;Get port address
+
+; DX = port address
+; CH = operation: 0 = write, 1 = init, 2 = status
+; AL = character
+
+ or ch, ch
+ jz LPT_OutChar
+ cmp ch, 1
+ jz LPT_Reset
+ jmp LPT_GetStatus
+ ret
+
+LPT_Reset:
+
+ inc dx
+ inc dx
+ mov al, L_RESET
+ iodelay
+ out dx, al
+
+ push dx
+
+ cCall GetSystemMsecCount
+ mov bx, ax
+
+LPT_ResetDelay:
+ push bx
+ cCall GetSystemMsecCount
+ pop bx
+ sub ax, bx
+ cmp ax, 300 ; 1/3 sec as good as any
+ jbe LPT_ResetDelay
+
+ pop dx
+
+ mov al, L_NORMAL
+ iodelay
+ iodelay
+ out dx, al
+ dec dx
+ dec dx
+ jmp LPT_GetStatus
+
+LPT_OutChar:
+ push ax ; save character to be written
+
+ ; first check to see if printer is ready for us
+ push di
+
+ push dx
+ call GetSystemMSecCount
+ mov di, ax
+ pop dx
+
+LPT_WaitReady:
+
+ inc dx ; point to status port
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ xchg al, ah
+
+ifndef NOOKIHACK
+ iodelay
+ in al, dx
+
+ dec dx
+
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah ; did any bits change?
+ jnz LPT_WaitReady
+else
+ dec dx
+endif
+
+
+ test ah, PS_PaperOut or PS_IOError
+ jnz LPT_PrinterNotReady
+ test ah, PS_Select
+ jz LPT_PrinterNotReady
+ test ah, PS_NotBusy
+ jnz LPT_PrinterReady
+
+ push ax
+ push dx
+ call GetSystemMSecCount
+ pop dx
+ pop bx
+ sub ax, di
+ cmp ax, 300 ; 1/3 sec timeout
+
+ jbe LPT_WaitReady
+
+; The device seems to be selected and powered up, but is just
+; busy (some printers seem to show selected but busy when they
+; are taken offline). Show that the transmit queue is full and
+; that the hold handshakes are set. This is so the windows
+; spooler will retry (and do yields so that other apps may run).
+
+
+ or ComErr[si],CE_TXFULL ;Show queue full
+ mov ah,bh
+ or ah, L_TIMEOUT
+
+LPT_PrinterNotReady:
+
+ pop di
+ pop cx ; throw away character
+ jmp short LPT_ReturnStatus
+
+LPT_PrinterReady:
+ pop di ; get di back
+ pop ax ; get character back
+
+ iodelay
+ out dx, al ; write character to port
+
+ inc dx ; access status port
+
+LPT_Strobe:
+ inc dx ; control port
+ mov al, L_STROBE ; set strobe high
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; ...
+
+ mov al, L_NORMAL ;
+ iodelay
+ iodelay
+ iodelay
+ iodelay
+ out dx, al ; set strobe low
+
+ sub dx, 2 ; point back to port base
+
+ ; FALL THRU
+
+LPT_GetStatus:
+ inc dx ; point to status port
+LPT_GS1:
+ iodelay
+ iodelay
+ in al, dx ; get status bits
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ mov ah, al
+
+ifndef NOOKIHACK
+ in al, dx
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah
+ jnz LPT_GS1 ; if they changed try again...
+endif
+
+LPT_ReturnStatus:
+
+ assumes ds,Data
+ and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)*256
+ shr ah,1
+ adc ah,al ;Get back Timeout bit
+ xor ah,HIGH CE_DNS ;Invert selected bit
+ .errnz LOW CE_DNS
+ or by ComErr+1[si],ah ;Save comm error
+ ret
+
+ .errnz CE_PTO-0200h
+ .errnz CE_IOE-0400h
+ .errnz CE_DNS-0800h
+ .errnz CE_OOP-1000h
+
+DoLPT40:
+ assumes ds,Data
+ or ComErr[si],CE_TXFULL ;Show queue full
+ ret
+
+DoLPT endp
+page
+
+
+CheckStatus proc near
+ in al, dx ; get status bits
+ mov ah, al
+ and al, L_BITS ; mask unused ones
+ xor al, L_BITS_INVERT ; flip a couple
+ xchg al, ah
+
+ifndef NOOKIHACK
+ iodelay
+ in al, dx
+
+ and al, L_BITS
+ xor al, L_BITS_INVERT
+ cmp al, ah ; did any bits change?
+ jnz CheckStatus
+endif
+ test ah, PS_PaperOut or PS_IOError
+ jz @F
+ stc
+ ret
+@@:
+ test ah, PS_Select
+ jnz @F
+ stc
+ ret
+@@:
+ and ah, PS_NotBusy
+ clc
+ ret
+
+CheckStatus endp
+
+
+;----------------------------Public Routine-----------------------------;
+;
+; StringToLPT - Send string To LPT Port
+;
+; Entry:
+; DS:SI -> DEB
+; ES:DI -> string to send
+; CX = # of bytes to send
+; Returns:
+; AX = # of bytes actually sent
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+PUBLIC StringToLPT
+StringToLPT proc near
+
+ mov dx, Port[si] ; get port address
+ inc dx ; access status port
+
+ push cx ; save count for later
+ push ds
+ mov bx, __0040H
+ mov ds, bx
+
+ cld
+
+ call CheckStatus ; quick status check before slowness
+ jc PrinterError
+ jz PrinterBusy ; if printer not ready for first char
+ ; then just return with CE_TXFULL
+
+CharacterToLPT:
+;; mov bh, 10 ; will wait 10 clock tics (~ 1/2 sec)
+ mov bh, 3 ; will wait 3 clock tics (~ 1/6 sec)
+l1:
+ mov bl, ds:[006Ch] ; low byte of tic counter
+l2:
+ call CheckStatus ; quick status check before slowness
+ jc PrinterError
+ jnz LPT_PrinterRdy
+
+ cmp bl, ds:[006Ch]
+ jz l2 ; tic count hasn't changed
+
+ dec bh
+ jz PrinterBusy ; out of tics, timeout
+ jmp short l1
+
+LPT_PrinterRdy:
+ mov al, es:[di]
+ inc di
+
+ dec dx ; point to data port
+
+ out dx, al ; write character to port
+
+ add dx, 2 ; access control port
+ mov al, L_STROBE ; set strobe high
+ out dx, al ; ...
+
+ mov al, L_NORMAL ;
+ iodelay
+ iodelay
+ out dx, al ; set strobe low
+
+ dec dx ; point to status port for check
+
+ loop CharacterToLPT
+ pop ds
+ jmp short LPT_Exit
+
+PrinterError:
+ pop ds
+ jmp short ReturnStatus
+
+PrinterBusy:
+ pop ds
+ or ComErr[si],CE_TXFULL ; set buffer full bit
+ or al, L_TIMEOUT ; show timeout bit
+
+ReturnStatus:
+ and ax,(PS_PaperOut+PS_Select+PS_IOError+PS_Timeout)
+ xchg al, ah
+ shr ah,1
+ adc ah,al ;Get back Timeout bit
+ xor ah,HIGH CE_DNS ;Invert selected bit
+ .errnz LOW CE_DNS
+ or by ComErr+1[si],ah ;Save comm error
+
+LPT_Exit:
+ pop ax ; get total count
+ sub ax, cx ; subtract remaining unsent charts
+
+ ret
+
+StringToLPT endp
+
+
+IFDEF DEBUG ;Publics for debugging
+ public LPT_Reset
+ public LPT_Outchar
+ public LPT_Strobe
+ public LPT_GetStatus
+ public DoLPT40
+ENDIF
+
+sEnd code
+End
diff --git a/private/mvdm/wow16/drivers/comm/ibmsetup.asm b/private/mvdm/wow16/drivers/comm/ibmsetup.asm
new file mode 100644
index 000000000..be430f747
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ibmsetup.asm
@@ -0,0 +1,2878 @@
+page,132
+;---------------------------Module-Header-------------------------------;
+; Module Name: IBMSETUP.ASM
+;
+; Copyright (c) Microsoft Corporation 1985-1990. All Rights Reserved.
+;
+; General Description:
+;
+; History:
+; sudeepb 10-Jan-1993 changed the costly cli/sti with non-trapping
+; FCLI/FSTI macros
+;
+;-----------------------------------------------------------------------;
+
+title IBMSetup - IBM PC, PC-XT, PC-AT, PS/2 Communications Interface
+
+.xlist
+include cmacros.inc
+include comdev.inc
+include ins8250.inc
+include ibmcom.inc
+include BIMODINT.INC
+include vint.inc
+.list
+
+
+EBIS_Sel1 equ SIZE Bimodal_Int_Struc
+EBIS_Sel2 equ EBIS_Sel1 + (SIZE EBIS_Sel_Struc)
+
+externA __WinFlags
+
+externFP GetSystemMsecCount
+externFP CreateSystemTimer
+externFP AllocCStoDSAlias
+externFP LockSegment
+externFP UnlockSegment
+externFP FreeSelector
+externFP GetSelectorBase
+externFP GetModuleHandle
+externFP GetProcAddress
+externFP GetPrivateProfileInt
+externFP GetPrivateProfileString
+externFP GetAppCompatFlags
+externFP WowCloseComPort
+
+externNP $RECCOM
+
+externA __0040H
+externA __F000h
+
+externB IRQhooks
+
+IF 0
+externD OldIntVecIntB
+externD OldIntVecIntC
+externD OurIntVecIntB
+externD OurIntVecIntC
+ENDIF
+
+externB szMessage
+externB pLPTByte
+externB szCOMMessage
+externB pCOMByte
+externB _szTitle
+
+
+MULTIPLEX equ 2Fh ; multiplex interrupt number
+GET386API equ 1684h ; Get API entry point from VxD
+VPD equ 000Fh ; device ID of VPD device
+VPD_GETPORT equ 0004h ; function: assign port to current VM
+VPD_RELPORT equ 0005h ; function: release port
+VCD equ 000Eh ; device ID of VCD device
+VCD_GETVER equ 0000h ; get version API
+VCD_GETPORT equ 0004h ; function: assign port to current VM
+VCD_RELPORT equ 0005h ; function: release port
+VCD_STEALPORT equ 0006h
+VPICD equ 0003h ; device ID of VPICD device
+
+POSTMESSAGE equ 110 ; export ordinal of PostMessage()
+MESSAGEBOX equ 1 ; export ordinal of MessageBox()
+MB_TASKMODAL equ 2000h
+MB_YESNO equ 0004h ; messagebox flags
+MB_ICONEXCLAMATION equ 0030h
+IDYES equ 6
+
+
+createSeg _INTERRUPT,IntCode,word,public,CODE
+sBegin IntCode
+assumes cs,IntCode
+
+ externFP FakeCOMIntFar
+ externFP TimerProc
+ externFP Control
+ externFP COMHandler
+ externFP APIHandler
+IFDEF No_DOSX_Bimodal_Services
+ externW RM_IntDataSeg
+ externFP RM_APIHandler
+ externFP Entry_From_RM
+ externD RM_CallBack
+ENDIF
+
+sEnd IntCode
+
+page
+sBegin Data
+
+externB lpCommBase
+externB CommBaseX
+externB lpCommIrq
+externB CommIrqX
+externB lpCommFifo
+externB CommFifoX
+externB lpCommDSR
+externB CommDSRx
+
+externB lpCommSection
+externB lpSYSTEMINI
+
+
+;------------------------------------------------------------------------------
+;
+; Reserve data space for COM ports
+;
+DefineCommX MACRO num
+ public Comm&num
+Comm&num label byte
+ db num-1
+.errnz DCB_Id
+ db ((DCBSize+1) AND 0FFFEh)-1 DUP (0) ; ComDCB
+ dw 0 ; ComErr
+ dw 0 ; Port
+ dw 0 ; NotifyHandle
+ dw 0 ; NotifyFlags
+ dw -1 ; RecvTrigger
+ dw 0 ; SendTrigger
+.errnz IRQhook - SendTrigger - 2
+ db (SIZE ComDEB) - IRQhook DUP(0)
+.errnz $ - Comm&num - (SIZE ComDEB)
+ Declare_PM_BIS 0,Control,COMHandler,APIHandler,_INTERRUPT,_DATA
+ db (SIZE EBIS_Sel_Struc) * 2 DUP(0) ; res space for 2 selectors
+ENDM
+DW_OFFSET_CommX MACRO num
+ dw DataOFFSET Comm&num
+ENDM
+
+
+??portnum = 1
+REPT MAXCOM+1
+ DefineCommX %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PUBLIC COMptrs ; table of offsets to CommX's declared above
+COMptrs label word
+??portnum = 1
+REPT MAXCOM+1
+ DW_OFFSET_CommX %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE DefineCommX
+PURGE DW_OFFSET_CommX
+
+;------------------------------------------------------------------------------
+;
+; Reserve data space for LPT ports
+;
+DefineLPTx MACRO num
+ public LPT&num
+LPT&num label byte
+ db num-1+LPTx
+.errnz DCB_Id
+ db ((DCBSize+1) AND 0FFFEh)-1 DUP (0) ; xComDCB
+ dw 0 ; xComErr
+ dw 0 ; xPort
+ dw 0 ; xNotifyHandle
+ dw 0 ; xNotifyFlags
+ dw -1 ; xRecvTrigger
+ dw 0 ; xSendTrigger
+IF num LE 3
+ dw LPTB + (num-1)*2
+ELSE
+ dw 0 ; BIOSPortLoc
+ENDIF
+ .errnz $-LPT&num - SIZE LptDEB
+ENDM
+
+??portnum = 1
+REPT MAXLPT+1
+ DefineLPTx %??portnum
+??portnum = ??portnum+1
+ENDM
+
+PURGE DefineLPTx
+
+page
+
+PUBLIC $MachineID, Using_DPMI
+$MachineID db 0 ;IBM Machine ID
+Using_DPMI db 0 ; 0FFh, if TRUE
+
+ ALIGN 2
+
+PUBLIC activeCOMs
+activeCOMs dw 0
+
+PUBLIC lpPostMessage, lpfnMessageBox, lpfnVPD, fVPD
+
+lpPostMessage dd 0
+lpfnMessageBox dd 0
+
+lpfnVPD dd 0 ; far pointer to win 386 VPD entry point
+lpfnVCD dd 0 ; far pointer to win 386 VCD entry point
+lpfnVPICD dd 0 ; far pointer to win 386 VPICD entry point
+PUBLIC VCD_int_callback
+VCD_int_callback df 0 ; VCD returns the address for this callback
+ ; on every call to acquire a COM port, but
+ ; it is always the same address, so we will
+ ; just maintain it globally.
+fVPD db 0 ; 0-not checked, 1 vpd present, -1 no vpd
+fVCD db 0 ; 0-not checked, 1 vcd present, -1 no vcd
+fVPICD db 0 ; 0-not checked, 1 vpicd present, -1 no vpicd
+
+szUser db 'USER',0
+
+
+default_table db 4, 3, 4, 3, 0 ; Default IRQ's (COM3 default is changed to
+ ; 3 for PS/2's during LoadLib)
+
+
+IFDEF No_DOSX_Bimodal_Services
+RM_Call_Struc Real_Mode_Call_Struc <>
+ENDIF
+
+IFDEF DEBUG_TimeOut
+%OUT including code to display MsgBox, if closing comm with data in buffer
+szSendTO db 'TimedOut CloseComm with data in buffer. Retry?', 0
+ENDIF
+
+
+sEnd Data
+
+ROMBios segment at 0F000h
+ org 0FFFEh
+
+MachineID label byte
+RomBios Ends
+
+
+sBegin Code
+assumes cs,Code
+assumes ds,Data
+
+page
+
+IFDEF No_DOSX_Bimodal_Services
+;----------------------------Private-Routine----------------------------;
+; SegmentFromSelector
+;
+; Converts a selector to a segment...note that this routine assumes
+; the memory pointed to by the selector is below the 1Meg line!
+;
+; Params:
+; AX = selector to convert to segment
+;
+; Returns:
+; AX = segment of selector given
+;
+; Error Returns:
+; None
+;
+; Registers Destroyed:
+; CX
+;
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public SegmentFromSelector
+SegmentFromSelector proc far
+
+.286
+ push dx
+ cCall GetSelectorBase,<ax> ;DX:AX = segment of selector
+ shr ax, 4
+ shl dl, 4
+ or ah, dl ;AX now points to interrupt *segment*
+ pop dx
+ ret
+.8086
+
+SegmentFromSelector endp
+ENDIF
+page
+
+;------------------------------------------------------------------------------
+;
+; Get_API_Entry
+;
+; entry - BX = device id
+; DS:DI -> DWORD for proc address
+; exit - Z flag set, if failed
+;
+Get_API_Entry proc near
+
+ push di
+ xor di, di
+ mov es, di
+ mov ax, GET386API
+ int MULTIPLEX
+ mov ax, di
+ pop di
+ mov [di], ax
+ mov [di+2], es
+ or ax, [di+2]
+ ret
+
+Get_API_Entry endp
+
+;----------------------------Private-Routine----------------------------;
+;
+; Contention_Dlg
+;
+; If running under Win386, this routine can be called to ask the user to
+; resolve contention for a COM or LPT port.
+;
+; entry - CX is offset of message string for dialog box
+;
+; exit - Z flag set, if user specified that Windows should steal the port
+
+Contention_Dlg proc near
+PUBLIC Contention_Dlg
+
+ xor ax,ax
+ push ax ; hwndOwner
+ push ds
+ push cx ; message ptr
+
+ cmp wo lpfnMessageBox[2], 0 ;Q: ptr to MessageBox proc valid?
+ jne short gmbp_done ; Y: we can call it
+ push ds ; N: get module handle of USER
+ lea ax, szUser
+ push ax
+ cCall GetModuleHandle
+
+ push ax ; module handle
+ mov ax, MESSAGEBOX
+ cwd
+ push dx
+ push ax
+ cCall GetProcAddress
+ mov wo lpfnMessageBox[0], ax ; save received proc address
+ mov wo lpfnMessageBox[2], dx
+gmbp_done:
+
+ push ds
+ lea ax, _szTitle
+ push ax
+ mov ax, MB_ICONEXCLAMATION or MB_YESNO or MB_TASKMODAL
+ push ax
+ cCall lpfnMessageBox
+ cmp ax, IDYES ; user allows us to take the port?
+ ret
+Contention_Dlg endp
+
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetPort386
+;
+; If running under Win386, tell the VPD to assign an LPT port to us.
+; The comm driver will handle contention.
+;
+; entry - DI contains offset in ROM area of port...
+; 8 - LPT1, A - LPT2, etc
+;
+; exit - registers saved, carry = clear if OK to proceed, set if
+; user won't allow assignment of port or Win386 error
+;
+
+GetPort386 proc near
+public GetPort386
+
+ cmp fVPD, 0
+ jl getport_VPDNotInstalled
+ jnz short getport_CallVPD
+
+ push di
+ mov bx, VPD
+ mov di, DataOFFSET lpfnVPD
+ call Get_API_Entry
+ pop di
+ jnz short getport_CallVPD
+ mov fVPD, -1
+
+getport_VPDNotInstalled:
+ clc
+ jmp short getport_exit
+
+getport_CallVPD:
+ mov fVPD, 1
+ push di
+ sub di, LPTB
+ shr di, 1 ; turn DI into port number
+
+ xor ax, ax
+ mov dx, VPD_GETPORT
+ mov cx, di
+ call [lpfnVPD]
+ jnc getport_gotit
+
+; port owned by another VM... ask the user for it
+
+ add cl, '1' ; fix up the port name...
+ mov pLPTByte, cl ; HACK HACK HACK
+ lea cx, szMessage
+ call Contention_Dlg
+ jnz getport_userwontallow
+
+ mov ax, 1 ; tell win386 we really do want it
+ mov cx, di ;
+ mov dx, VPD_GETPORT ;
+ call [lpfnVPD] ; return with C set or clear...
+ jmp short getport_gotit
+
+getport_userwontallow:
+ stc
+
+getport_gotit:
+ pop di
+
+getport_exit:
+ ret
+
+GetPort386 endp
+
+;----------------------------Private-Routine----------------------------;
+;
+; ReleasePort386
+;
+; If running under Win386, tell the VPD to deassign an LPT port.
+;
+; entry - DS:SI -> COMDEB
+;
+
+ReleasePort386 proc near
+
+ cmp fVPD, 1
+ jne release_noVPD
+
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ and cl, NOT LPTx ; clear high bit
+ mov dx, VPD_RELPORT
+ call [lpfnVPD]
+
+release_noVPD:
+ ret
+
+ReleasePort386 endp
+
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetCOMport386
+;
+; If running under Win386, tell the VCD to assign a COM port to us.
+; The comm driver will handle contention.
+;
+; entry - DS:SI -> COMDEB
+;
+; exit - registers saved, carry = clear if OK to proceed, set if
+; user won't allow assignment of port or Win386 error
+;
+.386
+GetCOMport386 proc near
+public GetCOMport386
+
+ push es
+ pushad
+ cmp fVCD, 0
+ jl short getcomport_VCDNotInstalled
+ jnz short getcomport_CallVCD
+
+ mov bx, VCD
+ mov di, DataOFFSET lpfnVCD
+ call Get_API_Entry
+ jz short getcomport_checknoVCD
+
+ mov dx, VCD_GETVER
+ call [lpfnVCD]
+ cmp ax, 30Ah ;Q: 3.1 or greater?
+ jae short getcomport_CallVCD ; Y:
+
+getcomport_checknoVCD:
+ mov fVCD, -1
+
+getcomport_VCDNotInstalled:
+ clc
+ jmp short getcomport_exit
+
+getcomport_CallVCD:
+ mov fVCD, 1
+
+ mov ax, 10b ; flag ring0 int handler
+ call VCD_GetPort_API
+ jnc short getcomport_success ; jump if acquire worked
+ jnz short getcomport_noport ; jump if port doesn't exist
+
+; port owned by another VM... ask the user for it
+
+ mov cl, [si.DCB_id]
+ add cl, '1' ; fix up the port name...
+ mov pCOMByte, cl
+ lea cx, szCOMMessage
+ call Contention_Dlg
+ stc
+ jnz short getcomport_exit
+
+ mov ax, 11b ; tell win386 we really do want it
+ call VCD_GetPort_API
+ jc short getcomport_exit
+
+getcomport_success:
+ mov dword ptr [VCD_int_callback], edi
+ mov word ptr [VCD_int_callback+4], cx
+ mov [si.VCD_data], ebx
+ xchg ax, [si.Port]
+ or ax, ax ;Q: already had port base?
+ jnz short getcomport_exit ; Y: don't update vector #, or FIFO
+ mov [si.IntVecNum], dl
+ call GetPortFlags
+ clc
+
+getcomport_exit:
+ popad
+ pop es
+ ret
+
+getcomport_noport:
+ mov [si.Port], -1
+ jmp getcomport_exit
+
+GetCOMport386 endp
+
+VCD_GetPort_API proc near
+ mov dx, VCD_GETPORT
+ xor cx, cx
+ mov cl, [si.DCB_Id] ; cx = port #
+ mov di, VCDflags ; offset from start of DEB
+ call [lpfnVCD]
+ ret
+VCD_GetPort_API endp
+.8086
+
+;----------------------------Private-Routine----------------------------;
+;
+; ReleaseCOMport386
+;
+; If running under Win386, tell the VCD to deassign a COM port.
+;
+; entry - DS:SI -> COMDEB
+;
+
+ReleaseCOMport386 proc near
+
+ifndef WOW
+ cmp fVCD, 1
+ jne release_noVCD
+
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ mov dx, VCD_RELPORT
+ call [lpfnVCD]
+else
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ push cx
+ call WowCloseComPort
+endif
+
+release_noVCD:
+ ret
+
+ReleaseCOMport386 endp
+
+PUBLIC StealPort
+StealPort proc near
+
+ cmp fVCD, 1
+ jne sp_yes
+ mov dx, VCD_STEALPORT
+ xor cx, cx
+ mov cl, [si.DCB_id]
+ call [lpfnVCD]
+ or al, al
+ jnz sp_yes
+
+sp_no:
+ stc
+ ret
+
+sp_yes:
+ clc
+ mov [si.VCDflags], 0
+ ret
+
+StealPort endp
+
+page
+
+;------------------------------------------------------------------------------
+;
+; ENTER: DS:SI -> ComDEB
+; EXIT: AL = 0, if IRQ was unmasked, else -1, if IRQ was already masked
+;
+MaskIRQ proc near
+ push es
+ push di
+ mov di, ds
+ mov es, di
+ lea di, [si+SIZE ComDEB]
+ mov ax, BIH_API_Get_Mask
+ call APIHandler ; returns Carry Set, if masked
+ jc short already_masked
+ pushf
+ mov ax, BIH_API_Mask
+ call APIHandler ; mask IRQ
+ xor ax, ax
+ popf
+ jnc short mask_exit
+already_masked:
+ or al, -1
+mask_exit:
+ pop di
+ pop es
+ ret
+MaskIRQ endp
+
+;------------------------------------------------------------------------------
+;
+; ENTER: DS:SI -> ComDEB
+;
+UnmaskIRQ proc near
+ push es
+ push di
+ mov di, ds
+ mov es, di
+ lea di, [si+SIZE ComDEB]
+ mov ax, BIH_API_Unmask
+ call APIHandler
+ pop di
+ pop es
+ ret
+UnmaskIRQ endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $INICOM - Initialize A Port
+;
+; Initalizes the requested port if present, and sets
+; up the port with the given attributes when they are valid.
+; This routine also initializes communications buffer control
+; variables. This routine is passed the address of a device
+; control block.
+;
+; The RLSD, CTS, and DSR signals should be ignored by all COM
+; routines if the corresponding timeout values are 0.
+;
+; For the LPT ports, a check is performed to see if the hardware
+; is present (via the LPT port addresses based at 40:8h. If the
+; port is unavailable, an error is returned. If the port is
+; available, then the DEB is set up for the port. $SETCOM will
+; be called to set up the DEB so that there will be something
+; valid to pass back to the caller when he inquires the DEB.
+;
+; No hardware initialization will be performed to prevent the
+; RESET line from being asserted and resetting the printer every
+; time this routine is called.
+;
+; Entry:
+; EX:BX --> Device Control Block with all fields set.
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = initialization error code otherwise
+; Registers Preserved:
+; None
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $INICOM
+$INICOM proc near
+ push si ;As usual, save register variables
+ push di
+ mov ah,es:[bx.DCB_Id] ;Get device i.d.
+ call GetDEB ;--> DEB for this device
+ mov ax, IE_BADID ; call it a bad id (spooler uses DOS)
+ jc InitCom15 ;Invalid device
+ jns InitCom20 ; jmp if COM port
+
+ push ds
+
+ mov di, [si.BIOSPortLoc]
+ cmp di, LPTB
+ jb short InitLPT_Installed
+
+ mov cx,__0040H ;[rkh] ...
+ mov ds,cx ;Point DS: at ROM Save Area.
+ assumes ds,nothing
+
+ mov ax, IE_HARDWARE
+ mov cx, wo [di]
+ jcxz InitCom10 ; if zero, no hardware
+
+ mov ax,IE_BadID ;Show bad device
+ cmp ch, 0 ; zero hibyte -> not valid (redir)
+ jz InitCom10 ; call it a bad id (spooler uses DOS)
+
+ cmp di, LPTB ; LPT1?
+ jz InitLPT_Installed ; yes, must be installed
+
+ cmp cx, wo [di-2] ;Q: duplicate of previous port
+ je InitCom10 ; Y: (redirected port)
+
+InitLPT_Installed:
+ pop ds
+ mov [si.Port], cx
+ call $SETCOM
+ call GetPort386 ; tell win386 we're using the port
+ mov ax, IE_OPEN ; port already open (by another VM)
+ jc InitCom15 ; error
+ jmp InitCom90 ;That's all
+
+InitCom10:
+ pop ds ; get DS back
+InitCom15:
+ jmp InitCom100
+
+
+ assumes ds,Data
+InitCom17:
+ mov ax, IE_OPEN
+ cmp [si.Port], -1 ;Q: determined that port didn't exist?
+ jne InitCom15 ; N: return IE_OPEN
+ jmp short InitCom27 ; Y: return IE_HARDWARE
+
+; *** Set up serial port ***
+;
+InitCom20:
+ cmp [si.Port], -1 ;Q: port exists?
+ je InitCom27 ; N: report not found
+
+ mov ax, __WinFlags
+ test ax, WF_ENHANCED
+ jz short @F
+ call GetCOMport386
+ jc InitCom17
+
+@@:
+ cmp [si.Port], 0 ;Q: already got info?
+ jnz @F
+ call FindCOMPort
+ jc InitCom27 ; report not found, if error
+ mov [si.Port], ax
+ mov [si.IntVecNum], dl
+@@:
+
+ push es ;Save these registers
+ push di
+ push cx ;needed later for $SETCOM etc
+ push bx
+
+ mov al, [si.IntVecNum]
+ xor ah, ah
+ lea di, [si+SIZE ComDEB]
+ mov [di.BIS_IRQ_Number], ax
+
+ mov di, DataOFFSET IRQhooks
+ mov cx, MAXCOM+1
+InitCom25:
+ cmp al, [di.IRQn] ;Q: hooked IRQ matches ours?
+ je short InitCom30 ; Y:
+ cmp [di.IRQn], 0 ;Q: end of hooked IRQ list?
+ je short InitCom35 ; Y:
+ add di, SIZE IRQ_Hook_Struc ; N: check next hook
+ loop InitCom25
+ int 3 ; data structures corrupt if we
+ ; get here, because no hook table
+ ; entries exist and there is suppose
+ ; to be at least 1 for each DEB
+InitCom26:
+ call ReleaseCOMport386 ; give port back to 386...
+ pop bx
+ pop cx
+ pop di
+ pop es
+
+InitCom27:
+ mov ax, IE_HARDWARE ; jump if port not available
+ jmp InitCom100
+
+InitCom30:
+ cmp [di.HookCnt], 0 ;Q: IRQ still hooked?
+ je short InitCom35 ; N: rehook
+ inc [di.HookCnt] ; Y: inc hook count
+ mov [si.IRQhook], di ; & link DEB into list
+ mov ax, [di.First_DEB]
+ mov [si.NextDEB], ax
+ mov [di.First_DEB], si
+ jmp short InitCom40
+
+InitCom35:
+ mov [di.IRQn], al ; hook IRQ for first time, or rehook
+ mov [si.IRQhook], di
+ mov [di.First_DEB], si
+ mov [di.HookCnt], 1
+ call MaskIRQ
+ mov [di.OldMask], al
+
+InitCom40: ; di -> IRQ_Hook_Struc
+
+ cmp [fVPICD], 0 ;Q: VPICD bimodel services available?
+ jl short InitCom415 ; N:
+ mov ax, ds ; Y: use them
+ mov es, ax
+ lea di, [si+SIZE ComDEB]
+
+ mov [di.BIS_Descriptor_Count], 2
+ mov ax, word ptr [si.QInAddr+2] ; get selector of in queue
+ mov [di.EBIS_Sel1.EBIS_User_Mode_Sel], ax
+ mov ax, word ptr [si.QOutAddr+2] ; get selector of out queue
+ mov [di.EBIS_Sel2.EBIS_User_Mode_Sel], ax
+
+ mov ax, VPICD_Install_Handler
+ call [lpfnVPICD]
+ jnc InitCom42
+ cmp [di.OldMask], 0
+ jne InitCom26
+ call UnmaskIRQ
+ jmp InitCom26
+
+InitCom42:
+;
+; save newly allocated selectors/segments into "Alt" queue pointers
+;
+ mov ax, [di.EBIS_Sel1.EBIS_Super_Mode_Sel]
+ mov word ptr [si.AltQInAddr+2], ax
+ mov ax, [di.EBIS_Sel2.EBIS_Super_Mode_Sel]
+ mov word ptr [si.AltQOutAddr+2], ax
+
+InitCom414:
+ jmp InitCom59
+
+InitCom415:
+ cmp [di.VecN], 0FFh ;Q: int already hooked?
+IFDEF No_DOSX_Bimodal_Services
+ jnz short InitCom52 ; Y: init RMode ptrs in BIS
+ELSE
+ jnz InitCom414 ; Y:
+ENDIF
+ mov al, [si.IntVecNum]
+ add al, 8 ; 1st PIC starts at vector 8h
+ cmp al, 16 ;Q: 2nd PIC?
+ jb short InitCom418 ; N:
+ add al, 70h-16 ; Y: 2nd PIC starts at vector 70h
+InitCom418:
+ mov [di.VecN], al
+
+; *** Set interrupt vectors ***
+;
+ mov ah,35h ;Get the DOS vector
+ int 21h ;DOS Get Vector Function
+ mov wo [di.OldIntVec][0], bx
+ mov wo [di.OldIntVec][2], es
+
+InitCom50:
+ push ds ;Save original DS
+ mov dx, [di.HandlerOff]
+ mov bx, _INTERRUPT
+ mov ds, bx ;Interrupt handler address in ds:dx
+ assumes ds,nothing
+ mov ah, 25h ;DOS Set Vector Function
+ int 21h ;Set the DOS vector
+ pop ds ;Original DS
+ assumes ds,Data
+
+IFDEF No_DOSX_Bimodal_Services
+InitCom52:
+ cmp [Using_DPMI], 0
+ jz short InitCom57
+
+ mov ax, Int31_Get_Version SHL 8
+ int 31h
+ mov bl, [si.IntVecNum]
+ mov bh, bl
+ add bl, dh ; assume master PIC
+ sub bh, 8 ;Q: IRQ in master?
+ jb @f ; Y: add master's base vec
+ add bh, dl ; N: add slave's base vec
+ mov bl, bh
+@@:
+ mov ax, Get_RM_IntVector
+ int 31h
+ mov wo [di.RM_OldIntVec][0], dx
+ mov wo [di.RM_OldIntVec][2], cx
+
+ mov dx, [di.RM_HandlerOff]
+ mov ax, _INTERRUPT
+ call SegmentFromSelector
+ mov cx, ax
+ push cx
+ mov ax, Set_RM_IntVector
+ int 31h
+
+ lea di, [si+SIZE ComDEB]
+ mov wo [di.BIS_Super_Mode_API], IntCodeOFFSET RM_APIHandler
+ pop cx
+ mov wo [di.BIS_Super_Mode_API+2], cx
+
+;
+; Get segment addresses for the Q's and set AltQInAddr and AltQOutAddr
+;
+ mov ax, wo [si.AltQInAddr+2]
+ call SegmentFromSelector
+ mov wo [si.AltQInAddr+2], ax
+ mov ax, wo [si.AltQOutAddr+2]
+ call SegmentFromSelector
+ mov wo [si.AltQOutAddr+2], ax
+InitCom57:
+ENDIF
+ mov ax, __WinFlags ;In Standard mode, the PIC IRQ
+ test al, WF_STANDARD ; priorities get rotated to favor
+ jz InitCom59 ; the comm ports.
+
+ call Rotate_PIC
+
+; *** Interrupt handler set : jump here if handler is already installed ***
+;
+InitCom59:
+ pop bx
+ pop cx
+ pop di
+ pop es
+
+InitCom60:
+ mov dx,[si.Port] ;Set comm card address
+ xor ax,ax ;Need a zero
+ inc dx ;--> Interrupt Enable Register
+ .errnz ACE_IER-ACE_RBR-1
+ out dx,al ;Turn off interrupts
+ call FlagNotActive
+ add dl,ACE_MCR-ACE_IER ;--> Modem Control Register
+ in al,dx
+ and al,ACE_DTR+ACE_RTS ;Leave DTR, RTS high if already so
+ iodelay ; but tri-state IRQ line
+ out dx,al
+
+InitCom70:
+ push es ;Zero queue counts and indexes
+
+ push ds
+ pop es
+ assumes es,Data
+
+ lea di,QInCount[si]
+ mov cx,(EFlags-QInCount)/2
+ .errnz (EFlags-QInCount) AND 1
+ xor ax,ax
+ cld
+ rep stosw
+
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+ .errnz EFlags-QOutPut-2 ;First non-queue item
+
+ pop es
+ assumes es,nothing
+
+ mov HSFlag[si],al ;Show no handshakes yet
+ mov MiscFlags[si],al ;Show not discarding
+ mov EvtWord[si],ax ;Show no events
+ mov [si.VCDflags], al
+
+ mov [si.SendTrigger], ax
+ dec ax
+ mov [si.RecvTrigger], ax
+
+;Call $SETCOM to perform further hardware initialization.
+
+InitCom80:
+ sub dl,ACE_MCR-ACE_FCR ; dx -> FCR
+ in al, dx
+ iodelay
+ test al, ACE_FIFO_E2 ;Q: FIFO already on?
+ jz short @F ; N:
+ or EFlags[si], fFIFOpre ; Y: flag it
+@@:
+
+ ; needs si, di, and es to be saved from the beginning of inicom
+ call $SETCOM ;Set up Comm Device
+ jnz short InitCom110 ;jump if failed
+
+ call UnmaskIRQ
+ and EFlags[si], fEFlagsMask ;Clear internal state
+
+InitCom90:
+ xor ax,ax ;Return AX = 0 to show success
+ mov ComErr[si],ax ;Get rid of any bogus init error
+
+InitCom100:
+ pop di
+ pop si
+ ret
+
+;
+; jump to here, if call to $SETCOM failed
+;
+; DANGER! *** Call into middle of Terminate to clean things up *** DANGER!
+;
+InitCom110:
+ push ax ;Failure, save error code
+ call Terminate45 ;Restore port address, int vec
+ pop ax ;Restore error code and exit
+ jmp InitCom100
+
+$INICOM endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $TRMCOM - Terminate Communications Channel
+;
+; Wait for any outbound data to be transmitted, drop the hardware
+; handshaking lines, and disable interrupts. If the output queue
+; contained data when it was closed, an error will be returned
+;
+; LPT devices have it easy. They just need to restore the I/O port
+; address.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = 8000h if invalid device ID
+; AX = -2 if output queue timeout occured
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $TRMCOM
+$TRMCOM proc near
+
+ push si
+ push di
+ xor cx,cx ;Show no error if LPT port
+ call GetDEB
+ jc TermCom60 ;ID is invalid, return error
+ js TermCom30 ;Port is a LPT port
+
+ push ax ;Save port id
+ or MiscFlags[si],Discard ;Show discarding serial data
+ mov ComErr[si],cx ;Clear error flags
+ mov QInCount[si],cx ;Show no chars in input queue
+ call $RECCOM ;Send XON if needed
+
+;-----------------------------------------------------------------------;
+; We have to wait for the output queue to empty. To do this,
+; a timer will be created. If no character has been transmitted
+; when the timeout occurs, then an error will be indicated and
+; the port closed anyway. If the timer cannot be created, then
+; just loop until the queue empties, which will be better than
+; discarding charatcers if there are any
+;-----------------------------------------------------------------------;
+
+ test [si.HSFlag], HHSAlwaysDown ; Q: handshaking ever up?
+ jnz TermCom17 ; N: skip wait loop
+
+TermCom10:
+ mov cx,QOutCount[si] ;Get current queue count
+ jcxz TermCom20 ;No characters in queue
+
+ cCall GetSystemMsecCount
+ mov di, ax
+
+TermCom15:
+ cmp QOutCount[si],cx ;Queue count change?
+ jne TermCom10 ; Yes, restart timeout
+
+ cCall GetSystemMsecCount
+ sub ax, di
+ cmp ax, Timeout * 1000 ;Q: Timeout reached?
+ jb TermCom15 ; No, keep waiting
+
+IFDEF DEBUG_TimeOut
+.286
+ pusha
+ lea cx, szSendTO
+ call Contention_Dlg
+ popa
+ jz TermCom10
+.8086
+ENDIF
+
+TermCom17:
+ mov cx, TimeoutError ; Yes, show timeout error
+
+TermCom20:
+ pop ax ;Restore cid
+
+TermCom30:
+ mov dx,Port[si] ;Get port base address
+ call Terminate ;The real work is done here
+ mov ax,cx ;Set return code
+
+TermCom60:
+ pop di
+ pop si
+ ret
+
+$TRMCOM endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; Terminate - Terminate Device
+;
+; Restore the port I/O address and make sure that interrupts are off
+;
+; Entry:
+; AH = Device Id.
+; DX = Device I/O port address.
+; SI --> DEB
+; Returns:
+; AX = 0
+; Error Returns:
+; AX = -1
+; Registers Destroyed:
+; AX,BX,DX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public Terminate ;Public for debugging
+Terminate proc near
+
+ or ah,ah ;LPT port?
+ jns Terminate10 ; No, process COM port
+ .errnz LPTx-10000000b
+
+Terminate5:
+ call ReleasePort386 ; give port back to 386...
+ jmp Terminate50 ;That's all
+
+
+;-----------------------------------------------------------------------;
+; It is a com port!
+;
+; We delay for a bit while the last character finishes transmitting
+; Then we drop DTR and RTS, and disable the interrupt generation at
+; the 8250. Even if fRTSDisable or fDTRDisable is set, those lines
+; will be dropped when the port is closed.
+;-----------------------------------------------------------------------;
+;
+; When the OUT2 bit is reset to 0 to disable interrupts, many ports
+; generate an interrupt which can not be identified, because the the
+; interrupt ID register will not be set. To work around this hardware
+; problem we first mask the IRQ, then set the port into loopback mode
+; and output a NULL to generate a receive interrupt request. Then we
+; reset OUT2 and unmask the IRQ. This will cause the interrupt to occur
+; and the interrupt handler will be able to correctly identify the
+; interrupt as coming from the com port.
+
+Terminate10:
+ inc dx ;Disable chip interrupts
+ .errnz ACE_IER-ACE_RBR-1
+ mov al, ACE_ERBFI ; except receive
+ out dx,al
+ call FlagNotActive ; don't need to check for postmessage
+ ; on timer ticks
+ add dl,ACE_LSR-ACE_IER ;--> line status register
+ iodelay
+
+Terminate20:
+ in al,dx ;Wait until xmit is empty
+ and al,ACE_THRE+ACE_TSRE
+ cmp al,ACE_THRE+ACE_TSRE
+ jne Terminate20 ;Not empty yet
+
+Terminate30:
+ xor al, al
+ test EFlags[si], fFIFOpre ;Q: leave FIFO enabled?
+ jz short @F ; N:
+ mov al, ACE_TRIG14 OR ACE_EFIFO OR ACE_CRFIFO OR ACE_CTFIFO
+@@:
+ sub dl, ACE_LSR-ACE_FCR
+ out dx, al
+ iodelay
+ call MaskIRQ
+ add dl, ACE_MCR-ACE_FCR ;--> Modem Control Register
+ in al,dx
+ iodelay
+ mov ah, al
+ or al,ACE_LOOP ; turn on loopback
+ out dx, al
+ iodelay
+ sub dl, ACE_MCR-ACE_THR
+ xor al, al
+ out dx, al ; output a NULL to generate an int
+ iodelay
+ add dl, ACE_LSR-ACE_THR
+Terminate35:
+ in al,dx ;Wait until xmit is empty
+ and al,ACE_THRE+ACE_TSRE
+ cmp al,ACE_THRE+ACE_TSRE
+ jne Terminate35 ;Not empty yet
+ mov al, ah
+ dec dl ; now clear OUT2 and loopback
+ .errnz ACE_LSR-ACE_MCR-1
+ and al,ACE_DTR+ACE_RTS ;Leave DTR, RTS high if already so
+ out dx,al ; but tri-state IRQ line
+
+ call UnmaskIRQ ; this will cause the receive int
+ ; to occur and be processed
+ sub dl, ACE_MCR-ACE_IER ; clear the receive int enable
+ xor al, al
+ out dx, al
+ dec dx
+ .errnz ACE_IER-ACE_RBR-1
+ call MaskIRQ
+
+;******* DANGER! ***** NOTICE! ***** DANGER! ***** WARNING! ***** NOTICE!
+;
+; Terminate45 is a secondary entrypoint into this routine--it's called
+; by the initialization code when that code is unable to properly init
+; a com port and needs to clean-up the mess it's made.
+;
+;******* DANGER! ***** NOTICE! ***** DANGER! ***** WARNING! ***** NOTICE!
+
+Terminate45:
+ push cx ;Save original cx
+ push bx ;Save original bx
+
+ cmp [fVPICD], 0 ;Q: VPICD bimodel services available?
+ jl short @F ; N:
+ mov ax, ds ; Y: use them
+ mov es, ax
+ lea di, [si+SIZE ComDEB]
+ mov ax, VPICD_Remove_Handler
+ call [lpfnVPICD]
+@@:
+
+ mov di, [si.IRQhook]
+ dec [di.HookCnt] ;Q: last port using IRQ?
+ jne short Terminate495 ; N: unmask IRQ again
+ mov al, 0FFh
+ xchg al, [di.VecN] ;Interrupt vector number
+ cmp al, 0FFh ;Q: IRQ vector hooked?
+ je short Terminate49 ; no...
+
+IFDEF No_DOSX_Bimodal_Services
+ cmp [Using_DPMI], 0
+ jz short term_no_dpmi
+
+;
+; unhook RM vector thru DPMI for standard mode
+;
+ push ax
+ mov ax, Int31_Get_Version SHL 8
+ int 31h
+ mov bl, [si.IntVecNum]
+ mov bh, bl
+ add bl, dh ; assume master PIC
+ sub bh, 8 ;Q: IRQ in master?
+ jb @f ; Y: add master's base vec
+ add bh, dl ; N: add slave's base vec
+ mov bl, bh
+@@:
+ mov dx, wo [di.RM_OldIntVec][0]
+ mov cx, wo [di.RM_OldIntVec][2]
+ mov ax, Set_RM_IntVector
+ int 31h
+ pop ax
+term_no_dpmi:
+ENDIF
+ mov dx, __WinFlags ;In Standard mode the PIC interrupt
+ test dl, WF_STANDARD ; priorities are changed to favor
+ jz Terminate48 ; the comm ports.
+
+ call Rotate_PIC ;This port no longer needs priority
+
+Terminate48:
+ ; *** reset int vector to it's previous state
+ assumes ds,nothing
+ push ds ;Save original DS [rkh] ...
+ lds dx, [di.OldIntVec]
+ mov ah, 25h ;DOS Set Vector Function
+ int 21h ;Set the DOS vector
+ pop ds ;Original DS
+ assumes ds,data
+
+; *** interrupt vectors have been reset if needed at this point ***
+;
+Terminate49:
+ mov cl, [di.OldMask]
+
+; Set the 8259 interrupt mask bit for this IRQ. Leave interrupts enabled
+; if they were already enabled when the comm port was initialized by us.
+
+ or cl, cl
+ jnz @f
+Terminate495:
+ call UnmaskIRQ
+@@:
+
+ xor ax, ax
+ xchg ax, [si.NextDEB]
+ cmp [di.First_DEB], si ;Q: DEB first for IRQ hook?
+ je short Terminate46 ; Y:
+ mov bx, [di.First_DEB] ; N: get first
+Terminate453:
+ cmp [bx.NextDEB], si ;Q: does this DEB point to one terminating?
+ je Terminate455 ; Y:
+ mov bx, [bx.NextDEB] ; N: get next DEB
+ jmp Terminate453
+Terminate455:
+ mov [bx.NextDEB], ax ; link previous DEB to NextDEB
+ jmp short Terminate47
+Terminate46:
+ mov [di.First_DEB], ax ; point IRQ hook at NextDEB
+Terminate47:
+ pop bx ;Original BX
+
+ call ReleaseCOMport386 ; give port back to 386...
+
+ pop cx ;Original CX
+
+Terminate50: ;Also called from $INICOM !
+ xor ax,ax ;Indicate no error
+ ret ;Port is closed and deallocated
+
+Terminate endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $ENANOTIFY - Enable Event Notification
+;
+; Entry:
+; AH = Device ID
+; BX = Window handle for PostMessage
+; CX = Receive threshold
+; DX = Transmit threshold
+; Returns:
+; AX = 1, if no errors occured
+; Error Returns:
+; AX = 0
+; Registers Preserved:
+; BX,SI,DI,DS
+; Registers Destroyed:
+; AX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $ENANOTIFY
+$ENANOTIFY proc near
+ push si
+ call GetDEB
+ mov ax, 0
+ jc scb_exit
+
+ mov ax, cx
+ inc ax
+ jz short scb_recv_ok
+ cmp cx, [si.QInSize] ;Q: receive threshold reasonable?
+ jb short scb_recv_ok ; Y:
+%OUT should we return an error, if thresholds invalid?
+ mov cx, [si.QInSize] ; N:
+ sub cx, 10
+scb_recv_ok:
+ inc dx
+ jz short scb_send_ok
+ dec dx
+ cmp dx, [si.QOutSize] ;Q: receive threshold reasonable?
+ jb short scb_send_ok ; Y:
+ mov dx, [si.QOutSize] ; N:
+ sub dx, 10
+scb_send_ok:
+ mov [si.NotifyHandle], bx
+ mov [si.NotifyFlagsHI], CN_Notify
+ or bx, bx ;Q: null callback?
+ jnz scb_save_thresholds ; N: save thresholds
+ or cx, -1 ; Y: zero thresholds
+ xor dx, dx
+ mov [si.NotifyFlagsHI], 0
+scb_save_thresholds:
+ mov [si.RecvTrigger], cx
+ mov [si.SendTrigger], dx
+ or [si.NotifyFlagsHI], CN_TRANSMIT ; we don't want to send
+ ; a transmit trigger notification until
+ ; the transmit buffer has been filled
+ ; above the trigger level and then
+ ; emptied below it again!
+
+ cmp wo lpPostMessage[2], 0 ;Q: gotten addr of PostMessage yet?
+ jne short scb_good ; Y:
+ push ds ; N: get module handle of USER
+ lea ax, szUser
+ push ax
+ cCall GetModuleHandle
+
+ push ax ; module handle
+ mov ax, POSTMESSAGE
+ cwd
+ push dx
+ push ax
+ cCall GetProcAddress
+ mov wo lpPostMessage[0], ax ; save received proc address
+ mov wo lpPostMessage[2], dx
+
+scb_good:
+ mov ax, 1
+
+scb_exit:
+ pop si
+ ret
+$ENANOTIFY endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SETQUE - Set up Queue Pointers
+;
+; Sets pointers to Receive and Transmit Queues, as provided by the
+; caller, and initializes those queues to be empty.
+;
+; Queues must be set before $INICOM is called!
+;
+; Entry:
+; AH = Device ID
+; ES:BX --> Queue Definition Block
+; Returns:
+; AX = 0 if no errors occured
+; Error Returns:
+; AX = error code
+; Registers Preserved:
+; BX,DX,SI,DI,DS
+; Registers Destroyed:
+; AX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SETQUE
+$SETQUE proc near
+
+ push si ;These will be used
+ push di
+ call GetDEB ;Get DEB
+ jc SetQue10 ;Invalid, ignore the call
+ js SetQue10 ;Ignore call for LPT ports
+ push ds ;Set ds:si --> QDB
+ push es ;Set es:di --> to ComDCB.QInAddr
+ pop ds
+ assumes ds,nothing
+ pop es
+ assumes es,Data
+ lea di,QInAddr[si]
+ mov si,bx
+ cld
+ FCLI ;No one else can play with queues
+ movsw ; QInAddr = QueueRxAddr
+ movsw
+ .errnz QueueRxAddr
+ sub si, 4 ; AltQInAddr = QueueRxAddr
+ mov cx, 5 ; QInSize = QueueRxSize
+ rep movsw ; QOutAddr = QueueTxAddr
+ sub si, 4
+ mov cx, 3 ; AltQOutAddr = QueueTxAddr
+ rep movsw ; QOutSize = QueueTxSize
+
+ xor ax,ax ;Will do some zero filling
+ mov cl,(EFlags-QInCount)/2
+ .errnz (EFlags-QInCount) AND 0FE01h
+ rep stosw
+ FSTI
+ push es ;Restore the data segment
+ pop ds
+ assumes ds,Data
+ assumes es,nothing
+
+SetQue10:
+ pop di ;Restore saved registers
+ pop si
+ ret
+
+; The above code made a few assumptions about how memory
+; was allocated within the structures:
+
+ .errnz AltQInAddr-QInAddr-4
+ .errnz (QueueRxSize-QueueRxAddr)-(QInSize-AltQInAddr)
+ .errnz (QueueTxAddr-QueueRxSize)-(QOutAddr-QInSize)
+ .errnz AltQOutAddr-QOutAddr-4
+ .errnz (QueueTxSize-QueueTxAddr)-(QOutSize-AltQOutAddr)
+
+ .errnz QueueRxSize-QueueRxAddr-4
+ .errnz QueueTxAddr-QueueRxSize-2
+ .errnz QueueTxSize-QueueTxAddr-4
+
+ .errnz QInSize-AltQInAddr-4
+ .errnz QOutAddr-QInSize-2
+ .errnz QOutSize-AltQOutAddr-4
+
+ .errnz QInCount-QOutSize-2
+ .errnz QInGet-QInCount-2
+ .errnz QInPut-QInGet-2
+ .errnz QOutCount-QInPut-2
+ .errnz QOutGet-QOutCount-2
+ .errnz QOutPut-QOutGet-2
+ .errnz EFlags-QOutPut-2 ;First non-queue item
+
+$SETQUE endp
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $SETCOM - Set Communications parameters
+;
+; Re-initalizes the requested port if present, and sets up the
+; port with the given attributes when they are valid.
+;
+; For LPT ports, just copies whatever is given since it's ignored
+; anyway.
+;
+; Entry:
+; ES:BX --> DCB with all fields set.
+; Returns:
+; 'Z' Set if no errors occured
+; AX = 0
+; Error Returns:
+; 'Z' clear if errors occured
+; AX = initialization error code.
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public $SETCOM
+$SETCOM proc near
+
+ cld
+ push si
+ push di
+ mov ah,es:[bx.DCB_Id] ;Get device i.d.
+ call GetDEB ;Get DEB pointer in SI
+ mov ax,IE_BadID ;Assume unknown device
+ jc SetCom10 ;Invalid device, return error
+ jns SetCom20 ;COM port
+ call SetCom100 ;Copy the DCB
+
+SetCom5:
+ xor ax,ax ;Show no error
+
+SetCom10:
+ or ax,ax ;Set/clear 'Z'
+ pop di ; and exit
+ pop si
+ ret
+
+;-----------------------------------------------------------------------;
+; Have a comm device, check all the serial parameters to make
+; sure they are correct before moving the new DCB into our space
+; and changing the ACE parameters.
+;-----------------------------------------------------------------------;
+
+SetCom20:
+ call SetCom300 ;Baud rate valid?
+ jcxz SetCom10 ; No, return error
+ call SetCom400 ;Byte size/parity/stop bits correct?
+ jc SetCom10 ; No, return error
+
+; The parameters seem correct. Copy the DCB into our space and
+; initialize the ACE with the new parameters
+
+ mov dx,Port[si] ;Disable interrupts from the 8250
+ inc dx
+ .errnz ACE_IER-1
+ xor ax,ax
+ out dx,al
+ call FlagNotActive
+
+ call SetCom100 ;Copy the DCB
+ mov bx,si ;Set ES:BX --> DCB
+ call SetCom200 ;Get timeout masks
+ xchg al,ah ;Want them in the correct registers
+ mov wo MSRMask[si],ax
+ .errnz MSRInfinite-MSRMask-1
+
+ call SetCom400 ;Get line control byte
+ push ax ; and save LCR value
+ inc dx ;--> LCR
+ inc dx
+ .errnz ACE_LCR-ACE_IER-2
+ or al,ACE_DLAB ;Want access to divisor latch
+ out dx,al
+ mov RxMask[si],ah ;Save Receive character mask
+ mov ax,di ;Get flags mask, error mask
+ and [si.DCB_Flags],ah ;Disable parity checking if no parity
+ mov ErrorMask[si],al ;Save line status error mask
+
+ call SetCom300 ;Get baud rate
+ sub dl,ACE_LCR-ACE_DLL ;--> LSB of divisor latch
+ mov al,cl
+ out dx,al
+ mov al,ch
+ inc dx ;--> MSB of divisor latch
+ .errnz ACE_DLM-ACE_DLL-1
+ iodelay
+ out dx,al
+ inc dx ;--> LCR and clear divisor access bit
+ inc dx
+ .errnz ACE_LCR-ACE_DLM-2
+ pop ax
+ out dx,al
+
+ inc dx ;--> Modem Control Register
+ .errnz ACE_MCR-ACE_LCR-1
+
+;-----------------------------------------------------------------------;
+; Compute initial state of DTR and RTS. If they have been disabled,
+; then do not raise them, and disallow being used as a handshaking
+; line. Also compute the bits to use as hardware handshake bits
+; (DTR and/or RTS as indicated, qualified with the disabled flags).
+;-----------------------------------------------------------------------;
+
+ mov al,[si.DCB_Flags] ;Align DTR/RTS disable flags for 8250
+ and al,fRTSDisable+fDTRDisable
+ rol al,1 ;d0 = DTR, d2 = RTS (1 = disabled)
+ shr al,1 ;'C'= DTR, d1 = RTS
+ adc al,0 ;d0 = DTR, d1 = RTS
+ .errnz fRTSDisable-00000010b
+ .errnz fDTRDisable-10000000b
+ .errnz ACE_DTR-00000001b
+ .errnz ACE_RTS-00000010b
+
+ mov ah,al ;Save disable mask
+ xor al,ACE_DTR+ACE_RTS+ACE_OUT2
+ out dx,al ;Set Modem Control Register
+
+ mov al,[si.DCB_Flags2] ;Get hardware handshake flags
+ rol al,1 ;Align flags as needed
+ rol al,1
+ rol al,1
+ and al,ACE_DTR+ACE_RTS ;Mask bits of interest
+ not ah ;Want inverse of disable mask
+ and al,ah ;al = bits to handshake with
+ mov HHSLines[si],al ;Save for interrupt code
+
+ .errnz fDTRFlow-00100000b
+ .errnz fRTSFlow-01000000b
+ .errnz ACE_DTR-00000001b
+ .errnz ACE_RTS-00000010b
+
+ mov al,[si.DCB_Flags] ;Compute the mask for the output
+ shl al,1 ; hardware handshake lines
+ and al,ACE_DSR+ACE_CTS
+ mov OutHHSLines[si],al
+
+ .errnz fOutXCTSFlow-00001000b
+ .errnz fOutXDSRFlow-00010000b
+ .errnz ACE_CTS-00010000b
+ .errnz ACE_DSR-00100000b
+
+; Compute the queue count where XOff should be issued (or hardware
+; lines dropped). This will prevent having to do it at interrupt
+; time.
+
+ mov ax,QInSize[si] ;Get where they want it
+ sub ax,[si.DCB_XoffLim] ; and compute queue count
+ mov XOffPoint[si],ax
+
+; Enable FIFO if possible when baudrate >= 4800
+;
+ sub dl,ACE_MCR - ACE_FCR ; dx = FCR
+ test EFlags[si], fNoFIFO ;Q: FIFO can be enabled?
+ jnz sc_nofifo ; N:
+ mov ax, [si.DCB_BaudRate]
+ cmp ax, 4800
+ jb sc_nofifo
+ cmp ah, -1 ;Q: baudrate index?
+ jne sc_fifo ; N: baudrate >= 4800, enable FIFO
+ cmp ax, CBR_4800
+ jb sc_nofifo
+%OUT this isn't correct, if lower baudrates are assigned indices above CBR_4800
+
+sc_fifo:
+ mov al, ACE_TRIG14 OR ACE_EFIFO OR ACE_CRFIFO OR ACE_CTFIFO
+ out dx, al ; attempt to enable FIFO
+ test EFlags[si], fFIFOchkd ;Q: FIFO detect been done?
+ jnz sc_fifodone ; Y: enabled FIFO
+ iodelay
+ .errnz ACE_IIDR-ACE_FCR
+ in al, dx
+ or EFlags[si], fFIFOchkd
+ test al, ACE_FIFO_E2 ;Q: FIFO enabled?
+ jz short @F
+ test al, ACE_FIFO_E1 ;Q: 16550A detected?
+ jnz sc_fifodone ; Y: enabled FIFO
+@@:
+ iodelay
+ or EFlags[si], fNoFIFO
+
+sc_nofifo:
+ xor al, al
+ out dx, al
+sc_fifodone:
+
+ sub dl,ACE_FCR-ACE_RBR ; dx -> RBR
+;
+; Delay for things to settle
+;
+ push dx
+ cCall GetSystemMsecCount
+ pop dx
+ mov cx, ax
+delay_loop:
+ in al, dx ;Read it once
+ push dx
+ cCall GetSystemMsecCount
+ pop dx
+ sub ax, cx
+ cmp ax, DELAY_TIME ;Q: Timeout reached?
+ifndef WOW
+ jb delay_loop ; N:
+endif
+
+ add dl,ACE_MSR ;--> Modem Status reg
+ in al,dx ;Throw away 1st status read
+ iodelay
+ in al,dx ;Save 2nd for MSRWait (Clear MSR int)
+ mov MSRShadow[si],al
+
+; Win 3.0 didn't check hardware handshaking until the line status changed.
+; Allow some apps to keep that behavior.
+
+ push dx
+ xor ax, ax
+ cCall GetAppCompatFlags,<ax>
+ pop dx
+ test ax, GACF_DELAYHWHNDSHAKECHK
+ jnz short sc_HHSup
+
+;
+; HACK FOR SOME MODEMS: apparently some modems set CTS, but don't set DSR
+; which means that COMM.DRV won't send if the app specifies that hardware
+; handshaking is based on CTS & DSR being set.
+;
+ mov ah,OutHHSLines[si]
+ mov al, MSRShadow[si]
+ and al,ah ;Only leave bits of interest
+ cmp al, ah ;Q: handshaking lines ok?
+ je short sc_HHSup ; Y:
+ cmp ah, ACE_CTS OR ACE_DSR ;Q: app looking for both high?
+ jne short sc_HHSdown ; N: skip hack
+ test [si.EFlags], fUseDSR ;Q: DSR is always significant?
+ jnz short sc_HHSdown ; Y: skip hack
+ cmp al, ACE_CTS ;Q: DSR low & CTS high
+ jne short sc_HHSdown ; N: skip hack
+ and ah, NOT ACE_DSR ; Y: ignore DSR line
+ mov OutHHSLines[si], ah
+ jmp short sc_HHSup
+
+sc_HHSdown:
+ or [si.HSFlag], HHSDown OR HHSAlwaysDown ; flag handshaking down
+sc_HHSup:
+
+;-----------------------------------------------------------------------;
+; Now, at last, interrupts can be enabled. Don't enable the
+; transmitter empty interrupt. It will be enabled by the first
+; call to KickTx.
+;-----------------------------------------------------------------------;
+
+ sub dl,ACE_MSR-ACE_IER ;--> Interrupt Enable Register
+
+; flag port as being active
+ push cx
+ mov cl, [si.DCB_Id]
+ mov ax, 1
+ shl ax, cl
+ or [activeCOMs], ax
+ pop cx
+
+ mov al,ACE_ERBFI+ACE_ELSI+ACE_EDSSI
+ FCLI
+ out dx,al ;Enable interrupts.
+ add dl,ACE_LSR-ACE_IER ;--> Line Status Register
+ iodelay
+ in al,dx ;Clear any Line Status interrupt
+ sub dl,ACE_LSR ;--> Receiver Buffer Register
+ iodelay
+ in al,dx ;Clear any Received Data interrupt
+ FSTI
+ jmp SetCom5 ;All done
+
+$SETCOM endp
+page
+
+FlagNotActive proc near
+ push cx
+ mov cl, [si.DCB_Id]
+ mov ax, NOT 1
+ rol ax, cl
+ and [activeCOMs], ax
+ pop cx
+ ret
+FlagNotActive endp
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom100
+;
+; Copy the given DCB into the appropriate DEB. The check has
+; already been made to determine that the ID was valid, so
+; that check can be skipped.
+;
+; Entry:
+; ES:BX --> DCB
+; DS:SI --> DEB
+; Returns:
+; DS:SI --> DEB
+; ES = Data
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,CX,ES,DI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom100 proc near
+ push si ;Save DEB pointer
+ mov di,si
+ mov si,bx
+ push es
+ mov ax,ds
+ pop ds
+ assumes ds,nothing
+
+ mov es,ax
+ assumes es,Data
+
+ mov cx,DCBSize
+ cld
+ rep movsb
+ mov ds,ax
+ assumes ds,Data
+
+ pop si ;Restore DEB pointer
+ ret
+
+SetCom100 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom200
+;
+; Based on whether or not a timeout has been specified for each
+; signal, set up a mask byte which is used to mask off lines for
+; which we wish to detect timeouts. 0 indicates that the line is
+; to be ignored.
+;
+; Also set up a mask to indicate those lines which are set for
+; infinite timeout. 1 indicates that the line has infinite
+; timeout.
+;
+; Entry:
+; ES:BX --> DCB
+; Returns:
+; ES:BX --> DCB
+; AH = lines to check
+; AL = lines with infinite timeout
+; Error Returns:
+; None
+; Registers Destroyed:
+; AX,CX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom200 proc near
+
+ xor ax,ax
+ xor cx,cx ;Get mask of lines with timeout = 0
+ call SetCom210
+ not al ;Invert result to get lines to check
+ and al,ACE_CTS+ACE_DSR+ACE_RLSD
+ xchg ah,al
+ dec cx ;Get mask of infinite timeouts
+
+SetCom210:
+ cmp es:[bx.DCB_RlsTimeout],cx ;Timeout set to passed value?
+ jne SetCom220 ; No
+ or al,ACE_RLSD ; Yes, show checking line
+
+SetCom220:
+ cmp es:[bx.DCB_CtsTimeout],cx ;Timeout set to passed value?
+ jne SetCom230 ; No
+ or al,ACE_CTS ; Yes, show checking line
+
+SetCom230:
+ cmp es:[bx.DCB_DsrTimeout],cx ;Timeout set to passed value?
+ jne SetCom240 ; No
+ or al,ACE_DSR ; Yes, show checking line
+
+SetCom240:
+ ret
+
+SetCom200 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom300
+;
+; Calculate the correct baudrate divisor for the comm chip.
+;
+; Note that the baudrate is allowed to be any integer in the
+; range 2-19200. The divisor is computed as 115,200/baudrate.
+;
+; Entry:
+; ES:BX --> DCB
+; Returns:
+; ES:BX --> DCB
+; CX = baudrate
+; Error Returns:
+; CX = 0 if error
+; AX = error code if invalid baud rate
+; Registers Destroyed:
+; AX,CX,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+BaudRateByIndexTable label word
+ dw 1047 ; CBR_110
+ dw 384 ; CBR_300
+ dw 192 ; CBR_600
+ dw 96 ; CBR_1200
+ dw 48 ; CBR_2400
+ dw 24 ; CBR_4800
+ dw 12 ; CBR_9600
+ dw 9 ; CBR_14400
+ dw 6 ; CBR_19200
+ dw 0 ; 0FF19h (reserved)
+ dw 0 ; 0FF1Ah (reserved)
+ dw 3 ; CBR_38400
+ dw 0 ; 0FF1Ch (reserved)
+ dw 0 ; 0FF1Dh (reserved)
+ dw 0 ; 0FF1Eh (reserved)
+ dw 2 ; CBR_56000
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom300 proc near
+
+ push dx
+ mov cx,es:[bx.DCB_BaudRate] ;Get requested baud rate
+ xor ax,ax ;Assume error
+ cmp cx, CBR_110 ;Q: baudrate specified as an index?
+ jae by_index
+ cmp cx,2 ;Within valid range?
+ jnae SetCom310 ; No, return error
+
+ mov dx,1 ;(dx:ax) = 115,200
+ mov ax,0C200h
+ div cx ;(ax) = 115,200/baud
+
+SetCom310:
+ mov cx,ax ;(cx) = baud rate, or error code (0)
+ mov ax,IE_Baudrate ;Set error code incase bad baud
+ pop dx
+ ret
+
+by_index:
+ cmp cx, CBR_56000 ;Q: above supported?
+ ja SetCom310 ; Y: return error
+ push bx
+ mov bx, cx
+ sub bx, CBR_110
+ shl bx, 1
+ mov ax, cs:[bx+BaudRateByIndexTable] ; get divisor
+ pop bx
+ jmp SetCom310 ; Y: return error
+
+
+SetCom300 endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; SetCom400
+;
+; Check the line configuration (Parity, Stop bits, Byte size)
+;
+; Entry:
+; ES:BX --> DCB
+; Returns:
+; ES:BX --> DCB
+; 'C' clear if OK
+; AL = Line Control Register
+; AH = RxMask
+; DI[15:8] = Flags mask (to remove parity checking)
+; DI[7:0] = Error mask (to remove parity error)
+; Error Returns:
+; 'C' set if error
+; AX = error code
+; Registers Destroyed:
+; AX,CX,DI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+SetCom400 proc near
+
+ mov ax,wo es:[bx.DCB_ByteSize] ;al = byte size, ah = parity
+ cmp ah,SpaceParity ;Parity out of range?
+ ja SetCom470 ; Yes, return error
+ mov di,0FF00h+ACE_OR+ACE_PE+ACE_FE+ACE_BI
+ or ah,ah ;Is parity "NONE"?
+ jnz SetCom410 ; No, something is there for parity
+ xor di,(fParity*256)+ACE_PE ;Disable parity checking
+
+SetCom410:
+ cmp al,8 ;Byte size out of range?
+ ja SetCom460 ; Yes, error
+
+SetCom420:
+ sub al,5 ;Shift byte size to bits 0&1
+ .errnz ACE_WLS-00000011b ;Word length must be these bits
+ jc SetCom460 ;Byte size is illegal, return error
+ add ah,ah ;Map parity to ACE bits
+ jz SetCom430 ;0=>0, 1=>1, 2=>3, 3=>5, 4=>7
+ dec ah
+
+SetCom430:
+ shl ah,1 ;Align with 8250 parity bits
+ shl ah,1
+ shl ah,1
+ or al,ah ;Add to byte size
+
+ .errnz NoParity-0
+ .errnz OddParity-1
+ .errnz EvenParity-2
+ .errnz MarkParity-3
+ .errnz SpaceParity-4
+ .errnz ACE_PEN-00001000b
+ .errnz ACE_PSB-00110000b
+ .errnz ACE_EPS-00010000b
+ .errnz ACE_SP-00100000b
+
+ or al,ACE_2SB ;Assume 2 stop bits
+ mov ah,es:[bx.DCB_StopBits] ;Get # of stop bits 0=1,1/2= .GT. 1
+ or ah,ah ;Out of range?
+ js SetCom470 ; Yes, return error
+ jz SetCom440 ;One stop bit
+ sub ah,2
+ jz SetCom450 ;Two stop bits
+ jns SetCom470 ;Not 1.5, return error
+ test al,ACE_WLS ;1.5 stop bits, 5 bit words?
+ jnz SetCom470 ; No, illegal
+ .errnz OneStopBit-0
+ .errnz One5StopBits-1
+ .errnz TwoStopBits-2
+ .errnz ACE_5BW
+
+SetCom440:
+ and al,NOT ACE_2SB ;Show 1 (or 1.5) stop bit(s)
+
+
+; From the byte size, get a mask to be used for stripping
+; off unused bits as the characters are received.
+
+SetCom450:
+ push dx
+ mov cl,es:[bx.DCB_ByteSize] ;Get data byte size
+ mov dx,00FFh ;Turn into mask by shifting bits
+ shl dx,cl
+ mov ah,dh ;Return mask in ah
+ pop dx
+ clc ;Show all is fine
+ ret
+
+SetCom460:
+ mov ax,IE_ByteSize ;Show byte size is wrong
+ stc ;Show error
+ ret
+
+SetCom470:
+ mov ax,IE_Default ;Show something is wrong
+ stc ;Show error
+ ret
+
+SetCom400 endp
+page
+
+;----------------------------------------------------------------------------
+; SuspendOpenCommPorts:
+;
+; This routine is called from 286 Winoldaps to simply deinstall the comm port
+; hooks.
+;----------------------------------------------------------------------------
+
+cProc SuspendOpenCommPorts,<FAR,PUBLIC,PASCAL>
+
+cBegin nogen
+
+ assumes cs,Code
+ assumes ds,Data
+
+%OUT not masking IRQ's
+
+ ; Nothing to do under 3.1!
+
+ ret
+
+cEnd nogen
+
+;----------------------------------------------------------------------------;
+; ReactivateOpenCommPorts: ;
+; ;
+; This routine reinstalls the comm hooks in real mode and reads the 8250 ;
+; data and status registers to clear pending interrupts. ;
+;----------------------------------------------------------------------------;
+
+cProc ReactivateOpenCommPorts,<FAR,PASCAL,PUBLIC>,<si,di>
+
+cBegin
+ call Rotate_PIC ;make comm ports highest priority
+
+ mov cx, MAXCOM+1
+ mov di,dataOffset COMptrs
+rcp_loop:
+ mov si, [di]
+ mov dx, Port[si]
+ or dx, dx
+ jz @f
+ call InitAPort ;read comm port regs to clr pending ints
+@@:
+ add di, 2
+ loop rcp_loop
+
+cEnd
+
+;----------------------------------------------------------------------------;
+; InitAPort: ;
+; ;
+; reads the data,status & IIR registers of a port (has to be 8250!) ;
+; ;
+; If the port has an out queue pending, then this woutine will also start ;
+; the transmit process by faking a comm interrupt. ;
+;----------------------------------------------------------------------------;
+
+public InitAPort
+InitAPort proc near
+
+ add dl,ACE_RBR ;dx=receive buffer register
+ in al,dx ;read the data port
+ jmp short $+2 ;i/o delay
+ add dl,ACE_LSR - ACE_RBR ;get to the status port
+ in al,dx ;read it too.
+ jmp short $+2 ;i/o delay
+ add dl,ACE_IIDR - ACE_LSR ;get to the line status register
+ in al,dx ;read it once more
+ jmp short $+2 ;i/o delay
+ add dl,ACE_MSR - ACE_IIDR ;get to the modem status register
+ in al,dx ;read it once more
+ jmp short $+2 ;i/o delay
+ add dl,ACE_RBR - ACE_MSR ;get to the receive buffer register
+ in al,dx ;read it once more
+ jmp short $+2 ;i/o delay
+ call UnmaskIRQ
+
+; now if the port has characters pending to be sent out then we must fake a
+; comm interrupt.
+
+ cmp [si].QOutCount,0 ;characters pending to be sent ?
+ jz @f ;no.
+ FCLI ;disable interrupts
+ call FakeCOMIntFar ;fake an interrupt
+ FSTI ;renable interrupts
+@@:
+ ret
+
+InitAPort endp
+
+page
+
+;----------------------------Public Routine-----------------------------;
+;
+; $DCBPtr - Return Pointer To DCB
+;
+; Returns a long pointer to the DCB for the requested device.
+;
+; Entry:
+; AH = Device ID
+; Returns:
+; DX:AX = pointer to DCB.
+; Error Returns:
+; DX:AX = 0
+; Registers Preserved:
+; SI,DI,DS
+; Registers Destroyed:
+; BX,CX,ES,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public $DCBPTR
+$DCBPTR proc near
+
+ push si
+ xor dx,dx
+ call GetDEB ;Get pointer to DEB
+ mov ax,dx
+ jc DCBPtr10 ;Jump if invalid device
+ mov ax,si ;else return value here
+ mov dx,ds
+
+DCBPtr10:
+ pop si
+ ret
+
+$DCBPTR endp
+page
+
+;----------------------------Private-Routine----------------------------;
+;
+; GetDEB - Get Pointer To Device's DEB
+;
+; Returns a pointer to appropriate DEB, based on device number.
+;
+; Entry:
+; AH = cid
+; Returns:
+; 'C' clear
+; 'S' set if LPT device
+; DS:SI --> DEB is valid cid
+; AH = cid
+; Error Returns:
+; 'C' set if error (cid is invalid)
+; AX = 8000h
+; Registers Preserved:
+; BX,CX,DX,DI,DS,ES
+; Registers Destroyed:
+; AX,SI,FLAGS
+; History:
+;-----------------------------------------------------------------------;
+
+;------------------------------Pseudo-Code------------------------------;
+; {
+; }
+;-----------------------------------------------------------------------;
+
+assumes ds,Data
+assumes es,nothing
+
+public GetDEB ;Public for debugging
+GetDEB proc near
+
+ push cx
+ mov cl, ah
+ and cx, (NOT LPTx AND 0FFh)
+ test ah, ah ;Q: LPT id?
+ js short GetDEB10 ; Y:
+.errnz LPTx - 80h
+ cmp ah, MAXCOM ;Q: Within range?
+ ja GetDEB30 ; N: return invalid ID
+ shl cx, 1
+ mov si, cx
+ mov si, [si+COMptrs]
+ jmp short GetDEB20
+
+GetDEB10:
+ cmp ah, LPTx+MAXLPT ;Q: Within range?
+ ja GetDEB30 ; N: return invalid ID
+ mov si, DataOFFSET LPT1
+ jcxz GetDEB20
+GetDEB15:
+ add si, SIZE LptDEB
+ loop GetDEB15
+GetDEB20:
+ pop cx
+ or ah, ah ; clear Carry & set S, if LPT port
+ ret
+
+GetDEB30:
+ pop cx
+ mov ax,8000h ;Set error code
+ stc ;Set 'C' to show error
+ ret
+
+GetDEB endp
+page
+
+
+CvtHex proc near
+; assume DS=SS
+ push si
+ mov cl, 4
+ mov si, di
+ xor dx, dx
+ cld
+ch_lp:
+ lodsb
+ sub al, '0' ;Q: char < '0'
+ jb ch_exit ; Y: return
+ cmp al, 9 ;Q: char <= '9'
+ jbe ch_got_digit ; Y: move digit into result
+ sub al, 'A' - '0' ;Q: char < 'A'
+ jb ch_exit ; Y: return
+ add al, 10
+ cmp al, 15 ;Q: char <= 'F'
+ jbe ch_got_digit ; Y: move hex char into result
+ sub al, 10 + 'a' - 'A' ;Q: char < 'a'
+ jb ch_exit ; Y: return
+ add al, 10
+ cmp al, 15 ;Q: char > 'f'
+ ja ch_exit ; Y: return
+ch_got_digit:
+ shl dx, cl
+ or dl, al
+ jmp ch_lp
+ch_exit:
+ mov ax, dx
+ pop si
+ ret
+CvtHex endp
+
+.286
+; attempt to read base from SYSTEM.INI
+GetComBase proc near
+ push ds ; save our DS
+ sub sp, 6
+ mov di, sp
+ mov byte ptr ss:[di], 0
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommBase
+ push ss ; temp buffer
+ push di
+ push ss ; default = temp buffer
+ push di
+ push 5
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileString ; our segment in real mode
+ or ax, ax
+ jz short gcb_exit
+ call CvtHex ; DS still equal to SS
+gcb_exit:
+ add sp, 6
+ pop ds ; restore our DS
+ assumes ds,Data
+ ret
+GetComBase endp
+
+GetPortIRQ proc near
+ push ds ; save our DS
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommIrq
+ push bx
+ mov bl, [si.DCB_Id]
+ cmp bl, 4
+ jb @f
+ mov bl, 4
+@@:
+ xor bh, bh
+ mov bl, [bx+default_table]
+ mov cx, bx
+ pop bx
+ push cx ; default
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileInt ; our segment in real mode
+ pop ds ; restore our DS
+ assumes ds,Data
+ ret
+GetPortIRQ endp
+
+
+GetPortFlags proc near
+ mov al, [si.DCB_Id]
+.erre MAXCOM LT 9 ;only single digit port numbers supported
+ add al, '1'
+ mov [CommFIFOX], al
+ mov [CommDSRx], al
+ call GetPortFIFO
+ call GetPortDSR
+ ret
+GetPortFlags endp
+
+GetPortFIFO proc near
+ push ds ; save our DS
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommFifo
+ push 2
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileInt ; our segment in real mode
+ pop ds ; restore our DS
+ assumes ds,Data
+ cmp ax, 1
+ ja short gpf_exit ; just check at open
+ jb short gpf_no_fifo ; force OFF, if = 0
+ or EFlags[si], fFIFOchkd ; flag as checked, to force ON
+ jmp short gpf_exit
+
+gpf_no_fifo:
+ or EFlags[si], fNoFIFO OR fFIFOchkd ; force OFF
+
+gpf_exit:
+ ret
+GetPortFIFO endp
+
+GetPortDSR proc near
+ push ds ; save our DS
+ push ds
+ push DataOFFSET lpCommSection
+ push ds
+ push DataOFFSET lpCommDSR
+ push 0
+ push ds
+ push DataOFFSET lpSYSTEMINI
+ mov cx, ss ; temporarily assign DS=SS
+ mov ds, cx ; to allow KERNEL to thunk
+ assumes ds,nothing
+ call GetPrivateProfileInt ; our segment in real mode
+ pop ds ; restore our DS
+ assumes ds,Data
+ or ax, ax
+ jz short gpd_exit
+ or EFlags[si], fUseDSR
+
+gpd_exit:
+ ret
+GetPortDSR endp
+
+
+; FindCOMPort
+;
+; DS:SI -> DEB
+;
+ PUBLIC FindCOMPort
+FindCOMPort proc near
+;
+; Examine BIOS data area to get base I/O addresses for COM and LPT ports
+;
+ push bx
+ push cx
+ push es
+ mov ax, __0040H
+ mov es, ax
+ assumes es,nothing
+
+ mov al, [si.DCB_Id]
+ mov ah, al
+.erre MAXCOM LT 9 ;only single digit port numbers supported
+ add ah, '1'
+ mov [CommBaseX], ah
+ mov [CommIRQX], ah
+ mov [CommFIFOX], ah
+ mov [CommDSRx], ah
+
+ cmp al, 4
+ jae fcp_not_phys_com
+ xor ah, ah
+ shl ax, 1
+ mov bx, ax
+ mov ax, es:[bx+RS232B]
+ or ax, ax
+ jnz fcp_got_com_base
+fcp_not_phys_com:
+ call GetComBase
+ or ax, ax
+ jnz fcp_got_com_base
+ mov bl, [si.DCB_Id]
+ cmp bl, 2
+ jne fcp_invalid ; jump, if base = 0 & com port <> com3
+ mov ax, 3E8h ; default COM3 to 3E8h
+fcp_got_com_base:
+ push ax
+ call GetPortIRQ
+ mov dx, ax
+ pop ax
+ or dl, dl ;Q: non-zero IRQ?
+ jz fcp_invalid ; N:
+ cmp dl, 15 ;Q: IRQ in range?
+ ja fcp_invalid ; N:
+ xor dh, dh
+ push ax
+ push dx
+ call GetPortFIFO
+ call GetPortDSR
+ pop dx
+ pop ax
+ clc
+fcp_exit:
+ pop es
+ pop cx
+ pop bx
+ ret
+
+fcp_invalid:
+ or ax, -1
+ mov dx, ax
+ stc
+ jmp fcp_exit
+
+FindCOMPort endp
+.8086
+
+page
+;--------------------------Private Routine-----------------------------;
+;
+; Rotate the PIC interrupt priorities so the communication ports are
+; highest priority.
+;
+; NOTE: Only rotates priorities on master PIC.
+;
+;-----------------------------------------------------------------------;
+
+ assumes ds,Data
+ assumes es,nothing
+
+ public Rotate_PIC
+
+Rotate_PIC proc near
+
+ push ax
+ push cx
+ push di
+
+ mov al, 8 ; 0 - 7 rotated
+ mov cx, MAXCOM+1
+ mov di, DataOFFSET IRQhooks
+rp_loop:
+ mov ah, [di.IRQn]
+ cmp ah, 0 ;End of hooked IRQ list?
+ je rp_set
+ cmp [di.VecN], 0FFh ;Hooked?
+ je rp_next
+ cmp ah, 8 ;If on slave PIC, treat as IRQ2
+ jb @f
+ mov ah, 2
+@@:
+ cmp ah, al
+ jae rp_next
+ mov al, ah ;AL = lowest hooked comm IRQ
+rp_next:
+ add di, SIZE IRQ_Hook_Struc
+ loop rp_loop
+
+rp_set:
+ dec al ;Setting IRQ(n-1) as the lowest
+ and al, 07h ; priority makes IRQn the highest
+ or al, 0C0h
+ out INTA0, al
+
+ pop di
+ pop cx
+ pop ax
+ ret
+
+Rotate_PIC endp
+
+
+ifdef DEBUG
+ public InitCom10, InitCom20, InitCom40, InitCom50, InitCom59
+ public InitCom60, InitCom70, InitCom80, InitCom90, InitCom100
+ public TermCom10, TermCom15, TermCom20, TermCom30
+ public TermCom60, Terminate5, Terminate10, Terminate20, Terminate30
+ public Terminate45, Terminate49, Terminate50
+ public SetQue10
+ public SetCom5, SetCom10, SetCom20, SetCom210, SetCom220, SetCom230
+ public SetCom240, SetCom310, SetCom410, SetCom420, SetCom430
+ public SetCom440, SetCom450, SetCom460, SetCom470
+ public GetDEB10, GetDEB20, GetDEB30
+ public DCBPtr10
+endif
+
+sEnd code
+
+page
+
+createSeg _INIT,init,word,public,CODE
+sBegin init
+assumes cs,init
+
+
+
+;------------------------------------------------------------------------------
+;------------------------------------------------------------------------------
+IBMmodel proc near
+ push ax
+ push bx
+ push es
+
+ mov ah, 0c0h
+ int 15h
+ jc IBMmodel_exit
+
+ assumes es,nothing
+
+ cmp by es:[bx+2], 0f8h ; PS/2 80
+ je IBMmodel_exit ; return carry clear
+
+ cmp by es:[bx+2], 0fch ; AT or PS/2 50 or 60
+ jne OldBios ; assume OldBios
+
+ cmp by es:[bx+3], 04h ; PS/2 50
+ je IBMmodel_exit ; return carry clear
+ cmp by es:[bx+3], 05h ; PS/2 60
+ je IBMmodel_exit ; return carry clear
+
+OldBios:
+ stc
+
+IBMmodel_exit:
+ pop es
+ pop bx
+ pop ax
+ ret
+
+IBMmodel endp
+
+cProc LoadLib, <FAR,PUBLIC,NODATA>,<si,di>
+cBegin
+
+ push ds
+ mov ax, __F000H
+ mov ds, ax
+ assumes ds, ROMBios
+ mov al, [MachineID]
+ pop ds
+ assumes ds,Data
+ mov [$MachineID], al
+
+ call IBMmodel ;Q: PS/2?
+ jc @F ; N:
+ mov [default_table+2], 3 ; Y: change COM3 default IRQ to 3
+@@:
+
+ push ds
+ mov ax, __0040H
+ mov ds, ax
+ assumes ds,nothing
+ cmp word ptr ds:[RS232B], 2F8h ;Q: COM2 base in COM1 slot?
+ pop ds
+ assumes ds,Data
+ jne @F ; N: leave IRQ default as 4
+ mov [default_table], 3 ; Y: change IRQ default to 3
+@@:
+
+ mov [fVPICD], -1 ; assume no
+
+ xor di, di
+ mov es, di
+ mov ax, GET386API
+ mov bx, VPICD
+ int MULTIPLEX
+ mov wo [lpfnVPICD], di
+ mov wo [lpfnVPICD+2], es
+ mov ax, es
+ or ax, di
+ jz short no_VPICD ; jump if no bimodel services available
+;
+; version check VPICD
+;
+ mov ax, VPICD_API_Get_Ver
+ call [lpfnVPICD]
+%OUT version check VPICD
+
+ mov [fVPICD], 1 ; flag services are available
+
+IFDEF No_DOSX_Bimodal_Services
+ jmp short skip_dosx_stuff
+
+no_VPICD:
+ mov ax, __WinFlags
+ and al, WF_PMODE or WF_WIN286
+ cmp al, WF_PMODE or WF_WIN286
+ jne skip_dosx_stuff
+
+.286
+ mov ax, Int31_Get_Version SHL 8
+ int 31h
+ test bl, 10b ;Q: processor goes to real mode
+ ; for int reflection?
+ jz skip_dosx_stuff ; N:
+ mov [Using_DPMI], 0FFh ; Y: flag use of DPMI
+
+ mov ax, ds
+ cCall GetSelectorBase,<ax> ;DX:AX = segment of selector
+ shr ax, 4
+ shl dl, 4
+ or ah, dl ;AX now points to interrupt *segment*
+ push ax ;save on stack
+ mov ax, _INTERRUPT ;write data SEGMENT into _INTERRUPT
+ cCall AllocCStoDSAlias,<ax> ; code segment -- requires a data alias
+ mov es, ax
+ pop ax
+ mov es:[RM_IntDataSeg],ax
+ push ds
+ push es
+ mov ax, ds
+ mov es, ax
+ mov ax, _INTERRUPT
+ mov ds, ax
+ mov ax, (Int31_Trans_Serv SHL 8) + Trans_Call_Back
+ mov si, IntCodeOFFSET Entry_From_RM
+ mov di, DataOFFSET RM_Call_Struc
+ int 31h
+ pop es
+ pop ds
+ mov ax, 0
+ jnc @f
+ jmp short LoadExit
+@@:
+ mov wo es:[RM_CallBack], dx
+ mov wo es:[RM_CallBack+2], cx
+ cCall FreeSelector,<es> ;don't need CS alias any longer
+.8086
+skip_dosx_stuff:
+ELSE
+no_VPICD:
+ENDIF
+
+;
+; find base values for LPT ports
+;
+ mov cx, __0040h
+ mov es, cx
+ mov cx, MAXLPT+1
+ mov si, DataOFFSET LPT1
+ll_initl_lp:
+ mov bx, [si.BIOSPortLoc]
+ or bx, bx
+ jz ll_not_phys_lpt
+ mov ax, es:[bx]
+ or ah, ah ;Q: lpt redirected, or 0?
+ jz ll_not_phys_lpt ; Y:
+ cmp bx, LPTB ;Q: first LPT?
+ je ll_got_lpt_base ; Y:
+ cmp ax, es:[bx-2] ;Q: base same as previous (redirected)?
+ jne ll_got_lpt_base ; N: must be real
+ll_not_phys_lpt:
+%OUT attempt to read base from SYSTEM.INI
+
+ll_got_lpt_base:
+ mov [si.Port], ax
+ loop ll_initl_lp
+
+;
+; create system timer for signalling chars in receive buffer
+;
+
+ifndef WOW
+ mov ax, 100 ; create 100msec timer
+ push ax
+ mov ax, _INTERRUPT
+ push ax
+ mov ax, IntCodeOFFSET TimerProc
+ push ax
+ call CreateSystemTimer ; ax = 0, if failed
+%OUT should I display an error message here?
+
+endif
+ assumes es,nothing
+LoadExit:
+cEnd
+
+sEnd init
+
+End LoadLib
diff --git a/private/mvdm/wow16/drivers/comm/ins8250.inc b/private/mvdm/wow16/drivers/comm/ins8250.inc
new file mode 100644
index 000000000..6d61a0227
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/ins8250.inc
@@ -0,0 +1,78 @@
+; INS8250 ACE Register Offsets And Bit Definitions
+
+
+ACE_RBR equ 0 ;Receiver Buffer
+ACE_THR equ 0 ;Transmit Holding Register
+
+ACE_IER equ 1 ;Interrupt Enable
+ ACE_ERBFI equ 00000001b ; Received Data Available
+ ACE_ETBEI equ 00000010b ; Transmitter Holding Register Empty
+ ACE_ELSI equ 00000100b ; Receiver Line Status
+ ACE_EDSSI equ 00001000b ; Modem Status
+
+ACE_FCR equ 2 ;FIFO control register
+ ACE_EFIFO equ 00000001b ; Enable FIFO
+ ACE_CRFIFO equ 00000010b ; Clear receive FIFO queue
+ ACE_CTFIFO equ 00000100b ; Clear transmit FIFO queue
+ ACE_TRIG01 equ 00000000b ; Trigger receive int on every char
+ ACE_TRIG04 equ 01000000b ; Trigger receive int on every 4th char
+ ACE_TRIG08 equ 10000000b ; Trigger receive int on every 8th char
+ ACE_TRIG14 equ 11000000b ; Trigger receive int on every 14th char
+
+ACE_IIDR equ 2 ;Interrupt Identification
+ ACE_IIP equ 00000001b ; Inverted Interrupt Pending (0=int)
+ ACE_IID equ 00000110b ; Interrupt ID
+ ACE_MSI equ 00000000b ; Modem Status
+ ACE_THREI equ 00000010b ; Transmitter Holding Register Empty
+ ACE_RDAI equ 00000100b ; Received Data Available
+ ACE_RLSI equ 00000110b ; Receiver Line Status
+ ACE_FIFO_E1 equ 01000000b ;set, if FIFO enabled on 16550A
+ ACE_FIFO_E2 equ 10000000b ;set, if FIFO enabled on 16550 or 16550A
+
+ACE_LCR equ 3 ;Line Control
+ ACE_WLS equ 00000011b ; Word Length Select Bits
+ ACE_WLS0 equ 00000001b ; Word Length Select Bit 0
+ ACE_WLS1 equ 00000010b ; Word Length Select Bit 1
+ ACE_5BW equ 00000000b ; 5 Bit Words
+ ACE_6BW equ 00000001b ; 6 Bit Words
+ ACE_7BW equ 00000010b ; 7 Bit Words
+ ACE_8BW equ 00000011b ; 8 Bit Words
+ ACE_STB equ 00000100b ; Stop Bits
+ ACE_1SB equ 00000000b ; 1 Stop Bits (1.5 for 5 bit words)
+ ACE_2SB equ 00000100b ; 2 Stop Bits
+ ACE_PEN equ 00001000b ; Parity Enable
+ ACE_PSB equ 00110000b ; Parity select bits
+ ACE_EPS equ 00010000b ; Even Parity Select
+ ACE_SP equ 00100000b ; Stick Parity
+ ACE_SB equ 01000000b ; Set Break
+ ACE_DLAB equ 10000000b ; Divisor Latch Access Bit
+
+ACE_MCR equ 4 ;Modem Control
+ ACE_DTR equ 00000001b ; Data Terminal ready
+ ACE_RTS equ 00000010b ; Request To Send
+ ACE_OUT1 equ 00000100b ; Output Line 1
+ ACE_OUT2 equ 00001000b ; Output Line 2
+ ACE_LOOP equ 00010000b ; Loopback
+
+ACE_LSR equ 5 ;Line Status
+ ACE_DR equ 00000001b ; Data Ready
+ ACE_OR equ 00000010b ; Overrun Error
+ ACE_PE equ 00000100b ; Parity Error
+ ACE_FE equ 00001000b ; Framing Error
+ ACE_BI equ 00010000b ; Break Interrupt
+ ACE_THRE equ 00100000b ; Transmitter Holding Register Empty
+ ACE_TSRE equ 01000000b ; Transmitter Shift Register Empty
+
+ACE_MSR equ 6 ;Modem Status
+ ACE_DCTS equ 00000001b ; Delta Clear to Send
+ ACE_DDSR equ 00000010b ; Delta Data Set Ready
+ ACE_TERI equ 00000100b ; Trailing Edge Ring Indicator
+ ACE_DRLSD equ 00001000b ; Delta Receive Line Signal Detect
+ ACE_CTS equ 00010000b ; Clear To Send
+ ACE_DSR equ 00100000b ; Data Set ready
+ ACE_RI equ 01000000b ; Ring Indicator
+ ACE_RLSD equ 10000000b ; Receive Line Signal Detect
+
+ACE_DLL equ 0 ;LSB Baud Rate Divisor
+
+ACE_DLM equ 1 ;MSB Baud Rate Divisor
diff --git a/private/mvdm/wow16/drivers/comm/makefile b/private/mvdm/wow16/drivers/comm/makefile
new file mode 100644
index 000000000..2b5303d44
--- /dev/null
+++ b/private/mvdm/wow16/drivers/comm/makefile
@@ -0,0 +1,127 @@
+# comm16 makefile
+#
+# Copyright (c) 1992, Microsoft Corporation
+#
+# History:
+# 27-Mar-1992 Nandurir
+# Created.
+# 6-Feb-1994 LeeHart
+# Modified for version resources & CV Symbols
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2.
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) -fo $@ $*.rc
+
+
+all: comm.drv comm.map comm.sym comm.lrf
+ binplace comm.drv comm.map comm.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+
+ccom.obj ccom.lst: ccom.asm ibmcom.inc comdev.inc
+
+ibmsetup.obj ibmsetup.lst: ibmsetup.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmcom.obj: $*.asm $*.inc comdev.inc ins8250.inc
+
+ibmint.obj: $*.asm ibmcom.inc comdev.inc ins8250.inc
+
+ibmlpt.obj: $*.asm ibmcom.inc comdev.inc
+
+commmsg.obj: $*.asm
+
+comm.res: $*.rc $*.rcv ..\..\inc\common.ver
+
+comm.lrf: makefile
+ echo ccom+ibmsetup+ibmcom+ibmint+ibmlpt+commmsg >$@
+ echo $*.exe/align:16>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /map /nod>>$@
+ echo $*;>>$@
+
+comm.drv: ccom.obj ibmsetup.obj ibmcom.obj ibmint.obj ibmlpt.obj commmsg.obj \
+ $*.def $*.res $*.lrf
+ link16 @$*.lrf;
+ rc16 -t $*.res $*.exe
+ if exist *.drv del *.drv
+ ren $*.exe $@
+
+comm.sym: $*.map
+ mapsym $*
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/display/config.asm b/private/mvdm/wow16/drivers/display/config.asm
new file mode 100644
index 000000000..d8b7c3a2a
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/config.asm
@@ -0,0 +1,64 @@
+;***************************************************************************
+; *
+; Copyright (C) 1985-1989 by Microsoft Inc. *
+; *
+;***************************************************************************
+
+ title Hardware Dependent Parameters
+ %out config
+ page ,132
+
+
+RGB macro R, G, B
+ db R,G,B,0
+ endm
+
+
+
+OEM segment public
+
+; Machine dependent parameters
+
+ dw 14 ;Height of vertical thumb
+ dw 18 ;Width of horizontal thumb
+ dw 2 ;Icon horiz compression factor
+ dw 2 ;Icon vert compression factor
+ dw 1 ;Cursor horz compression factor
+ dw 1 ;Cursor vert compression factor
+ dw 0 ;Kanji window height
+ dw 1 ;cxBorder (thickness of vertical lines)
+ dw 1 ;cyBorder (thickness of horizontal lines)
+
+; Default system color values
+
+ RGB 129,129,129 ;clrScrollbar
+ RGB 192,192,192 ;clrDesktop
+ RGB 000,000,128 ;clrActiveCaption
+ RGB 255,255,255 ;clrInactiveCaption
+ RGB 255,255,255 ;clrMenu
+ RGB 255,255,255 ;clrWindow
+ RGB 000,000,000 ;clrWindowFrame
+ RGB 000,000,000 ;clrMenuText
+ RGB 000,000,000 ;clrWindowText
+ RGB 255,255,255 ;clrCaptionText
+ RGB 128,128,128 ;clrActiveBorder
+ RGB 255,255,255 ;clrInactiveBorder
+ RGB 255,255,255 ;clrAppWorkspace
+ RGB 000,000,128 ;clrHiliteBk
+ RGB 255,255,255 ;clrHiliteText
+ RGB 255,255,255 ;clrBtnFace
+ RGB 128,128,128 ;clrBtnShadow
+ RGB 128,128,128 ;clrGrayText
+ RGB 000,000,000 ;clrBtnText
+
+; dw 0 ;Unused words
+; dw 0
+; dw 0
+; dw 0
+; dw 0
+; dw 0
+ dw 0
+ dw 0
+
+OEM ends
+end
diff --git a/private/mvdm/wow16/drivers/display/display.asm b/private/mvdm/wow16/drivers/display/display.asm
new file mode 100644
index 000000000..5573f7eac
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.asm
@@ -0,0 +1,88 @@
+ TITLE DISPLAY.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; DISPLAY.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 13-MAY-1992 Matt Felton (mattfe)
+; Created.
+;
+; WinProj 3.0 does the following API:-
+; GetModuleFileName(GetModuleHandle("DISPLAY"), buffer, sizeof(buffer));
+; In WOW we do not require a display driver becuase we always call GDI32 to
+; perform screen IO.
+
+
+
+ .286p
+
+ .xlist
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+DISPLAY_Identifier db 'DISPLAY'
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+cProc DISPLAY,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+ cBegin <nogen>
+ mov ax,1 ;always indicate success
+ ret
+ cEnd <nogen>
+
+assumes DS,NOTHING
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+cProc Disable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+ parmD lp_device
+
+cBegin
+ mov ax,-1
+cEnd
+
+cProc Enable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+ parmD lp_device ;Physical device or GDIinfo destination
+ parmW style ;Style, Enable Device, or Inquire Info
+ parmD lp_device_type ;Device type (i.e FX80, HP7470, ...)
+ parmD lp_output_file ;DOS output file name (if applicable)
+ parmD lp_stuff ;Device specific information
+
+cBegin
+ mov ax,0
+cEnd
+
+assumes DS,DATA
+
+assumes DS,NOTHING
+
+sEnd CODE
+
+end DISPLAY
diff --git a/private/mvdm/wow16/drivers/display/display.def b/private/mvdm/wow16/drivers/display/display.def
new file mode 100644
index 000000000..175fbfa33
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.def
@@ -0,0 +1,17 @@
+LIBRARY DISPLAY
+
+DESCRIPTION 'Windows Display Driver'
+
+EXETYPE WINDOWS
+STUB '..\..\BIN\WINSTUB.EXE'
+
+CODE PRELOAD MOVEABLE
+
+DATA PRELOAD MOVEABLE SINGLE
+
+HEAPSIZE 0
+
+EXPORTS
+ WEP
+ Disable @4
+ Enable @5
diff --git a/private/mvdm/wow16/drivers/display/display.rc b/private/mvdm/wow16/drivers/display/display.rc
new file mode 100644
index 000000000..585d45cce
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.rc
@@ -0,0 +1,8 @@
+/* Resource file for EGA (4-plane) display driver */
+
+#define OEMRESOURCE
+#define WIN31
+#include "windows.h"
+#include "display.rcv"
+
+1 oembin PRELOAD config.bin
diff --git a/private/mvdm/wow16/drivers/display/display.rcv b/private/mvdm/wow16/drivers/display/display.rcv
new file mode 100644
index 000000000..596a32d4d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/display.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* DISPLAY.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_DISPLAY
+#define VER_FILEDESCRIPTION_STR "WOW Display Driver Module"
+#define VER_INTERNALNAME_STR "VGA"
+#define VER_ORIGINALFILENAME_STR "VGA.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/display/makefile b/private/mvdm/wow16/drivers/display/makefile
new file mode 100644
index 000000000..673e1a1ad
--- /dev/null
+++ b/private/mvdm/wow16/drivers/display/makefile
@@ -0,0 +1,121 @@
+# display16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 13-May-1992 Matt Felton (MattFe)
+#
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2.
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .res .rc
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r -fo $@ $(INCS) $*.rc
+
+all: display.exe display.map display.sym
+ copy display.exe vga.drv
+ copy display.sym vga.sym
+ copy display.map vga.map
+ binplace vga.drv vga.map vga.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+display.obj: $*.asm ..\..\..\inc\wow.inc
+ masm -l $(AOBJ) $*;
+
+config.obj: $*.asm
+ masm -l $(AOBJ) $*;
+
+config.exe: $*.obj
+ link16 $*;
+
+config.bin: $*.exe
+ exe2bin $*.exe
+
+display.res: $*.rc config.bin $*.rcv ..\..\inc\common.ver
+
+display.lrf: makefile
+ echo $*.obj >$@
+ echo $*.exe>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrt.lib /nod>>$@
+ echo $*;>>$@
+
+display.exe display.map: display.obj display.lrf display.def display.res
+ link16 @display.lrf;
+ rc16 -t display.res display.exe
+
+display.sym: $*.map
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/keyboard/kbd.def b/private/mvdm/wow16/drivers/keyboard/kbd.def
new file mode 100644
index 000000000..c5961214d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/kbd.def
@@ -0,0 +1,118 @@
+LIBRARY KEYBOARD
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; (except for SetSpeed)
+; ============================================================
+
+; Copyright (C) 1989 by Microsoft Corporation
+
+DESCRIPTION 'KEYBOARD (Enhanced keyboard):'
+
+EXETYPE WINDOWS
+
+; (use LINK4 default stub, not WINSTUB)
+
+CODE PRELOAD FIXED
+DATA PRELOAD FIXED SINGLE
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; ============================================================
+
+SEGMENTS
+; Initialization once-only code
+ _INIT PRELOAD FIXED DISCARDABLE
+
+; Translation tables
+ _TABS LOADONCALL FIXED DISCARDABLE
+
+; NewTable()'s and GetCSAlias()'s segment
+ _NEWTAB PRELOAD FIXED DISCARDABLE
+
+; OemKeyScan's segment
+ _OEMSC LOADONCALL DISCARDABLE
+
+; VkKeyScan's segment
+ _VKKSC LOADONCALL DISCARDABLE
+
+; SetSpeed's segment
+ _SETSP PRELOAD FIXED DISCARDABLE
+
+; GetKeyboardType's segment
+ _GETTYPE LOADONCALL DISCARDABLE
+
+; MapVirtualKey's segment
+ _MAPVK LOADONCALL DISCARDABLE
+
+; GetKeyNameText's segment
+ _GETNAME LOADONCALL DISCARDABLE
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; (except for SetSpeed)
+; ============================================================
+
+EXPORTS
+ Inquire @1 ;Internal
+ Enable @2 ;Internal
+ Disable @3 ;Internal
+ ToAscii @4
+ AnsiToOem @5
+ OemToAnsi @6
+
+; Special call for setting keyboard repeat speed on AT-type keyboards
+; (omit in Olivetti M24 and NOKIA drivers, since they're not for AT keyboards)
+ SetSpeed @7 ;Internal
+
+; Special call for OS/2 Compatibility box
+; (omit in Olivetti M24 drivers)
+ ScreenSwitchEnable @100 ;Internal
+
+; Routines for initializing keyboard tables
+
+ GetTableSeg @126 ;Internal
+ NewTable @127 ;Internal
+
+; Special call for WIN386 WINOLDAP
+; (omit in Olivetti M24 drivers, since they're 8086 only)
+ OEMKeyScan @128
+
+; Special ASCII to virtual keycode routine
+ VkKeyScan @129
+
+; Return keyboard type number, etc.
+ GetKeyboardType @130
+
+; Return translations VK-> scancode, scancode-> VK, VK-> ASCII.
+ MapVirtualKey @131
+
+; Return code page of current Oem/Ansi translation tables.
+ GetKBCodePage @132
+
+; Get name string for key
+ GetKeyNameText @133
+
+; Translate routines
+ AnsiToOemBuff @134
+ OemToAnsiBuff @135
+
+; Enable SysReq trap
+ EnableKBSysReq @136 ;Internal
+
+; codeview support
+ GetBIOSKeyProc @137
+
+ WEP ;Internal
+
+; ============================================================
+; ANY CHANGES TO KBD.DEF SHOULD ALSO BE MADE IN THE FOLLOWING:
+; KBDNOKIA.DEF KBDHP.DEF KBDOLI.DEF
+; ============================================================
+
+
+IMPORTS
+ CVWBREAK = KERNEL.205
diff --git a/private/mvdm/wow16/drivers/keyboard/kbdlocal.asm b/private/mvdm/wow16/drivers/keyboard/kbdlocal.asm
new file mode 100644
index 000000000..e736ccfa6
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/kbdlocal.asm
@@ -0,0 +1,301 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; KBDLOCAL.ASM
+;
+; Win16 KEYBOARD APIS that are 'internal'
+; We make these apis a 'nop'. Relevant code has been copied from WIN31.
+; The intention here is to maintain the stack. Any arguments to the apis
+; are popped and that is it.
+;
+; History:
+;
+; Created 06-Jan-1992 by NanduriR
+;--
+
+ TITLE KBDLOCAL.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowkbd.inc
+ include cmacros.inc
+ include windefs.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+; Double byte range values for the Far East.
+; The values defined here are for the Rest Of the World.
+; These values are for the inquireData (KBINFO) structure defined below.
+; ('KeyInfo' in the Kernel, pState in USER)
+;
+BeginRange1 equ 255
+EndRange1 equ 254
+BeginRange2 equ 255
+EndRange2 equ 254
+
+sBegin DATA
+
+globalD bios_proc, 0
+globalD nmi_vector, 0
+;externD nmi_vector
+
+
+public fSysReq
+fSysReq db 0 ; Enables CTRL-ALT-SysReq if NZ
+
+; Keyboard information block (copied to 'KeyInfo' in the kernel)
+; this is a KBINFO data structure.. defined in KERNEL.INC, USER.INC, USER.H
+; and WINDEFS.INC.
+;
+; As of 3.0, build 1.30, KBINFO includes the number of function keys
+; As of 3.0, build 1.59, the number of bytes in the state block is
+; fixed at 4 MAX, for compatibility with Excel 2.1c!!!
+;
+ PUBLIC inquireData
+ PUBLIC iqdNumFunc
+inquireData LABEL BYTE
+ DB BeginRange1
+ DB EndRange1
+ DB BeginRange2
+ DB EndRange2
+ DW 4 ; #bytes of state info for ToAscii()
+iqdNumFunc label word
+ dw 10 ; number of function keys
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+assumes DS,DATA
+
+;***************************************************************************
+;
+; Inquire( pKBINFO ) - copies information about the keyboard hardware into
+; the area pointer to by the long pointer argument. Returns a count of the
+; number of bytes copied.
+;
+; The Windows kernel calls this to copy information to its 'KeyInfo' data
+; structure.
+;
+;***************************************************************************
+cProc Inquire,<PUBLIC,FAR>,<si,di>
+ parmD pKBINFO
+
+cBegin Inquire
+ ; .. now pass data to Windows ..
+ les di,pKBINFO ; Get far pointer of destination area
+ mov si, OFFSET inquireData ; Get source
+ mov ax,size KBINFO ; Get number of bytes to move
+ mov cx,ax ; (Return byte count in AX)
+ rep movsb ; Move the bytes
+
+cEnd Inquire
+
+;---------------------------------------------------------------------
+;
+;---- ScreenSwitchEnable( fEnable ) ----------------------------------
+;
+; This function is called by the display driver to inform the keyboard
+; driver that the display driver is in a critical section and to ignore
+; all OS/2 screen switches until the display driver leaves its
+; critical section. The fEnable parameter is set to 0 to disable
+; screen switches, and a NONZERO value to re-enable them. At startup,
+; screen switches are enabled.
+;---------------------------------------------------------------------
+;
+
+cProc ScreenSwitchEnable,<PUBLIC,FAR>
+parmW fEnable
+
+cBegin ScreenSwitchEnable
+
+ mov ax,fEnable ; get WORD parameter
+ or al,ah ; stuff any NZ bits into AL
+;;; mov fSwitchEnable,al ; save BYTE.
+
+cEnd ScreenSwitchEnable
+
+;---------------------------------------------------------------------
+;
+;---- EnableKBSysReq( fSys ) ----------------------------------
+;
+; This function enables and shuttles off NMI interrupt simulation
+; (trap to debugger) when CTRL-ALT-SysReq is pressed.
+; CVWBreak overides int 2.
+; fSysParm = 01 enable int 2
+; = 02 disable int 2
+; = 04 enable CVWBreak
+; = 08 disable CVWBreak
+;
+;---------------------------------------------------------------------
+;
+cProc EnableKBSysReq,<PUBLIC,FAR>
+parmW fSysParm
+
+cBegin EnableKBSysReq
+
+ mov ax, fSysParm ; get WORD parameter
+
+ test al,01 ; turn on int 2?
+ jz @F
+ or fSysReq,01 ; yes, turn it on!
+@@: test al,02 ; turn off int 2?
+ jz @F
+ and fSysReq,NOT 01 ; yes, turn it off!
+
+@@: test al,04 ; turn on CVWBreak?
+ jz @F
+ or fSysReq,02 ; yes, turn it on!
+@@: test al,08 ; turn off CVWBreak?
+ jz @F
+ and fSysReq,NOT 02 ; yes, turn it off!
+@@:
+ xor ah,ah
+ mov al,fSysReq
+
+ifdef NEWNMI
+ push ax ; save return value
+ call short GetNmi ; save NMI
+ pop ax ; restore ..
+endif
+
+cEnd EnableKBSysReq
+
+
+; save NMI vector. Called above in EnableKBSysReq() and in Enable().
+
+ifdef NEWNMI
+GetNmi proc near
+ mov ax,3502h
+ int 21h
+ mov word ptr ds:[nmi_vector][0],bx
+ mov word ptr ds:[nmi_vector][2],es
+ ret
+GetNmi endp
+endif
+
+;***************************************************************************
+;
+; Enable( eventProc ) - enable hardware keyboard interrupts, with the passed
+; procedure address being the target of all keyboard events.
+;
+; lpKeyState is a long pointer to the Windows 256 byte keystate table
+;
+;***************************************************************************
+cProc Enable,<PUBLIC,FAR>,<si,di>
+ parmD eventProc
+ parmD lpKeyState
+cBegin Enable
+ sub ax, ax
+cEnd Enable
+
+;***************************************************************************
+; Disable( eventProc ) - disable hardware keyboard interrupts, restoring
+; the previous IBM BIOS keyboard interrupt handler.
+;
+;***************************************************************************
+cProc Disable,<PUBLIC,FAR>,<si,di>
+
+cBegin Disable
+
+ sub ax,ax
+
+cEnd Disable
+
+; ** GetTableSeg() ***************************************
+;
+; This finds the paragraph of the TABS segment and stores
+; it in TableSeg.
+;
+; Calling this will force the segment to be loaded.
+;
+; This segment isn't written to.
+;
+; REMEMBER that AX is TRASHED !!
+
+
+cProc GetTableSeg,<PUBLIC,FAR>,<si,di>
+cBegin GetTableSeg
+
+;;; mov ax,cs
+;;; mov TableSeg,ax
+
+cEnd GetTableSeg
+
+;***************************************************************************
+;
+; NewTable()
+;
+; Change keyboard tables, if a keyboard table DLL is defined in
+; SYSTEM.INI and the function GetKbdTable() exists and returns
+; successfully.
+;
+; This function is passed no parameters by the caller -- it obtains
+; the following from SYSTEM.INI:
+;
+; [keyboard]
+; TYPE = 4 ; 1..6. 4 is enhanced kbd.
+; SUBTYPE = 0 ; 0 for all but Olivetti
+; ; 8086 systems & AT&T 6300+
+; KEYBOARD.DLL = kbdus.dll ; name of DLL file
+; OEMANSI.BIN = XLATNO.BIN ; oem/ansi tables file
+;
+; The module name of the DLL is expected to be the root of the DLL's
+; file name. In any event, the module name must be different for
+; each keyboard-table DLL!
+;
+;***************************************************************************
+
+cProc NewTable,<PUBLIC,FAR>,<si,di>
+ ; LOCAL variables on stack:
+
+cBegin NewTable
+ sub ax,ax
+cEnd NewTable
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; SetSpeed.asm
+;
+;
+; Sets 'typematic' speed of AT-type keyboards (type code 3 or 4 in this
+; driver).
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+cProc SetSpeed,<FAR,PASCAL,PUBLIC>
+ parmW rate_of_speed
+cBegin
+
+SS_error_return:
+ mov ax,-1 ; error return
+
+SS_end:
+cEnd
+
+
+cProc GetBIOSKeyProc, <FAR, PUBLIC>
+cBegin
+ mov ax, word ptr [bios_proc][0]
+ mov dx, word ptr [bios_proc][2]
+cEnd
+
+sEnd CODE
+
+
+end
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.asm b/private/mvdm/wow16/drivers/keyboard/keyboard.asm
new file mode 100644
index 000000000..e234209b9
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.asm
@@ -0,0 +1,155 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; KBD.ASM
+; Win16 KEYBOARD thunks
+;
+; History:
+;
+; Created 06-Jan-1992 by NanduriR
+;--
+
+ TITLE KEYBOARD.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowkbd.inc
+ include cmacros.inc
+ include windefs.inc
+ include vdmtib.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows
+KEYBOARD_Identifier db 'KEYBOARD16 Data Segment'
+externD bios_proc
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+; Hung App Support
+; If USER32 is unable to terminate an app via End Task then it calls
+; WOW32 to kill the app. We do this by generating a keyboard h/w
+; interrupt 9. Since in WOW all keyboard input comes via USER32 the
+; keyboard h/w interrupt is unused for anything else so we can reuse
+; this interrupt.
+
+
+cProc KEYBOARD16,<PUBLIC,FAR>
+cBegin
+ mov ax,3500h or 09h
+ int 21h ; vector is in ES:BX
+ mov word ptr [bios_proc][0], bx
+ mov word ptr [bios_proc][2], es
+
+; Setup keyboard interrupt vector to point to our interrupt routine
+ mov ax,2500h or 09h
+ mov dx,OFFSET keybd_int
+ push ds ; save DS
+ push cs
+ pop ds ; set DS = CS
+ int 21h ; set the vector
+ pop ds ; restore DS
+ mov ax,1
+cEnd
+
+
+INTA0 equ 20h ;X'20' 8259 Interrupt Control Port
+EOI equ 20h ;X'20' 8259 End-of-Interrupt ack
+
+public keybd_int
+keybd_int PROC FAR
+ push ax
+ push bx
+ push es
+
+ mov al,EOI ; Send Non-Specific EOI
+ out INTA0,al
+
+;
+; Now we test the bit in low memory that is set by wow32 to see if this
+; is really a keyboard int forced in by the hung app support.
+;
+ mov ax, 40h ;use bios data selector
+ mov es, ax
+ mov bx, FIXED_NTVDMSTATE_LINEAR - 400h
+
+ .386 ;make it assemble
+.errnz VDM_WOWHUNGAPP AND 0ff00ffffh ;make sure it's the third byte
+ test byte ptr es:[bx+2], VDM_WOWHUNGAPP SHR 16
+
+ jnz short hungapp_exit ;jump if this is really a hung app
+
+ pop es
+ pop bx
+ pop ax
+ iret
+
+hungapp_exit:
+ and byte ptr es:[bx+2], 255 - (VDM_WOWHUNGAPP SHR 16) ; turn it off
+ pop es
+ pop bx
+ pop ax
+ .286p
+
+ mov ax,4CFFH ; They said OK to Nuke app.
+ int 21h
+keybd_int ENDP
+
+
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+
+assumes DS,NOTHING
+
+;;; KbdThunk INQUIRE ;Internal LOCALAPI
+;;; KbdThunk ENABLE ;Internal
+;;; KbdThunk DISABLE ;Internal
+ KbdThunk TOASCII
+ KbdThunk ANSITOOEM
+ KbdThunk OEMTOANSI
+;;; KbdThunk SETSPEED ;Internal
+;;; KbdThunk SCREENSWITCHENABLE ;Internal
+;;; KbdThunk GETTABLESEG ;Internal
+;;; KbdThunk NEWTABLE ;Internal
+ KbdThunk OEMKEYSCAN
+ KbdThunk VKKEYSCAN
+ KbdThunk GETKEYBOARDTYPE
+ KbdThunk MAPVIRTUALKEY
+ KbdThunk GETKBCODEPAGE
+ KbdThunk GETKEYNAMETEXT
+ KbdThunk ANSITOOEMBUFF
+ KbdThunk OEMTOANSIBUFF
+;;; KbdThunk ENABLEKBSYSREQ ;Internal LOCALAPI
+;;; KbdThunk GETBIOSKEYPROC ; in kbdlocal.asm
+
+
+
+sEnd CODE
+
+end KEYBOARD16
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.def b/private/mvdm/wow16/drivers/keyboard/keyboard.def
new file mode 100644
index 000000000..4bbe239c7
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.def
@@ -0,0 +1,30 @@
+LIBRARY KEYBOARD
+
+DESCRIPTION 'WOW REPLACEMENT KEYBOARD (Enhanced keyboard)'
+EXETYPE WINDOWS
+CODE PRELOAD FIXED
+DATA PRELOAD FIXED SINGLE
+HEAPSIZE 0
+
+EXPORTS
+ WEP
+ INQUIRE @1 ;Internal
+ ENABLE @2 ;Internal
+ DISABLE @3 ;Internal
+ TOASCII @4
+ ANSITOOEM @5
+ OEMTOANSI @6
+ SETSPEED @7 ;Internal
+ SCREENSWITCHENABLE @100 ;Internal
+ GETTABLESEG @126 ;Internal
+ NEWTABLE @127 ;Internal
+ OEMKEYSCAN @128
+ VKKEYSCAN @129
+ GETKEYBOARDTYPE @130
+ MAPVIRTUALKEY @131
+ GETKBCODEPAGE @132
+ GETKEYNAMETEXT @133
+ ANSITOOEMBUFF @134
+ OEMTOANSIBUFF @135
+ ENABLEKBSYSREQ @136 ;Internal
+ GETBIOSKEYPROC @137
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.rc b/private/mvdm/wow16/drivers/keyboard/keyboard.rc
new file mode 100644
index 000000000..abd869a70
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* KEYBOARD.RC */
+/********************************************************************/
+#include "keyboard.rcv"
diff --git a/private/mvdm/wow16/drivers/keyboard/keyboard.rcv b/private/mvdm/wow16/drivers/keyboard/keyboard.rcv
new file mode 100644
index 000000000..58989318c
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/keyboard.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* KEYBOARD.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_KEYBOARD
+#define VER_FILEDESCRIPTION_STR "WOW Keyboard Driver Module"
+#define VER_INTERNALNAME_STR "KEYBOARD"
+#define VER_ORIGINALFILENAME_STR "KEYBOARD.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/keyboard/makefile b/private/mvdm/wow16/drivers/keyboard/makefile
new file mode 100644
index 000000000..11ecfe472
--- /dev/null
+++ b/private/mvdm/wow16/drivers/keyboard/makefile
@@ -0,0 +1,114 @@
+# keyboard16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 26-Jan-1991 Jeff Parsons (jeffpar)
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2.
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\libw.lib ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) $*.rc -fo $@
+
+all: keyboard.drv keyboard.map keyboard.sym
+ binplace keyboard.drv keyboard.map keyboard.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+keyboard.obj: $*.asm ..\..\..\inc\wow.inc ..\..\..\inc\wowkbd.inc
+
+kbdlocal.obj: $*.asm ..\..\..\inc\wow.inc ..\..\..\inc\wowkbd.inc
+
+keyboard.res: $*.rc $*.rcv ..\..\inc\common.ver
+
+keyboard.lrf: makefile
+ echo $*.obj kbdlocal.obj >$@
+ echo $*.exe/align:16>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /map /nod>>$@
+ echo $*;>>$@
+
+keyboard.drv: $*.obj kbdlocal.obj $*.def $*.res $*.lrf
+ link16 @$*.lrf;
+ rc16 -t $*.res $*.exe
+ if exist *.drv del *.drv
+ ren $*.exe $@
+
+keyboard.sym: $*.map
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/mouse/makefile b/private/mvdm/wow16/drivers/mouse/makefile
new file mode 100644
index 000000000..20e1807c5
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/makefile
@@ -0,0 +1,110 @@
+# mouse16 makefile
+#
+# Copyright (c) 1991, Microsoft Corporation
+#
+# History:
+# 30-Sept-1992 Chandan Chauhan (ChandanC)
+#
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2.
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\libw.lib ..\..\lib\snocrtd.lib
+
+
+.asm.obj:
+ masm $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) $*.rc -fo $@
+
+all: mouse.exe mouse.map mouse.sym
+ copy mouse.exe mouse.drv
+ binplace mouse.drv mouse.map mouse.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.drv del *.drv
+ if exist *.lst del *.lst
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.res del *.res
+
+mouse.obj: $*.asm ..\..\..\inc\wow.inc
+ masm -l $(AOBJ) $*;
+
+mouse.lrf: makefile
+ echo $*.obj >$@
+ echo $*.exe>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /nod>>$@
+ echo $*;>>$@
+
+mouse.res: mouse.rc mouse.rcv ..\..\inc\common.ver
+
+mouse.exe mouse.map: mouse.obj mouse.lrf mouse.def mouse.res
+ link16 @mouse.lrf;
+ rc16 -t mouse.res mouse.exe
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.asm b/private/mvdm/wow16/drivers/mouse/mouse.asm
new file mode 100644
index 000000000..82d26ffd0
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.asm
@@ -0,0 +1,224 @@
+ TITLE MOUSE.ASM
+ PAGE ,132
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; MOUSE.ASM
+; Thunks in 16-bit space to route Windows API calls to WOW32
+;
+; History:
+; 30-Sept-1992 Chandan Chauhan (ChandanC)
+; Created.
+;
+; Freehand and ??? need mouse driver.
+;
+
+
+ .286p
+
+ .xlist
+ include cmacros.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows //!!!!! what is this
+
+mouse_Identifier db 'mouse'
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,DATA
+assumes ES,NOTHING
+
+
+
+cProc MOUSE,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+ cBegin <nogen>
+ mov ax,1 ;always indicate success
+ ret
+ cEnd <nogen>
+
+
+
+;--------------------------Exported-Routine-----------------------------;
+; int Inquire(lp_mouse_info);
+;
+; Information regarding the mouse is returned to the caller.
+;
+; Entry:
+; None
+; Returns:
+; AX = # bytes returned in lp_mouse_info
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc Inquire,<FAR,PUBLIC,WIN,PASCAL>,<di>
+
+ parmD lp_mouse_info
+
+cBegin
+ xor ax, ax
+
+cEnd
+
+
+
+
+;--------------------------Exported-Routine-----------------------------;
+; void Enable(lp_event_proc);
+;
+; Enable hardware mouse interrupts, with the passed procedure address
+; being the target of all mouse events.
+;
+; This routine may be called while already enabled. In this case the
+; passed event procedure should be saved, and all other initialization
+; skipped.
+;
+; Entry:
+; None
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc Enable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+
+ parmD new_event_proc
+
+cBegin
+
+; The new event procedure is always saved regardless of the
+; mouse already being enabled. This allows the event proc
+; to be changed as needed.
+
+ xor ax, ax
+
+cEnd
+
+;--------------------------Exported-Routine-----------------------------;
+; void Disable();
+;
+; Disable hardware mouse interrupts, restoring the previous mouse
+; interrupt handler and 8259 interrupt enable mask.
+;
+; This routine may be called while already disabled. In this case the
+; disabling should be ignored.
+;
+; Entry:
+; None
+; Returns:
+; None
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc Disable,<FAR,PUBLIC,WIN,PASCAL>,<si,di>
+
+cBegin
+ xor ax, ax
+
+cEnd
+
+;--------------------------Exported-Routine-----------------------------;
+; WORD WEP();
+;
+; Generic WEP.
+;
+; Entry:
+; None
+; Returns:
+; AX = 1
+; Error Returns:
+; None
+; Registers Preserved:
+; all
+; Registers Destroyed:
+; none
+;-----------------------------------------------------------------------;
+
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc WEP,<FAR,PUBLIC,WIN,PASCAL>
+; parmW stuff
+cBegin nogen
+ mov ax,1
+ ret 2
+cEnd nogen
+
+;--------------------------Exported-Routine-----------------------------;
+; int MouseGetIntVect();
+;
+; The interrupt vector used by the mouse is returned to the caller.
+; If no mouse is found, then -1 is returned.
+;
+; Entry:
+; None
+; Returns:
+; AX = interrupt vector
+; AX = -1 if no mouse was found
+; Error Returns:
+; None
+; Registers Preserved:
+; SI,DI,DS,BP
+; Registers Destroyed:
+; AX,BX,CX,DX,ES,FLAGS
+;-----------------------------------------------------------------------;
+
+
+ assumes cs,Code
+ assumes ds,Data
+
+cProc MouseGetIntVect,<FAR,PUBLIC,WIN,PASCAL>
+
+cBegin
+ mov al, -1
+cEnd
+
+
+
+assumes DS,DATA
+
+assumes DS,NOTHING
+
+sEnd CODE
+
+end MOUSE
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.def b/private/mvdm/wow16/drivers/mouse/mouse.def
new file mode 100644
index 000000000..05dd6a179
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.def
@@ -0,0 +1,16 @@
+LIBRARY MOUSE
+
+DESCRIPTION 'Microsoft Mouse'
+
+EXETYPE WINDOWS
+STUB '..\..\bin\WINSTUB.EXE'
+
+CODE PRELOAD DISCARDABLE
+DATA PRELOAD FIXED SINGLE
+
+EXPORTS
+ Inquire @1
+ Enable @2
+ Disable @3
+ MouseGetIntVect @4
+ WEP
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.rc b/private/mvdm/wow16/drivers/mouse/mouse.rc
new file mode 100644
index 000000000..63c7913b7
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* MOUSE.RC */
+/********************************************************************/
+#include "mouse.rcv"
diff --git a/private/mvdm/wow16/drivers/mouse/mouse.rcv b/private/mvdm/wow16/drivers/mouse/mouse.rcv
new file mode 100644
index 000000000..c18f8290a
--- /dev/null
+++ b/private/mvdm/wow16/drivers/mouse/mouse.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* MOUSE.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_MOUSE
+#define VER_FILEDESCRIPTION_STR "WOW MOUSE Driver Module"
+#define VER_INTERNALNAME_STR "MOUSE"
+#define VER_ORIGINALFILENAME_STR "MOUSE.DRV"
+
+#include <common.ver>
diff --git a/private/mvdm/wow16/drivers/sound/makefile b/private/mvdm/wow16/drivers/sound/makefile
new file mode 100644
index 000000000..71554cdc9
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/makefile
@@ -0,0 +1,109 @@
+# Sound16 makefile
+#
+# Copyright (c) 1992, Microsoft Corporation
+#
+# History:
+# 27-Mar-1992 Nandurir
+# Created.
+#
+
+!IFDEF USEBUILD
+
+# If using BUILD.EXE, edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2.
+
+!INCLUDE $(NTMAKEENV)\makefile.def
+
+!ELSE
+
+.SUFFIXES:
+.SUFFIXES: .c .asm .h .inc .obj .lst .sys .exe .com .map .sym .def .lib .rc .res
+
+
+!ifdef INCLUDE
+INCS =
+!else
+INCS = -I..\..\inc -I..\..\..\inc
+!endif
+
+########## Path definition so we find 16 bit tools ##########
+# Also works around stupid bug in RC 3.1 that doesn't allow rcpp.err to be
+# in a directory that is greater than 128 chars down the path, even if
+# rc 3.1 is running as an OS/2 app.
+
+PATH = $(_NTBINDIR)\private\mvdm\tools16;$(PATH)
+
+# DEFINES = -DWOW -DDEBUG $(MVDMFLAGS)
+DEFINES = -DWOW $(MVDMFLAGS)
+
+AOBJ = -Ml -t $(DEFINES) $(INCS)
+
+CW16 = -AS -G2sw -Os -W3 -Zp $(DEFINES) $(INCS)
+CW16B = $(CW16) -B1 c1l.exe -B2 c2l.exe -B3 c3l.exe
+
+LINK = /map /align:16
+
+!if "$(NTDEBUG)"!="" && "$(NTDEBUG)"!="retail" && "$(NTDEBUG)" != "ntsdnodbg"
+AOBJ = $(AOBJ) -Zd
+CW16 = $(CW16) /Od /Oi /Zd
+LINK = $(LINK) /LI
+!endif
+
+W16LIBS = ..\..\lib\snocrtd.lib
+
+.asm.obj:
+ masm -L $(AOBJ) $*;
+
+.asm.lst:
+ masm $(AOBJ) -l $*,nul,$*.lst;
+
+.c.obj:
+ cl16 -c -nologo $(CW16) $*.c
+
+.c.lst:
+ cl16 -c -nologo $(CW16) -Fonul -Fc$*.lst $*.c
+
+
+.def.lib:
+ implib $*.lib $*.def
+
+.map.sym:
+ mapsym $*
+
+.rc.res:
+ rc16 -r $(INCS) -fo $@ $*.rc
+
+all: sound.drv sound.map sound.sym
+ binplace sound.drv sound.map sound.sym
+
+clean: cleanup all
+
+cleanup:
+ if exist *.lrf del *.lrf
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist *.drv del *.drv
+ if exist *.res del *.res
+
+sound.res: $*.rc $*.rcv ..\..\inc\common.ver
+
+sound.obj: $*.asm ..\..\..\inc\wow.inc ..\..\..\inc\wowsnd.inc
+ masm $(AOBJ) $*;
+
+sound.lrf: makefile
+ echo $*.obj >$@
+ echo $*.exe/align:16>>$@
+ echo $* $(LINK)>>$@
+ echo ..\..\lib\libw.lib ..\..\lib\snocrtd.lib /map /nod>>$@
+ echo $*;>>$@
+
+sound.drv: $*.obj $*.lrf $*.def $*.res
+ link16 @$*.lrf;
+ rc16 -t $*.res $*.exe
+ if exist $*.drv del $*.drv
+ ren $*.exe $@
+
+!ENDIF
diff --git a/private/mvdm/wow16/drivers/sound/sound.asm b/private/mvdm/wow16/drivers/sound/sound.asm
new file mode 100644
index 000000000..4ff4f7de6
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.asm
@@ -0,0 +1,88 @@
+;++
+;
+; WOW v1.0
+;
+; Copyright (c) 1991, Microsoft Corporation
+;
+; SOUND.ASM
+; Win16 SOUND thunks
+;
+; History:
+;
+; Created 06-Jan-1992 by NanduriR
+;--
+
+ TITLE SOUND.ASM
+ PAGE ,132
+
+ .286p
+
+ .xlist
+ include wow.inc
+ include wowsnd.inc
+ include cmacros.inc
+ include windefs.inc
+ .list
+
+ __acrtused = 0
+ public __acrtused ;satisfy external C ref.
+
+
+createSeg _TEXT,CODE,WORD,PUBLIC,CODE
+createSeg _DATA,DATA,WORD,PUBLIC,DATA,DGROUP
+defgrp DGROUP,DATA
+
+sBegin DATA
+Reserved db 16 dup (0) ;reserved for Windows
+SOUND_Identifier db 'SOUND16 Data Segment'
+
+
+sEnd DATA
+
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+cProc SOUND16,<PUBLIC,FAR,PASCAL,NODATA,ATOMIC>
+
+ cBegin <nogen>
+ mov ax,1
+ ret
+ cEnd <nogen>
+
+
+cProc WEP,<PUBLIC,FAR,PASCAL,NODATA,NOWIN,ATOMIC>
+ parmW iExit ;DLL exit code
+
+ cBegin
+ mov ax,1 ;always indicate success
+ cEnd
+
+
+assumes DS,NOTHING
+
+ SoundThunk OPENSOUND
+ SoundThunk CLOSESOUND
+ SoundThunk SETVOICEQUEUESIZE
+ SoundThunk SETVOICENOTE
+ SoundThunk SETVOICEACCENT
+ SoundThunk SETVOICEENVELOPE
+ SoundThunk SETSOUNDNOISE
+ SoundThunk SETVOICESOUND
+ SoundThunk STARTSOUND
+ SoundThunk STOPSOUND
+ SoundThunk WAITSOUNDSTATE
+ SoundThunk SYNCALLVOICES
+ SoundThunk COUNTVOICENOTES
+ SoundThunk GETTHRESHOLDEVENT
+ SoundThunk GETTHRESHOLDSTATUS
+ SoundThunk SETVOICETHRESHOLD
+ SoundThunk DOBEEP
+ SoundThunk MYOPENSOUND
+
+
+sEnd CODE
+
+end SOUND16
diff --git a/private/mvdm/wow16/drivers/sound/sound.def b/private/mvdm/wow16/drivers/sound/sound.def
new file mode 100644
index 000000000..fdb91863d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.def
@@ -0,0 +1,27 @@
+LIBRARY SOUND
+
+DESCRIPTION 'WOW REPLACEMENT SOUND DRIVER'
+EXETYPE WINDOWS
+CODE PRELOAD FIXED
+DATA FIXED SINGLE PRELOAD
+
+EXPORTS
+ OPENSOUND @1
+ CLOSESOUND @2
+ SETVOICEQUEUESIZE @3
+ SETVOICENOTE @4
+ SETVOICEACCENT @5
+ SETVOICEENVELOPE @6 NODATA
+ SETSOUNDNOISE @7 NODATA
+ SETVOICESOUND @8
+ STARTSOUND @9
+ STOPSOUND @10
+ WAITSOUNDSTATE @11
+ SYNCALLVOICES @12 NODATA
+ COUNTVOICENOTES @13
+ GETTHRESHOLDEVENT @14
+ GETTHRESHOLDSTATUS @15
+ SETVOICETHRESHOLD @16
+ DOBEEP @17 NODATA ;Internal
+ MYOPENSOUND @18 ;Internal
+ WEP NODATA ;Internal
diff --git a/private/mvdm/wow16/drivers/sound/sound.rc b/private/mvdm/wow16/drivers/sound/sound.rc
new file mode 100644
index 000000000..1d5afb03d
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.rc
@@ -0,0 +1,4 @@
+/********************************************************************/
+/* SOUND.RC */
+/********************************************************************/
+#include "sound.rcv"
diff --git a/private/mvdm/wow16/drivers/sound/sound.rcv b/private/mvdm/wow16/drivers/sound/sound.rcv
new file mode 100644
index 000000000..2a8856150
--- /dev/null
+++ b/private/mvdm/wow16/drivers/sound/sound.rcv
@@ -0,0 +1,12 @@
+/********************************************************************/
+/* SOUND.RCV */
+/********************************************************************/
+#include <version.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SOUND
+#define VER_FILEDESCRIPTION_STR "WOW SOUND Driver Module"
+#define VER_INTERNALNAME_STR "SOUND"
+#define VER_ORIGINALFILENAME_STR "SOUND.DRV"
+
+#include <common.ver>