Skip to content

Serial Port Driver

opencode-agent[bot] edited this page May 10, 2026 · 1 revision

Serial Port Driver

Driver for serial ports (COM1-4) with UART register access via I/O ports. Handles communication via RS-232 serial interface.

Overview

The Serial Port Driver provides access to standard PC serial ports (COM1-COM4) using the 16550/16450 UART hardware. It implements the SerialPortAPI interface and extends the Driver framework, integrating with JNode's device management system. The driver uses programmed I/O (PIO) to access UART registers through I/O ports, supporting configurable baud rate, data bits, stop bits, and parity.

Key Components

Class/File Purpose
SerialPortDriver.java Main driver implementation - extends Driver, implements SerialPortAPI and ByteChannel
SerialPortAPI.java API interface defining baud rate constants and configuration methods
SerialPortFinder.java Device finder that registers serial0 and serial1 devices at boot

How It Works

UART Register Layout

The driver accesses UART registers via I/O ports starting at a configurable base address. Each register is at offset basePort + n:

Offset Register Access Purpose
+0 Data/ divisor LSB R/W DLAB=0: receive/transmit data; DLAB=1: divisor bits 0-7
+1 IER / divisor MSB R/W DLAB=0: interrupt enable; DLAB=1: divisor bits 8-15
+2 FCR / IIR W/R FIFO control (write) / FIFO status (read)
+3 LCR R/W Line control: DLAB, parity, stop bits, data length
+4 MCR R/W Modem control: DTR, RTS, loopback
+5 LSR R/W Line status: data ready, overrun, framing, parity
+6 MSR R/W Modem status: CTS, DSR, RI, CD
+7 Scratch R/W 1-byte scratch register

Baud Rate Configuration

Baud rate is configured via a divisor value using the formula: baudRate = 115200 / divisor

Standard baud rate divisors:

  • 9600 baud: divisor = 12 (BAUD9600 constant)
  • 4800 baud: divisor = 24 (BAUD4800 constant)
  • 2400 baud: divisor = 48 (BAUD2400 constant)
  • 1200 baud: divisor = 96 (BAUD1200 constant)

Configuration sequence (from SerialPortDriver.java:121-124):

port.outPortByte(basePort + 3, control | 128);  // Set DLAB=1
port.outPortByte(basePort + 0, divisor);        // Divisor LSB
port.outPortByte(basePort + 1, divisor >> 8);   // Divisor MSB
port.outPortByte(basePort + 3, control);        // Clear DLAB, set LCR

Device Discovery

SerialPortFinder implements DeviceFinder to register serial ports at boot:

Device Name I/O Port Base Standard Mapping
serial0 0x3f8 COM1
serial1 0x2f8 COM2

The finder creates a Device instance for each port, associates it with a SerialPortDriver instance, and registers it with the DeviceManager.

ByteChannel Implementation

The driver implements ByteChannel for NIO-based I/O:

  • read(ByteBuffer) - reads bytes into buffer via readSingle() polling
  • write(ByteBuffer) - writes bytes via writeSingle() polling
  • isOpen() / close() - channel state management

Both read and write use busy-wait loops polling the line status register (LSR).

Gotchas

  1. Busy-wait I/O: The current implementation uses busy-wait polling for both read and readSingle (SerialPortDriver.java:136-138) and write (SerialPortDriver.java:143-145). This is CPU-intensive and blocks the calling thread.

  2. No interrupt support: The driver does not use UART interrupts for data availability notification. Interrupt-driven I/O would be more efficient.

  3. FIFO not utilized: Although the UART supports 16-byte transmit/receive FIFOs, the driver does not enable or utilize them, potentially limiting throughput.

  4. Limited port detection: Only COM1 (0x3f8) and COM2 (0x2f8) are registered. COM3/COM4 at 0x3e8 and 0x2e8 are not automatically discovered.

  5. No DMA support: Serial port DMA transfers are not implemented.

Related Pages

Clone this wiki locally