The BIOS Data Area contains a list of up to four COM port base addresses.
During POST the older BIOSes tests for and initialize COM1 and COM2; newer
ones also handle COM 3 and COM 4.

  The COM1 adapter decodes ports 3f8H through 3ffH
  The COM2 adapter decodes ports 2f8H through 2ffH
  The COM3 adapter decodes ports 3e8H through 3efH
  The COM4 adapter decodes ports 2e8H through 2efH

The ROM BIOS INT 14H will work with any of the four ports, as long as you
store the port's base address into the COMn port table starting at
0040:0000.  It is critical that no two adapters share the same physical
port addresses or neither will work.

BIOS supports a simple polling-style serial I/O.  The adapter is able to
force a hardware interrupt on a variety of conditions, depending upon the
values in the Interrupt Enable Register (3f9H or 2f9H).

  COM1 forces interrupt level 4 (IRQ 4 is handled by INT 0cH vector)
  COM2 forces interrupt level 3 (IRQ 3 is handled by INT 0bH vector)
  COM3 shares IRQ4.  BIOS checks the Int ID regs to see who rang
  COM4 shares IRQ3.  BIOS checks the Int ID regs to see who rang

In the following chart, pb+n is one of 3f8H+n, 2f8H+n, 3e8H+n, 2e8H+n,
depending upon the port.  For instance, for COM1, pb+3=3fbH.

Port  Description
pb+0  Write: transmitter holding register.  8 bits of character to be sent.
Read:  receiver buffer register. 8 bits of character received.

Write: (if DLAB=1) divisor latch low byte  Baud Divisor  Baud Divisor
After OUT pb+3,80H this port holds                            
the low byte of the clock divisor    110    1040  1200      96
which, together with the high byte   150    768   2400      48
(port pb+1) constitute 16-bit value  300    384   4800      24
that sets the baud rate as shown:    600    192   9600      12
pb+1  Write: divisor latch high byte (when DLAB=1; i.e., after OUT pb+3,80H)
Write: interrupt enable register
 7 6 5 4 3 2 1 0 
 0 0 0 0         
          0: 1=enable interrupt when rec'd data is available
          1: 1=enable interrupt when transmit buffer is empty
          2: 1=enable int on rec'r line status (err or break)
          3: 1=enable int on modem status (CTS,DSR,RI,RLSD)
pb+2  Read: interrupt identification reg.  When an interrupt occurs, read
this register to find what caused it.
 7 6 5 4 3 2 1 0 
     0 0         
                   0: 1=no interrupt pending; can be used in polling
                1-2: 00=receiver line status interrupt.  Occurs on:
                       overrun, parity, or framing error, or break
                       Reset by reading line status (port pb+5)
                    01=received data available
                       Reset by reading receiver buffer (port pb+0)
                    10=transmitter buffer empty
                       Reset by writing transmitter buffer (pb+0)
                    11=modem status.  Occurs upon:
                       Clear To Send, Data Set Ready, Ring Ind, or
                       Rec'd Line Signal Detect.
                       Reset by reading modem status (port pb+6).
                  3: (16550 UARTs) 1=Receiver FIFO time-out
                6-7: (16550 UARTs) 00=FIFOs disabled (or old 8250)
11=FIFOs enabled
01=FIFOs enabled and DMA mode

Write: (16550 UARTs) FIFO control register (write only)
 7 6 5 4 3 2 1 0 
     0 0         
                   0: 1=enable FIFO mode
                  1: 1=clear receiver FIFO
                  2: 1=clear transmit FIFO
                  3: DMA mode select
                6-7: FIFO interrupt triggger level: 00=1 byte;
01=four bytes; 10=8 bytes; 11=16 bytes
pb+3  Read/Write: line control register
 7 6 5 4 3 2 1 0 
       par s len 
                  0-1: word length: 00=5, 01=6, 10=7, 11=8
                  2: stop bits: 0=1,1=2 (some oddball exceptions)
                3-4: parity: x0=None, 01=Odd, 11=Even
                  5: stuck parity  (not used by BIOS)
                  6: enable break control. 1=start sending 0s (spcs)
                  7: DLAB (Divisor Latch Access Bit)  Determines mode
of ports pb+1 and pb+2.  1=set baud, 0=normal
pb+4  Write: modem control register
 7 6 5 4 3 2 1 0 
 0 0 0           
            0: 1=activate -DTR (-data trmnl rdy), 0=deactivate
            1: 1=activate -RTS (-request to send), 0=deactivate
            2: 1=activate -OUT1 (spare, user-designated output)
            3: 1=activate -OUT2
            4: 1=activate loopback for diagnostic testing
pb+5  Read: line status register
 7 6 5 4 3 2 1 0 
                  Note: bits 1-4 cause interrupt if enabled (pb+1)
                 0: 1=data ready (DR). Reset by reading recv'r buffer
                 1: 1=overrun error (OE).  Previous character is lost
                 2: 1=parity error (PE). Reset by reading line status
                 3: 1=framing error (FE). Bad stop bit in character
                 4: 1=break indicated (BI).  Sustained space received
                 5: 1=transmitter holding register empty.  OK to send
                 6: 1=transmitter empty.  No data being processed.
                 7: (16450 UARTs) 1=Receiver FIFO error
pb+6  Read: modem status register
 7 6 5 4 3 2 1 0 
                  Note: bits 0-3 cause an interrupt if enabled (pb+1)
                  0: 1=Delta Clear To Send (DCTS) has changed state
                  1: 1=Delta Data Set Ready (DDSR) has changed state
                  2: 1=Trailing Edge Ring Indicator (TERI) is active
                  3: 1=Delta Data Carrier Detect (DDCD) has changed
                  4: 1=Clear To Send (CTS) is active
                  5: 1=Data Set Ready (DSR) is active
                  6: 1=Ring Indicator (RI) is active
                  7: 1=Data Carrier Detect (DCD) is active
pb+7  Read/Write scratch pad
See Also: INT 14H (serial port I/O)
- -

Asynchronous Adapter Ports