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--4 | 0000 | reserved |
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 | |
= 00 | 1 byte | |
= 01 | 4 bytes | |
= 10 | 8 bytes | |
= 11 | 14 bytes | |
Bit 5-4 | = 00 | reserved |
Bit 3 | = 1 | Change RxRDY TxRDY pins from mode 0 to mode 1 |
Bit 2 | = 1 | Clear Tx FIFO |
Bit 1 | = 1 | Clear Rx FIFO |
Bit 0 | = 1 | enable 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 1 | RTS | (pin 4/25 or 7/9) |
= 1 | RTS Space | |
= 0 | RTS Mark | |
Bit 0 | DTR | (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 7 | CD | (pin 8/25 or 1/9) (Loopback OUT2) |
= 1 | CD Space | |
= 0 | CD Mark | |
Bit 6 | RI | (pin 22/25 or 9/9) (Loopback OUT1) |
= 1 | RI Space | |
= 0 | RI Mark | |
Bit 5 | DSR | (pin 6/25 or 6/9) (Loopback DTR) |
= 1 | DSR Space | |
= 0 | DSR Mark | |
Bit 4 | CTS | (pin 5/25 or 8/9) (Loopback RTS) |
= 1 | CTS Space | |
= 0 | CTS Mark | |
Bit 3 | = 1 | A Change either way has occurred on the CD line |
Bit 2 | = 1 | A Change from Space to Mark has occurred on the RI line |
Bit 1 | = 1 | A Change either way has occurred on the DSR line |
Bit 0 | = 1 | A 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.