Asynchronous Adapter Ports

 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│ │ │ │ ║
      ╙─┴─┴─┴─┴╥┴╥┴╥┴╥╜ bit
               ║ ║ ║ ╚═► 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│ │   │ ║
      ╙─┴─┴─┴─┴╥┴─┴─┴╥╜ bit
       ╚╦╝     ║ ╚╦╝ ╚═►  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│ │ │ │ ║
      ╙─┴─┴─┴─┴╥┴╥┴╥┴╥╜ bit
       ╚╦╝     ║ ║ ║ ╚═►  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║
      ╙╥┴╥┴╥┴─┴─┴╥┴─┴─╜ bit
       ║ ║ ║ ╚╦╝ ║ ╚═╩═► 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│ │ │ │ │ ║
      ╙─┴─┴─┴╥┴╥┴╥┴╥┴╥╜ bit
             ║ ║ ║ ║ ╚═► 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)
      ╙╥┴╥┴╥┴╥┴╥┴╥┴╥┴╥╜ bit
       ║ ║ ║ ║ ║ ║ ║ ╚► 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)
      ╙╥┴╥┴╥┴╥┴╥┴╥┴╥┴╥╜ bit
       ║ ║ ║ ║ ║ ║ ║ ╚═► 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)
          BIOS Data Area
          Cables and Pin Outs
          I/O Port Map
                                    -♦-