Compare commits

..

No commits in common. "4218da32eb27119c81330942a6ca20f1f9cd6932" and "f666825417c589cbba7dd911156f79a65bce3151" have entirely different histories.

10 changed files with 80 additions and 525 deletions

View file

@ -1,4 +1,4 @@
// commdrv.c - KPCOMM.DRV -- High-speed COMM.DRV replacement // commdrv.c - High-speed COMM.DRV replacement
// //
// All exported COMM.DRV functions, ring buffer management, port // All exported COMM.DRV functions, ring buffer management, port
// initialization, 16550 FIFO detection, and flow control. // initialization, 16550 FIFO detection, and flow control.
@ -10,154 +10,12 @@
#include <dos.h> #include <dos.h>
#include <string.h> #include <string.h>
// -----------------------------------------------------------------------
// Debug logging via OutputDebugString
// -----------------------------------------------------------------------
#define DBG_ENABLED 0
#if DBG_ENABLED
static void dbgStr(const char FAR *msg)
{
OutputDebugString(msg);
}
// Log a label and a 16-bit hex value: "label: 0xNNNN\r\n"
static void dbgHex16(const char FAR *label, uint16_t val)
{
static const char hex[] = "0123456789ABCDEF";
char buf[48];
int i;
for (i = 0; i < 40 && label[i]; i++) {
buf[i] = label[i];
}
buf[i++] = ':';
buf[i++] = ' ';
buf[i++] = '0';
buf[i++] = 'x';
buf[i++] = hex[(val >> 12) & 0xF];
buf[i++] = hex[(val >> 8) & 0xF];
buf[i++] = hex[(val >> 4) & 0xF];
buf[i++] = hex[val & 0xF];
buf[i++] = '\r';
buf[i++] = '\n';
buf[i] = '\0';
OutputDebugString(buf);
}
// Log a label and a signed 16-bit value: "label: -NNNN\r\n"
static void dbgInt16(const char FAR *label, int16_t val)
{
char buf[48];
int i;
uint16_t uv;
for (i = 0; i < 40 && label[i]; i++) {
buf[i] = label[i];
}
buf[i++] = ':';
buf[i++] = ' ';
if (val < 0) {
buf[i++] = '-';
uv = (uint16_t)(-(int)val);
} else {
uv = (uint16_t)val;
}
// Print decimal (up to 5 digits)
{
char digits[6];
int n = 0;
do {
digits[n++] = (char)('0' + (uv % 10));
uv /= 10;
} while (uv > 0);
while (n > 0) {
buf[i++] = digits[--n];
}
}
buf[i++] = '\r';
buf[i++] = '\n';
buf[i] = '\0';
OutputDebugString(buf);
}
// Log a FAR pointer as "label: SSSS:OOOO\r\n"
static void dbgFarPtr(const char FAR *label, void FAR *ptr)
{
static const char hex[] = "0123456789ABCDEF";
char buf[48];
int i;
uint16_t seg;
uint16_t off;
seg = _FP_SEG(ptr);
off = _FP_OFF(ptr);
for (i = 0; i < 32 && label[i]; i++) {
buf[i] = label[i];
}
buf[i++] = ':';
buf[i++] = ' ';
buf[i++] = hex[(seg >> 12) & 0xF];
buf[i++] = hex[(seg >> 8) & 0xF];
buf[i++] = hex[(seg >> 4) & 0xF];
buf[i++] = hex[seg & 0xF];
buf[i++] = ':';
buf[i++] = hex[(off >> 12) & 0xF];
buf[i++] = hex[(off >> 8) & 0xF];
buf[i++] = hex[(off >> 4) & 0xF];
buf[i++] = hex[off & 0xF];
buf[i++] = '\r';
buf[i++] = '\n';
buf[i] = '\0';
OutputDebugString(buf);
}
// Hex dump first 'count' bytes at a FAR pointer
static void dbgDump(const char FAR *label, void FAR *ptr, int count)
{
static const char hex[] = "0123456789ABCDEF";
char buf[80];
uint8_t FAR *p;
int i;
int bi;
p = (uint8_t FAR *)ptr;
// Print label
for (bi = 0; bi < 32 && label[bi]; bi++) {
buf[bi] = label[bi];
}
buf[bi++] = ':';
buf[bi++] = ' ';
for (i = 0; i < count && bi < 70; i++) {
buf[bi++] = hex[(p[i] >> 4) & 0xF];
buf[bi++] = hex[p[i] & 0xF];
buf[bi++] = ' ';
}
buf[bi++] = '\r';
buf[bi++] = '\n';
buf[bi] = '\0';
OutputDebugString(buf);
}
#else
#define dbgStr(msg) ((void)0)
#define dbgHex16(label, val) ((void)0)
#define dbgInt16(label, val) ((void)0)
#define dbgFarPtr(label, p) ((void)0)
#define dbgDump(l, p, n) ((void)0)
#endif
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Prototypes // Prototypes
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export inicom(DCB FAR *dcb); int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize);
int16_t FAR PASCAL _export setcom(DCB FAR *dcb); int16_t FAR PASCAL _export setcom(DCB FAR *dcb);
int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSize, int16_t txSize); int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBuf, int16_t rxSize, char FAR *txBuf, int16_t txSize);
int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch); int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch);
@ -169,14 +27,13 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func);
int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue); int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue);
int16_t FAR PASCAL _export csetbrk(int16_t commId); int16_t FAR PASCAL _export csetbrk(int16_t commId);
int16_t FAR PASCAL _export cclrbrk(int16_t commId); int16_t FAR PASCAL _export cclrbrk(int16_t commId);
DCB FAR * FAR PASCAL _export getdcb(int16_t commId); int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb);
void FAR PASCAL _export suspendOpenCommPorts(void); void FAR PASCAL _export suspendOpenCommPorts(void);
void FAR PASCAL _export reactivateOpenCommPorts(void); void FAR PASCAL _export reactivateOpenCommPorts(void);
int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh); int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh);
int FAR PASCAL _export commNotifyWndProc(void);
int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpCmdLine); int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lpCmdLine);
int FAR PASCAL _export WEP(int nParam); int FAR PASCAL _export WEP(int nParam);
@ -189,7 +46,7 @@ static int16_t freeBuffers(PortStateT *port);
static int16_t initBuffers(PortStateT *port, uint16_t rxSz, uint16_t txSz); static int16_t initBuffers(PortStateT *port, uint16_t rxSz, uint16_t txSz);
static void initPortState(PortStateT *port, int16_t commId); static void initPortState(PortStateT *port, int16_t commId);
void primeTx(PortStateT *port); void primeTx(PortStateT *port);
static void readPortConfig(int16_t commId, uint16_t FAR *baseAddr, uint8_t FAR *irq); static void readPortConfig(int16_t commId, uint16_t *baseAddr, uint8_t *irq);
static uint16_t readSystemIni(const char FAR *section, const char FAR *key, uint16_t defVal); static uint16_t readSystemIni(const char FAR *section, const char FAR *key, uint16_t defVal);
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -213,18 +70,6 @@ PortStateT ports[MAX_PORTS];
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
static HANDLE ghInstance = NULL; static HANDLE ghInstance = NULL;
// -----------------------------------------------------------------------
// Dynamically resolved PostMessage
//
// comm.drv is loaded from [boot] before USER.EXE, so we can't have a
// static import for PostMessage. Resolve it on first use via
// GetProcAddress(GetModuleHandle("USER"), "PostMessage").
// -----------------------------------------------------------------------
PostMessageProcT pfnPostMessage = NULL;
// ISR hit counter for diagnostics
volatile uint16_t isrHitCount = 0;
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// applyBaudRate - Set the baud rate divisor on the UART // applyBaudRate - Set the baud rate divisor on the UART
@ -370,8 +215,6 @@ int16_t FAR PASCAL _export cclrbrk(int16_t commId)
PortStateT *port; PortStateT *port;
uint8_t lcr; uint8_t lcr;
dbgInt16("KPCOMM: cclrbrk Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -400,22 +243,6 @@ int32_t FAR PASCAL _export cevt(int16_t commId, int16_t evtMask)
{ {
PortStateT *port; PortStateT *port;
uint16_t FAR *ptr; uint16_t FAR *ptr;
int32_t retVal;
#if DBG_ENABLED
{
uint16_t ssSeg;
uint16_t bpVal;
_asm mov ssSeg, ss
_asm mov bpVal, bp
dbgHex16("KPCOMM: cevt SS", ssSeg);
dbgHex16("KPCOMM: cevt BP", bpVal);
dbgDump("KPCOMM: cevt stk", (void FAR *)((uint32_t)ssSeg << 16 | (bpVal + 6)), 16);
}
#endif
dbgInt16("KPCOMM: cevt Id", commId);
dbgHex16("KPCOMM: cevt mask", (uint16_t)evtMask);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return 0L; return 0L;
@ -423,18 +250,13 @@ int32_t FAR PASCAL _export cevt(int16_t commId, int16_t evtMask)
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: cevt not open\r\n");
return 0L; return 0L;
} }
port->comDeb.evtMask = (uint16_t)evtMask; port->evtMask = (uint16_t)evtMask;
ptr = &port->comDeb.evtWord; ptr = &port->evtWord;
retVal = (int32_t)(void FAR *)ptr; return (int32_t)(void FAR *)ptr;
dbgHex16("KPCOMM: cevt retSeg", (uint16_t)(retVal >> 16));
dbgHex16("KPCOMM: cevt retOff", (uint16_t)(retVal & 0xFFFF));
dbgStr("KPCOMM: cevt OK\r\n");
return retVal;
} }
@ -448,8 +270,6 @@ uint16_t FAR PASCAL _export cevtget(int16_t commId, int16_t evtMask)
PortStateT *port; PortStateT *port;
uint16_t events; uint16_t events;
dbgInt16("KPCOMM: cevtget Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return 0; return 0;
} }
@ -460,8 +280,8 @@ uint16_t FAR PASCAL _export cevtget(int16_t commId, int16_t evtMask)
} }
_disable(); _disable();
events = port->comDeb.evtWord & (uint16_t)evtMask; events = port->evtWord & (uint16_t)evtMask;
port->comDeb.evtWord &= ~(uint16_t)evtMask; port->evtWord &= ~(uint16_t)evtMask;
_enable(); _enable();
return events; return events;
@ -479,9 +299,6 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func)
uint8_t mcr; uint8_t mcr;
uint16_t base; uint16_t base;
dbgInt16("KPCOMM: cextfcn Id", commId);
dbgInt16("KPCOMM: cextfcn func", func);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -511,9 +328,9 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func)
mcr &= ~MCR_RTS; mcr &= ~MCR_RTS;
port->rtsState = FALSE; port->rtsState = FALSE;
break; break;
case ESC_SETBREAK: case SETBREAK:
return csetbrk(commId); return csetbrk(commId);
case ESC_CLRBREAK: case CLRBREAK:
return cclrbrk(commId); return cclrbrk(commId);
case RESETDEV: case RESETDEV:
// No-op for serial ports // No-op for serial ports
@ -547,8 +364,6 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue)
{ {
PortStateT *port; PortStateT *port;
dbgInt16("KPCOMM: cflush Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -563,9 +378,6 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue)
port->rxHead = 0; port->rxHead = 0;
port->rxTail = 0; port->rxTail = 0;
port->rxCount = 0; port->rxCount = 0;
port->comDeb.qInHead = 0;
port->comDeb.qInTail = 0;
port->comDeb.qInCount = 0;
// Reset FIFO to clear hardware buffer too // Reset FIFO to clear hardware buffer too
if (port->is16550 && port->fifoEnabled) { if (port->is16550 && port->fifoEnabled) {
_outp(port->baseAddr + UART_FCR, FCR_ENABLE | FCR_RX_RESET | port->fifoTrigger); _outp(port->baseAddr + UART_FCR, FCR_ENABLE | FCR_RX_RESET | port->fifoTrigger);
@ -574,9 +386,6 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue)
port->txHead = 0; port->txHead = 0;
port->txTail = 0; port->txTail = 0;
port->txCount = 0; port->txCount = 0;
port->comDeb.qOutHead = 0;
port->comDeb.qOutTail = 0;
port->comDeb.qOutCount = 0;
if (port->is16550 && port->fifoEnabled) { if (port->is16550 && port->fifoEnabled) {
_outp(port->baseAddr + UART_FCR, FCR_ENABLE | FCR_TX_RESET | port->fifoTrigger); _outp(port->baseAddr + UART_FCR, FCR_ENABLE | FCR_TX_RESET | port->fifoTrigger);
} }
@ -592,26 +401,10 @@ int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len) int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len)
{ {
dbgInt16("KPCOMM: commWriteStr Id", commId);
return sndcom(commId, buf, len); return sndcom(commId, buf, len);
} }
// -----------------------------------------------------------------------
// commNotifyWndProc - Ordinal 101 stub (undocumented, Win 3.1 compat)
//
// The stock COMM.DRV and CyberCom export an unnamed function at ordinal
// 101. Purpose is undocumented; may be an internal callback used by
// USER.EXE. CyberCom's implementation uses plain RETF (no params).
// Return 0 (not handled).
// -----------------------------------------------------------------------
int FAR PASCAL _export commNotifyWndProc(void)
{
dbgStr("KPCOMM: ord101 called\r\n");
return 0;
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// csetbrk - Assert break signal (ordinal 13) // csetbrk - Assert break signal (ordinal 13)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -620,8 +413,6 @@ int16_t FAR PASCAL _export csetbrk(int16_t commId)
PortStateT *port; PortStateT *port;
uint8_t lcr; uint8_t lcr;
dbgInt16("KPCOMM: csetbrk Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -646,8 +437,6 @@ int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch)
{ {
PortStateT *port; PortStateT *port;
dbgInt16("KPCOMM: ctx Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -715,35 +504,19 @@ int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t
{ {
PortStateT *port; PortStateT *port;
dbgInt16("KPCOMM: enableNotif Id", commId);
dbgHex16("KPCOMM: enableNotif hwnd", (uint16_t)hwnd);
dbgInt16("KPCOMM: enableNotif rxTh", rxThresh);
dbgInt16("KPCOMM: enableNotif txTh", txThresh);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return FALSE; return FALSE;
} }
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: enableNotif not open\r\n");
return FALSE; return FALSE;
} }
// Lazily resolve PostMessage from USER.EXE
// (not available at boot when comm.drv is loaded from [boot])
if (!pfnPostMessage) {
HMODULE hUser = GetModuleHandle("USER");
if (hUser) {
pfnPostMessage = (PostMessageProcT)GetProcAddress(hUser, "PostMessage");
}
}
port->hwndNotify = hwnd; port->hwndNotify = hwnd;
port->rxNotifyThresh = rxThresh; port->rxNotifyThresh = rxThresh;
port->txNotifyThresh = txThresh; port->txNotifyThresh = txThresh;
dbgStr("KPCOMM: enableNotif OK\r\n");
return TRUE; return TRUE;
} }
@ -778,32 +551,23 @@ static int16_t freeBuffers(PortStateT *port)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// getdcb - Return pointer to internal DCB (ordinal 15) // getdcb - Copy current DCB settings (ordinal 15)
//
// Takes int16_t commId (2 bytes, RETF 2). Returns DCB FAR * in DX:AX.
// The caller (USER.EXE / COMMTASK.DLL) copies from this pointer.
// CyberCom confirms: RETF 2, return pointer.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
DCB FAR * FAR PASCAL _export getdcb(int16_t commId) int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb)
{ {
PortStateT *port; PortStateT *port;
dbgInt16("KPCOMM: getdcb Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
dbgStr("KPCOMM: getdcb bad id\r\n"); return -1;
return NULL;
} }
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: getdcb not open\r\n"); return -1;
return NULL;
} }
dbgHex16("KPCOMM: getdcb isrHits", isrHitCount); _fmemcpy(dcb, &port->dcb, sizeof(DCB));
dbgStr("KPCOMM: getdcb OK\r\n"); return 0;
return &port->dcb;
} }
@ -817,7 +581,7 @@ DCB FAR * FAR PASCAL _export getdcb(int16_t commId)
// //
// Returns commId (0-3) on success, negative error code on failure. // Returns commId (0-3) on success, negative error code on failure.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export inicom(DCB FAR *dcb) int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize)
{ {
int16_t commId; int16_t commId;
PortStateT *port; PortStateT *port;
@ -825,52 +589,25 @@ int16_t FAR PASCAL _export inicom(DCB FAR *dcb)
uint16_t txBufSize; uint16_t txBufSize;
uint8_t mcr; uint8_t mcr;
dbgStr("KPCOMM: inicom enter\r\n"); (void)rxBuf;
(void)rxSize;
// Dump raw stack to see actual parameters passed by caller
{
uint16_t bpVal;
uint16_t ssVal;
void FAR *stkPtr;
_asm mov bpVal, bp
_asm mov ssVal, ss
stkPtr = (void FAR *)((uint32_t)ssVal << 16 | (bpVal + 6));
dbgHex16("KPCOMM: inicom SS", ssVal);
dbgHex16("KPCOMM: inicom BP", bpVal);
dbgDump("KPCOMM: inicom stk", stkPtr, 24);
}
if (!dcb) { if (!dcb) {
dbgStr("KPCOMM: inicom NULL dcb\r\n");
return IE_DEFAULT; return IE_DEFAULT;
} }
dbgFarPtr("KPCOMM: inicom dcb", (void FAR *)dcb);
dbgDump("KPCOMM: inicom raw", (void FAR *)dcb, 16);
dbgHex16("KPCOMM: sizeof(DCB)", (uint16_t)sizeof(DCB));
commId = dcb->Id; commId = dcb->Id;
dbgInt16("KPCOMM: inicom Id", commId);
dbgHex16("KPCOMM: inicom BaudRate", dcb->BaudRate);
dbgHex16("KPCOMM: inicom ByteSize", (uint16_t)dcb->ByteSize);
dbgHex16("KPCOMM: inicom Parity", (uint16_t)dcb->Parity);
dbgHex16("KPCOMM: inicom StopBits", (uint16_t)dcb->StopBits);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
dbgStr("KPCOMM: inicom IE_BADID\r\n");
return IE_BADID; return IE_BADID;
} }
port = &ports[commId]; port = &ports[commId];
if (port->isOpen) { if (port->isOpen) {
dbgStr("KPCOMM: inicom IE_OPEN\r\n");
return IE_OPEN; return IE_OPEN;
} }
// Initialize port state // Initialize port state
initPortState(port, commId); initPortState(port, commId);
dbgHex16("KPCOMM: inicom baseAddr", port->baseAddr);
dbgHex16("KPCOMM: inicom irq", (uint16_t)port->irq);
// Read buffer sizes from SYSTEM.INI if available (COMnBuffer key) // Read buffer sizes from SYSTEM.INI if available (COMnBuffer key)
{ {
@ -889,26 +626,20 @@ int16_t FAR PASCAL _export inicom(DCB FAR *dcb)
rxBufSize = readSystemIni("386Enh", bufKey, DEFAULT_RX_SIZE); rxBufSize = readSystemIni("386Enh", bufKey, DEFAULT_RX_SIZE);
} }
txBufSize = rxBufSize; txBufSize = rxBufSize;
dbgHex16("KPCOMM: inicom rxBufSize", rxBufSize);
// Allocate ring buffers // Allocate ring buffers
if (initBuffers(port, rxBufSize, txBufSize) != 0) { if (initBuffers(port, rxBufSize, txBufSize) != 0) {
dbgStr("KPCOMM: inicom IE_MEMORY\r\n");
return IE_MEMORY; return IE_MEMORY;
} }
dbgStr("KPCOMM: inicom buffers OK\r\n");
// Detect 16550 FIFO // Detect 16550 FIFO
port->is16550 = (uint8_t)detect16550(port->baseAddr); port->is16550 = (uint8_t)detect16550(port->baseAddr);
dbgHex16("KPCOMM: inicom is16550", (uint16_t)port->is16550);
// Hook ISR // Hook ISR
if (hookIsr(port) != 0) { if (hookIsr(port) != 0) {
dbgStr("KPCOMM: inicom hookIsr FAIL\r\n");
freeBuffers(port); freeBuffers(port);
return IE_HARDWARE; return IE_HARDWARE;
} }
dbgStr("KPCOMM: inicom ISR hooked\r\n");
port->isOpen = TRUE; port->isOpen = TRUE;
@ -944,19 +675,12 @@ int16_t FAR PASCAL _export inicom(DCB FAR *dcb)
// Clear any pending status // Clear any pending status
_inp(port->baseAddr + UART_LSR); _inp(port->baseAddr + UART_LSR);
port->comDeb.msrShadow = (uint8_t)_inp(port->baseAddr + UART_MSR); _inp(port->baseAddr + UART_MSR);
_inp(port->baseAddr + UART_RBR); _inp(port->baseAddr + UART_RBR);
// Populate ComDEB for third-party compatibility
port->comDeb.port = port->baseAddr;
port->comDeb.baudRate = port->baudRate;
port->comDeb.qInSize = port->rxSize;
port->comDeb.qOutSize = port->txSize;
// Enable receive and line status interrupts // Enable receive and line status interrupts
_outp(port->baseAddr + UART_IER, IER_RDA | IER_LSI | IER_MSI); _outp(port->baseAddr + UART_IER, IER_RDA | IER_LSI | IER_MSI);
dbgInt16("KPCOMM: inicom OK, ret", commId);
return commId; return commId;
} }
@ -1109,8 +833,6 @@ void FAR PASCAL _export reactivateOpenCommPorts(void)
PortStateT *port; PortStateT *port;
uint8_t mcr; uint8_t mcr;
dbgStr("KPCOMM: reactivate\r\n");
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
port = &ports[i]; port = &ports[i];
if (!port->isOpen) { if (!port->isOpen) {
@ -1151,7 +873,6 @@ void FAR PASCAL _export reactivateOpenCommPorts(void)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len) int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len)
{ {
dbgInt16("KPCOMM: readCommStr Id", commId);
return reccom(commId, buf, len); return reccom(commId, buf, len);
} }
@ -1162,7 +883,7 @@ int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t
// Checks [386Enh] for COMnBase (hex) and COMnIRQ overrides. // Checks [386Enh] for COMnBase (hex) and COMnIRQ overrides.
// Falls back to standard defaults if not present. // Falls back to standard defaults if not present.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
static void readPortConfig(int16_t commId, uint16_t FAR *baseAddr, uint8_t FAR *irq) static void readPortConfig(int16_t commId, uint16_t *baseAddr, uint8_t *irq)
{ {
char key[10]; char key[10];
char buf[16]; char buf[16];
@ -1242,8 +963,6 @@ int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len)
uint8_t FAR *dst; uint8_t FAR *dst;
int16_t bytesRead; int16_t bytesRead;
dbgInt16("KPCOMM: reccom Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -1283,47 +1002,29 @@ int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len)
_enable(); _enable();
} }
// Sync ComDEB queue counts
port->comDeb.qInCount = port->rxCount;
port->comDeb.qInTail = port->rxTail;
return bytesRead; return bytesRead;
} }
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// setcom - Apply DCB settings to hardware (ordinal 2) // setcom - Apply DCB settings to hardware (ordinal 2)
//
// Takes DCB FAR * (4 bytes, RETF 4). CommId is in dcb->Id.
// Both USER.EXE and COMMTASK.DLL push 4 bytes for this call.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export setcom(DCB FAR *dcb) int16_t FAR PASCAL _export setcom(DCB FAR *dcb)
{ {
int16_t commId; int16_t commId;
PortStateT *port; PortStateT *port;
dbgStr("KPCOMM: setcom enter\r\n");
if (!dcb) { if (!dcb) {
dbgStr("KPCOMM: setcom NULL dcb\r\n");
return -1; return -1;
} }
commId = dcb->Id; commId = dcb->Id;
dbgInt16("KPCOMM: setcom Id", commId);
dbgHex16("KPCOMM: setcom BaudRate", dcb->BaudRate);
dbgHex16("KPCOMM: setcom ByteSize", (uint16_t)dcb->ByteSize);
dbgHex16("KPCOMM: setcom Parity", (uint16_t)dcb->Parity);
dbgHex16("KPCOMM: setcom StopBits", (uint16_t)dcb->StopBits);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
dbgStr("KPCOMM: setcom IE_BADID\r\n");
return IE_BADID; return IE_BADID;
} }
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: setcom port not open\r\n");
return -1; return -1;
} }
@ -1352,14 +1053,8 @@ int16_t FAR PASCAL _export setcom(DCB FAR *dcb)
port->xonLim = dcb->XonLim; port->xonLim = dcb->XonLim;
port->xoffLim = dcb->XoffLim; port->xoffLim = dcb->XoffLim;
// Sync ComDEB shadow fields
port->comDeb.baudRate = port->baudRate;
port->comDeb.lcrShadow = (uint8_t)_inp(port->baseAddr + UART_LCR);
port->comDeb.mcrShadow = (uint8_t)_inp(port->baseAddr + UART_MCR);
_enable(); _enable();
dbgStr("KPCOMM: setcom OK\r\n");
return 0; return 0;
} }
@ -1367,25 +1062,22 @@ int16_t FAR PASCAL _export setcom(DCB FAR *dcb)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// setque - Resize RX/TX buffers (ordinal 3) // setque - Resize RX/TX buffers (ordinal 3)
// //
// Caller passes port ID and requested RX/TX buffer sizes. // The stock driver ignores the buffer pointers passed by the caller
// We manage our own GlobalAlloc'd buffers. // and manages its own. We do the same: free old buffers, alloc new.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSz, int16_t txSz) int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBufArg, int16_t rxSz, char FAR *txBufArg, int16_t txSz)
{ {
PortStateT *port; PortStateT *port;
dbgInt16("KPCOMM: setque Id", commId); (void)rxBufArg;
dbgInt16("KPCOMM: setque rxSz", rxSz); (void)txBufArg;
dbgInt16("KPCOMM: setque txSz", txSz);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
dbgStr("KPCOMM: setque bad id\r\n");
return -1; return -1;
} }
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: setque port not open\r\n");
return -1; return -1;
} }
@ -1393,21 +1085,10 @@ int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSz, int16_t txSz)
freeBuffers(port); freeBuffers(port);
if (initBuffers(port, (uint16_t)rxSz, (uint16_t)txSz) != 0) { if (initBuffers(port, (uint16_t)rxSz, (uint16_t)txSz) != 0) {
_enable(); _enable();
dbgStr("KPCOMM: setque IE_MEMORY\r\n");
return IE_MEMORY; return IE_MEMORY;
} }
// Sync ComDEB queue sizes
port->comDeb.qInSize = port->rxSize;
port->comDeb.qInCount = 0;
port->comDeb.qInHead = 0;
port->comDeb.qInTail = 0;
port->comDeb.qOutSize = port->txSize;
port->comDeb.qOutCount = 0;
port->comDeb.qOutHead = 0;
port->comDeb.qOutTail = 0;
_enable(); _enable();
dbgStr("KPCOMM: setque OK\r\n");
return 0; return 0;
} }
@ -1424,8 +1105,6 @@ int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len)
uint8_t FAR *src; uint8_t FAR *src;
int16_t bytesWritten; int16_t bytesWritten;
dbgInt16("KPCOMM: sndcom Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
@ -1455,10 +1134,6 @@ int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len)
} }
_enable(); _enable();
// Sync ComDEB queue counts
port->comDeb.qOutCount = port->txCount;
port->comDeb.qOutHead = port->txHead;
// Prime transmitter if we wrote anything // Prime transmitter if we wrote anything
if (bytesWritten > 0 && !port->txStopped) { if (bytesWritten > 0 && !port->txStopped) {
primeTx(port); primeTx(port);
@ -1479,16 +1154,12 @@ int16_t FAR PASCAL _export stacom(int16_t commId, COMSTAT FAR *stat)
PortStateT *port; PortStateT *port;
int16_t errors; int16_t errors;
dbgInt16("KPCOMM: stacom Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
dbgStr("KPCOMM: stacom bad id\r\n");
return -1; return -1;
} }
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: stacom not open\r\n");
return -1; return -1;
} }
@ -1506,7 +1177,6 @@ int16_t FAR PASCAL _export stacom(int16_t commId, COMSTAT FAR *stat)
stat->cbOutQue = port->txCount; stat->cbOutQue = port->txCount;
} }
dbgHex16("KPCOMM: stacom errors", (uint16_t)errors);
return errors; return errors;
} }
@ -1522,8 +1192,6 @@ void FAR PASCAL _export suspendOpenCommPorts(void)
int16_t i; int16_t i;
PortStateT *port; PortStateT *port;
dbgStr("KPCOMM: suspend\r\n");
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
port = &ports[i]; port = &ports[i];
if (!port->isOpen) { if (!port->isOpen) {
@ -1553,15 +1221,12 @@ int16_t FAR PASCAL _export trmcom(int16_t commId)
{ {
PortStateT *port; PortStateT *port;
dbgInt16("KPCOMM: trmcom Id", commId);
if (commId < 0 || commId >= MAX_PORTS) { if (commId < 0 || commId >= MAX_PORTS) {
return -1; return -1;
} }
port = &ports[commId]; port = &ports[commId];
if (!port->isOpen) { if (!port->isOpen) {
dbgStr("KPCOMM: trmcom port not open\r\n");
return -1; return -1;
} }
@ -1587,8 +1252,6 @@ int16_t FAR PASCAL _export trmcom(int16_t commId)
port->isOpen = FALSE; port->isOpen = FALSE;
dbgHex16("KPCOMM: trmcom isrHits", isrHitCount);
dbgStr("KPCOMM: trmcom OK\r\n");
return 0; return 0;
} }
@ -1605,8 +1268,6 @@ int FAR PASCAL LibMain(HANDLE hInstance, WORD wDataSeg, WORD wHeapSize, LPSTR lp
ghInstance = hInstance; ghInstance = hInstance;
dbgStr("KPCOMM: LibMain\r\n");
if (wHeapSize > 0) { if (wHeapSize > 0) {
UnlockData(0); UnlockData(0);
} }

View file

@ -1,5 +1,5 @@
LIBRARY COMM LIBRARY COMM
DESCRIPTION 'KPCOMM -- High-Speed Serial Communications Driver' DESCRIPTION 'High-Speed Serial Communications Driver'
EXETYPE WINDOWS EXETYPE WINDOWS
CODE PRELOAD FIXED CODE PRELOAD FIXED
DATA PRELOAD FIXED SINGLE DATA PRELOAD FIXED SINGLE
@ -20,10 +20,8 @@ EXPORTS
CSETBRK @13 CSETBRK @13
CCLRBRK @14 CCLRBRK @14
GETDCB @15 GETDCB @15
WEP @16 RESIDENTNAME
SUSPENDOPENCOMMPORTS @17 SUSPENDOPENCOMMPORTS @17
REACTIVATEOPENCOMMPORTS @18 REACTIVATEOPENCOMMPORTS @18
COMMWRITESTRING @19 COMMWRITESTRING @19
READCOMMSTRING @20 READCOMMSTRING @20
ENABLENOTIFICATION @100 ENABLENOTIFICATION @100
COMMNOTIFYWNDPROC @101

View file

@ -1,4 +1,4 @@
// commdrv.h - KPCOMM.DRV -- High-speed COMM.DRV replacement // commdrv.h - High-speed COMM.DRV replacement
// //
// Types, UART register definitions, port state structure, and prototypes. // Types, UART register definitions, port state structure, and prototypes.
// Drop-in replacement for Windows 3.1 stock COMM.DRV with proper 16550 // Drop-in replacement for Windows 3.1 stock COMM.DRV with proper 16550
@ -8,7 +8,6 @@
#define COMMDRV_H #define COMMDRV_H
#include <windows.h> #include <windows.h>
#include <conio.h>
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// stdint types for MSVC 1.52 (no stdint.h available) // stdint types for MSVC 1.52 (no stdint.h available)
@ -169,7 +168,6 @@ typedef signed char int8_t;
// exceeds 65535, high baud rates use CBR_* index constants instead // exceeds 65535, high baud rates use CBR_* index constants instead
// of raw values. Values >= 0xFF00 are indices, not raw rates. // of raw values. Values >= 0xFF00 are indices, not raw rates.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Most CBR_* constants defined by windows.h; add any missing ones
#ifndef CBR_110 #ifndef CBR_110
#define CBR_110 0xFF10 #define CBR_110 0xFF10
#define CBR_300 0xFF11 #define CBR_300 0xFF11
@ -178,20 +176,10 @@ typedef signed char int8_t;
#define CBR_2400 0xFF14 #define CBR_2400 0xFF14
#define CBR_4800 0xFF15 #define CBR_4800 0xFF15
#define CBR_9600 0xFF16 #define CBR_9600 0xFF16
#endif
#ifndef CBR_14400
#define CBR_14400 0xFF17 #define CBR_14400 0xFF17
#endif
#ifndef CBR_19200
#define CBR_19200 0xFF18 #define CBR_19200 0xFF18
#endif
#ifndef CBR_38400
#define CBR_38400 0xFF1B #define CBR_38400 0xFF1B
#endif
#ifndef CBR_56000
#define CBR_56000 0xFF1F #define CBR_56000 0xFF1F
#endif
#ifndef CBR_115200
#define CBR_115200 0xFF24 #define CBR_115200 0xFF24
#endif #endif
@ -201,29 +189,15 @@ typedef signed char int8_t;
#define FIFO_DEPTH 16 #define FIFO_DEPTH 16
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Comm error flags (CE_* -- most defined by windows.h, fill any gaps) // Comm error flags (CE_* -- matches Windows SDK definitions)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
#ifndef CE_RXOVER #define CE_RXOVER 0x0001 // Receive Queue overflow
#define CE_RXOVER 0x0001 #define CE_OVERRUN 0x0002 // Hardware overrun
#endif #define CE_RXPARITY 0x0004 // Parity error
#ifndef CE_OVERRUN #define CE_FRAME 0x0008 // Framing error
#define CE_OVERRUN 0x0002 #define CE_BREAK 0x0010 // Break detected
#endif #define CE_TXFULL 0x0020 // TX Queue is full
#ifndef CE_RXPARITY #define CE_MODE 0x8000 // Requested mode unsupported
#define CE_RXPARITY 0x0004
#endif
#ifndef CE_FRAME
#define CE_FRAME 0x0008
#endif
#ifndef CE_BREAK
#define CE_BREAK 0x0010
#endif
#ifndef CE_TXFULL
#define CE_TXFULL 0x0020
#endif
#ifndef CE_MODE
#define CE_MODE 0x8000
#endif
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Comm event flags (EV_* -- matches Windows SDK definitions) // Comm event flags (EV_* -- matches Windows SDK definitions)
@ -263,10 +237,7 @@ typedef signed char int8_t;
#define HS_BOTH 3 #define HS_BOTH 3
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// EscapeCommFunction codes // EscapeCommFunction codes (matches Windows SDK)
//
// SETXON through RESETDEV defined by windows.h.
// SETBREAK/CLRBREAK are our extensions for routing through cextfcn.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
#ifndef SETXON #ifndef SETXON
#define SETXON 1 #define SETXON 1
@ -276,9 +247,9 @@ typedef signed char int8_t;
#define SETDTR 5 #define SETDTR 5
#define CLRDTR 6 #define CLRDTR 6
#define RESETDEV 7 #define RESETDEV 7
#define SETBREAK 8
#define CLRBREAK 9
#endif #endif
#define ESC_SETBREAK 8
#define ESC_CLRBREAK 9
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Flush queue selectors // Flush queue selectors
@ -286,48 +257,10 @@ typedef signed char int8_t;
#define FLUSH_RX 0 #define FLUSH_RX 0
#define FLUSH_TX 1 #define FLUSH_TX 1
// -----------------------------------------------------------------------
// Stock COMM.DRV compatible ComDEB structure
//
// SetCommEventMask (cevt) returns a FAR pointer to offset 0 of this
// structure. Third-party code (ProComm COMMTASK.DLL, etc.) accesses
// fields at known offsets -- most importantly offset 35 (MSR shadow)
// per Microsoft KB Q101417. Our layout must match the stock driver.
// -----------------------------------------------------------------------
typedef struct {
uint16_t evtWord; // +0: Accumulated event flags (EV_*)
uint16_t evtMask; // +2: Event enable mask
uint16_t qInAddr; // +4: RX queue offset (compat, unused)
uint16_t qInSize; // +6: RX buffer size
uint16_t qInCount; // +8: RX bytes in buffer
uint16_t qInHead; // +10: RX write position
uint16_t qInTail; // +12: RX read position
uint16_t qOutAddr; // +14: TX queue offset (compat, unused)
uint16_t qOutSize; // +16: TX buffer size
uint16_t qOutCount; // +18: TX bytes in buffer
uint16_t qOutHead; // +20: TX write position
uint16_t qOutTail; // +22: TX read position
uint16_t port; // +24: UART base I/O address
uint16_t baudRate; // +26: Current baud rate
uint8_t lcrShadow; // +28: LCR shadow
uint8_t mcrShadow; // +29: MCR shadow
uint8_t ierShadow; // +30: IER shadow
uint8_t commErr; // +31: Error flags (low byte)
uint8_t flags1; // +32: Internal flags
uint8_t flags2; // +33: More internal flags
uint8_t recvTrigger; // +34: FIFO trigger level
uint8_t msrShadow; // +35: MSR shadow (documented KB Q101417)
uint8_t padding[4]; // +36: Pad to 40 bytes
} ComDebT;
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Port state structure // Port state structure
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
typedef struct { typedef struct {
// Stock-compatible ComDEB -- must be kept synchronized.
// cevt returns a FAR pointer to this.
ComDebT comDeb;
uint16_t baseAddr; // UART base I/O address uint16_t baseAddr; // UART base I/O address
uint8_t irq; // IRQ number (3 or 4) uint8_t irq; // IRQ number (3 or 4)
int16_t commId; // Port ID (0=COM1, 1=COM2, ...) int16_t commId; // Port ID (0=COM1, 1=COM2, ...)
@ -372,6 +305,8 @@ typedef struct {
uint16_t errorFlags; // CE_* error flags (sticky until read) uint16_t errorFlags; // CE_* error flags (sticky until read)
// Event notification // Event notification
uint16_t evtMask; // Event enable mask
uint16_t evtWord; // Accumulated events
HWND hwndNotify; // Window for WM_COMMNOTIFY HWND hwndNotify; // Window for WM_COMMNOTIFY
int16_t rxNotifyThresh; // CN_RECEIVE threshold (-1=disabled) int16_t rxNotifyThresh; // CN_RECEIVE threshold (-1=disabled)
int16_t txNotifyThresh; // CN_TRANSMIT threshold (-1=disabled) int16_t txNotifyThresh; // CN_TRANSMIT threshold (-1=disabled)
@ -393,23 +328,14 @@ typedef struct {
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
extern PortStateT ports[MAX_PORTS]; extern PortStateT ports[MAX_PORTS];
// -----------------------------------------------------------------------
// Dynamically resolved PostMessage (USER.EXE not loaded at boot)
// -----------------------------------------------------------------------
typedef BOOL (FAR PASCAL *PostMessageProcT)(HWND, UINT, WPARAM, LPARAM);
extern PostMessageProcT pfnPostMessage;
// ISR hit counter for diagnostics
extern volatile uint16_t isrHitCount;
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Exported function prototypes (COMM.DRV API) // Exported function prototypes (COMM.DRV API)
// //
// These use the Windows COMM.DRV calling convention: FAR PASCAL // These use the Windows COMM.DRV calling convention: FAR PASCAL
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t FAR PASCAL _export inicom(DCB FAR *dcb); int16_t FAR PASCAL _export inicom(DCB FAR *dcb, char FAR *rxBuf, int16_t rxSize);
int16_t FAR PASCAL _export setcom(DCB FAR *dcb); int16_t FAR PASCAL _export setcom(DCB FAR *dcb);
int16_t FAR PASCAL _export setque(int16_t commId, int16_t rxSize, int16_t txSize); int16_t FAR PASCAL _export setque(int16_t commId, char FAR *rxBuf, int16_t rxSize, char FAR *txBuf, int16_t txSize);
int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export reccom(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export sndcom(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch); int16_t FAR PASCAL _export ctx(int16_t commId, int16_t ch);
@ -421,13 +347,12 @@ int16_t FAR PASCAL _export cextfcn(int16_t commId, int16_t func);
int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue); int16_t FAR PASCAL _export cflush(int16_t commId, int16_t queue);
int16_t FAR PASCAL _export csetbrk(int16_t commId); int16_t FAR PASCAL _export csetbrk(int16_t commId);
int16_t FAR PASCAL _export cclrbrk(int16_t commId); int16_t FAR PASCAL _export cclrbrk(int16_t commId);
DCB FAR * FAR PASCAL _export getdcb(int16_t commId); int16_t FAR PASCAL _export getdcb(int16_t commId, DCB FAR *dcb);
void FAR PASCAL _export suspendOpenCommPorts(void); void FAR PASCAL _export suspendOpenCommPorts(void);
void FAR PASCAL _export reactivateOpenCommPorts(void); void FAR PASCAL _export reactivateOpenCommPorts(void);
int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export commWriteString(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len); int16_t FAR PASCAL _export readCommString(int16_t commId, void FAR *buf, int16_t len);
int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh); int16_t FAR PASCAL _export enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh);
int FAR PASCAL _export commNotifyWndProc(void);
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// ISR prototypes (isr.c) // ISR prototypes (isr.c)

View file

@ -1,4 +1,4 @@
// isr.c - Interrupt service routines for KPCOMM.DRV // isr.c - Interrupt service routines for COMM.DRV replacement
// //
// ISR entry points for IRQ3 (COM2/4) and IRQ4 (COM1/3), DPMI interrupt // ISR entry points for IRQ3 (COM2/4) and IRQ4 (COM1/3), DPMI interrupt
// vector hooking/unhooking, and interrupt dispatch with 16550 FIFO support. // vector hooking/unhooking, and interrupt dispatch with 16550 FIFO support.
@ -106,12 +106,12 @@ static void checkNotify(PortStateT *port)
} }
// CN_EVENT: any event bits accumulated // CN_EVENT: any event bits accumulated
if (port->comDeb.evtWord & port->comDeb.evtMask) { if (port->evtWord & port->evtMask) {
notifyBits |= CN_EVENT; notifyBits |= CN_EVENT;
} }
if (notifyBits && pfnPostMessage) { if (notifyBits) {
pfnPostMessage(port->hwndNotify, WM_COMMNOTIFY, (WPARAM)port->commId, (LPARAM)notifyBits); PostMessage(port->hwndNotify, WM_COMMNOTIFY, (WPARAM)port->commId, (LPARAM)notifyBits);
} }
} }
@ -132,10 +132,10 @@ static void handleLsr(PortStateT *port, uint8_t lsr)
} }
if (lsr & LSR_BI) { if (lsr & LSR_BI) {
port->errorFlags |= CE_BREAK; port->errorFlags |= CE_BREAK;
port->comDeb.evtWord |= EV_BREAK; port->evtWord |= EV_BREAK;
} }
if (lsr & (LSR_OE | LSR_PE | LSR_FE)) { if (lsr & (LSR_OE | LSR_PE | LSR_FE)) {
port->comDeb.evtWord |= EV_ERR; port->evtWord |= EV_ERR;
} }
} }
@ -149,11 +149,8 @@ static void handleMsr(PortStateT *port)
msr = (uint8_t)_inp(port->baseAddr + UART_MSR); msr = (uint8_t)_inp(port->baseAddr + UART_MSR);
// Update ComDEB MSR shadow (offset 35) for third-party code
port->comDeb.msrShadow = msr;
if (msr & MSR_DCTS) { if (msr & MSR_DCTS) {
port->comDeb.evtWord |= EV_CTS; port->evtWord |= EV_CTS;
// RTS/CTS flow control: stop/start TX based on CTS // RTS/CTS flow control: stop/start TX based on CTS
if (port->hsMode == HS_RTSCTS || port->hsMode == HS_BOTH) { if (port->hsMode == HS_RTSCTS || port->hsMode == HS_BOTH) {
@ -170,15 +167,15 @@ static void handleMsr(PortStateT *port)
} }
if (msr & MSR_DDSR) { if (msr & MSR_DDSR) {
port->comDeb.evtWord |= EV_DSR; port->evtWord |= EV_DSR;
} }
if (msr & MSR_TERI) { if (msr & MSR_TERI) {
port->comDeb.evtWord |= EV_RING; port->evtWord |= EV_RING;
} }
if (msr & MSR_DDCD) { if (msr & MSR_DDCD) {
port->comDeb.evtWord |= EV_RLSD; port->evtWord |= EV_RLSD;
} }
} }
@ -233,7 +230,7 @@ static void handleRx(PortStateT *port, uint8_t lsr)
} }
// Set event bit // Set event bit
port->comDeb.evtWord |= EV_RXCHAR; port->evtWord |= EV_RXCHAR;
// Read LSR again for next byte // Read LSR again for next byte
lsr = (uint8_t)_inp(base + UART_LSR); lsr = (uint8_t)_inp(base + UART_LSR);
@ -273,7 +270,7 @@ static void handleTx(PortStateT *port)
// Nothing to send -- disable THRE interrupt // Nothing to send -- disable THRE interrupt
_outp(base + UART_IER, (uint8_t)(_inp(base + UART_IER) & ~IER_THRE)); _outp(base + UART_IER, (uint8_t)(_inp(base + UART_IER) & ~IER_THRE));
// TX empty event // TX empty event
port->comDeb.evtWord |= EV_TXEMPTY; port->evtWord |= EV_TXEMPTY;
return; return;
} }
@ -424,14 +421,6 @@ void isrDispatch(PortStateT *port)
} }
} }
// Sync queue counts into ComDEB for third-party code
port->comDeb.qInCount = port->rxCount;
port->comDeb.qInHead = port->rxHead;
port->comDeb.qInTail = port->rxTail;
port->comDeb.qOutCount = port->txCount;
port->comDeb.qOutHead = port->txHead;
port->comDeb.qOutTail = port->txTail;
checkNotify(port); checkNotify(port);
} }
@ -489,12 +478,6 @@ void _far _interrupt isr3(void)
{ {
int16_t i; int16_t i;
// Load DLL's data segment -- _interrupt saves/restores DS but doesn't
// set it. Without this, DS belongs to whatever code was interrupted
// and all global accesses (ports[], ring buffers) read garbage.
_asm mov ax, seg ports
_asm mov ds, ax
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
if (ports[i].isOpen && ports[i].irq == 3) { if (ports[i].isOpen && ports[i].irq == 3) {
isrDispatch(&ports[i]); isrDispatch(&ports[i]);
@ -513,12 +496,6 @@ void _far _interrupt isr4(void)
{ {
int16_t i; int16_t i;
// Load DLL's data segment -- see comment in isr3
_asm mov ax, seg ports
_asm mov ds, ax
isrHitCount++;
for (i = 0; i < MAX_PORTS; i++) { for (i = 0; i < MAX_PORTS; i++) {
if (ports[i].isOpen && ports[i].irq == 4) { if (ports[i].isOpen && ports[i].irq == 4) {
isrDispatch(&ports[i]); isrDispatch(&ports[i]);

View file

@ -6,11 +6,11 @@
# Prerequisites: # Prerequisites:
# - MSVC 1.52 (cl, link in PATH) # - MSVC 1.52 (cl, link in PATH)
# #
# Output is KPCOMM.DRV -- drop-in replacement for stock Windows 3.1 driver. # Output is COMM.DRV -- drop-in replacement for stock Windows 3.1 driver.
# #
# Install: # Install:
# 1. Copy KPCOMM.DRV to \WINDOWS\SYSTEM # 1. Copy COMM.DRV to \WINDOWS\SYSTEM
# 2. Edit SYSTEM.INI [boot] section: comm.drv=kpcomm.drv # 2. Edit SYSTEM.INI [boot] section: comm.drv=comm.drv
# 3. Add to [386Enh] section: COM1FIFO=1 (for each port in use) # 3. Add to [386Enh] section: COM1FIFO=1 (for each port in use)
# 4. Restart Windows # 4. Restart Windows
# #
@ -28,9 +28,9 @@ LINK = link
# -ASw Small model, SS!=DS (Windows DLL) # -ASw Small model, SS!=DS (Windows DLL)
# -Gsw No stack probes, Windows prolog/epilog # -Gsw No stack probes, Windows prolog/epilog
# -Ow Safe optimizations for Windows # -Ow Safe optimizations for Windows
# -Zp2 Pack structures on 2-byte boundaries (matches Windows SDK) # -Zp1 Pack structures on 1-byte boundaries (hardware register layouts)
# -Ze Enable Microsoft extensions # -Ze Enable Microsoft extensions
CFLAGS = -c -W3 -ASw -Gsw -Ow -Zp2 -Ze CFLAGS = -c -W3 -ASw -Gsw -Ow -Zp1 -Ze
# Linker flags: # Linker flags:
# /NOD No default libraries # /NOD No default libraries
@ -44,7 +44,7 @@ LFLAGS = /NOD /NOE /AL:16
LIBS = sdllcew libw LIBS = sdllcew libw
# Output # Output
TARGET = kpcomm.drv TARGET = comm.drv
# Objects # Objects
OBJS = commdrv.obj isr.obj OBJS = commdrv.obj isr.obj

View file

@ -61,7 +61,7 @@ OBJS = mscomm.obj serial.obj
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
all: $(TARGET) all: $(TARGET)
$(TARGET): $(OBJS) mscomm.def mscomm.res vbapi.lib $(TARGET): $(OBJS) mscomm.def mscomm.res
$(LINK) $(LFLAGS) $(OBJS), $(TARGET),,$(LIBS), mscomm.def $(LINK) $(LFLAGS) $(OBJS), $(TARGET),,$(LIBS), mscomm.def
$(RC) mscomm.res $(TARGET) $(RC) mscomm.res $(TARGET)

View file

@ -5,13 +5,6 @@
#ifndef MSCOMM_H #ifndef MSCOMM_H
#define MSCOMM_H #define MSCOMM_H
// -----------------------------------------------------------------------
// Resource IDs
// -----------------------------------------------------------------------
#define IDB_MSCOMM 8000
#ifndef RC_INVOKED
#include "vbapi.h" #include "vbapi.h"
#include "serial.h" #include "serial.h"
@ -28,6 +21,11 @@ typedef signed char int8_t;
#define _STDINT_DEFINED #define _STDINT_DEFINED
#endif #endif
// -----------------------------------------------------------------------
// Resource IDs
// -----------------------------------------------------------------------
#define IDB_MSCOMM 8000
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Property indices (position in npproplist array) // Property indices (position in npproplist array)
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -140,6 +138,4 @@ typedef struct {
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
extern HANDLE ghInstance; extern HANDLE ghInstance;
#endif // RC_INVOKED
#endif // MSCOMM_H #endif // MSCOMM_H

View file

@ -12,7 +12,7 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
int16_t serialClose(int16_t commId); int16_t serialClose(int16_t commId);
int16_t serialConfigure(int16_t commId, int16_t port, const char FAR *settings); int16_t serialConfigure(int16_t commId, int16_t port, const char FAR *settings);
BOOL serialEnableNotify(int16_t commId, HWND hwnd, int16_t rxThreshold, int16_t txThreshold); int16_t serialEnableNotify(int16_t commId, HWND hwnd, int16_t rxThreshold, int16_t txThreshold);
int16_t serialEscape(int16_t commId, int16_t func); int16_t serialEscape(int16_t commId, int16_t func);
int16_t serialFlush(int16_t commId, int16_t queue); int16_t serialFlush(int16_t commId, int16_t queue);
UINT serialGetEventMask(int16_t commId, UINT mask); UINT serialGetEventMask(int16_t commId, UINT mask);

View file

@ -37,17 +37,13 @@ typedef signed char int8_t;
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Escape function constants (mirrors EscapeCommFunction values) // Escape function constants (mirrors EscapeCommFunction values)
//
// SETDTR through RESETDEV are defined by windows.h.
// SETBREAK/CLRBREAK are not in windows.h (SetCommBreak/ClearCommBreak
// are separate API functions), so we define numeric values directly.
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
#define SERIAL_SETDTR SETDTR #define SERIAL_SETDTR SETDTR
#define SERIAL_CLRDTR CLRDTR #define SERIAL_CLRDTR CLRDTR
#define SERIAL_SETRTS SETRTS #define SERIAL_SETRTS SETRTS
#define SERIAL_CLRRTS CLRRTS #define SERIAL_CLRRTS CLRRTS
#define SERIAL_SETBREAK 8 #define SERIAL_SETBREAK SETBREAK
#define SERIAL_CLRBREAK 9 #define SERIAL_CLRBREAK CLRBREAK
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Function prototypes // Function prototypes

View file

@ -17,15 +17,17 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Core types // Core types
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
#ifndef USHORT
typedef unsigned short USHORT;
#endif
typedef WORD HCTL; // Handle to a VBX control instance typedef WORD HCTL; // Handle to a VBX control instance
typedef WORD HSZ; // Handle to a VB-managed string typedef WORD HSZ; // Handle to a VB-managed string
typedef LONG HLSTR; // Handle to a VB long string typedef LONG HLSTR; // Handle to a VB long string
typedef USHORT ERR; // Error code typedef USHORT ERR; // Error code
// Segment type for MSVC 1.52
#ifndef _SEGMENT_DEFINED
typedef unsigned short _segment;
#define _SEGMENT_DEFINED
#endif
// Flag type // Flag type
typedef DWORD FL; typedef DWORD FL;
@ -194,7 +196,7 @@ struct tagMODEL {
FL fl; // MODEL_* flags FL fl; // MODEL_* flags
PCTLPROC pctlproc; // Control procedure PCTLPROC pctlproc; // Control procedure
USHORT fsClassStyle; // Window class style bits USHORT fsClassStyle; // Window class style bits
FL flWndStyle; // Window style bits USHORT flWndStyle; // Window style bits
USHORT cbCtlExtra; // Bytes of per-instance data USHORT cbCtlExtra; // Bytes of per-instance data
USHORT idBmpPalette; // Toolbox bitmap resource ID USHORT idBmpPalette; // Toolbox bitmap resource ID
PSTR npszDefCtlName; // Default control name (near) PSTR npszDefCtlName; // Default control name (near)