// commdrv.h - KPCOMM.DRV -- 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 #include // ----------------------------------------------------------------------- // 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. // ----------------------------------------------------------------------- // Most CBR_* constants defined by windows.h; add any missing ones #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 #endif #ifndef CBR_14400 #define CBR_14400 0xFF17 #endif #ifndef CBR_19200 #define CBR_19200 0xFF18 #endif #ifndef CBR_38400 #define CBR_38400 0xFF1B #endif #ifndef CBR_56000 #define CBR_56000 0xFF1F #endif #ifndef CBR_115200 #define CBR_115200 0xFF24 #endif // ----------------------------------------------------------------------- // 16550 FIFO depth // ----------------------------------------------------------------------- #define FIFO_DEPTH 16 // ----------------------------------------------------------------------- // Comm error flags (CE_* -- most defined by windows.h, fill any gaps) // ----------------------------------------------------------------------- #ifndef CE_RXOVER #define CE_RXOVER 0x0001 #endif #ifndef CE_OVERRUN #define CE_OVERRUN 0x0002 #endif #ifndef CE_RXPARITY #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) // ----------------------------------------------------------------------- #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 // // SETXON through RESETDEV defined by windows.h. // SETBREAK/CLRBREAK are our extensions for routing through cextfcn. // ----------------------------------------------------------------------- #ifndef SETXON #define SETXON 1 #define SETXOFF 2 #define SETRTS 3 #define CLRRTS 4 #define SETDTR 5 #define CLRDTR 6 #define RESETDEV 7 #endif #define ESC_SETBREAK 8 #define ESC_CLRBREAK 9 // ----------------------------------------------------------------------- // Flush queue selectors // ----------------------------------------------------------------------- #define FLUSH_RX 0 #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 // ----------------------------------------------------------------------- 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 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 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]; // ----------------------------------------------------------------------- // 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) // // These use the Windows COMM.DRV calling convention: FAR PASCAL // ----------------------------------------------------------------------- int16_t FAR PASCAL _export inicom(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 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); DCB FAR * FAR PASCAL _export getdcb(int16_t commId); 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); int FAR PASCAL _export commNotifyWndProc(void); // ----------------------------------------------------------------------- // 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