WinComm/drv/commdrv.h
2026-02-23 20:53:02 -06:00

373 lines
16 KiB
C

// commdrv.h - High-speed COMM.DRV replacement
//
// Types, UART register definitions, port state structure, and prototypes.
// Drop-in replacement for Windows 3.1 stock COMM.DRV with proper 16550
// FIFO management for reliable operation at 57600 and 115200 baud.
#ifndef COMMDRV_H
#define COMMDRV_H
#include <windows.h>
// -----------------------------------------------------------------------
// stdint types for MSVC 1.52 (no stdint.h available)
// -----------------------------------------------------------------------
#ifndef _STDINT_DEFINED
typedef short int16_t;
typedef unsigned short uint16_t;
typedef long int32_t;
typedef unsigned long uint32_t;
typedef unsigned char uint8_t;
typedef signed char int8_t;
#define _STDINT_DEFINED
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
// -----------------------------------------------------------------------
// Maximum ports supported
// -----------------------------------------------------------------------
#define MAX_PORTS 4
// -----------------------------------------------------------------------
// Default buffer sizes
// -----------------------------------------------------------------------
#define DEFAULT_RX_SIZE 4096
#define DEFAULT_TX_SIZE 4096
// -----------------------------------------------------------------------
// UART register offsets from base address
// -----------------------------------------------------------------------
#define UART_RBR 0 // Receive Buffer Register (read, DLAB=0)
#define UART_THR 0 // Transmit Holding Register (write, DLAB=0)
#define UART_DLL 0 // Divisor Latch Low (DLAB=1)
#define UART_IER 1 // Interrupt Enable Register (DLAB=0)
#define UART_DLM 1 // Divisor Latch High (DLAB=1)
#define UART_IIR 2 // Interrupt Identification Register (read)
#define UART_FCR 2 // FIFO Control Register (write)
#define UART_LCR 3 // Line Control Register
#define UART_MCR 4 // Modem Control Register
#define UART_LSR 5 // Line Status Register
#define UART_MSR 6 // Modem Status Register
#define UART_SCR 7 // Scratch Register
// -----------------------------------------------------------------------
// IER bits - Interrupt Enable Register
// -----------------------------------------------------------------------
#define IER_RDA 0x01 // Received Data Available
#define IER_THRE 0x02 // Transmitter Holding Register Empty
#define IER_LSI 0x04 // Line Status Interrupt
#define IER_MSI 0x08 // Modem Status Interrupt
// -----------------------------------------------------------------------
// IIR bits - Interrupt Identification Register
// -----------------------------------------------------------------------
#define IIR_PENDING 0x01 // 0=interrupt pending, 1=no interrupt
#define IIR_ID_MASK 0x0E // Interrupt ID mask
#define IIR_MSR 0x00 // Modem Status change
#define IIR_THRE 0x02 // Transmitter Holding Register Empty
#define IIR_RDA 0x04 // Received Data Available
#define IIR_LSR 0x06 // Line Status (error/break)
#define IIR_TIMEOUT 0x0C // Character Timeout (16550 FIFO)
#define IIR_FIFO_MASK 0xC0 // FIFO enabled bits
// -----------------------------------------------------------------------
// FCR bits - FIFO Control Register (write-only)
// -----------------------------------------------------------------------
#define FCR_ENABLE 0x01 // Enable FIFOs
#define FCR_RX_RESET 0x02 // Reset RX FIFO
#define FCR_TX_RESET 0x04 // Reset TX FIFO
#define FCR_DMA_MODE 0x08 // DMA mode select
#define FCR_TRIG_1 0x00 // RX trigger level: 1 byte
#define FCR_TRIG_4 0x40 // RX trigger level: 4 bytes
#define FCR_TRIG_8 0x80 // RX trigger level: 8 bytes
#define FCR_TRIG_14 0xC0 // RX trigger level: 14 bytes
// -----------------------------------------------------------------------
// LCR bits - Line Control Register
// -----------------------------------------------------------------------
#define LCR_WLS_MASK 0x03 // Word Length Select mask
#define LCR_WLS_5 0x00 // 5 data bits
#define LCR_WLS_6 0x01 // 6 data bits
#define LCR_WLS_7 0x02 // 7 data bits
#define LCR_WLS_8 0x03 // 8 data bits
#define LCR_STB 0x04 // Number of Stop Bits (0=1, 1=2)
#define LCR_PEN 0x08 // Parity Enable
#define LCR_EPS 0x10 // Even Parity Select
#define LCR_SPAR 0x20 // Stick Parity
#define LCR_SBRK 0x40 // Set Break
#define LCR_DLAB 0x80 // Divisor Latch Access Bit
// -----------------------------------------------------------------------
// MCR bits - Modem Control Register
// -----------------------------------------------------------------------
#define MCR_DTR 0x01 // Data Terminal Ready
#define MCR_RTS 0x02 // Request To Send
#define MCR_OUT1 0x04 // Output 1
#define MCR_OUT2 0x08 // Output 2 (master interrupt enable)
#define MCR_LOOP 0x10 // Loopback mode
// -----------------------------------------------------------------------
// LSR bits - Line Status Register
// -----------------------------------------------------------------------
#define LSR_DR 0x01 // Data Ready
#define LSR_OE 0x02 // Overrun Error
#define LSR_PE 0x04 // Parity Error
#define LSR_FE 0x08 // Framing Error
#define LSR_BI 0x10 // Break Interrupt
#define LSR_THRE 0x20 // Transmitter Holding Register Empty
#define LSR_TEMT 0x40 // Transmitter Empty (shift register too)
#define LSR_FIFO 0x80 // Error in RX FIFO (16550)
// -----------------------------------------------------------------------
// MSR bits - Modem Status Register
// -----------------------------------------------------------------------
#define MSR_DCTS 0x01 // Delta CTS
#define MSR_DDSR 0x02 // Delta DSR
#define MSR_TERI 0x04 // Trailing Edge Ring Indicator
#define MSR_DDCD 0x08 // Delta DCD
#define MSR_CTS 0x10 // Clear To Send
#define MSR_DSR 0x20 // Data Set Ready
#define MSR_RI 0x40 // Ring Indicator
#define MSR_DCD 0x80 // Data Carrier Detect
// -----------------------------------------------------------------------
// PIC constants
// -----------------------------------------------------------------------
#define PIC_CMD 0x20 // PIC command port
#define PIC_DATA 0x21 // PIC data (mask) port
#define PIC_EOI 0x20 // End of Interrupt command
// -----------------------------------------------------------------------
// Standard port base addresses and IRQs
// -----------------------------------------------------------------------
#define COM1_BASE 0x03F8
#define COM2_BASE 0x02F8
#define COM3_BASE 0x03E8
#define COM4_BASE 0x02E8
#define COM1_IRQ 4
#define COM2_IRQ 3
#define COM3_IRQ 4
#define COM4_IRQ 3
// -----------------------------------------------------------------------
// Baud rate divisor (115200 / baud)
// -----------------------------------------------------------------------
#define BAUD_DIVISOR_BASE 115200UL
// -----------------------------------------------------------------------
// CBR_* baud rate index constants
//
// The 16-bit DCB BaudRate field is a UINT (16 bits). Since 115200
// exceeds 65535, high baud rates use CBR_* index constants instead
// of raw values. Values >= 0xFF00 are indices, not raw rates.
// -----------------------------------------------------------------------
#ifndef CBR_110
#define CBR_110 0xFF10
#define CBR_300 0xFF11
#define CBR_600 0xFF12
#define CBR_1200 0xFF13
#define CBR_2400 0xFF14
#define CBR_4800 0xFF15
#define CBR_9600 0xFF16
#define CBR_14400 0xFF17
#define CBR_19200 0xFF18
#define CBR_38400 0xFF1B
#define CBR_56000 0xFF1F
#define CBR_115200 0xFF24
#endif
// -----------------------------------------------------------------------
// 16550 FIFO depth
// -----------------------------------------------------------------------
#define FIFO_DEPTH 16
// -----------------------------------------------------------------------
// Comm error flags (CE_* -- matches Windows SDK definitions)
// -----------------------------------------------------------------------
#define CE_RXOVER 0x0001 // Receive Queue overflow
#define CE_OVERRUN 0x0002 // Hardware overrun
#define CE_RXPARITY 0x0004 // Parity error
#define CE_FRAME 0x0008 // Framing error
#define CE_BREAK 0x0010 // Break detected
#define CE_TXFULL 0x0020 // TX Queue is full
#define CE_MODE 0x8000 // Requested mode unsupported
// -----------------------------------------------------------------------
// Comm event flags (EV_* -- matches Windows SDK definitions)
// -----------------------------------------------------------------------
#define EV_RXCHAR 0x0001 // Any character received
#define EV_RXFLAG 0x0002 // Event character received
#define EV_TXEMPTY 0x0004 // TX buffer empty
#define EV_CTS 0x0008 // CTS changed
#define EV_DSR 0x0010 // DSR changed
#define EV_RLSD 0x0020 // DCD/RLSD changed
#define EV_BREAK 0x0040 // Break received
#define EV_ERR 0x0080 // Line status error
#define EV_RING 0x0100 // Ring indicator
// -----------------------------------------------------------------------
// CN_* notification codes (lParam for WM_COMMNOTIFY)
// -----------------------------------------------------------------------
#ifndef CN_RECEIVE
#define CN_RECEIVE 0x0001
#define CN_TRANSMIT 0x0002
#define CN_EVENT 0x0004
#endif
// -----------------------------------------------------------------------
// WM_COMMNOTIFY message
// -----------------------------------------------------------------------
#ifndef WM_COMMNOTIFY
#define WM_COMMNOTIFY 0x0044
#endif
// -----------------------------------------------------------------------
// Handshaking modes
// -----------------------------------------------------------------------
#define HS_NONE 0
#define HS_XONXOFF 1
#define HS_RTSCTS 2
#define HS_BOTH 3
// -----------------------------------------------------------------------
// EscapeCommFunction codes (matches Windows SDK)
// -----------------------------------------------------------------------
#ifndef SETXON
#define SETXON 1
#define SETXOFF 2
#define SETRTS 3
#define CLRRTS 4
#define SETDTR 5
#define CLRDTR 6
#define RESETDEV 7
#define SETBREAK 8
#define CLRBREAK 9
#endif
// -----------------------------------------------------------------------
// Flush queue selectors
// -----------------------------------------------------------------------
#define FLUSH_RX 0
#define FLUSH_TX 1
// -----------------------------------------------------------------------
// Port state structure
// -----------------------------------------------------------------------
typedef struct {
uint16_t baseAddr; // UART base I/O address
uint8_t irq; // IRQ number (3 or 4)
int16_t commId; // Port ID (0=COM1, 1=COM2, ...)
uint8_t isOpen; // Port open flag
uint8_t is16550; // 16550 FIFO detected
uint8_t fifoEnabled; // FIFO enabled (COMnFIFO setting)
uint8_t fifoTrigger; // RX FIFO trigger FCR bits (FCR_TRIG_*)
// Ring buffers (GlobalAlloc'd)
uint8_t FAR *rxBuf; // Receive ring buffer
uint16_t rxSize; // Buffer size
uint16_t rxHead; // Write position (ISR writes)
uint16_t rxTail; // Read position (app reads)
uint16_t rxCount; // Bytes in buffer
uint8_t FAR *txBuf; // Transmit ring buffer
uint16_t txSize; // Buffer size
uint16_t txHead; // Write position (app writes)
uint16_t txTail; // Read position (ISR reads)
uint16_t txCount; // Bytes in buffer
// DCB shadow
uint16_t baudRate; // Current baud rate
uint8_t byteSize; // Data bits (5-8)
uint8_t parity; // Parity mode
uint8_t stopBits; // Stop bits
// Flow control state
uint8_t hsMode; // Handshaking mode
uint8_t txStopped; // TX halted by flow control
uint8_t rxStopped; // We sent XOFF / dropped RTS
uint8_t xonChar; // XON character (default 0x11)
uint8_t xoffChar; // XOFF character (default 0x13)
uint16_t xoffLim; // Send XOFF when rxCount > rxSize - xoffLim
uint16_t xonLim; // Send XON when rxCount < xonLim
// Modem control shadow
uint8_t dtrState; // DTR line state
uint8_t rtsState; // RTS line state (when not flow-controlled)
// Error accumulator
uint16_t errorFlags; // CE_* error flags (sticky until read)
// Event notification
uint16_t evtMask; // Event enable mask
uint16_t evtWord; // Accumulated events
HWND hwndNotify; // Window for WM_COMMNOTIFY
int16_t rxNotifyThresh; // CN_RECEIVE threshold (-1=disabled)
int16_t txNotifyThresh; // CN_TRANSMIT threshold (-1=disabled)
// ISR state
void (FAR *prevIsr)(void); // Previous ISR in chain
uint8_t irqMask; // PIC mask bit for this IRQ
uint8_t breakState; // Break signal active
// Priority transmit
int16_t txImmediate; // -1=none, else char to send immediately
// DCB copy for GetCommState
DCB dcb; // Full DCB for GETDCB/SETCOM
} PortStateT;
// -----------------------------------------------------------------------
// Global port state array
// -----------------------------------------------------------------------
extern PortStateT ports[MAX_PORTS];
// -----------------------------------------------------------------------
// Exported function prototypes (COMM.DRV API)
//
// These use the Windows COMM.DRV calling convention: FAR PASCAL
// -----------------------------------------------------------------------
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 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 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 trmcom(int16_t commId);
int16_t FAR PASCAL _export stacom(int16_t commId, COMSTAT FAR *stat);
int32_t FAR PASCAL _export cevt(int16_t commId, int16_t evtMask);
uint16_t FAR PASCAL _export cevtget(int16_t commId, int16_t evtMask);
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 csetbrk(int16_t commId);
int16_t FAR PASCAL _export cclrbrk(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 reactivateOpenCommPorts(void);
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 enableNotification(int16_t commId, HWND hwnd, int16_t rxThresh, int16_t txThresh);
// -----------------------------------------------------------------------
// ISR prototypes (isr.c)
// -----------------------------------------------------------------------
int16_t hookIsr(PortStateT *port);
void unhookIsr(PortStateT *port);
void isrDispatch(PortStateT *port);
// -----------------------------------------------------------------------
// Internal helpers
// -----------------------------------------------------------------------
int16_t detect16550(uint16_t baseAddr);
void applyBaudRate(PortStateT *port, uint16_t baud);
void applyLineParams(PortStateT *port, uint8_t byteSize, uint8_t parity, uint8_t stopBits);
void enableFifo(PortStateT *port);
void primeTx(PortStateT *port);
#endif // COMMDRV_H