16c95x Serial Port Driver May 2026

16c95x Serial Port Driver May 2026

On Windows, commercial solutions from vendors like Moxa or Advantech provide certified 16C95x drivers. Alternatively, a custom KMDF (Kernel Mode Driver Framework) driver can be developed, leveraging the Serial Controller Extension.

The driver must implement an algorithm to calculate the divisor and prescaler values for the fractional baud rate generator. This requires more complex math than the simple integer division used in 16550A drivers to achieve non-standard or very high baud rates.

The driver must configure the FIFO Control Register (FCR) with a value of 0xE1 to enable the 128-byte mode (bit 7 set). Legacy drivers only set 0xC1 for 16 bytes. In the 16C95x driver, the transmit and receive trigger levels are programmable. 16c95x serial port driver

Driver snippet concept:

#define UART_FCR_128BYTE 0x80
serial_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
           UART_FCR_CLEAR_RCVR |
           UART_FCR_CLEAR_XMIT |
           UART_FCR_128BYTE);

This report provides a technical analysis of the driver architecture for the 16C95x family of Universal Asynchronous Receiver-Transmitters (UARTs). The 16C95x series (including theOX16C954 and ST16C554/850/950 variants) represents a high-performance evolution of the industry-standard 16550A UART. While backward compatible with the 16550A, the 16C95x introduces advanced features such as 128-byte FIFOs, fractional baud rate generators, and enhanced flow control. The driver for this hardware must manage these advanced capabilities while maintaining compatibility with standard operating system serial interfaces. On Windows, commercial solutions from vendors like Moxa

The 16C95x family (often referred to as 16C950 / 16C954 / related PCI UART-style devices) are multi-channel serial controller chips commonly found on industrial I/O cards and embedded platforms. This post explains the device features, driver architecture, key implementation details, common pitfalls, and a small reference implementation outline suitable for a Linux-like environment. The goal is practical: give an engineer what they need to write, port, or debug a driver for a 16C95x-based serial card.

The Tx interrupt (THRE – Transmitter Holding Register Empty) asserts when the Tx FIFO falls below the programmed trigger level (default empty). The driver’s Tx ISR should fill the FIFO up to its capacity or until the Tx buffer is empty. This report provides a technical analysis of the

void uart_isr_tx(uart_t *dev)
while (!(read_reg(dev->base + UART_LSR) & LSR_TXFIFO_FULL)) 
        if (ringbuf_empty(&dev->tx_ring)) 
            // No more data: disable Tx interrupt
            uint8_t ier = read_reg(dev->base + UART_IER);
            write_reg(dev->base + UART_IER, ier & ~IER_THRE);
            break;
uint8_t data = ringbuf_pop(&dev->tx_ring);
        write_reg(dev->base + UART_THR, data);

A common pitfall: After initial Tx, you must enable THRE interrupt only when there is data to send. Many drivers enable it unconditionally, causing an immediate interrupt storm.

A correctly implemented driver exposes the following hardware strengths:

Go to Top