4. The 8250 and descendant chips in the PCs.

The original PCs used the 8250 UART. Later machines use 16450 or 16550 chips, or there may be highly integrated ASICs whose UART section works the same as the 16550. The main improvements have been longer receiver queues in the chip, suitable for higher data rates. The programming interface seems to be much the same for them all.

Of course, if you are doing ioctl(2) calls with Linux, all this is basically handled by the driver in the kernel, so it may serve as a reference. If you are looking at the kernel source (located in a file such as /usr/src/linux/drivers/char/serial.c) some of this may be useful for a cross-reference. And if you are working with non PC hardware it will probably be rather irrelevant. In that case, if on some kind of Unix, go look up sections 2, 4, and 5 in the unix manuals and skip right to section 5 here.

There are 8 ports beginning at 0x3F8, 0x2F8, or elsewhere, for each serial connector ("COM-port").

Port 0 0x3F8 - (R/W) Data register (Port 3 Bit 7 "DLAB" = 0) or low byte of baud-rate divisor. (Port 3 Bit 7 "DLAB" = 1)

Port 1 0x3F9 - (R/W) interrupt enables (Port 3 Bit 7 "DLAB" = 0) or high byte of baud-rate divisor. (Port 3 Bit 7 "DLAB" = 1)

Bits 7--40000reserved
Bit 3 = 1 modem-status interrupt enabled (see these on Port 6)
Bit 2 = 1 receiver status line interrupt enabled
Bit 1 = 1 transmitter empty interrupt enabled
Bit 0 = 1 received data available interrupt enabled (and 16550 has FIFO full or time-out)

Port 2 0x3FA - (R/O) Information on pending interrupts:

Bits 7-6 = 00 reserved on 8250-16450
= 11 when 16550 FIFO queues are enabled
Bits 5-4 = 00 reserved
Bit 3 = 0 for 8250-16450
= 1 for 16550 timeout interrupt pending
Bit 2-1   Pending interrupts:
= 11 receiver status line interrupt
= 10 receiver data available interrupt
= 01 transmitter empty interrupt
= 00 modem status line interrupt
Bit 0 = 0 means any interrupt pending
= 1 means no interrupt pending

Port 2 0x3FA - (W/O) on 16550s:

Bit 7-6 FIFO length
= 001 byte
= 014 bytes
= 108 bytes
= 1114 bytes
Bit 5-4= 00reserved
Bit 3 = 1Change RxRDY TxRDY pins from mode 0 to mode 1
Bit 2 = 1Clear Tx FIFO
Bit 1 = 1Clear Rx FIFO
Bit 0 = 1enable Clear Rx and Tx FIFOs. Must be set with bits 2 and/or 1 to actually clear the FIFOs.

Port 3 0x3FB - (R/W) Line control register.

Bit 7 DLAB. Set to 0 for data on 0x3F8 and set to 1 for setting/reading the divisor for baud rate on 0x3F8 and 0x3F9.
Bit 6 = 1 Emit a Break: Forces a Space state on the output and leaves it there. See Port 5 Bit 4 for Rx Break.
Bit 5 = 1 change parity setting at all
= 0 ignore bits 4,3
Bit 4 = 1 Parity enable
Bit 3 = 1 Even parity
= 0 Odd parity
Bit 2 = 0 One Stop bit
= 1 Zero Stop bit
Bit 1-0 Word length:
= 00 5 bits
= 01 6 bits
= 10 7 bits
= 11 8 bits

Port 4 0x3FC - (R/W) Modem control register

Bits 7-5 = 000 reserved
Bit 4 = 1 to enable loopback (transmitter transmits right into the receiver, as if pins 2 and 3 had been shorted together on the outside plug.)
Bit 3 = "Aux user output port 2". This is set to 1 to actually enable interrupts within the PC. This is define by the internal wiring in the PC, it is not part of the 8250 chip as such. A real nice gotcha! this...
Bit 2 = "Aux user output port 1" No idea what this is used for.
Bit 1RTS (pin 4/25 or 7/9)
= 1 RTS Space
= 0 RTS Mark
Bit 0DTR (pin 20/25 or 4/9)
= 1 DTR Space
= 0 DTR Mark

Port 5 0x3FD - (R/O) Data-Line status register

Bit 7 = 0 reserved
Bit 6 = 1 Transmitter shift and holding registers are both empty
Bit 5 = 1 Tx holding register empty. Ready for another byte.
Bit 4 = 1 Break condition detected: Rx is held at Space level for longer than a character time.
See Port 3 Bit 6 for Tx break.
Bit 3 = 1 Framing error detected. Stop bit was wrong.
Bit 2 = 1 Parity error. Wrong character parity received.
Bit 1 = 1 Overrun error. Receiver was not emptied in time for the next incoming character to be stored.
One character is lost.
Bit 0 = 1 Data ready, a complete character has been received and is available for reading.

Port 6 0x3FE - (R/O) Modem status register

Port 1 Bit 3 = 1 enables interrupts on changes on any of these lines. When the interrupt occurs, look at Port 2 bits 2-1 and if this is 00 then Bits 3-0 here will tell what has happened and Bits 7-4 will tell what is happening.

The 4 wires are general inputs in the sense that their actual states do not appear to affect the transmitter or receiver operation as such. When left unconnected they will read as 0 (Mark)

Bit 7CD(pin 8/25 or 1/9) (Loopback OUT2)
= 1 CD Space
= 0 CD Mark
Bit 6RI(pin 22/25 or 9/9) (Loopback OUT1)
= 1 RI Space
= 0 RI Mark
Bit 5DSR(pin 6/25 or 6/9) (Loopback DTR)
= 1 DSR Space
= 0 DSR Mark
Bit 4CTS(pin 5/25 or 8/9) (Loopback RTS)
= 1 CTS Space
= 0 CTS Mark
Bit 3 = 1A Change either way has occurred on the CD line
Bit 2 = 1A Change from Space to Mark has occurred on the RI line
Bit 1 = 1A Change either way has occurred on the DSR line
Bit 0 = 1A Change either way has occurred on the CTS line

Bits 3, 1, and 0 are set whenever one of the CD, DSR, or CTS input lines change state, in either direction (from Mark to Space or Space to Mark). Bit 2 goes to 1 only when the RI line changes from Space to Mark, but not the other way.

The low 4 bits are reset when this port is read, so the next time they will read 0 unless another change has occurred.

I have noticed some funny problems with the RI line on one of my machines (9/9), it looks as if it is grounded on the outside and has some weird internal dependency on CTS, (pin 8/9, bit 1 port 4). Bit 6 goes 1 or 0 by what seems to be its own will. Bit 2 faithfully reports that bit 6 has changed from 1 to 0 however. Since this serial port works with a modem I am not too concerned. It does mean that I can't use this line as an input on that particular machine.

Port 7 0x3FF - (R/W) Scratch register. This may be written and read back but does not do anything other than behave as a one-byte memory.

To 0. Introduction

To 3. Serial data format.

To 5. Where do you find the ports?

Table of ASCII codes

To index page