Last friday I found myself patching the Linux kernel sources to be able to add custom baud rates support for 16C950 UART cards. I needed to communicate, via a serial port, with one of the devices built by the hardware guys at work. Unfortunately, a non-standard baud rate and 9-bits were needed.

The Sealevel Ultra COMM+422 PCI card we are using is already provided with a patch that adds 9-bit support. However, I was not able to found how to change the baud rate to a non-standard one.

Following the 9-bit patch approach, I added extra requests to ioctl in order to modify the 16C950 registers needed to achieve custom baud rates. Here is the list of added extra ioctl requests (also the 9-bit ones) with the necessary parameters and updated/accessed 16C950 registers:

Request

Parameters

16C950 registers

Description

TIOC9BITGET

out: integer

NMR

Get current 9-bit status

TIOC9BITSET

NMR

Enable 9-bit support

TIOC9BITCLR

NMR

Disable 9-bit support

TIOCPRESCALERGET

out: integer

EFR, MCR

Get prescaler status

TIOCPRESCALERSET

EFR, MCR

Enable prescaler

TIOCPRESCALERCLR

EFR, MCR

Disable prescaler

TIOCDIVLATCHGET

out: integer

LCR, DLL/DLM

Get divisor latch register

TIOCDIVLATCHSET

in: integer

LCR, DLL/DLM

Set divisor latch register

TIOCSAMPLINGCLKGET

out: integer

TCR

Get sampling clock

TIOCSAMPLINGCLKSET

in: integer

TCR

Set sampling clock

TIOCPRESCALERCLKGET

out: integer

CPR

Get prescaler clock

TIOCPRESCALERCLKSET

in: integer

CPR

Set prescaler clock

I’m not sure if this is the best way to do it, but it works. So, if you need 9-bit and custom baud rates support, apply one the following patches to the kernel (I have aslo updated the Sealevel patch for older and newer kernels than the one provided):