How to Configure Serial COM Ports, IRQ Lines, and Baud Rates in Linux Using setserial

Serial communication remains a foundational protocol for low-level embedded hardware, server out-of-band management consoles, industrial PLCs, and network appliances. In Linux, standard serial ports (such as /dev/ttyS0 through /dev/ttyS3) and USB-to-serial bridges are driven by the kernel’s Universal Asynchronous Receiver-Transmitter (UART) subsystem. When dealing with legacy hardware addressing, non-standard I/O port assignments, interrupt collisions, or custom non-standard baud rates, the standard stty tool lacks the low-level hardware abstraction necessary to reconfigure hardware lines. The setserial utility provides direct administrative control over UART controller types, base baud multipliers, I/O port addresses, and IRQ line assignments in Linux.

Understanding UART Architecture and setserial Capabilities

The Linux serial driver maps hardware UART chips (such as 8250, 16450, 16550A, 16650, or 16750) to logical device nodes. Each serial port requires four core hardware parameters:

  • UART Chip Type: Identifies the hardware model and its internal FIFO buffer size (e.g., 16-byte FIFO on 16550A, 64-byte FIFO on 16750). Misidentifying the UART can cause buffer overruns or disable hardware flow control.
  • I/O Port Address: The legacy x86 hardware memory address (typically 0x3F8 for COM1/ttyS0, 0x2F8 for COM2/ttyS1).
  • Interrupt Request Line (IRQ): The hardware interrupt line assigned to signal incoming byte buffers to the CPU (typically IRQ 4 for COM1, IRQ 3 for COM2).
  • Baud Base and Custom Multipliers: The master clock oscillator frequency (commonly 115200 Hz). By setting the spd_cust flag, administrators can divide this base clock to generate arbitrary custom baud rates (such as 250000 baud for DMX lighting or 500000 baud for custom microcontroller debug links).

Installing setserial on Linux Distributions

The setserial package is available in the standard repositories across all major Linux distributions:

# Debian, Ubuntu, and Raspberry Pi OS
sudo apt update && sudo apt install -y setserial

# Fedora, RHEL, and Rocky Linux
sudo dnf install -y setserial

# Arch Linux
sudo pacman -S setserial

Querying Serial Port Configuration and UART Types

To inspect the current hardware configuration of an active serial port, execute setserial with the verbose -v flag:

setserial -v /dev/ttyS0

The command outputs the operational parameters:

/dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4, Flags: spd_normal skip_test

To probe and audit all potential motherboard serial ports across the system, use the -g (get) flag:

setserial -g /dev/ttyS[0-3]

If a port returns UART: unknown, the Linux serial driver has not detected an active physical controller at that specified I/O address.

Configuring Hardware I/O Ports and IRQ Interrupts

When installing multi-port PCIe serial expansion cards or legacy industrial ISA cards with hardware jumper switches, auto-detection may fail. Use setserial to explicitly map the hardware resources:

# Explicitly configure ttyS1 to use I/O port 0x02f8 and IRQ 3
sudo setserial /dev/ttyS1 port 0x02f8 irq 3 uart 16550A

If sharing an interrupt line across multiple serial ports (common on 4-port PCIe serial cards), instruct the serial driver to enable interrupt sharing:

sudo setserial /dev/ttyS2 port 0x03e8 irq 4 uart 16550A fourport
sudo setserial /dev/ttyS3 port 0x02e8 irq 4 uart 16550A fourport

Configuring Custom Non-Standard Baud Rates

Standard Linux utilities like stty and terminal emulators like screen or minicom typically restrict baud rates to standardized values (9600, 19200, 38400, 57600, 115200). When communicating with custom microcontrollers requiring non-standard speeds, configure custom divisor mapping:

  1. Check the base baud rate of the UART (typically 115200):
    setserial /dev/ttyS0 baud_base
  2. Calculate the divisor: divisor = baud_base / target_baud. For example, to achieve a custom speed of 57600 on a base of 115200, the divisor is 2. For 28800 baud, the divisor is 4.
  3. Apply the custom divisor and enable the spd_cust flag:
    sudo setserial /dev/ttyS0 spd_cust divisor 4
  4. Connect using a terminal emulator at 38400 baud. The Linux serial driver intercepts the 38400 request and redirects hardware timing to the custom divisor calculation (achieving true 28800 baud).

Persisting setserial Settings Across Reboots

Because hardware settings applied via setserial are stored in volatile kernel memory, they reset when the system reboots. Modern systemd-based distributions persist settings using configuration files or systemd units:

On Debian and Ubuntu, edit /etc/serial.conf:

sudo nano /etc/serial.conf

Append your explicit device line:

/dev/ttyS0 uart 16550A port 0x03f8 irq 4

On distributions without a built-in serial daemon, persist settings via a simple systemd one-shot service:

sudo nano /etc/systemd/system/serial-hardware.service
[Unit]
Description=Apply Custom Serial Hardware Settings
Before=getty.target

[Service]
Type=oneshot
ExecStart=/sbin/setserial /dev/ttyS0 uart 16550A port 0x03f8 irq 4
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable --now serial-hardware.service

Mastering setserial ensures deterministic communication with serial devices, resolves interrupt conflicts, and enables custom industrial protocols across Linux servers and embedded workstations.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.