================================================================
Gotchas
================================================================
For most serial port chips in PCs, Out2 must be set to enable
interrupts

For PCs, don't forget to enable interrupts at the 8259
interrupt controller chip.

After detecting and initializing the serial chip, clear any
dangling interrupts before entering the main rx/tx loop.

The TEMT bit does not generate an interrupt. If you want
interrupt-driven transmit, use the THRE bit instead. If you
want to use stick parity to transmit 9-bit values, you must
use polling, because you can't change the parity bit (9th
bit) until TEMT.
	TEMT = Transmitter Empty
		= b6 in LSR (Line Status Register = register 5)
	THRE = Transmitter Transmitter Holding Register Empty
		= b5 in LSR (Line Status Register = register 5)

If the chip doesn't have a FIFO, it's crap.

Enabling the FIFO with serial mice makes the mouse 'sluggish'.

The FIFO may be enabled by default. If you don't want this,
probe the chip to see if it has a FIFO (16550+), then turn
the FIFO off.

If the receive FIFO is enabled, the receive interrupt handler
should drain the FIFO completely (i.e. there should be a
while() loop in the interrupt handler)

If you do put a loop in the interrupt handler, handle ALL
possible interrupt sources. Otherwise, the loop may be
infinite, and the system will hang.

Keep track of errors (parity, framing, overrun). They can give
you valuable information if something doesn't work.

Start with the transmit interrupt disabled. When you have
something to transmit, queue it and enable transmit interrupt.
When the transmit queue is empty, the serial interrupt
routine should disable further transmit interrupts.

Loopback seems to be broken on most chips.

================================================================
Interrupts
================================================================
Source of Interrupt         Action Required to Clear
------------------------    ------------------------------------
Receiver error or BREAK     Read Line Status register
Receiver data               Read data from data register
Transmitter Buffer Empty    Write to data register or read IID reg
RS-232 input                Read Modem Status register

================================================================
Loopback
================================================================
(from National Semiconductor PC16550D data sheet; page 18)

Bit 4: This bit provides a local loopback feature for diagnos-
tic testing of the UART.

When bit 4 is set to logic 1, the following occur: the transmitter
Serial Output (SOUT) is set to the Marking (logic 1) state; the
receiver Serial Input (SIN) is disconnected.

The output of the Transmitter Shift Register is ``looped back''
into the Receiver Shift Register input.

The four MODEM Control inputs (DSR, CTS, RI, and DCD) are
disconnected; and the four MODEM Control outputs (DTR, RTS,
OUT 1, and OUT 2) are internally connected to the four MODEM
Control inputs, and the MODEM Control output pins are forced to
their inactive state (high).

In the loopback mode, data that is transmitted is immediately
received. This feature allows the processor to verify the
transmit- and received-data paths of the UART.

In the loopback mode, the receiver and transmitter interrupts are
fully operational. Their sources are external to the part.

The MODEM Control Interrupts are also operational, but the
interrupts' sources are now the lower four bits of the MODEM
Control Register instead of the four MODEM Control inputs. The
interrupts are still controlled by the Interrupt Enable Register.

xxx - in my system, it appears that the handshaking lines are
looped back, but not the serial data...

================================================================
Serial software notes
================================================================
From: "Charles A. Crayne" <ccrayne@crayne.org>
Newsgroups: comp.lang.asm.x86
Subject: Re: Questions to UART gods.
Date: Fri, 18 Jul 2003 17:43:24 -0700
Message-ID: <20030718174324.1dce7803.ccrayne@crayne.org>
References: <200307180534.h6I5YIHP005749@f48.peterstar.ru>

On Wed, 16 Jul 2003 11:52:10 +0400 (MSD)
"PetroffHeroj" <petroffheroj@REMemailOVEacc.com> wrote:

:If you can reply on _any_ question in this letter, your help will be greatly
:appreciated. Thank you in advance for your patience.

Let me start by saying that my answers are based upon my experience in
writing and maintaining a multi-user bulletin board system. Your
application may require different considerations.

: * On THRE with FIFOs on, can we really send up to 16 bytes at once?
:
: * On RDA with FIFOs on (but _not_ on FIFO timeout), is it correct to
: receive up to <Rx_trig> bytes at once? 

If by "at once" you mean without checking the LSR between bytes, I do not
recommend it. The timing may be such, for example, that by the time you have
written 16 bytes, one or more of those bytes have already been shifted out of
the buffer, making room for additional writes. Likewise, on read, by the time
that your interrupt routine has gained control and read <Rx_trig> bytes,
additional bytes may have already been placed into the FIFO.

: * On FIFO timeout (with FIFOs) / on RDA (without FIFOs), is it correct to
:check for RDA bit in LSR, instead of checking for RDA int indication in IIR?

Yes. The IIR should only be used for scheduling interrupt handling routines,
not for controlling them.

: * On FIFO timeout, to read exactly the number of bytes left in Rx FIFO, is
:there a better way than checking for RDA int indication or RDA bit in LSR?

As long as the interrupt handler's read routine loops on the LSR bit, then
the same code works for all cases.

: * What chips have the problem missing THRE int indication time to time when
:both RDA and THRE ints occur? What is the best walkaround for this problem?

I never encountered such a problem, but the solution would be -- as you
suggested -- to check the LSR for THRE.

: * THRE ints: are we required to disable them in THRE int handler when
:there's no more data to be sent?

Definitely not. When the THRE int handler discovers that there is no more
data to be sent, it should post the application which issued the write. 

: * The best way for starting transmission: is it faster to "re-enable" THRE
:ints blindly by writing to IER, or would it be better to rely on some
:variable telling whether THRE ints have been stopped (disabled / locked up),
:and only "re-enable" them if they indeed were?

It is both faster and better to not disable them in the first place. Then you
don't have to re-enable them.

: * Is that true that because of PIC's edge-triggered mode in PCs, a stopped
:THRE int may stay undetected when "re-enabling" it and transmission should
: be started manually by writing to THR?

On those PCs which still use edge-triggered interrupts, it is possible for any
interrupt to be lost at any time, which means that you need some sort of
"missing interrupt handler", usually driven by the timer interrupt. However,
even on level-triggered interrupts, I do not recommend starting (or restarting)
data transmission by writing to the IER.

: * When reading LSR or MSR _not_ in respective int handlers, for instance,
:when checking for RDA bit in LSR in a RDA int handler, does that
:automatically service the corresponding interrupt? In other words, would a
:program miss the change if we _don't_ save values of respective registers,
:on such intermediate reads, unlike in LSR/MSR handlers?

I am not sure that I understand what you mean by "automatically service the
corresponding interrupt", but if you read the LSR from anywhere in your code,
then you will cause the receiver line status bit in the IIR to be cleared --
without any other action taking place. If this matters to your code, then you
need to save the information somewhere. This also applies to clearing the modem
status bit by reading the MSR.

: * Various interrupt categories sometimes lock up if not servicing the whole
:interrupt chain in one int call (leaving after servicing the first int, for
:example); is that normal, e.g. does UART _require_ servicing all ints in a
:chain in one int call?

This question would be easier to answer if you provided a specific case, but the
short answer is that, if you decide to defer handling one or more of them, you
better be sure that you know exactly what you are doing.

: * Is it possible to implement flow control on internal modems by simply
:delaying THRE and RDA? (..._the modem_ doesn't indicate THRE int and clears
:THRE bit if its buffer is full and it doesn't want us to send for now; _the
:program_ disables RDA ints and doesn't react on RDA bit = 1 in LSR if our
:buffer is full and we don't want to receive from the modem for now.) If it's
:possible theoretically, are there any implementations of this method?

That sounds like the sort of thing that a "Winmodem" might do, but even there,
it doesn't solve the "end to end" flow control problem.

: * And finally, did various 8250's indeed contain _that_ many bugs? (...which
:makes one wish to forget about supporting them at all :I )

Perhaps I was just lucky, but I never had any problems.

-- Chuck

================================================================
High-speed serial (>115200 bits/sec)
================================================================
10. High-Speed PC Serial Ports
16 Feb (1 post) Archive Link: "[PATCH][CFT] High-speed PC serial ports."
People: David Woodhouse

David Woodhouse announced:

Most PC superio chips have supported up to 460800 or 921600 baud for
years.

This patch adds kernel support for the two most common ways of
achieving this -- the SMSC chips' "magic multipliers" where a value of
0x8001 or 0x8002 as divisor actually means _multiply_ by 2 or 4
respectively, and the National Semiconductor version where you can set
the baud_base to any of three values, but whenever you touch the original
16550-compatible divisor registers, it reverts baud_base to 115200 for
compatibility.

Although both of these modes are designed for backward-compatibility,
there's _also_ a bit in the superio chip which can disable them and force
_complete_ 16550A compatibility. If your BIOS doesn't enable these, you
may need Shsmod <http://www.devdrv.com/shsmod/> to do so for you.

If you have an SMSC superio chip, the driver can't autodetect this -- you
need the (also-attached) patch to setserial, and to run 'setserial /dev/ttySx
magic_multiplier' for each port. This will make it support baud rates of up
to 460800.

If you have a NatSemi chip and it's set to enable high-speed before the
8250 driver probes it, then its high-speed capability should be
automatically detected and you'll get up to 921600 baud from it without
having to do anything special. If your BIOS doesn't enable the high-speed
mode, then after using Shsmod to do so, run 'setserial /dev/ttyS0
autoconfig'.

I've also had a hacked-up superio probe enabling high-speed mode on these
ports automatically so you can boot with 'console=ttyS0,460800' etc., but
that's an ugly hack and adds a _third_ set of superio probe code to the
kernel, so doing that can come later. Eventually we can do the superio
probe centrally and remove it from the parport, IrDA, SH board setup, and
other code where it's currently duplicated. That's probably a 2.7 task
though.

================================================================
Serial communications protocols
================================================================
                    error-      block
name        duplex  checking    size  batch?    handshaking
----------- ------  --------    ----- ------    -----------
xmodem      half    1-byte      128b  no        ACK or NAK after each block
                    checksum
xmodem CRC  full?   CRC-16      128b  no        ACK or NAK after each block?
xmodem 1K   full?   ?           1K    no        ACK or NAK after each block?
ymodem      full?   ?           1K    no        ACK or NAK after each block?
ymodem G    full?   ?           ?     yes       ACK or NAK after each block?
zmodem      full?   CRC-16/32   ?     yes       ACK only when transfer is done
kermit      full?               var   ?         ?

file compression: zlib/gzip/lz-77, lzo

XMODEM: invented by Ward Christensen in 1979
        128-byte blocks, 1-byte checksum, 1-byte block number
XMODEM/CRC: 1-byte checksum replaced by 16-bit CRC
YMODEM: XMODEM/CRC with protocol and/or batch enhancements,
        1-byte block number
ZMODEM: 16-bit CRC, can fall back to YMODEM. Variable-length blocks.
        Frame start marked by special code, which is escaped.
  "Link Escape coding does add some overhead.  The worst case, a file
   consisting entirely of ZDLE characters, would incur a 50% overhead."
   ZDLE == 030 == 24 == 0x18 == ASCII CAN
   A string of CAN characters can abort a ZMODEM session,
   compatible with X/YMODEM session abort.

packet == type byte followed by
        four flags bytes -OR- four position bytes (little-endian)

A binary header packet begins with the sequence ZPAD, ZDLE, ZBIN.


The receiving program will decode any sequence of ZDLE followed by a byte
with bit 6 set and bit 5 reset (upper case letter, either parity) to the
equivalent control character by inverting bit 6.  This allows the
transmitter to escape any control character that cannot be sent by the
communications medium.  The ZMODEM software currently escapes ZDLE, 021,
0221, 023, and 0223.  In addition, the receiver recognizes escapes for
0177 and 0377 should these characters need to be escaped.


Problems with XMODEM: awkward user interface, short block length is
not efficient, 8-bit checksum is no good, only one file can be sent
per command, transmitted program can accumulate up to 127 extraneous
bytes, modification date and other file attributes are lost, requires
8-bit transparency (doesn't work with software X-on/X-off handshaking)

YMODEM-k: 1K blocks
YMODEM-g: efficient batch transfers, preserves exact file length and
  file modification date. No error recovery: requires reliable link.
  IF YMODEM-g detects a CRC error, data transfers are aborted.
  YMODEM-g is easy to implement because it closely resembles XMODEM-CRC.

================================================================
================================================================
If you are writing a program to communicate with a serial device, keep in
mind the following:

1. Always set DTR and RTS. Many serial devices "play dead" if DTR is not
   set.

2. You may need to add a small time delay (0.25 sec) between transmitted
   characters. This can be reduced or eliminated once everything is
   working.

3. Make sure that your receive buffer is sufficiently large. You want to
   avoid buffer overflow.

xxx - interrupt notes: read data repeatedly until DR=0?
	write bytes to be transmitted until THRE=0?
