home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / FAQSYS18.ZIP / FAQS.DAT / SERPORT.18 < prev    next >
Internet Message Format  |  1995-12-12  |  133KB

  1. From chris@chris.telip.uni-sb.de Wed Mar  1 17:57:18 1995
  2. From: chris@chris.telip.uni-sb.de (Chris Blum)
  3. Newsgroups: comp.sys.ibm.pc.hardware.comm,comp.os.msdos.programmer
  4. Subject: The Serial Port rel. 18, part 1/3
  5. Date: 23 Feb 1995 00:22:09 +0100
  6. Organization: The Outside of the Asylum
  7. Reply-To: chris@phil.uni-sb.de (Chris Blum)
  8. NNTP-Posting-Host: chris.telip.uni-sb.de
  9. Keywords: comm, COM, UART, serial port
  10.  
  11. Date of release: 22 Feb 1995             Release 18
  12.  
  13. This is a summary on serial communication using the TTY protocol. It
  14. contains information on the TTY protocol and hardware and software implemen-
  15. tations for IBM PCs which has been derived from National Semiconductor data
  16. sheets and practical experience of the author and his supporters. Starting
  17. with release 5, some information on modems has been added.
  18.  
  19. If you want to contribute to this file in any way, please email me (probably
  20. just reply to this posting). My email address is: chbl@stud.uni-sb.de or
  21. chris@phil.uni-sb.de. See the end for details.
  22.  
  23. It's the seventeenth publication of this file. Some errors have been corrected
  24. and some information has been added (which has surely brought other errors
  25. with it, see Murphy's Law).
  26.  
  27. [] brackets often indicate comments to sneaked material; copied lines are
  28. indented. I've made great efforts to always mention who's to be credited.
  29. Please tell me if you find something that you've written that's not correctly
  30. associated with your name.
  31.  
  32. This compilation of information is (C) Copyright 1993 - 1995 by Christian
  33. Blum; all rights reserved. This file is not to be reproduced commercially,
  34. not even partially, without written permission. You are allowed to use it
  35. in any other way you like. I don't want any (monetary) profit being drawn
  36. out of it (neither by me nor by others! I don't mind if you have a look
  37. or two at it at work though... :-). Please feel free to provide this file
  38. to others for free or at your own expenses.
  39.  
  40.  
  41. Changes since the last publication
  42. ==================================
  43.  
  44. Used more proper interrupt acknowledging in the examples (namely the
  45. method I suggested some chapters before :) in order to avoid lock-ups
  46. on MCA computers. (Thanks, Erik)
  47.  
  48. Added some info on the auto flow-control feature of the TL16C550C.
  49. (Thanks, naddy)
  50.  
  51.  
  52. What I'm doing
  53. ==============
  54.  
  55. I'm no longer very much into DOS (though I still make some money with it :),
  56. so don't expect me reading all the groups regularly that I'm posting this
  57. to.
  58.  
  59.  
  60. What others are doing
  61. =====================
  62.  
  63. There is a file available from ftp.phil.uni-sb.de, pub/staff/chris called
  64. The_Serial_Port.more05 that contains an article by Bob Niland covering
  65. serial communication under Windows. It is regularly posted to
  66. comp.sys.ibm.pc.hardware.comm and other groups; if you obtain it from
  67. there it's probably more up to date.
  68.  
  69.  
  70. No more "Automatic File Delivery" (AFD) service
  71. ===============================================
  72.  
  73. The automatic mail reply service I've mentioned in earlier releases of
  74. this file is still available, but I won't do anything to keep it
  75. alive from now on. Please obtain the files via anonymous ftp from
  76. ftp.phil.uni-sb.de (134.96.80.220), pub/staff/chris.
  77.  
  78. If you don't have access to ftp, try using an ftp to email gateway
  79. (ftpmail@decwrl.dec.com or bitftp@pucc.princeton.edu, and probably
  80. a lot more; put 'help' in the body to obtain instructions). If everything
  81. fails, write to me.
  82.  
  83.  
  84. Acknowledgements   (quite a bunch of people by now...)
  85. ================
  86.  
  87. The following persons have contributed (directly or indirectly :-) to this
  88. summary by providing information or making suggestions/reporting errors.
  89. Tell me if your name is missing.
  90.  
  91.       Madis Kaal <mast@anubis.kbfi.ee>
  92.       Steve Poulsen <stevep@ims.com>
  93.       Scott C. Sadow <NS16550A@mycro.UUCP>
  94.       Dan Norstedt <?>
  95.       Alan J. Brumbaugh <brumba@maize.rtsg.mot.com>
  96.       Mike Surikov <surikov@adonis.iasnet.com>
  97.       Varol Kaptan <E66964%trmetu.bitnet@relay.EU.net>
  98.       Richard F. Drushel <rfd@po.CWRU.Edu>
  99.       John A. Limpert <johnl@n3dmc.svr.md.us>
  100.       Brent Beach <ub359@freenet.victoria.bc.ca>
  101.       Torbjoern (sp?) Lindgren <tl@etek.chalmers.se>
  102.       Stephen Warner <ee_d316@dcs.kingston.ac.uk>
  103.       Kristian Koehntopp <kris@black.toppoint.de>
  104.       Angelo Haritsis <ah@doc.ic.ac.uk>
  105.       Jim Graham <jim@n5ial.mythical.com>
  106.       Ralf Brown <ralf@cs.cmu.edu>
  107.       Alfred Arnold <zam036@zam112.zam.kfa-juelich.de>
  108.       Andrew M. Langmead <aml@world.std.com>
  109.       Richard Clayton <richard@locomotive.com>
  110.       Christof Baumgaertner <baumg@rhrk.uni-kl.de>
  111.       Goran Bostrom <GORAN@infovox.se>
  112.       Brian Mork <bmork@opus-ovh.spk.wa.us>
  113.       Richard Steven Walz <rstevew@armory.com>
  114.       Scott David Daniels <daniels@cse.ogi.edu>
  115.       Brian Onn <Brian.Onn@Canada.Sun.COM>
  116.       Erik Suurmaa <erik@lerdeil.ee>
  117.       Terence Edwards <Terence@tedwards.demon.co.uk>
  118.       Christian 'naddy' Weisgerber <naddy@mips.pfalz.de>
  119.  
  120.  
  121.  
  122. Introduction
  123. ============
  124.  
  125. One of the most universal parts of the PC (except for the CPU, of course :-)
  126. is its serial port. You can connect a mouse, a modem, a printer, a plotter,
  127. another PC, dongles :) ...
  128.  
  129. But its usage (both software and hardware) is one of the best-kept secrets
  130. for most users, besides that it is not difficult to understand how to
  131. connect (not plug in) devices to it and how to program it.
  132.  
  133. Regard this file as a manual for the serial port of your PC for both
  134. hardware and software.
  135.  
  136.  
  137. Historical summary
  138. ------------------
  139.  
  140. In early days of telecommunication, errand-boys and optical signals (flags,
  141. lights, clouds of smoke) were the only methods of transmitting information
  142. across long distances. With increasing requirements on speed and growing
  143. amount of information, more practical methods were developed. One milestone
  144. was the first wire-bound transmission on May 24th, 1844 ("What hath God
  145. wrought", using the famous Morse alphabet). Well, technology improved a bit,
  146. and soon there were machines that could be used like typewriters, except that
  147. you typed not only on your own sheet of paper but also on somebody elses.
  148. The only thing that has changed on the step from the teletype to your PC
  149. regarding serial communications is speed.
  150.  
  151.  
  152. The TTY (teletyping) protocol
  153. -----------------------------
  154.  
  155. Definition: A protocol is a clear description of the LOGICAL method of
  156. transmitting information. This does NOT include physical realization.
  157.  
  158. There is a difference between bits per second and baud (named after J. M. E.
  159. Baudot, one of those guys who gave a real push to teletyping): 'baud' means
  160. 'state changes of the line per second' while 'bits per second' ...
  161. well, bits per second means bits per second. You may find this a bit weird
  162. because the numbers are often the same; there's only a difference if the
  163. line has more than two states. Since this is not the case with the RS-232C
  164. (EIA-232) port of your PC, most people don't differentiate between 'baud' and
  165. 'bits per second', while I do. For your convenience, I've replaced baud with
  166. bps even in copied material without special notice. Where you still find baud,
  167. it should read bps in most cases (I didn't change labels in source codes, pin
  168. names in data sheet information etc.). To illustrate the difference I give you
  169. some figures: 2400 bps at 8n1 carry 1920 bits of information per second, and
  170. modems send them at 600 baud thru' the phone wires using eight line states,
  171. while 1200 bps at 7e1 carry 840 bits of information per second that modems
  172. send at 600 baud using four different line states. I know it's confusing...
  173. that's why I quote this from a letter I received from Brent Beach. He explained
  174. it more clearly than I did (I've added some information):
  175.  
  176.   Perhaps a small diagram might help, showing the relationship among the
  177.   players:
  178.  
  179.                                     [bps]             [baud]
  180.      CPU Data              Serial                               Phone
  181.      Bus      -- bytes --> Port  -- bits --> Modem -- tones --> line --
  182.                                                                       |
  183.                                                                       |
  184.      CPU Data              Serial                                     |
  185.      Bus      <-- bytes -- Port  <-- bits -- Modem <-- tones ----------
  186.                    (1)               (2)               (3)
  187.  
  188.   The serial port accepts bytes from the CPU data bus and passes bits to the
  189.   modem. In doing this, the serial port can add or delete bits, depending on
  190.   the coding scheme in use.
  191.  
  192.   At (1) we are concerned with bytes per second. At (2) we are concerned with
  193.   bits per second, and at (3) it's baud. We distinguish because the number of
  194.   bits at (2) need not be equal to the number of bits (that is, bytes times 8)
  195.   at (1), and the number of state changes at (3) is not necessarily the same
  196.   as the number of bits before.
  197.   Bits can be stripped going from (1) to (2): the serial port may transmit
  198.   only 6 or 7 of the 8 bits in the byte. Bits can be added going from (1) to
  199.   (2): the serial port can add a parity bit and stop bits. From (2) to (3),
  200.   bits may be clustered to groups that are transmitted using different
  201.   encoding schemes like 'Frequency Shift Keying' or 'Quadrature Amplitude
  202.   Modulation', to name some.
  203.  
  204.   You can determine the transfer rate in bytes per second depending on the
  205.   serial port speed and the coding system. For example,
  206.  
  207.      8n1: 1 start bit + 8 data bits + 1 stop bit = 10 bits per word.
  208.           At 2400 bps, this is 240 bytes/characters per second. 2400 bps are
  209.           normally transmitted using QAM ('Quadrature Amplitude Modulation')
  210.           where 4 bits are clustered, and hence encoded to 600 baud.
  211.  
  212.      7e1: 1 start bit, 7 data bits, 1 even parity bit, 1 stop bit = 10 bits
  213.           per word. At 1200 bps, this is 120 bytes/characters per second. 1200
  214.           bps are encoded using DPSK ('Differential Phase Shift Keying', two
  215.           bits are clustered), and this results again in 600 baud.
  216.  
  217.  
  218. Now let's leave modems for a while and have a look at the serial port itself.
  219.  
  220. The TTY protocol uses two different line states called 'mark' and 'space'.
  221. (For the sake of clearness I name the line states 'high' (voltage) for
  222. positive and 'low' (voltage) for negative voltages). If no data is
  223. transmitted, the line is in its quiescent 'low' ('mark') state or in the
  224. 'break' state ('high'). Data looks like
  225.  
  226.       space            +---+       +---+   +---+         high  '0' +12V
  227.                        |   |       |   |   |   |
  228.       mark   ----------+   +-------+   +---+   +-------  low   '1' -12V
  229.  
  230.                         (1)  --------(2)-------- (3)
  231.  
  232.   (1) start bit   (2) data bits   (3) stop bit(s)
  233.  
  234. Steve Walz reported that in most (all?) books these kind of diagrams are drewn
  235. the other way round (I just copied what I saw on the oscilloscope) and
  236. that he'd use the labels 'high' and 'low' the other way round, corresponding
  237. to the signals on the TTL level (a matter of taste I guess); here is what he
  238. told me:
  239.  
  240.   In American texts, we will expect to see the data frame for serial transfer
  241.   of all kinds represented, despite the method of transfer (RS-232C, RS-422,
  242.   and optical even), as being an interruption of a normally HI state, and we
  243.   expect to see the diagram you drew in the older release 8, but with the 
  244.   labelling corrected as I have indicated:
  245.  
  246.          mark  ----------+   +-------+   +---+   +-------  high  '1' -12V
  247.              logical  1  | S | 1   1 | 0 | 1 | 0 | Stop
  248.         space            +---+       +---+   +---+         low   '0' +12V
  249.                           (1) --------(2)---------(3)
  250.                  (1) start bit   (2) data bits   (3) stop bit(s)
  251.   Thus transmitting the bit stream 01011, which is LSB first, MSB last.
  252.  
  253.   Indeed it seems to us that a zero SHOULD be the quiescent state, and the
  254.   one an active state, but the first teletypes used a current loop to
  255.   continuously monitor the state of the line, and thus current flow was
  256.   regarded as a 1 and it is "MARK" -ing time, and a signal then left a "SPACE"
  257.   in the graph of current flow designating a zero. Thus the bits following
  258.   the start bit at level zero were true to their bit values, and a 11111 in
  259.   5 bit baudot looked like this, using three dashes per bit:
  260.  
  261.    mark   ------   ------------------------ 1  HI  +5V TTL  -12V RS-232C
  262.   space         ---                         0  LO   0V TTL  +12V RS-232C
  263.                  s  1  1  1  1  1  stop
  264.  
  265.   and the baudot 10101 would appear thus:
  266.  
  267.    mark   ------   ---   ---   ------------ 1  HI  +5V TTL  -12V RS-232C
  268.   space         ---   ---   ---             0  LO   0V TTL  +12V RS-232C
  269.                  s  1  0  1  0  1  stop
  270.  
  271.   and the baudot 01010 would appear thus:
  272.  
  273.    mark   ------      ---   ---   --------- 1  HI  +5V TTL  -12V RS-232C 
  274.   space         ------   ---   ---          0  LO   0V TTL  +12V RS-232C
  275.                  s  0  1  0  1  0  stop
  276.  
  277.   and finally baudot 00000 would appear:
  278.  
  279.    mark   ------                  --------- 1  HI  +5V TTL  -12V RS-232C
  280.   space         ------------------          0  LO   0V TTL  +12V RS-232C
  281.                  s  0  0  0  0  0  stop
  282.  
  283.   Now I know that we don't send five bit baudot over RS-232C now, but I
  284.   wasn't about to try 8 bits, if you don't mind! :)
  285.  
  286.   I know that people get confused about the proper way to draw these, since
  287.   we use inverted voltages to send them via RS-232C interface now, but they
  288.   are still called logical "1" and "mark" when it is really -12 Volts DC, and
  289.   it is called "0" and "space" when it is +12 Volts. And logical one or "mark"
  290.   corresponds to +5 Volts, while logical zero is "space" and corresponds to 0
  291.   Volts. It is this way both within the parallel bus of the computer or the
  292.   transmit output of a UART/USART, with the exception that this data frame is
  293.   terminated by remaining logic "1" or "mark" as a stop bit and preface
  294.   to the next data frame.
  295.  
  296. Both transmitter (TX) and receiver (RX) use the same data rate (measured
  297. in bps, see above), which is the reciprocal value of the smallest time
  298. interval between two changes of the line state. TX and RX know about the
  299. number of data bits (probably with a parity bit added), and both know about
  300. the (minimum!) size of the stop step (called the stop bit or the stop bits,
  301. depending on the size of the stop step; normally 1, 1.5 or 2 times the size
  302. of a data bit). Data is transmitted bit-synchronously and word-asynchronously,
  303. which means that the size of the bits, the length of the words etc.pp. is
  304. clearly defined while the time between two words is undefined.
  305.  
  306. The start bit indicates the beginning of a new data word (this means one
  307. single character). It is used to synchronize transmitter and receiver and
  308. is always a logical '0' (so the line goes 'high' or 'space').
  309.  
  310. Data is transmitted LSB to MSB, which means that the least significant
  311. bit (LSB, Bit 0) is transmitted first with 4 to 7 bits of data following,
  312. resulting in 5 to 8 bits of data. A logical '0' is transmitted by the
  313. 'space' state of the line (+12V), a logical '1' by 'mark' (-12V).
  314.  
  315. A parity bit can be added to the data bits to allow error detection.
  316. There are two (well, actually five) kinds of parity: odd and even (plus
  317. none, mark and space). Odd parity means that the number of 'low' or 'mark'
  318. steps in the data word (including an optional parity bit, but not the
  319. framing bits) is always odd, so the parity bit is set accordingly (I don't
  320. have to explain 'even' parity, must I?). It is also possible to set the
  321. parity bit to a fixed state or to omit it. See Registers section for
  322. details on types of parity.
  323.  
  324. The stop bit does not indicate the end of the word (as it could be derived
  325. >from its name); it rather separates two consecutive words by putting the
  326. line into the quiescent state for a minimum time (that means the stop bit
  327. is a logical '1' or 'mark') in order for the next start bit to be clearly
  328. visible.
  329.  
  330. The framing protocol is usually described by a sequence of numbers and
  331. letters, eg. 8n1 means 1 start bit (always the same, thus omitted), 8 bits
  332. of data, no parity bit, 1 stop bit. 7e2 would indicate 7 bits of data,
  333. even parity, 2 stop bits (but I've never seen this one...). The usual thing
  334. is 8n1 or 7e1.
  335.  
  336. Your PC is capable of serial transmission at up to 115,200 bps (step size
  337. of 8.68 microseconds!). Typical rates are 300 bps, 1200 bps, 2400 bps and
  338. 9600 bps, with 19200 bps, 38400 bps and 57600 bps becoming more and more
  339. popular with high speed modems. Note that some serial ports have difficulties
  340. with high speeds! I've seen PS/2's failing to operate at more than 38400 bps!
  341. How come that IBM machines are often the least IBM compatible? :-)
  342.  
  343. This is what John A. Limpert told me about teletypes:
  344.  
  345.   Real (mechanical) teletypes used 1 start bit, 5 data bits and 1.42 stop
  346.   bits.  Support for 1.5 stop bits in UARTs was a compromise to make the
  347.   UART timing simpler.  Normal speeds were 60 WPM (word per minute),
  348.   66 WPM, 75 WPM and 100 WPM.  A word was defined as 6.1 characters.
  349.   The odd stop bit size was a result of the mechanical nature of the
  350.   machine.  It was the time that the printer needed to finish the current
  351.   character and get ready for the next character.  Most teletypes used
  352.   a 60 mA loop with a 130 V battery.  20 mA loops and lower battery voltages
  353.   became common when 8 level ASCII teletypes were introduced.  The typical
  354.   ASCII teletype ran at 110 bps with 2 stop bits (11 bits per character).
  355.  
  356. It's surely more exact than what I wrote in previous releases. I've just got
  357. to add that at least in Germany 50 bps was a familiar speed. And I think the
  358. lower battery voltage he's talking about was 24 volts.
  359.  
  360.  
  361. The physical transmission
  362. -------------------------
  363.  
  364. Teletypes used a closed-loop line with a quiescent current of 20ma and a
  365. space current of 0ma (typically), which allows to detect a 'broken line'
  366. (hence the name of the 'break' flag, see the Registers section). The RS-232C
  367. port of your PC uses voltages rather than currents to indicate logical states:
  368. 'mark'/'low' is signaled by -3v to -15v (typically -12V) and represents a
  369. logical '1', 'space'/'high' is signaled by +3v to +15v (typically +12V) and
  370. represents a logical '0'. The typical output impedance of the serial port of
  371. a PC is 2 kiloohms (resulting in about 5ma @ 10v), the typical input impedance
  372. is about 4.3 kiloohms, so there should be a maximum fan-out of 5 (5 inputs can
  373. be connected to 1 output). Please don't rely on this, it may differ from PC
  374. to PC.
  375.  
  376. Three lines (RX, TX & ground) are at least needed to make up a bidirectional
  377. connection.
  378.  
  379. Q. Why does my PC have a 25pin/9pin connector if there are only 3 lines
  380.    needed?
  381. A. There are several status lines that are only used with modems etc. See the
  382.    Hardware section and the Registers section of this file.
  383.  
  384. Q. How can I easily connect two PCs by a three-wire lead?
  385. A. Connect RX1 to TX2 and vice versa, GND1 to GND2. In addition to this,
  386.    connect RTS to CTS & DCD and connect DTR to DSR at each end (modem software
  387.    often relies on that). See the hardware section for further details.
  388.  
  389. Please be aware that at 115,200 bps (ie. ca. 115 kHz, but we need the
  390. harmonics up to at least 806 kHz) lines can no longer be regarded as 'ideal'
  391. transmission lines. They are low-pass filters and tend to reflect and mutilate
  392. the signals, but some ten meters of twisted wire should always be OK (I use 3m
  393. of screened audio cable for file transfer purposes, and it works fine. Not
  394. that other kinds of wire wouldn't do; I took what I found). See a good book on
  395. transmission lines if you're interested in why long lines can be a problem.
  396.  
  397. This has been posted to comp.os.msdos.programmer by Andrew M. Langmead:
  398.  
  399.   The RS-232C spec. has an official limit of 50 ft for RS-232C cables.
  400.   Realistically they can be much longer.  The book "Managing UUCP and
  401.   Usenet" by O'Reilly and Associates has a table that they credit to
  402.   "Technical Aspects of Data Communications", by McNamara (Digital
  403.   Press, 1992). It lists the maximum distances for an RS-232C
  404.   connection.
  405.  
  406.   Baud Rate       | max distance      | max distance
  407.                   | shielded cable    | unshielded cable
  408.   ----------------------------------------------------------
  409.         110       |      5000ft       |     3000ft
  410.         300       |      5000ft       |     3000ft
  411.         1200      |      3000ft       |     3000ft
  412.         2400      |      1000ft       |     500ft
  413.         4800      |      1000ft       |     250ft
  414.         9600      |      250ft        |     250ft
  415.  
  416. Please note that "baud" is correct in this case, because we're speaking of
  417. the transmission line itself.
  418.  
  419. This is what Torbjoern (sp?) Lindgren told me:
  420.  
  421.   I have successfully transmitted at 115,200 with over 30m long cables!
  422.   And it wasn't especially good wires. I had some old telecables with 20
  423.   individual wires, and used 7 of them for transfer, and left the others
  424.   unconnected.
  425.  
  426.   I don't remember the exact length, but I know it was something over
  427.   30m, and it probably was closer to 40m than 30m. The unused lines
  428.   probably shielded the lines from each other or something like that.
  429.   The computers used were two PC-compatibles with off-the-shelf
  430.   com-ports. Nothing fancy.
  431.  
  432. Note that some serial ports are more critical with mutilated signals than
  433. others, so you just have to try and find out yourself what works.
  434.  
  435.  
  436.  
  437. Hardware
  438. ========
  439.  
  440.  
  441. The connectors
  442. --------------
  443.  
  444. PCs have 9pin/25pin male SUB-D connectors. The pin layout is as follows
  445. (seen from outside your PC):
  446.  
  447.         1                         13         1         5
  448.       _______________________________      _______________
  449.       \  . . . . . . . . . . . . .  /      \  . . . . .  /
  450.        \  . . . . . . . . . . . .  /        \  . . . .  /
  451.         ---------------------------          -----------
  452.         14                       25           6       9
  453.  
  454.  Name (V24)  25pin  9pin  Dir  Full name               Remarks
  455. --------------------------------------------------------------------------
  456.     TxD         2     3    o   Transmit Data           Data
  457.     RxD         3     2    i   Receive Data            Data
  458.     RTS         4     7    o   Request To Send         Handshaking
  459.     CTS         5     8    i   Clear To Send           Handshaking
  460.     DTR        20     4    o   Data Terminal Ready     Status
  461.     DSR         6     6    i   Data Set Ready          Status
  462.     RI         22     9    i   Ring Indicator          Status
  463.     DCD         8     1    i   Data Carrier Detect     Status
  464.     GND         7     5    -   Signal ground           Reference level
  465.      -          1     -    -   Protective ground       Don't use this one
  466.                                                        as signal ground!
  467.  
  468. The most important lines are RxD, TxD, and GND. Others are used with
  469. modems, printers and plotters to indicate internal states.
  470.  
  471. '1' ('mark', 'low') means -3v to -15v, '0' ('space', 'high') means +3v
  472. to +15v. On status lines, 'high' is the active state: status lines go to the
  473. positive voltage level to signal events.
  474.  
  475. The lines are:
  476.  
  477.   RxD, TxD: These lines carry the data; 1 is transmitted as 'mark' (what I
  478.     call 'low') and 0 is transmitted as 'space' ('high').
  479.  
  480.   RTS, CTS: Are used by the PC and the modem/printer/whatsoever (further
  481.     on referred to as the data set, or DCE) to start/stop a communication.
  482.     The PC sets RTS to 'high', and the data set responds with CTS 'high'.
  483.     (always in this order). If the data set wants to stop/interrupt the
  484.     communication (eg. imminent buffer overflow), it drops CTS to 'low';
  485.     the PC uses RTS to control the data flow.
  486.  
  487.   DTR, DSR: Are used to establish a connection at the very beginning, ie.
  488.     the PC and the data set 'shake hands' first to assure they are both
  489.     present. The PC sets DTR to 'high', and the data set answers with DSR
  490.     'high'. Modems often indicate hang-up by resetting DSR to 'low' (and
  491.     sometimes are hung up by dropping DTR).
  492.  
  493.   (These six lines plus GND are often referred to as '7 wire'-connection or
  494.   'hand shake'-connection.)
  495.  
  496.   DCD: The modem uses this line to indicate that it has detected the
  497.     carrier of the modem on the other side of the phone line. The signal is
  498.     rarely used by the software.
  499.  
  500.   RI: The modem uses this line to signal that 'the phone rings' (even if
  501.     there is neither a bell fitted to your modem nor a phone connected :-).
  502.  
  503.   GND: The 'signal ground', ie. the reference level for all signals.
  504.  
  505.   Protective ground: This line is connected to the power ground of the
  506.     serial adapter. It should not be used as a signal ground, and it
  507.     MUST NOT be connected to GND (even if your DMM [Digital MultiMeter] shows
  508.     up an ohmic connection!). Connect this line to the screen of the lead (if
  509.     there is one). Connecting protective ground on both sides makes sure that
  510.     no large currents flow thru' GND in case of an insulation defect on one
  511.     side (hence the name).
  512.  
  513. Technical data (typical values for PCs):
  514.  
  515.   Signal level: -10.5v/+11v
  516.   Short circuit current: 6.8ma
  517.   Output impedance: ca 2 kiloohms (non-linear!)
  518.   Input impedance: ca 4.3 kiloohms (non-linear!)
  519.  
  520.  
  521. Other asynchronous hardware than RS-232C
  522. ----------------------------------------
  523.  
  524. There are several other standards that use the same chipset and protocol as
  525. RS-232C. RS-422 and the more robust (but compatible) version RS-485 (to name
  526. some) use two wires for every signal. The transmitters can usually be
  527. disabled and enabled by software, which makes it possible to use such
  528. equipment in a bus system (RX and TX part share the same lines). Despite
  529. >from the possibility to enable and disable the receiver/transmitter section
  530. of the port, they are fully compatible to existing RS-232C software if a
  531. compatible chipset is used.
  532.  
  533. It's not possible to connect eg. RS-232C to RS-485 without an appropriate
  534. interface.
  535.  
  536.  
  537. Connecting devices (or computers)
  538. ------------------
  539.  
  540. When you connect a data set or DCE (eg. a modem), use this connection:
  541.  
  542.         GND1    to    GND2
  543.         RxD1    to    RxD2
  544.         TxD1    to    TxD2
  545.         DTR1    to    DTR2
  546.         DSR1    to    DSR2
  547.         RTS1    to    RTS2
  548.         CTS1    to    CTS2
  549.         RI1     to    RI2
  550.         DCD1    to    DCD2
  551.  
  552. In other words, simply connect each pin of the first plug with the
  553. corresponding pin of the other. This can easily be done using a
  554. 25-wire ribbon cable and two crimp connectors.
  555.  
  556. When you connect another computer (or any other DTE, like a terminal), this
  557. is the wiring you need (it is called a "null modem" connection):
  558.  
  559.         GND1    to    GND2
  560.         RxD1    to    TxD2
  561.         TxD1    to    RxD2
  562.         DTR1    to    DSR2
  563.         DSR1    to    DTR2
  564.         RTS1    to    CTS2
  565.         CTS1    to    RTS2
  566.  
  567. If software wants it, connect DCD1 to CTS1 and DCD2 to CTS2.
  568.  
  569. If hardware handshaking is not needed, you can omit the status lines.
  570. Connect:
  571.  
  572.         GND1    to    GND2
  573.         RxD1    to    TxD2
  574.         TxD1    to    RxD2
  575.  
  576. Additionally, connect (if software needs it):
  577.  
  578.         RTS1    to    CTS1 & DCD1
  579.         RTS2    to    CTS2 & DCD2
  580.         DTR1    to    DSR1
  581.         DTR2    to    DSR2
  582.  
  583. You won't need long wires for these! :-)
  584.  
  585. Remember: the names DTR, DSR, CTS & RTS refer to the lines as seen from
  586. the DTE (your PC). This means that for your data set DTR & RTS are incoming
  587. signals and DSR & CTS are outputs! Modems, printers, plotters etc. are
  588. connected 1:1, ie. pin x to pin x.
  589.  
  590.  
  591. Base addresses & interrupts
  592. ---------------------------
  593.  
  594. Normally, the following list is correct for your PC; note however that
  595. if the BIOS can't find a port, it won't leave spaces in its port
  596. table, so if there is no UART at 0x3E8, the port at 0x2E8 will be
  597. called COM3 by DOS. Compare the section on logical vs. phyical names.
  598.  
  599.   Port Name   Base address    Int #  Int level (IRQ)
  600.  
  601.     COM1         0x3F8        0xC      4
  602.     COM2         0x2F8        0xB      3
  603.     COM3         0x3E8        0xC      4
  604.     COM4         0x2E8        0xB      3
  605.  
  606. In your programs, you should refer to the table in the BIOS data segment.
  607. This is an excerpt from Ralf Brown's interrupt list (the actual author
  608. of this section is Robin Walker):
  609.  
  610.   Format of BIOS Data Segment at segment 40h:
  611.   Offset Size Description
  612.    00h WORD Base I/O address of 1st serial I/O port, zero if none
  613.    02h WORD Base I/O address of 2nd serial I/O port, zero if none
  614.    04h WORD Base I/O address of 3rd serial I/O port, zero if none
  615.    06h WORD Base I/O address of 4th serial I/O port, zero if none
  616.         Note: Above fields filled in turn by POST as it finds serial
  617.         ports. POST never leaves gaps. DOS and BIOS serial device
  618.         numbers may be redefined by re-assigning these fields.
  619.  
  620. Please note that this table is not the bible and that the BIOS is not an
  621. evangelist (and I'm rather sceptical anyway :-). Your BIOS might not tell
  622. you the pure truth; if you get a zero it does not necessarily mean that
  623. there are no more serial ports available. Your programs should nevertheless
  624. have a look at the usual places for comm ports. See the "Programming" section
  625. for an example program that checks if a UART is installed at a given base
  626. address. Compare the "logical vs. physical names" section below.
  627.  
  628. Another good idea is writing a small program that's then run in the
  629. AUTOEXEC.BAT and that fills the empty fields in the table with the
  630. correct values. My Award BIOS fails to recognize my fourth port at
  631. 0x2E8, so I typed a few bytes (14 altogether) in the debugger that
  632. write 0x2E8 to 0040:0006 and wrote them to a .COM file called in the
  633. AUTOEXEC.BAT.
  634.  
  635. Also see the Programming section for a routine that detects the interrupt
  636. level/number that a UART uses. It's not a good idea to hard-code level
  637. 4 and 3; make it at least user configurable.
  638.  
  639. See the chapter "Multi-Port Serial Adapters" for further information.
  640.  
  641.  
  642. Logical vs. physical ports
  643. --------------------------
  644.  
  645. DOS users (like card manufacturers) tend to confuse logical and
  646. physical names. COM1, COM2, etc. are _logical_ names for the serial
  647. ports 0, 1, etc. found by the BIOS during POST (Power-On Self Test).
  648. The BIOS searches at four different I/O addresses for UARTS: 0x3F8,
  649. 0x2F8, 0x3E8, 0x2E8, in exactly this order. Every UART found has an
  650. entry in the comm port table at segment 0x40, offset 0. The BIOS
  651. manages up to four different UARTs, because the table has no more than
  652. four spaces. To make the confusion complete, Microsoft decided
  653. that DOS users wouldn't be comfortable with counting from zero, so
  654. they numbered the logical names of the comm ports from 1 to 4. Thus
  655. COM1 is the first UART found by the BIOS during POST, COM2 the second,
  656. and so on. Usually COM1 has 0x3F8 as base addresses, COM2 0x2F8 and so
  657. on, but that's not necessarily the case. Please do not use the logical
  658. DOS names when you really mean physical addresses. It is _not_
  659. possible to 'jumper a UART as COM3', at least not directly.
  660.  
  661.  
  662. The chipsets
  663. ------------
  664.  
  665. In PCs, serial communication is realized with a set of three chips
  666. (there are no further components needed! (I know of the need of address
  667. logic & interrupt logic ;-) )): a UART (Universal Asynchronous
  668. Receiver/Transmitter) and two line drivers. Normally, the 82450/16450/8250
  669. does the 'brain work' while the 1488 and 1489 drive the lines (they are
  670. level shifting inverters; the 1488 drives the outputs).
  671.  
  672. These chips are produced by many manufacturers; it's of no importance
  673. which letters are printed in front of the numbers (mostly NS for National
  674. Semiconductor). Don't regard the letters behind the number also (if it's not
  675. the 16550A or the 82C50A); they just indicate special features and packaging
  676. (Advanced, New, MILitary, bug fixes [see below] etc.) or classification.
  677. Letters in between the numbers (eg. 16C450) indicate technology (C=CMOS).
  678.  
  679. You might have heard that it is possible to replace the 16450 by a 16550A
  680. to improve reliability and reduce software overhead. This is only useful if
  681. your software is able to use the FIFO (first in-first out) buffer feature.
  682. The chips are fully pin-compatible except for two pins that are not used by
  683. any serial adapter card known to the author: pin 24 (CSOUT, chip select out)
  684. and pin 29 (NC, no internal connection). With the 16550A, pin 24 is -TXRDY
  685. and pin 29 is -RXRDY, signals that aren't needed (except for DMA access -
  686. but not in the PC) and that even won't care if they are shorted to +5V or
  687. ground. Therefore it should always be possible to simply replace the 16450
  688. by the 16550A - even if it's not always useful due to lacking software
  689. capabilities. IT IS DEFINITELY NOT NECESSARY FOR COMMUNICATION AT UP TO LOUSY
  690. 9600 BPS! These rates can easily be handled by any CPU, and the
  691. interrupt-driven communication won't slow down the computer substantially. But
  692. if you want to use high-speed transfer with or without using the interrupt
  693. features (ie. by 'polling'), or multitasking, or multiple channels 'firing' at
  694. the same time, or disk I/O during transmission, it is recommendable to use the
  695. 16550A in order to make transmission more reliable if your software supports
  696. it (see excursion some pages below).
  697.  
  698. There *are* differences between the 16550A, 16550AF, and 16550AFN. The 16550AF
  699. has one more timing parameter (t_RXI) specified that's concerned with the
  700. -RXRDY pin and that's of no importance in the PC. And the 16550AFN is the
  701. only one still believed to be free of bugs (see below). So the best choice for
  702. your PC is 16550AFN, but you are well off with the 16550AN, too. [Info from a
  703. posting of Jim Graham.]
  704.  
  705. Don't worry about the missing 'A' if you have chips named xxx16550 which are
  706. not from National Semiconductor (eg. UM16550). As long as the first example
  707. in the 'Programming' section tells you that it is a 16550A, everything is
  708. fine. I've never heard of non-NS 16550s with the FIFO bug (see below).
  709.  
  710.  
  711. How to detect which chip is used
  712. --------------------------------
  713.  
  714. This is really not difficult. The 8250 normally has no scratch register (see
  715. data sheet info below), the 16450/82450 has no FIFO, the 16550 has no working
  716. FIFO :-) and the 16550A performs alright. See the Programming section for
  717. an example program that detects which one is used in your PC.
  718.  
  719. Note that there _are_ versions of the 8250 that _do_ have a scratch register!
  720. It's rather impossible to distinguish them from the 16450, but then it's not
  721. necessary either... I know of the SAB 82C50 from Siemens and the UM8250B
  722. (from UMC, a taiwanese company with a globe symbol; thanks, Alfred, for
  723. helping me out with that). You won't find 8250s in fast computers however,
  724. because their bus timing is too slow.
  725.  
  726.  
  727. Data sheet information
  728. ----------------------
  729.  
  730. Some hardware information taken from the data sheet of National
  731. Semiconductor (shortened and commented):
  732.  
  733. Pin description of the 16450 (16550A) [Dual-In-Line package]:
  734.  
  735.                    +-----+ +-----+
  736.                D0 -|  1  +-+   40|- VCC
  737.                D1 -|  2        39|- -RI
  738.                D2 -|  3        38|- -DCD
  739.                D3 -|  4        37|- -DSR
  740.                D4 -|  5        36|- -CTS
  741.                D5 -|  6        35|- MR
  742.                D6 -|  7        34|- -OUT1
  743.                D7 -|  8        33|- -DTR
  744.              RCLK -|  9        32|- -RTS
  745.               SIN -| 10        31|- -OUT2
  746.              SOUT -| 11        30|- INTR
  747.               CS0 -| 12        29|- NC (-RXRDY)
  748.               CS1 -| 13        28|- A0
  749.              -CS2 -| 14        27|- A1
  750.          -BAUDOUT -| 15        26|- A2
  751.               XIN -| 16        25|- -ADS
  752.              XOUT -| 17        24|- CSOUT (-TXRDY)
  753.               -WR -| 18        23|- DDIS
  754.                WR -| 19        22|- RD
  755.               VSS -| 20        21|- -RD
  756.                    +-------------+
  757.  
  758. Note: The status signals are negated compared to the port! If you write a
  759. '1' to the appropriate register bit, the pin goes 'low' (to ground level).
  760. On its way to the port, the signal is inverted again; this means that the
  761. status line at the port goes 'high' if you write a '1'. The same is true
  762. for inputs: you get a '1' from the register bit if the line at the port is
  763. 'high'. SIN and SOUT are inverted, too. (negative voltage at the port
  764. means +5v at the UART).
  765.  
  766. A0, A1, A2, Register Select, Pins 26-28:
  767. Address signals connected to these 3 inputs select a UART register for
  768. the CPU to read from or to write to during data transfer. A table of
  769. registers and their addresses is shown below. Note that the state of the
  770. Divisor Latch Access Bit (DLAB), which is the most significant bit of the
  771. Line Control Register, affects the selection of certain UART registers.
  772. The DLAB must be set high by the system software to access the Baud
  773. Generator Divisor Latches. [I'm sorry, but it's called that way even if it's
  774. a bps rate generator... :-)]. 'x' means don't care.
  775.  
  776.   DLAB  A2  A1  A0    Register
  777.     0    0   0   0    Receive Buffer (read) Transmitter Holding Reg. (write)
  778.     0    0   0   1    Interrupt Enable
  779.     x    0   1   0    Interrupt Identification (read)
  780.     x    0   1   0    FIFO Control (write) [undefined with the 16450. CB]
  781.     x    0   1   1    Line Control
  782.     x    1   0   0    Modem Control
  783.     x    1   0   1    Line Status
  784.     x    1   1   0    Modem Status
  785.     x    1   1   1    Scratch [special use on some boards. CB]
  786.     1    0   0   0    Divisor Latch (LSB)
  787.     1    0   0   1    Divisor Latch (MSB)
  788.  
  789. -ADS, Address Strobe, Pin 25: The positive edge of an active Address
  790. Strobe (-ADS) signal latches the Register Select (A0, A1, A2) and Chip
  791. Select (CS0, CS1, -CS2) signals.
  792. Note: An active -ADS input is required when Register Select and Chip
  793. Select signals are not stable for the duration of a read or write
  794. operation. If not required, tie the -ADS input permanently low. [As it is
  795. done in your PC. CB]
  796.  
  797. -BAUDOUT, Baud Out, Pin 15: This is the 16x clock signal from the
  798. transmitter section of the UART. The clock rate is equal to the main
  799. reference oscillator frequency divided by the specified divisor in the
  800. Baud Generator Divisor Latches. The -BAUDOUT may also be used for the
  801. receiver section by tying this output to the RCLK input of the chip. [Yep,
  802. that's true for your PC. CB].
  803.  
  804. CS0, CS1, -CS2, Chip Select, Pins 12-14: When CS0 and CS1 are high and CS2
  805. is low, the chip is selected. This enables communication between the UART
  806. and the CPU.
  807.  
  808. -CTS, Clear To Send, Pin 36: When low, this indicates that the modem or
  809. data set is ready to exchange data. This signal can be tested by reading
  810. bit 4 of the MSR. Bit 4 is the complement of this signal, and Bit 0 is '1'
  811. if -CTS has changed state since the previous reading (bit0=1 generates an
  812. interrupt if the modem status interrupt has been enabled).
  813.  
  814. D0-D7, Data Bus, Pins 1-8: Connected to the data bus of the CPU.
  815.  
  816. -DCD, Data Carrier Detect, Pin 38: blah blah blah, can be tested by
  817. reading bit 7 / bit 3 of the MSR. Same text as -CTS.
  818.  
  819. DDIS, Driver Disable, Pin 23: This goes low whenever the CPU is reading
  820. data from the UART. It can be used to control bus arbitrary logic.
  821.  
  822. -DSR, Data Set Ready, Pin 37: blah, blah, blah, bit 5 / bit 1 of MSR.
  823.  
  824. -DTR, Data Terminal Ready, Pin 33: can be set active low by programming
  825. bit 0 of the MCR '1'. Loop mode operation holds this signal in its
  826. inactive state.
  827.  
  828. INTR, Interrupt, Pin 30: goes high when an interrupt is requested by the
  829. UART. Reset low by the MR.
  830.  
  831. MR, Master Reset, Pin 35: Schmitt Trigger input, resets internal registers
  832. to their initial values (see below).
  833.  
  834. -OUT1, Out 1, Pin 34: user-designated output, can be set low by
  835. programming bit 2 of the MCR '1' and vice versa. Loop mode operation holds
  836. this signal inactive high. [Not used in the PC. CB]
  837.  
  838. -OUT2, Out 2, Pin 31: blah blah blah, bit 3, see above. [Used in your PC to
  839. connect the UART to the interrupt line of the slot when '1'. CB]
  840.  
  841. RCLK, Receiver Clock, Pin 9: This input is the 16x bps rate clock for
  842. the receiver section of the chip. [Normally connected to -BAUDOUT, as in
  843. your PC. CB]
  844.  
  845. RD, -RD, Read, Pins 22 and 21: When RD is high *or* -RD is low while the
  846. chip is selected, the CPU can read data from the UART. [One of these is
  847. normally tied. CB]
  848.  
  849. -RI, Ring Indicator, Pin 39: blah blah blah, Bit 6 / Bit 2 of the MSR.
  850. [Bit 2 only indicates change from active low to inactive high! Curious,
  851. isn't it? CB]
  852.  
  853. -RTS, Request To Send, Pin 32: blah blah blah, see DTR (Bit 1).
  854.  
  855. SIN, Serial Input, Pin 10.
  856.  
  857. SOUT, Serial Output, Pin 11.
  858.  
  859. -RXRDY, -TXRDY: refer to NS data sheet. These pins are used for DMA
  860. channeling. Since they are not connected in your PC, I won't describe them
  861. here.
  862.  
  863. VCC, Pin 40, +5v
  864.  
  865. VSS, Pin 20, GND
  866.  
  867. WR, -WR: same as RD, -RD for writing data.
  868.  
  869. XIN, XOUT, Pins 16 and 17: Connect a crystal here (1.5k betw. xtal & pin 17)
  870. and pin 16 with a capacitor of approx. 20p to GND and other xtal conn. 40p
  871. to GND. Resistor of approx. 1meg parallel to xtal. Or use pin 16 as an input
  872. and pin 17 as an output for an external clock signal of up to 8 MHz.
  873.  
  874.  
  875. Absolute Maximum Ratings:
  876.  
  877.   Temperature under bias: 0 C to +70 C
  878.   Storage Temperature: -65 C to 150 C
  879.   All input or output voltages with respect to VSS: -0.5v to +7.0v
  880.   Power dissipation: 1W
  881.  
  882. Further electrical characteristics see the very good data sheet of NS.
  883.  
  884.  
  885. UART Reset Configuration
  886.  
  887. Register/Signal        Reset Control      Reset State
  888. --------------------------------------------------------------------
  889.   IER                       MR            0000 0000
  890.   IIR                       MR            0000 0001
  891.   FCR                       MR            0000 0000
  892.   LCR                       MR            0000 0000
  893.   MCR                       MR            0000 0000
  894.   LSR                       MR            0110 0000
  895.   MSR                       MR            xxxx 0000 (according to signals)
  896.   SOUT                      MR            high (neg. voltage at the port)
  897.   INTR (RCVR errs)     Read LSR/MR        low
  898.   INTR (data ready)    Read RBR/MR        low
  899.   INTR (THRE)          Rd IIR/Wr THR/MR   low
  900.   INTR (modem status)  Read MSR/MR        low
  901.   -OUT2                     MR            high
  902.   -RTS                      MR            high
  903.   -DTR                      MR            high
  904.   -OUT1                     MR            high
  905.   RCVR FIFO           MR/FCR1&FCR0/DFCR0  all bits low
  906.   XMIT FIFO           MR/FCR1&FCR0/DFCR0  all bits low
  907.  
  908.  
  909.  
  910. Known problems with several chips
  911. ---------------------------------
  912.  
  913. (From material Madis Kaal received from Dan Norstedt and stuff Erik Suurmaa
  914. sent me)
  915.  
  916.     8250 and 8250-B:
  917.  
  918.         * These UARTs pulse the INT line after each interrupt cause has
  919.           been serviced (which none of the others do). [Generates interrupt
  920.           overhead. CB]
  921.  
  922.         * The start bit is about 1 us longer than it ought to be. [This
  923.           shouldn't be a problem. CB]
  924.  
  925.         * 5 data bits and 1.5 stop bits doesn't work.
  926.  
  927.         * When a 1 is written to the bit 1 (Tx int enab) in the IER,
  928.           a Tx interrupt is generated. This is an erroneous interrupt
  929.           if the THRE bit is not set. [So don't set this bit as long as
  930.           the THRE bit isn't set. CB]
  931.  
  932.         * The first valid Tx interrupt after the Tx interrupt is enabled
  933.           is probably missed. Suggested workaround:
  934.           1) Wait for the THRE bit to become set.
  935.           2) Disable CPU interrupts. [?]
  936.           3) Write Tx interrupt enable to the IER.
  937.           4) Write Tx interrupt enable to the IER again.
  938.              [Don't ask me why. I don't think it's necessary. CB]
  939.           5) Enable CPU interrupts.  [?]
  940.  
  941.         * The TEMT (bit 6) doesn't work properly.
  942.  
  943.         * If both the Rx and Tx interrupts are enabled, and a Rx interrupt
  944.           occurs, the IIR indication of the Tx interrupt may be lost.
  945.           Suggested workarounds:
  946.           1) Test THRE bit in the Rx routine, and either set IER bit 1
  947.              or call the Tx routine directly if it is set.
  948.           2) Test the THRE bit instead of using the IIR for Tx.
  949.  
  950.         [If one of these chips vegetates in your PC, go get your solder
  951.         iron heated... CB]
  952.  
  953.     8250A, 82C50A, 16450 and 16C450:
  954.  
  955.         * (Same problem as above:)
  956.           If both the Rx and Tx interrupts are enabled, and a Rx interrupt
  957.           occurs, the IIR indication may be lost; Suggested workarounds:
  958.           1) Test THRE bit in the Rx routine, and either set IER bit 1
  959.              or call the Tx routine directly if it is set.
  960.           2) Test the THRE bit instead of using the IIR.
  961.           3) [Don't enable both interrupts at the same time. CB]
  962.           4) [Replace the chip by a 16550AFN; it has this bug fixed. CB]
  963.  
  964.     16550 (without the A):
  965.  
  966.         * Rx FIFO bug: Sometimes the FIFO will get extra characters.
  967.           [This seemed to be very embarrassing for NS; they've added a
  968.           simple detection method for the 16550A (bit 6 of IIR). CB]
  969.  
  970.     16550 AF
  971.  
  972.         * When the TX FIFO is enabled, a character loss can appear if
  973.           the CPU writes a byte into the THR while the last one is still
  974.           in the shift register (not completely sent). [This is documented
  975.           by National Semiconductor; I've never experienced that, but that
  976.           might be because I've never seen a 16550 AF :) CB]
  977.  
  978.         * Terence Edwards reports that his RS485 adapter with 16550 AF
  979.           chips and a 16 MHz xtal gets parity bits wrong at 512 kbps; not
  980.           very astonishing I'd say because the chip is only guaranteed to
  981.           operate at 256kbps, with an 8 MHz xtal, and parity generators are
  982.           rather slow circuits.
  983.  
  984.  
  985. No 16550 AFN bugs reported (yet?)
  986.  
  987. [Same is true for the 16552, a two-in-one version of the 16550AFN, and the
  988. 16554, a quad-in-one version. CB]
  989.  
  990. You might call this a bug, though: in FIFO mode, THRE (bit 5 or LSR) is
  991. cleared when there is at least one character in the Tx FIFO, not if the
  992. FIFO can't take any more bytes; that's rather absurd, but that's the way
  993. it is.
  994.  
  995. A very solid method of handling the UART interrupts that avoids all possible
  996. int failures has been suggested by Richard Clayton, and I recommend it as
  997. well. Let your interrupt handler do the following:
  998.   1. Disarm the UART interrupts by masking them in the IMR of the ICU.
  999.   2. Send a specific or an unspecific EOI to the ICU (first slave, then
  1000.      master, if you're using channels above 7).
  1001.   3. Enable CPU interrupts (STI) to allow high priority ints to be processed.
  1002.   4. Read IIR and follow its contents until bit 0 is set.
  1003.   5. Check if transmission is to be kicked (when XON received or if CTS
  1004.      goes high); if yes, call tx interrupt handler manually.
  1005.   6. Disable CPU interrupts (CLI).
  1006.   7. Rearm the UART interrupts by unmasking them in the IMR of the ICU.
  1007.   8. Return from interrupt.
  1008. This way you can arm all four UART ints at initialization time without
  1009. having to worry about stuck interrupts. Start transmission by simply calling
  1010. the tx interrupt handler after you've written characters to the tx fifo of
  1011. your program.
  1012.  
  1013. If you need details about programming the ICU, refer to Chris Hall's
  1014. document about the 8259 that's available from my archive.
  1015.  
  1016.  
  1017. [... continued ...]
  1018.  
  1019. --
  1020. Chris Blum <chris@phil.uni-sb.de>  http://www.phil.uni-sb.de/~chris/
  1021.  
  1022. From chris@chris.telip.uni-sb.de Wed Mar  1 17:57:22 1995
  1023. From: chris@chris.telip.uni-sb.de (Chris Blum)
  1024. Newsgroups: comp.sys.ibm.pc.hardware.comm,comp.os.msdos.programmer
  1025. Subject: The Serial Port rel. 18, part 2/3
  1026. Date: 23 Feb 1995 00:23:16 +0100
  1027. Organization: The Outside of the Asylum
  1028. Reply-To: chris@phil.uni-sb.de (Chris Blum)
  1029. NNTP-Posting-Host: chris.telip.uni-sb.de
  1030. Keywords: comm, COM, UART, serial port
  1031.  
  1032. [... continued ...]
  1033.  
  1034.  
  1035. Registers
  1036. =========
  1037.  
  1038. First some tables; full descriptions follow. Base addresses as specified by
  1039. IBM for a full-blown system; compare the section on logical & physical names.
  1040.  
  1041.  
  1042. 1st  2nd  3rd  4th  Offs. DLAB  Register
  1043. ------------------------------------------------------------------------------
  1044. 3F8h 2F8h 3E8h 2E8h  +0     0   RBR  Receive Buffer Register (read only) or
  1045.                                 THR  Transmitter Holding Register (write only)
  1046. 3F9h 2F9h 3E9h 2E9h  +1     0   IER  Interrupt Enable Register
  1047. 3F8h 2F8h 3E8h 2E8h  +0     1   DL   Divisor Latch (LSB)  These registers can
  1048. 3F9h 2F9h 3E9h 2E9h  +1     1   DL   Divisor Latch (MSB)  be accessed as word
  1049. 3FAh 2FAh 3EAh 2EAh  +2     x   IIR  Interrupt Identification Register (r/o) or
  1050.                                 FCR  FIFO Control Register (w/o, 16550+ only)
  1051. 3FBh 2FBh 3EBh 2EBh  +3     x   LCR  Line Control Register
  1052. 3FCh 2FCh 3ECh 2ECh  +4     x   MCR  Modem Control Register
  1053. 3FDh 2FDh 3EDh 2EDh  +5     x   LSR  Line Status Register
  1054. 3FEh 2FEh 3EEh 2EEh  +6     x   MSR  Modem Status Register
  1055. 3FFh 2FFh 3EFh 2EFh  +7     x   SCR  Scratch Register (16450+ and some 8250s,
  1056.                                      special use with some boards)
  1057.  
  1058.  
  1059.            80h      40h      20h      10h      08h      04h      02h      01h
  1060. Register  Bit 7    Bit 6    Bit 5    Bit 4    Bit 3    Bit 2    Bit 1    Bit 0
  1061. -------------------------------------------------------------------------------
  1062. IER         0        0        0        0      EDSSI    ELSI     ETBEI    ERBFI
  1063. IIR (r/o) FIFO en  FIFO en    0        0      IID2     IID1     IID0    pending
  1064. FCR (w/o)  - RX trigger -     0        0      DMA sel  XFres    RFres   enable
  1065. LCR       DLAB     SBR    stick par  even sel Par en  stopbits  - word length -
  1066. MCR         0        0       AFE     Loop     OUT2     OUT1     RTS     DTR
  1067. LSR       FIFOerr  TEMT     THRE     Break    FE       PE       OE      RBF
  1068. MSR       DCD      RI       DSR      CTS      DDCD     TERI     DDSR    DCTS
  1069.  
  1070. EDSSI:       Enable Delta Status Signals Interrupt
  1071. ELSI:        Enable Line Status Interrupt
  1072. ETBEI:       Enable Transmitter Buffer Empty Interrupt
  1073. ERBFI:       Enable Receiver Buffer Full Interrupt
  1074. FIFO en:     FIFO enable
  1075. IID#:        Interrupt IDentification
  1076. pending:     an interrupt is pending if '0'
  1077. RX trigger:  RX FIFO trigger level select
  1078. DMA sel:     DMA mode select
  1079. XFres:       Transmitter FIFO reset
  1080. RFres:       Receiver FIFO reset
  1081. DLAB:        Divisor Latch Access Bit
  1082. SBR:         Set BReak
  1083. stick par:   Stick Parity select
  1084. even sel:    Even Parity select
  1085. stopbits:    Stop bit select
  1086. word length: Word length select
  1087. FIFOerr:     At least one error is pending in the RX FIFO chain
  1088. TEMT:        Transmitter Empty (last word has been sent)
  1089. THRE:        Transmitter Holding Register Empty (new data can be written to THR)
  1090. Break:       Broken line detected
  1091. FE:          Framing Error
  1092. PE:          Parity Error
  1093. OE:          Overrun Error
  1094. RBF:         Receiver Buffer Full (Data Available)
  1095. DCD:         Data Carrier Detect
  1096. RI:          Ring Indicator
  1097. DSR:         Data Set Ready
  1098. CTS:         Clear To Send
  1099. DDCD:        Delta Data Carrier Detect
  1100. TERI:        Trailing Edge Ring Indicator
  1101. DDSR:        Delta Data Set Ready
  1102. DCTS:        Delta Clear To Send
  1103. AFE:         Automatic Flow control Enable
  1104.  
  1105.  
  1106. RBR (Receive Buffer Register)                       3F8h 2F8h 3E8h 2E8h +0 r/o
  1107. ------------------------------------------------------------------------------
  1108.  
  1109. This is where you get received characters from. This register is read-only.
  1110.  
  1111.  
  1112.  
  1113. THR (Transmitter Holding Register)                  3F8h 2F8h 3E8h 2E8h +0 w/o
  1114. ------------------------------------------------------------------------------
  1115.  
  1116. Send characters by writing them to this register. It is write-only.
  1117.  
  1118.  
  1119.  
  1120. IER (Interrupt Enable Register)                     3F9h 2F9h 3E9h 2E9h +1 r/w
  1121. ------------------------------------------------------------------------------
  1122.  
  1123. Enable several interrupts by setting these bits:
  1124.    Bit 0:   If set, DR (Data Ready) interrupt is enabled. It is generated
  1125.             if data waits to be read by the CPU.
  1126.    Bit 1:   If set, THRE (THR Empty) interrupt is enabled. This interrupt
  1127.             tells the CPU to write characters to the THR.
  1128.    Bit 2:   If set, Status interrupt is enabled. It informs the CPU of
  1129.             occurred transmission errors during reception.
  1130.    Bit 3:   If set, Modem status interrupt is enabled. It is triggered
  1131.             whenever one of the delta-bits is set (see MSR).
  1132. Bits 4-7 are not used and should be set 0.
  1133.  
  1134.  
  1135.  
  1136. DL (Divisor Latch)                                  3F8h 2F8h 3E8h 2E8h +0 r/w
  1137. ------------------------------------------------------------------------------
  1138.  
  1139. To access this *WORD*, set DLAB in the LCR to 1. Then write a word (16 bits)
  1140. to this register or write the lower byte to base+0 and the higher byte to
  1141. base+1 (the order is not important) to program the bps rate as follows:
  1142.  
  1143.      xtal frequency in Hz / 16 / desired rate = divisor
  1144.      xtal frequency in Hz / 16 / divisor      = obtained rate
  1145.  
  1146. Your PC uses an xtal frequency of 1.8432 MHz (that's 1843200 Hz :-).
  1147.  
  1148. Do *NOT* use 0 as a divisor (your maths teacher told you so)! It results in
  1149. a rate of about 3500 bps, but it is not guaranteed to work with all chips in
  1150. the same way.
  1151.  
  1152. An error of up to 3-5 percent is irrelevant.
  1153.  
  1154. Some values (1.8432 MHz quartz, as in the PC):
  1155.  
  1156.      bps rate    Divisor (hex)   Divisor (dec)   Percent Error
  1157.          50          900             2304            0.0%
  1158.          75          600             1536            0.0%
  1159.         110          417             1047            0.026%
  1160.         134.5        359              857            0.058%
  1161.         150          300              768            0.0%
  1162.         300          180              384            0.0%
  1163.         600           C0              192            0.0%
  1164.        1200           60               96            0.0%
  1165.        1800           40               64            0.0%
  1166.        2000           3A               58            0.69%
  1167.        2400           30               48            0.0%
  1168.        3600           20               32            0.0%
  1169.        4800           18               24            0.0%
  1170.        7200           10               16            0.0%
  1171.        9600            C               12            0.0%
  1172.       19200            6                6            0.0%
  1173.       38400            3                3            0.0%
  1174.       57600            2                2            0.0%
  1175.      115200            1                1            0.0%
  1176.  
  1177. The 16450 is capable of up to 512 kbps according to NS.
  1178.  
  1179. NS specifies that the 16550A is capable of 256 kbps if you use a 4 MHz
  1180. or an 8 MHz crystal. But a staff member of NS Germany (I know that this
  1181. abbreviation is not well-chosen :-( ) told one of my friends on the phone
  1182. that it runs correctly at 512 kbps as well; I don't know if the 1488/1489
  1183. manage this, though. This is true for the 16C552, too. See the "known
  1184. problems" section.
  1185.  
  1186. BTW: Ever tried 1.76 bps, the slowest rate possible? Kindergarten kids
  1187. write faster.
  1188.  
  1189. The Microsoft mouse uses 1200 bps, 7n1, the Mouse Systems mouse uses 1200
  1190. bps, 8n1. See the Mouse chapter for details.
  1191.  
  1192.  
  1193.  
  1194. IIR (Interrupt Identification Register)            3FAh 2FAh 3EAh 2EAh  +2 r/o
  1195. ------------------------------------------------------------------------------
  1196.  
  1197. This register allows you to detect the cause of an interrupt. Only one
  1198. interrupt is reported at a time; they are priorized. If an interrupt occurs,
  1199. Bit 0 tells you if the UART has triggered it. Follow the information in this
  1200. register, then test bit 0 again. If it is still not set, there is another
  1201. interrupt to be serviced. BTW: If you AND the value of this register with
  1202. 06h, you get a pointer to a table of four words... ideal for near calls.
  1203. Another hint: make sure your software reads this register just once and then
  1204. follows the information it got before it is read again, otherwise your code
  1205. won't work. (Turbo Pascal "programmers" beware! :)
  1206.  
  1207. The bits 6 and 7 allow you to detect if the FIFOs of the 16550+ have been
  1208. activated.
  1209.  
  1210.  
  1211.    Bit 3  Bit 2  Bit 1  Bit 0    Priority   Source    Description
  1212.      0      0      0      1                 none      no interrupt pending
  1213.      0      1      1      0      highest    Status    OE, PE, FE or BI of the
  1214.                                                       LSR set. Serviced by
  1215.                                                       reading the LSR.
  1216.      0      1      0      0      second     Receiver  DR or trigger level rea-
  1217.                                                       ched. Serviced by read-
  1218.                                                       ing RBR 'til under level
  1219.      1      1      0      0      second     FIFO      No Receiver FIFO action
  1220.                                                       since 4 words' time
  1221.                                                       (neither in nor out) but
  1222.                                                       data in RX-FIFO. Serviced
  1223.                                                       by reading RBR.
  1224.      0      0      1      0      third      Transm.   THRE. Serviced by read-
  1225.                                                       ing IIR (if source of
  1226.                                                       int only!) or writing
  1227.                                                       to THR.
  1228.      0      0      0      0      lowest     Modem     One of the delta flags
  1229.                                                       in the MSR set. Serviced
  1230.                                                       by reading MSR.
  1231.    Bit 6 & 7: 16550A: set if FCR bit 0 set.
  1232.               16550:  bit 7 set, bit 6 cleared if FCR bit 0 set.
  1233.               others: clear
  1234.    Other bits: clear (but don't rely on it; this is subject to change).
  1235.  
  1236. In most software applications bits 3 to 7 should be masked when servicing
  1237. the interrupt since they are not relevant. These bits cause trouble with
  1238. old software relying on that they are cleared...
  1239.  
  1240. NOTE! Even if some of these interrupts are disabled, the service routine
  1241. can be confronted with *all* states shown above when the IIR is loop-polled
  1242. until bit 0 is set (don't ask me why; it's just that I encontered this, and
  1243. it's not much more work to play it safe). Check examples in the Programming
  1244. section.
  1245.  
  1246.  
  1247.  
  1248. FCR (FIFO Control Register)                        3FAh 2FAh 3EAh 2EAh  +2 w/o
  1249. ------------------------------------------------------------------------------
  1250.  
  1251. This register allows you to control the FIFOs of the 16550+. It does not exist
  1252. on the 8250/16450.
  1253.  
  1254.    Bit 0:    FIFO enable.
  1255.    Bit 1:    Clear receiver FIFO. This bit is self-clearing.
  1256.    Bit 2:    Clear transmitter FIFO. This bit is self-clearing.
  1257.    Bit 3:    DMA mode (pins -RXRDY and -TXRDY), see below
  1258.    Bits 6-7: Trigger level of the DR-interrupt.
  1259.  
  1260.    Bit 7  Bit 6    Receiver FIFO trigger level
  1261.      0      0          1
  1262.      0      1          4
  1263.      1      0          8
  1264.      1      1         14
  1265.  
  1266. Note: if bit 0 is cleared, all other bits are ignored.
  1267.  
  1268. DMA mode operation is not available with your PC, but for the sake of
  1269. completeness... here we go.
  1270.  
  1271. If bit 3 is 0, DMA mode 0 is selected. The -RXRDY pin goes active-low
  1272. whenever there is at least one character in the RX FIFO or in the RBR if
  1273. the FIFO is disabled. -TXRDY goes active-low when the TX FIFO or the THR
  1274. is empty. It goes high if one character is written to the THR (same as THRE,
  1275. that's bit 5 of the LSR).
  1276.  
  1277. If this bit is 1, DMA mode 1 is selected. The -RXRDY pin goes low if
  1278. the trigger level of the RX FIFO is reached or if reception timed out
  1279. (no characters received for a time that would have allowed to receive 4
  1280. characters). -TXRDY goes low when the TX FIFO is empty. It goes high again
  1281. if the FIFO is completely full. (Not that setting this bit to '1' would fix
  1282. the weird behaviour of the THRE bit in FIFO mode operation, though). If the
  1283. FIFOs are disabled, DMA mode 1 operates in the same way as DMA mode 0.
  1284.  
  1285.  
  1286.  
  1287. LCR (Line Control Register)                        3FBh 2FBh 3EBh 2EBh  +3 r/w
  1288. ------------------------------------------------------------------------------
  1289.  
  1290. This register allows you to select the transmission protocol. It also contains
  1291. the DLAB bit which switches the function of the addresses +0 and +1.
  1292.  
  1293.    Bit 1  Bit 0    word length         Bit 2      Stop bits
  1294.      0      0        5 bits              0            1
  1295.      0      1        6 bits              1          1.5/2
  1296.      1      0        7 bits         (1.5 if word length is 5)
  1297.      1      1        8 bits   (1.5 does not work with some chips, see above)
  1298.  
  1299.    Bit 5  Bit 4  Bit 3     Parity type       Bit 6   SOUT condition
  1300.      x      x      0       no parity           0     normal operation
  1301.      0      0      1       odd parity          1     forces TxD +12V (break)
  1302.      0      1      1       even parity       Bit 7   DLAB
  1303.      1      0      1       mark parity         0     normal registers
  1304.      1      1      1       space parity        1     divisor at reg 0, 1
  1305.  
  1306.   Mark parity: The parity bit is always '1' (the line is 'low').
  1307.   Space parity: The parity bit is always '0' (the line is 'high').
  1308.  
  1309.  
  1310.  
  1311. MCR (Modem Control Register)                       3FCh 2FCh 3ECh 2ECh  +4 r/w
  1312. ------------------------------------------------------------------------------
  1313.  
  1314. This register allows to program some modem control lines and to switch to
  1315. loopback mode.
  1316.  
  1317.    Bit 0:   Programs -DTR. If set, -DTR is low and the DTR pin of the port
  1318.             goes 'high'.
  1319.    Bit 1:   Programs -RTS. dito.
  1320.    Bit 2:   Programs -OUT1. Normally not used in a PC, but used with some
  1321.             multi-port serial adapters to enable or disable a port. Best
  1322.             thing is to write a '1' to this bit.
  1323.    Bit 3:   Programs -OUT2. If set to 1, interrupts generated by the UART
  1324.             are transferred to the ICU (Interrupt Control Unit) while 0
  1325.             sets the interrupt output of the card to high impedance.
  1326.             (This is PC-only).
  1327.    Bit 4:   '1': local loopback. All outputs disabled. This is a means of
  1328.             testing the chip: you 'receive' all the data you send.
  1329.             Interrupts are fully operational in this mode.
  1330.    Bit 5:   (Texas Instruments TL16C550C only, maybe some more; this
  1331.             is not a standard feature) '1': Enable automatic flow
  1332.             control. If RTS (bit 1) is '0', only auto-CTS is done, which
  1333.             means that no more characters are sent from the FIFO and
  1334.             no more Tx interrupts are generated as long as CTS is '0'.
  1335.             If RTS (bit 1) is '1', the RTS signal is dropped whenever the
  1336.             FIFO trigger level is reached. Note that if this bit is '1',
  1337.             delta CTS (see below) won't generate a modem status interrupt!
  1338.  
  1339.  
  1340.  
  1341. LSR (Line Status Register)                         3FDh 2FDh 3EDh 2EDh  +5 r/w
  1342. ------------------------------------------------------------------------------
  1343.  
  1344. This register allows error detection and polled-mode operation.
  1345.  
  1346.    Bit 0    Data Ready (DR). Reset by reading RBR (but only if the RX FIFO is
  1347.             empty, 16550+).
  1348.    Bit 1    Overrun Error (OE). Reset by reading LSR. Indicates loss of data.
  1349.    Bit 2    Parity Error (PE). Indicates transmission error. Reset by LSR.
  1350.    Bit 3    Framing Error (FE). Indicates missing stop bit. Reset by LSR.
  1351.    Bit 4    Break Indicator (BI). Set if RxD is 'space' for more than 1 word
  1352.             ('break'). Reset by reading LSR.
  1353.    Bit 5    Transmitter Holding Register Empty (THRE). Indicates that a new
  1354.             word can be written to THR. Reset by writing THR. Note that this
  1355.             bit works in a weird way when FIFOs are enabled: it goes 0
  1356.             whenever there are characters in the TX-FIFO, not when the FIFO
  1357.             is full!
  1358.    Bit 6    Transmitter Empty (TEMT). Indicates that no transmission is
  1359.             running. Reset by reading LSR.
  1360.    Bit 7    (16550+ only) Set if at least one character in the RX FIFO has
  1361.             been received with an error. Cleared by reading LSR if there is
  1362.             no further error in the FIFO. Clear with all other chips.
  1363.  
  1364.  
  1365.  
  1366. MSR (Modem Status Register)                        3FEh 2FEh 3EEh 2EEh  +6 r/w
  1367. ------------------------------------------------------------------------------
  1368.  
  1369. This register allows you to check several modem status lines. The delta bits
  1370. are set if the corresponding signals have changed state since the last reading
  1371. (except for TERI which is only set if -RI changed from active-low to
  1372. inactive-high, that is if the RI line at the port changed from 'high' to
  1373. 'low' and the phone stopped ringing).
  1374.  
  1375.    Bit 0:   Delta CTS. Set if CTS has changed state since last reading.
  1376.    Bit 1:   Delta DSR. Set if DSR has changed state since last reading.
  1377.    Bit 2:   TERI. Set if -RI has changed from low to high (ie. RI at port
  1378.             has changed from +12V to -12V).
  1379.    Bit 3:   Delta DCD. Set if DCD has changed state since last reading.
  1380.    Bit 4:   CTS. 1 if 'high' at port.
  1381.    Bit 5:   DSR. dito.
  1382.    Bit 6:   RI. dito.
  1383.    Bit 7:   DCD.
  1384.  
  1385. In loopback mode (MCR bit 4 = 1), bit 4 shows the state of RTS (MCR bit 1),
  1386. bit 5 shows the state of DTR (MCR bit 0), RI shows the state of OUT1 (MCR
  1387. bit 2), and DCD shows the state of OUT2 (MCR bit 3). The delta registers
  1388. act accordingly to the 'level transitions' of the data written to MCR.
  1389. This is a good means of testing if a UART is present.
  1390.  
  1391.  
  1392.  
  1393. SCR (Scratch Register)                             3FFh 2FFh 3EFh 2EFh  +7 r/w
  1394. ------------------------------------------------------------------------------
  1395.  
  1396. This is an all-purpose 8 bit store. NS recommends to store the value of the
  1397. FCR (which is w/o) in this register for further use, but this is not
  1398. mandatory and not recommended by me (see below). This register is only
  1399. available with the 16450+; the standard 8250 doesn't have a scratch register
  1400. (but then again some versions do).
  1401.  
  1402. On some boards (especially RS-422/RS-485 boards), this register has a special
  1403. meaning (enable receiver/transmitter drivers etc.), and with multi-port
  1404. serial adapters it is often used to select the interrupt levels of the
  1405. several ports and to determine which port has triggered interrupt. So you
  1406. shouldn't use it for anything else in your programs.
  1407.  
  1408.  
  1409.  
  1410. Excursion: Why and how to use the FIFOs (by Scott C. Sadow)
  1411. -----------------------------------------------------------
  1412.  
  1413.   Normally when transmitting or receiving, the UART generates one
  1414.   interrupt for every character sent or received. For 2400 bps, typically
  1415.   this is 240/second. For 115,200 bps, this means 11,520/second. With FIFOs
  1416.   enabled, the number of interrupts is greatly reduced.
  1417.   
  1418.   A transmitter holding register empty interrupt is not generated until the
  1419.   FIFO is empty (last byte is being sent).
  1420.   
  1421. So if you know it's a 16550A and the FIFOs are enabled, your TX interrupt
  1422. routine can write up to 16 characters to the THR. Monitoring bit 5 (THRE) of
  1423. the LSR is _no_good_ because this bit will be cleared immediately after your
  1424. routine has written the first character to the THR! The chip gives you no
  1425. feedback at all.
  1426.   
  1427.   Thus, the number of transmitter interrupts is reduced by a factor of 16.
  1428.   For 115,200 bps, this means only 720 interrupts per second. For receive
  1429.   data interrupts, the processing is similar to transmitter interrupts. The
  1430.   main difference is that the number of bytes in the FIFO (the trigger level)
  1431.   can be specified. When the trigger level is reached, a receive data
  1432.   interrupt is generated; any other data received is just put in the FIFO.
  1433.   The receive data interrupt is not cleared until the number of bytes in the
  1434.   FIFO is below the trigger level again.
  1435.  
  1436.   To add 16550A support to existing code, there are 2 requirements to be met:
  1437.  
  1438.      1) When reading the IIR to determine the interrupt source, only
  1439.         use the lower 3 bits.
  1440.  
  1441.      2) After the existing UART initialization code, try to enable the
  1442.         FIFOs by writing to the FCR. (A value of C7 hex will enable FIFO
  1443.         mode, clear both FIFOs, and set the receive trigger level at 14
  1444.         bytes). Next, read the IIR. If Bit 6 of the IIR is not set, the
  1445.         UART is not a 16550A, so write 0 to the FCR to disable FIFO mode.
  1446.  
  1447.  
  1448. Multi-Port Serial Adapters
  1449. --------------------------
  1450.  
  1451. This is material I received from Mike Surikov.
  1452.  
  1453.   I want to give you some information on Multi-Serial adapters that
  1454.   provide four or eight asynchronous serial communication ports.
  1455.  
  1456.   Some of them have an Interrupt Vector (one for each four
  1457.   channels).  The Interrupt Vector is used to enable/disable
  1458.   global interrupt and to detect which of the four channels is
  1459.   creating the interrupt (one IRQ is used for a group of four
  1460.   channels).  Bit 7 of the Interrupt Vector is used to enable or
  1461.   disable ALL four channels by writing a logical 1 to enable or 0
  1462.   to disable interrupts.  At the same time, each channel can be
  1463.   enabled or disabled separately by programming the OUT2 (and/or
  1464.   OUT1) signal in the 16450 chip.
  1465.  
  1466.   When you read the interrupt vector, you get an indication which
  1467.   port has triggered the interrupt, as it is shown below.
  1468.  
  1469.   [Since this may be different with each board, check your manual for
  1470.   details.]
  1471.  
  1472.   MSB           LSB
  1473.   7 6 5 4 3 2 1 0 <-- Interrupt Vector Register
  1474.                 Channel 0 interrupt indicator (0-active)
  1475.       N/A     Channel 1 interrupt indicator (0-active)
  1476.             Channel 2 interrupt indicator (0-active)
  1477.           Channel 3 interrupt indicator (0-active)
  1478.   Global interrupt: 1-enable; 0-disable
  1479.  
  1480.   For example, an 8 PORT RS-232C CARD can have the following
  1481.   configuration:
  1482.      
  1483.           Base      IRQ    Channel  Interrupt 
  1484.          Address   Level   Number     Vector  
  1485.      
  1486.            2A0       7        0        2BF    
  1487.            2A8       7        1        2BF    
  1488.            2B0       7        2        2BF    
  1489.            2B8       7        3        2BF    
  1490.            1A0       5        0        1BF    
  1491.            1A8       5        1        1BF    
  1492.            1B0       5        2        1BF    
  1493.            1B8       5        3        1BF    
  1494.  
  1495.   [The base addresses should be configurable by jumpers or DIP switches.]
  1496.  
  1497.   Note that the Interrupt Vector Registers overlap Scratch
  1498.   Registers, so the detect_UART routine must be changed for these
  1499.   boards. [See the Programming Section.]
  1500.  
  1501.  
  1502.  
  1503. Some words about timing
  1504. -----------------------
  1505.  
  1506. The 8250 is a rather slow peripheral chip; it has a cycle delay for both
  1507. reading and writing of 500nsec, which means that after every read or write
  1508. access to any of the chip's registers the CPU has to wait at least 500nsec
  1509. before reading or writing one of its registers again. Good thing that this
  1510. chip is only used with some old XTs... the 8088/8086/V20/V30 family is slow
  1511. enough for that.
  1512.  
  1513. The 16450 and 16550A are rather fast; they need a delay of 125nsec after
  1514. read access and 150nsec after write access before any other transfer.
  1515. This means we only have a problem with these fancy new machines that allow
  1516. cycle times of 50nsec and less. Luckily they add wait states to I/O bus
  1517. accesses (wait states are additional cycles during which the bus does
  1518. not change its state) or use a slower clock speed for I/O transfers (8 or
  1519. 12 MHz). So if you have 12 MHz I/O clock speed and one wait state for I/O
  1520. transfers, you don't have to worry.
  1521.  
  1522. Some people believe in delaying I/O operations by adding NOPs or JMP $+2 to
  1523. every I/O instruction (both do nothing but wasting time), but I don't think
  1524. that's any good with a chip that needs stable data lines for at least
  1525. 100nsec (so the CPU or the bus controller has to add a wait state anyway).
  1526. You can always blame the hardware or the setup if your program doesn't work
  1527. for timing reasons. :)
  1528.  
  1529. However, there may be a problem with block instructions, esp. OUTSB. This
  1530. instruction allows you to fill the Tx fifo of the 16550A rather fast (just
  1531. 5 cycles per transfer on the 286, others take longer), but even a 25MHz 286
  1532. takes 200nsec for each transfer, so this should be on the safe side, too.
  1533. I don't use this instruction, but for other reasons than timing difficulties.
  1534. It's just not very useful: it takes more time to make sure in advance that
  1535. you don't overrun your buffer margins during an OUTSB than to check for
  1536. the margins after every single transfer.
  1537.  
  1538. Please note that all this relates to ISA boards. I don't have any experience
  1539. with EISA or other fancy things like VLB!
  1540.  
  1541.  
  1542.  
  1543. Handshaking
  1544. -----------
  1545.  
  1546. The method of exchanging signals for data flow control between computers
  1547. and data sets is called handshaking. The most popular and most often used
  1548. handshaking variant is called XON/XOFF; it's done by software, while other
  1549. methods are hardware-based.
  1550.  
  1551. XON/XOFF
  1552.  
  1553.   Two bytes that are not mapped to normal characters in the ASCII charset are
  1554.   called XON (DC1, Ctrl-Q, ASCII 17) and XOFF (DC3, Ctrl-S, ASCII 19).
  1555.   Whenever either one of the sides wants to interrupt the data flow from the
  1556.   other (eg. full buffers), it sends an XOFF ('Transmission Off'). When its
  1557.   buffers have been purged again, it sends an XON ('Transmission On') to
  1558.   signal that data can be sent again. (With some implementations, this can
  1559.   be any character).
  1560.  
  1561.   XON/XOFF is of course limited to text transmission. It cannot be used with
  1562.   binary data since binary files tend to contain every single one of the 256
  1563.   characters...
  1564.  
  1565.   That's why hardware handshaking is normally used with modems, while
  1566.   XON/XOFF is often used with printers and plotters and terminals.
  1567.  
  1568. DTR/DSR
  1569.  
  1570.   The 'Data Terminal Ready' and 'Data Set Ready' signals of the serial port
  1571.   can be used for handshaking purposes, too. Their names express what they
  1572.   do: the computer signals with DTR that it is ready to send and receive data,
  1573.   while the data set sets DSR. With most modems, the meaning of these signals
  1574.   is slightly different: DTR is ignored or causes the modem to hang up if it
  1575.   is dropped, while DSR signals that a connection has been established.
  1576.  
  1577. RTS/CTS
  1578.  
  1579.   While DTR and DSR are mostly used to establish a connection, RTS and CTS
  1580.   have been specially designed for data flow control. The computer signals
  1581.   with RTS ('Request To Send') that it wishes to send data to the data set,
  1582.   while the data set (modem) sets CTS ('Clear To Send') when it is ready to
  1583.   do one part of its job: to send data thru' the phone wires.
  1584.  
  1585. A normal handshaking protocol between a computer and a modem looks like this:
  1586.  
  1587.  
  1588. DTR  ___--------------------------------------------------------------____
  1589.  
  1590. DSR  _____-------------------------------------------------------------___
  1591.  
  1592. RTS  ___________-----------------------_____----------------------________
  1593.  
  1594. CTS  ____________-------____------------_____----------------------_______
  1595.  
  1596.        (1)(2) (3)(4)   (5) (6)      (7)(8)(9)(10)            (11)(12)(13)
  1597.  
  1598. (1)  The computer sets DTR to indicate that it wants to make use of the
  1599.      modem.
  1600. (2)  The modem signals that it is ready and that a connection has been
  1601.      established.
  1602. (3)  The computer requests permission to send.
  1603. (4)  The modem informs the computer that it is now ready to receive data from
  1604.      the computer and send it through the phone wires.
  1605. (5)  The modem drops CTS to signal to the computer that its internal buffers
  1606.      are full; the computer stops sending characters to the modem.
  1607. (6)  The buffers of the modem have been purged, so the computer may continue
  1608.      to send data.
  1609. (7)  This situation is not clear; either the computer's buffers are
  1610.      full and it wants to inform the modem of this, or it doesn't have any
  1611.      more data to be send to the modem. Normally, modems are configured to
  1612.      stop any transmission between the computer and the modem when RTS is
  1613.      dropped.
  1614. (8)  The modem acknowledges RTS cleared by dropping CTS.
  1615. (9)  RTS is again raised by the computer to re-establish data transmission.
  1616. (10) The modem shows that it is ready to do its job.
  1617. (11) No more data is to be sent.
  1618. (12) The modem acknowledges this.
  1619. (13) DTR is dropped by the computer; this causes most modems to hang up.
  1620.      After hang-up, the modem acknowledges with DSR low. If the connection
  1621.      breaks, the modem also drops DSR to inform the computer about it.
  1622.  
  1623.  
  1624. BIOS API (Application Programs Interface)
  1625. -----------------------------------------
  1626.  
  1627. PC programs are meant to use the BIOS routines to program the UARTs.
  1628. Even though this is *NOT RECOMMENDED* by me (awfully slow, limited and
  1629. complicated), I give you the BIOS calls as specified by Big Blue. Call
  1630. INT 14h with:
  1631.  
  1632.  
  1633.   AH=00h    Serial port - Initialize
  1634.  
  1635.      AL: see table
  1636.      DX: Port number (0-3; 0 equ. 0x3f8, 1 equ. 0x2f8, etc., see Hardware)
  1637.  
  1638.      Bit 7  Bit 6  Bit 5      Rate [bps]         Bit 4  Bit 3     Parity
  1639.        1      1      1        9600                 0      0       none
  1640.        1      1      0        4800                 1      0       none
  1641.        1      0      1        2400                 0      1       odd
  1642.        1      0      0        1200                 1      1       even
  1643.        0      1      1         600
  1644.        0      1      0         300               Bit 1  Bit 0     Data bits
  1645.        0      0      1         150                 0      0         5
  1646.        0      0      0         110                 0      1         6
  1647.                                                    1      0         7
  1648.      Bit 2   0 -> 1 stop bit, 1 -> 2 stop bits     1      1         8
  1649.  
  1650.      Returns:
  1651.      AH: RS-232C line status bits
  1652.        Bit
  1653.         0: RBF  - input data is available in buffer
  1654.         1: OE   - data has been lost
  1655.         5: THRE - room is available in output buffer
  1656.         6: TEMT - output buffer empty
  1657.      AL: Modem status bits
  1658.         3: always 1
  1659.         7: DCD - carrier detect
  1660.  
  1661.    AH=01h    Serial port - Write character
  1662.  
  1663.      AL: character to be sent
  1664.      DX: Port
  1665.  
  1666.      Returns:
  1667.      AH: Bit 7 clear if successful, set if not. Bits 0-6 see INT 14h AH=03h
  1668.  
  1669.    AH=02h    Serial port - Read character
  1670.  
  1671.      DX: Port
  1672.  
  1673.      Returns:
  1674.      AH: Line Status (see AH=03h)
  1675.      AL: Received character (if AH bit 7 is clear)
  1676.  
  1677.      Note:
  1678.      This routine times out if DSR is not asserted, even if data is
  1679.      available! (That's why you need the short wires from the "Connecting
  1680.      devices" chapter with some programs).
  1681.  
  1682.    AH=03h    Serial port - Get port status
  1683.  
  1684.      DX: Port
  1685.  
  1686.      Returns:
  1687.      AH: Line Status
  1688.         Bit 7: Timeout
  1689.         Bit 6: TEMT Transmitter empty
  1690.         Bit 5: THRE Transmitter Holding Register Empty
  1691.         Bit 4: Break (broken line detected)
  1692.         Bit 3: FE Framing error
  1693.         Bit 2: PE Parity error
  1694.         Bit 1: OE Overrun error
  1695.         Bit 0: RDF Receiver buffer full (data available)
  1696.      AL: Modem Status
  1697.         Bit 7: DCD Carrier detect
  1698.         Bit 6: RI Ring indicator
  1699.         Bit 5: DSR Data set ready
  1700.         Bit 4: CTS Clear to send
  1701.         Bit 3: DDCD Delta carrier detect
  1702.         Bit 2: TERI Trailing edge of ring indicator
  1703.         Bit 1: DDSR Delta data set ready
  1704.         Bit 0: DCTS Delta Clear to send
  1705.  
  1706.  
  1707. BIOS variables in the Data Segment at segment 40h:
  1708.  
  1709.      Offset   Size     Description
  1710.       00h     WORD     Base I/O address of 1st serial I/O port, zero if none
  1711.       02h     WORD     Base I/O address of 2nd serial I/O port, zero if none
  1712.       04h     WORD     Base I/O address of 3rd serial I/O port, zero if none
  1713.       06h     WORD     Base I/O address of 4th serial I/O port, zero if none
  1714.      Note: Above fields filled in turn by POST as it finds serial
  1715.      ports. POST never leaves gaps. DOS and BIOS serial device
  1716.      numbers may be redefined by re-assigning these fields.
  1717.      [POST: Power-On Self Test. CB]
  1718.      [Madis Kaal told me that there are BIOSes that leave gaps in the table,
  1719.      and I know of some that don't recognize COM4 correctly.]
  1720.  
  1721.  
  1722. This information is sneaked from Ralf Brown's famous interrupt list (hope
  1723. he doesn't mind). If you want more detailed facts on this interrupt, refer
  1724. to this list. It's available from lots of FTP sites (choose one in your
  1725. vicinity; it is *huge*).
  1726.  
  1727.  
  1728.  
  1729. Mice
  1730. ----
  1731.  
  1732. The Microsoft Serial Mouse (or compatibles) is the device that is most often
  1733. used with the Serial Port of the PC; it's the one with the two buttons. Mouse
  1734. Systems compatible mice have three buttons. Here's some information I
  1735. received from Stephen Warner and Angelo Haritsis:
  1736.  
  1737. Pins Used:
  1738.   TxD, RTS and/or DTR are used as power sources for the mouse.
  1739.   RxD is used to receive data from the mouse.
  1740.  
  1741. Mouse reset:
  1742.   Set UART to 'broken line' state (set bit 6 of the LCR) and clear the bits
  1743.   0-1 of the MCR; wait a while and reverse the bits again.
  1744.  
  1745. Serial transmission parameters:
  1746.   Microsoft Mouse        1200 bps, 7 data bits, 1 stop bit, no parity
  1747.   Mouse Systems Mouse    1200 bps, 8 data bits, 1 stop bit, no parity
  1748.  
  1749. Data packet format of the Microsoft mouse:
  1750.   The data packet consists of 3 bytes. It is sent to the computer every time
  1751.   the mouse changes state (ie. the mouse is moved or the buttons are released/
  1752.   pressed).
  1753.  
  1754.               D6    D5    D4    D3    D2    D1    D0
  1755.  
  1756.   1st byte    1     LB    RB    Y7    Y6    X7    X6
  1757.   2nd byte    0     X5    X4    X3    X2    X1    X0
  1758.   3rd byte    0     Y5    Y4    Y3    Y2    Y1    Y0
  1759.  
  1760.   The byte marked with 1 is sent first and then the others. The bit D6 in the
  1761.   first byte is used for synchronizing the software to the mouse packets
  1762.   if it goes out of sync.
  1763.  
  1764.   LB is the state of the left  button (1 being the LB is pressed)
  1765.   RB is the state of the right button (1 being the RB is pressed)
  1766.   X0-7 movement of the mouse in the X direction since last packet (+ right)
  1767.   Y0-7 movement of the mouse in the Y direction since last packet (+ down )
  1768.  
  1769.   The Microsoft Mouse uses RTS as power source. Whenever RTS is set to '0'
  1770.   and reset to '1', the mouse performs an internal reset and sends the
  1771.   character 'M' to signal its presence. Three-button-mice send 'M3' if you
  1772.   drop and raise RTS (see above) in Microsoft mode; this is compatible
  1773.   with the Microsoft mouse driver and allows the firmware to check if it
  1774.   is really a three-button mouse.
  1775.                    [Scott David Daniels received this info from Brian Onn]
  1776.  
  1777.  
  1778. Data packet format of the Mouse Systems mouse:
  1779.   The data packet consists of 5 bytes.
  1780.  
  1781.               D7    D6    D5    D4    D3    D2    D1    D0
  1782.  
  1783.   1st byte    1     0     0     0     0     LB    MB    RB
  1784.   2nd byte    X7    X6    X5    X4    X3    X2    X1    X0
  1785.   3rd byte    Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
  1786.   4th byte    equal to 2nd byte
  1787.   5th byte    equal to 3rd byte
  1788.  
  1789.   Bits 7-3 of the 1st byte are used for synchronization; it's rather
  1790.   improbable that they appear the same way in any of the other bytes.
  1791.  
  1792.   LB is the state of the left button (1 being the LB is pressed)
  1793.   MB is the state of the middle button (1 being the MB is pressed)
  1794.   RB is the state of the right button (1 being the RB is pressed)
  1795.   X0-7 movement of the mouse in the X direction since last packet (+ right)
  1796.   Y0-7 movement of the mouse in the Y direction since last packet (+ up   )
  1797.  
  1798. The mouse should rather be used with the mouse driver software; this
  1799. ensures compatibility to future changes as well as bus mice and greatly
  1800. reduces programming overhead. See Ralf Brown's interrupt list, interrupt 33h.
  1801. It is available from lots of FTP sites (eg. garbo.uwasa.fi, /pc/programming),
  1802. the files are called inter*.zip.
  1803.  
  1804.  
  1805. Modems
  1806. ======
  1807.  
  1808. This chapter is rather brief for several reasons. I'm no modem expert at all
  1809. and there exist better sources than this document if you want information on
  1810. modems. Patrick Chen, the author of "The Joy of Telecomputing", has written
  1811. such a file, and there's one available from Sergey Shulgin, too (I don't have
  1812. their internet addresses). You can obtain these files from my archive;
  1813. they are named "modem1" and "modem2".
  1814.  
  1815.  
  1816. A modem (MOdualtor-DEModulator) is an interface between the serial port of
  1817. your computer and the public telephone network. Modern modems are small
  1818. computers of their own: they accept commands, do the dialing for you, buffer
  1819. incoming data, perform data compression and such things. Several standards
  1820. have been established (Bell, CCITT), and several "command languages" are in
  1821. use, with the Hayes and Microcom commands being the most popular ones.
  1822.  
  1823. Modems have two internal modes: the command mode and the data mode. After
  1824. power-up, the modem is in the command mode, and this mode can be restalled
  1825. by sending an 'escape sequence' (normally a pause of at least 1 second,
  1826. then three '+' signs in one second, then a pause of at least 1 second).
  1827.  
  1828. All I know about modems is some commands and some encoding schemes; I
  1829. share this knowledge with you - please share yours with me!
  1830.  
  1831.  
  1832. Encoding schemes
  1833. ----------------
  1834.  
  1835. I've sneaked this table from the posting 'FAQ zu /Z-NETZ/TELECOM/ALLGEMEIN'
  1836. of Kristian Koehntopp <kris@black.toppoint.de> in 'de.newusers.questions'.
  1837. He has copyrighted his posting, so please contact him if you wish to reproduce
  1838. this information in any commercial way.
  1839.  
  1840.   These are the schemes recommended by CCITT (more than one speed means
  1841.   fallback/auto-retrain speeds):
  1842.  
  1843.           Transmission speed in bps  Baud  Modulation duplex     usage
  1844.    --------------------------------------------------------------------
  1845.    V.17        14400                 2400     TCM      half       FAX
  1846.                12000, 9600, 7200     2400     TCM      half       FAX
  1847.                 4800                 2400     QAM      half       FAX
  1848.    V.21          300                  300     FSK      full
  1849.    V.22         1200                  600    DPSK      full
  1850.    V.22bis      2400                  600     QAM      full
  1851.    V.23         1200/75              1200/75  FSK   asymmetric    BTX
  1852.    V.27ter      4800                 1600    DPSK      half       FAX
  1853.                 2400                 1200    DPSK      half       FAX
  1854.    V.29         9600                 2400     QAM      half       FAX
  1855.                 7200                 2400     QAM      half       FAX
  1856.    V.32         9600                 2400   TCM/QAM    full
  1857.                 4800                 2400     QAM      full
  1858.    V.32bis     14400                 2400     TCM      full
  1859.                12000, 9600, 7200     2400     TCM      full
  1860.                 4800                 2400     QAM      full
  1861.  
  1862.        FSK     Frequency Shift Keying
  1863.        DPSK    Differential Phase Shift Keying
  1864.        QAM     Quadrature Amplitude Modulation
  1865.        TCM     Trellis Coded Modulation
  1866.  
  1867.    Other V-Recommendations often heard of:
  1868.  
  1869.    V.24    - Meaning of the signals at the serial port.
  1870.    V.28    - Electrical levels (V.24, V.28, and ISO 2110 are equivlaent to EIA
  1871.              RS232)
  1872.    V.42    - Data protection method, not dependening on the modulation scheme
  1873.              in use.
  1874.    V.42bis - Compression scheme, also called BTLZ.
  1875.  
  1876. Erich Smythe <esmythe@digex.net> posted a very informative and humorous
  1877. article explaining different modulation schemes used with modems. You
  1878. can find it in the FTP archive, named The_Serial_Port.more06.
  1879.  
  1880.  
  1881. Hayes commands
  1882. --------------
  1883.  
  1884. Each command line starts with 'AT', then several commands, then carriage
  1885. return.
  1886.  
  1887. The list is not comprehensive at all; most modems have several commands of
  1888. their own, but these commands are available with most modems:
  1889.  
  1890. A/  Repeat last command (no prepending AT)
  1891.  
  1892. A   Take over phone line (if you've already picked up the phone).
  1893.  
  1894. B   Set communications standard.
  1895.     B0 - CCITT
  1896.     B1 - Bell
  1897.  
  1898. C   Switch carrier on/off.
  1899.     C0 - carrier off
  1900.     C1 - carrier on
  1901.  
  1902. D   Dial a number. Normally followed by
  1903.     T - tone dial
  1904.     P - pulse dial
  1905.     nothing - according to actual setting (see ATP/ATT)
  1906.     then a sequence of the follwing characters:
  1907.     0-9 - the numbers to be dialed
  1908.     W - wait for dial tone
  1909.     , - wait 2 seconds
  1910.     @ - wait 5 seconds (?)
  1911.     ! - flash (put the phone on the hook for 1/2 second)
  1912.     > - earth key
  1913.     R - start connection right after dialing (eg. ATDPR equals ATA)
  1914.     If you just enter ATD, the modem takes over the line without dialing.
  1915.  
  1916. E   Echo on/off in the command mode
  1917.     E0 - no echo
  1918.     E1 - echo
  1919.  
  1920. H   Hang up
  1921.  
  1922. L   Volume control; followed by 0-3 (0 equ. lowest, 3 equ. highest volume)
  1923.  
  1924. M   Monitor
  1925.     M0 - Speaker off
  1926.     M1 - Speaker on while dialing and establishing a connection
  1927.     M2 - Speaker always on
  1928.     M3 - Speaker on while establishing a connection
  1929.  
  1930. O   Switch to data mode
  1931.     O0 - promptly
  1932.     O1 - with retrain (reduction of the data rate)
  1933.  
  1934. P   Pulse dial
  1935.  
  1936. Q   Responses to commands on/off
  1937.     Q0 - on
  1938.     Q1 - off
  1939.  
  1940. S   Set/read internal register, eg.
  1941.     S17=234 set reg. 17 to 234
  1942.     S17?    read reg. 17
  1943.  
  1944. T   Tone dial
  1945.  
  1946. V   Verbose mode on/off
  1947.     V0 - short responses
  1948.     V1 - full responses
  1949.  
  1950. X   Phone tones recognition on/off
  1951.     X0 - Ignore busy sign, don't wait for dial tone, and just answer with
  1952.          "CONNECT" when a connection has been established (other settings
  1953.          produce more detailed messages)
  1954.     X1 - Ignore busy sign, don't wait for dial tone, but give full connect
  1955.          message
  1956.     X2 - Ignore busy sign but wait for dial tone
  1957.     X3 - Don't ignore busy sign, but don't wait for dial tone
  1958.     X4 - Don't ignore anything
  1959.  
  1960. Y   Break setting
  1961.     Y0 - Don't hang up when break signal is detected
  1962.     Y1 - Hang up when break is detected (&D2, &M0)
  1963.  
  1964. Z   Initialize modem
  1965.     Z  - Default parameters
  1966.     Z0 - Setting 0
  1967.     Z1 - Setting 1
  1968.  
  1969. &C  DCD mode
  1970.     &C0 - always 1
  1971.     &C1 - DCD according to carrier
  1972.  
  1973. &D  DTR mode
  1974.     &D0 - ignore DTR
  1975.     &D1 - switch to command mode when DTR goes 0
  1976.     &D2 - hang up if DTR goes 0
  1977.     &D3 - initialize modem when DTR goes 0
  1978.  
  1979. &F  Set operation mode
  1980.     &F0 - according to Hayes, no data protocol
  1981.     &F1 - according to Microcom; MNP1-4 or MNP5 as specified by %C
  1982.     &F2 - according to Sierra; MNP1-4 or MNP5 as specified by %C
  1983.     &F3 - according to Sierra, V.42 or V.42bis as specified by %C
  1984.  
  1985.     These are the default settings:
  1986.     &F0 - B0, E1, L2, M1, P, Q0, V1, Y0, X1, &C1, &D0, &G0, &R0, &S0,
  1987.           S0=0, S1=0, S2=43, S3=13, S4=10, S5=8, S6=2, S7=30, S8=2,
  1988.           S9=6,S10=14, S11=75, S12=50, S14=AAh, S16=80h, S21=20h,
  1989.           S22=76h, S23=7, S25=5, S26=1, S27=40h
  1990.     &F1 - \A3, \C0, \E0, \G0, \K5, \N1, \Q0, \T0, \V0, \X0, %A0, %C1,
  1991.           %E1, %G0, &G1, S36=7h, S46=138h, S48=128h, S82=128h
  1992.     &F2 - \A3, \C2, \E0, \G1, \K5, \N3, \Q1, \T0, \V1, \X0, %A13, %C1,
  1993.           S36=7h, S46=138h, S48=128h, S82=128h
  1994.     &F3 - \A3, \C0, \E0, \G0, \K5, \N3, \O1, \T0, \V1, \X0, %A0, %C1,
  1995.           %E0, S36=7h, S46=138h, S48=7h, S82=128h
  1996.  
  1997. &G  Guard tone
  1998.     &G0 - off
  1999.     &G1 - 550 Hz
  2000.     &G2 - 1800 Hz
  2001.  
  2002. &K  Data flow control
  2003.     &K0 - none
  2004.     &K3 - bidirectional RTS/CTS handshaking
  2005.     &K4 - bidirectional XON/XOFF
  2006.     &K5 - unidirectional XON/XOFF
  2007.  
  2008. &M  Synchronous/asynchronous operation
  2009.     &M0 - asynchronous (the usual thing)
  2010.     &M1 - command mode asynchronous, data mode synchronous.
  2011.     &M2 - switch to synchronous mode, start dialing after DTR 0->1
  2012.     &M3 - switch to synchronous mode, don't dial
  2013.  
  2014. &Q  Further specification of the communication
  2015.     &Q0 to &Q3 - no V.42bis
  2016.     &Q5 - V.42bis
  2017.     &Q6 - V.42bis off, buffer data
  2018.  
  2019. &R  CTS mode
  2020.     &R0 - CTS follows RTS with the delay time of S26
  2021.     &R1 - CTS is 1 if the modem is in the data mode
  2022.  
  2023. &S  DSR mode
  2024.     &S0 - DSR always 1
  2025.     &S1 - according to CCITT V.24
  2026.  
  2027. &T  Test
  2028.     &T0 - normal operation (no test)
  2029.     &T1 - local analog loopback
  2030.     &T3 - local digital loopback
  2031.     &T4 - accept distant digital loopback
  2032.     &T5 - ignore distant digital loopback
  2033.     &T6 - start distant digital loopback
  2034.     &T7 - start distant digital loopback and self test
  2035.     &T8 - start distant analog loopback and self test
  2036.  
  2037. &V  Show modem status
  2038.  
  2039. &Wn Save actual configuration (some modems only). Setting can be
  2040.     restored with ATZn. n normally ranges between 0 and 1.
  2041.     The following parameters are stored:
  2042.     B, C, E, L, M, P/T, Q, V, X, Y, &C, &D, &G, &R, &S, &T4/&T5,
  2043.     S0, S14, S18, S21, S22, S25, S26, S27
  2044.  
  2045. &X  Specify clock source for synchronous operation
  2046.     &X0 - modem generates clock
  2047.     &X1 - modem synchronizes with local clock
  2048.     &X2 - modem synchronizes with distant clock
  2049.  
  2050. &Y  Define default setting (see &W and Z)
  2051.     &Y0 - setting 0 is default
  2052.     &Y1 - setting 1 is default
  2053.  
  2054. &Z  Store phone number in diary
  2055.     &Zn=XXXXXX stores phone number XXXXXX under index n, where
  2056.     XXXXXX can be up to 30 digits and n ranges between 0 and 3.
  2057.  
  2058.  
  2059. Microcom commands
  2060. -----------------
  2061.  
  2062. \A  Set block length for MNP
  2063.     \A0 - 64 characters
  2064.     \A1 - 128 characters
  2065.     \A2 - 192 characters
  2066.     \A3 - 256 characters
  2067.  
  2068. \Bn Send break signal for n times 100ms (MNP defaults to n=3).
  2069.  
  2070. \C  Set buffering
  2071.     \C0 - none at all
  2072.     \C1 - buffer data for 4 seconds as long as 200 characters aren't
  2073.           reached or as long as no MNP block is found
  2074.     \C2 - don't buffer. Switch back to normal operation after reception
  2075.           of the control character (fall-back, see %C)
  2076.  
  2077. D/n Dial phone number n in the diary (see &Z)
  2078.  
  2079. DL  Redial last number
  2080.  
  2081. \E  Echo on/off in data mode
  2082.     \E0 - no echo
  2083.     \E1 - echo
  2084.  
  2085. \G  Data flow on/off (see \Q)
  2086.     \G0 - off
  2087.     \G1 - on
  2088.  
  2089. \J  Data rate adjust
  2090.     \J0 - the data rates computer-modem and modem-modem are independent
  2091.     \J1 - the data rate computer-modem follows the data rate modem-modem
  2092.  
  2093. \Kn Break setting (don't know anything about this, just that it exists ;-)
  2094.  
  2095. \N  MNP select
  2096.     \N0 - standard mode, no MNP, data is buffered
  2097.     \N1 - direct mode, no MNP, no buffering
  2098.     \N2 - MNP, data is buffered
  2099.     \N3 - allow MNP on/off during connection, data is buffered
  2100.  
  2101. \O  Switch on MNP during connection (the rest of the line is being ignored!)
  2102.  
  2103. \Pn Same as &Z
  2104.  
  2105. \Q  Set handshake (compare &K)
  2106.     \Q0 - no handshaking
  2107.     \Q1 - XON/XOFF
  2108.     \Q2 - modem controls data flow with CTS
  2109.     \Q3 - data flow control with RTS/CTS
  2110.  
  2111. \S  List complete configuration
  2112.  
  2113. \Tn Set idle timer
  2114.     \T0 - timer off
  2115.     \Tnn - break connection after nn minutes without data exchange
  2116.            (1-90)
  2117.  
  2118. \U  Acknowledge MNP operation; rest of line is ignored!
  2119.  
  2120. \V  Verbose mode
  2121.     \V0 - messages according to Hayes, even if MNP (no \REL)
  2122.     \V1 - messages according to Microcom (\REL appended if MNP)
  2123.  
  2124. \X  Filter XON/XOFF characters
  2125.     \X0 - filter XOM/XOFF characters
  2126.     \X1 - don't filter them (the usual thing)
  2127.  
  2128. \Y  Same as AT\O\U with the difference that it is not necessary to
  2129.     first send AT\O to one modem and then AT\U to the other; just
  2130.     send AT\Y to each modem within 5 seconds
  2131.  
  2132. %An Specify control character that provokes fallback from MNP to
  2133.     normal operation (see \C2). n=0..255 (ASCII code)
  2134.  
  2135. %C  MNP5
  2136.     %C0 - not allowed
  2137.     %C1 - allowed
  2138.  
  2139. %E  auto-retrain
  2140.     %E0 - no auto-retrain allowed
  2141.     %E1 - auto-retrain allowed according to CCITT
  2142.  
  2143. %R  Show all S registers
  2144.  
  2145. %V  Same as I3 (but don't ask me what it is ;-) Gives info on the firmware
  2146.     version with some modems.
  2147.  
  2148.     
  2149.  [... continued ...]  
  2150.  
  2151. --
  2152. Chris Blum <chris@phil.uni-sb.de>  http://www.phil.uni-sb.de/~chris/
  2153.  
  2154. From chris@chris.telip.uni-sb.de Wed Mar  1 17:57:25 1995
  2155. From: chris@chris.telip.uni-sb.de (Chris Blum)
  2156. Newsgroups: comp.sys.ibm.pc.hardware.comm,comp.os.msdos.programmer
  2157. Subject: The Serial Port rel. 18, part 3/3
  2158. Date: 23 Feb 1995 00:24:27 +0100
  2159. Organization: The Outside of the Asylum
  2160. Reply-To: chris@phil.uni-sb.de (Chris Blum)
  2161. NNTP-Posting-Host: chris.telip.uni-sb.de
  2162. Keywords: comm, COM, UART, serial port
  2163.  
  2164. [... continued ...]
  2165.    
  2166.  
  2167. IRQ sharing - can it be done?   (this applies to ISA bus systems only)
  2168. -----------------------------
  2169.  
  2170. Yes and no. Yes, it can be done in principle, and no, it can't be done
  2171. by just configuring two ports to use the same interrupt.
  2172.  
  2173. Let us first consider the hardware involved. PCs have ICUs (interrupt control
  2174. units, or PICs - programmable interrupt controllers) of the 8259A type. They
  2175. can be programmed to be triggered by a high signal level or a raising edge,
  2176. which is already annoying because low level or falling edge would make add-on
  2177. card design simpler. But to top this all off, they have internal pull-up
  2178. resistors! Which means that if no card is using the interrupt, it is in
  2179. the triggered state.
  2180.  
  2181. How would cards share interrupts? They'd only be allowed to have their
  2182. IRQ output in two states: active high or 'floating'. 'Floating' means the line
  2183. is not driven at all, neither high nor low, it 'floats'. If all sharers of
  2184. an interrupt line in the PC would only drive the line high or let it 'float',
  2185. we'd have a simple interrupt sharing scheme (that would allow for even
  2186. simpler design if the active state of the line was low) - if there wasn't
  2187. this nasty internal pull-up resistor in the 8259A. <sarcasm on> Sadly IBM
  2188. didn't provide an external pull-down resistor on the main board of the very
  2189. first PC, so later designs could not have one either for compatibility's
  2190. sake. <sarcasm off> 1.5kOhms would be a fine value; the 8259A produces 300uA
  2191. that have to be sunk below 0.8v (so 2.6kOhms would be enough in theory,
  2192. but having some safety margin can't hurt).
  2193.  
  2194. So how can you have your ports sharing a common interrupt line? There are
  2195. two approaches to this, each assuming you're familiar with using a soldering
  2196. iron. What you must provide is a logical OR of all interrupt outputs that
  2197. drive the line; while this can be done with an OR gate of course, it is far
  2198. more practical to use some wired-OR facility. First you'll have to add the
  2199. external pull-down resistor, either on the main board (where it really
  2200. belongs) or on one of the cards. Use 1.5kOhms for this. Then cut the line
  2201. between the card edge connector and the IRQ line driver (LS125) on each and
  2202. every card. Do this carefully; if it's a multi-layer card, you'd better cut
  2203. the pin of the LS125, or maybe you can just replace a jumper with a diode.
  2204. Now solder a diode (1N4148 will do, slow power diodes won't) over the cut
  2205. with the cathode (usually marked with a ring, but you'd better check that
  2206. thoroughly if there are multiple rings; the 1N4148 normally has a yellow
  2207. cathode ring) to the card edge connector. There you are! Now hardware will no
  2208. longer be in the way of interrupt sharing. (A 'cleaner' solution would be to
  2209. use a LS126 line driver instead of the diode with 'enable' connected to
  2210. 'input', but that's only practical with from-scratch designs.)
  2211.  
  2212. Now let's face the software problems. In theory, interrupt sharing works fine
  2213. between different pieces of hardware, but practically this is limited to real
  2214. operating systems that do all interrupt processing by themselves; MSDOS
  2215. doesn't do that, so it's not a good option for PCs (even Linux users boot DOS
  2216. sometimes, if only to play games). Sharing interrupts even between UARTs
  2217. becomes problematic if there are several programs involved, eg. the mouse
  2218. driver and some comm application; they'd have to know of each other. 'Daisy
  2219. chaining' the interrupt (a program 'hooks' the interrupt by placing its
  2220. handler's address in the IRQ serivce table and letting the handler call the
  2221. address it found in that table at install time when it exits; no interrupt
  2222. acknowledging is done by the handlers themselves, just by the stub handler at
  2223. the end of the chain) doesn't work because DOS doesn't even provide a stub
  2224. interrupt handler! So one of the programs would have to issue EOI (end of
  2225. interrupt) to the ICU, but which one? How would it know it's the last one in
  2226. the chain? Better forget daisy chaining interrupts under DOS if you want your
  2227. programs to work reliably.
  2228.  
  2229. The situation is much simpler if all UARTs sharing the same interrupt are
  2230. used by the same program. This program has to be aware of the sharing
  2231. mechanism, but programs that can make use of more than one serial port
  2232. (especially libraries) usually are. Now there's only one problem to be
  2233. solved: lock-up situations. As I already wrote, the ICUs in the PC are
  2234. programmed to use raising edge trigger mode, and you can't change this
  2235. without crashing the system. Now consider the following situation. Two
  2236. UARTs share one IRQ line. UART #1 raises the line because it needs service;
  2237. the service routine is called and detects that UART #1 needs service. Before
  2238. it can perform the serivce, UART #2 raises the IRQ, too. Now UART #1 is
  2239. serviced, the line should go to the 'low' state but it doesn't because of
  2240. the other UART keeping it high; the handler checks the next UART in its
  2241. table and sees that UART #2 needs service, too. Now UART #1 receives another
  2242. character and keeps the line high while UART #2 is being serviced. How should
  2243. the handler know that this has happened? If it just issued EOI and returned,
  2244. the IRQ line would never have gone 'low' during the service, so there won't
  2245. be any future raising edges to be detected, and thus no more interrupts!
  2246.  
  2247. What does the service routine do to avoid lock-ups? It has to mask the
  2248. interrupt in the ICU; this resets the edge detector. If it unmasks the
  2249. interrupt again at the end of the handler and the line is still 'high',
  2250. this will trigger the edge detector and the interrupt will be scheduled
  2251. again. See the 'known problems' section for a very solid method of handling
  2252. interrupts suggested by Richard Clayton.
  2253.  
  2254. Windows allows for UARTs sharing interrupts; just make sure the COM ports
  2255. are configured properly in the system setup.
  2256.  
  2257. A note to Linux users: Linux is fully capable of sharing interrupts between
  2258. serial ports if the hardware problems described above are solved. Using the
  2259. same interrupt for several UARTs even reduces CPU load, so it is definitely a
  2260. Good Thing as long as there are not too many sharers. Having a well-designed
  2261. and kernel-supported multi-port card is even better because these cards
  2262. provide a mechanism for the handler to detect which UART has triggered
  2263. interrupt without having to look at every single IIR, which reduces overhead
  2264. even further.
  2265.  
  2266.  
  2267.  
  2268. Programming
  2269. ===========
  2270.  
  2271. Now for the clickety-clickety thing. I hope you're a bit keen in
  2272. assembler programming. Programming the UART in high level languages is,
  2273. of course, possible, but not at very high rates. I give you several
  2274. routines in assembler and C that do the dirty work for you.
  2275.  
  2276. If you're keen on examples of how to program the UART in high level
  2277. languages, even interrupt-driven, you should have a look at some code
  2278. I received from Frank Whaley (ftp: "The_Serial_Port.more04") and at
  2279. the "Async Routines Library" Scott A. Deming is currently developing
  2280. (ftp: "asyam.zip").
  2281.  
  2282. First thing to do is detect which chip is used. It shouldn't be difficult
  2283. to convert this C function into assembler; I'll omit the assembly version.
  2284.  
  2285. int detect_UART(unsigned baseaddr)
  2286. {
  2287.    // this function returns 0 if no UART is installed.
  2288.    // 1: 8250, 2: 16450 or 8250 with scratch reg., 3: 16550, 4: 16550A
  2289.    int x,olddata;
  2290.  
  2291.    // check if a UART is present anyway
  2292.    olddata=inp(baseaddr+4);
  2293.    outp(baseaddr+4,0x10);
  2294.    if ((inp(baseaddr+6)&0xf0)) return 0;
  2295.    outp(baseaddr+4,0x1f);
  2296.    if ((inp(baseaddr+6)&0xf0)!=0xf0) return 0;
  2297.    outp(baseaddr+4,olddata);
  2298.    // next thing to do is look for the scratch register
  2299.    olddata=inp(baseaddr+7);
  2300.    outp(baseaddr+7,0x55);
  2301.    if (inp(baseaddr+7)!=0x55) return 1;
  2302.    outp(baseaddr+7,0xAA);
  2303.    if (inp(baseaddr+7)!=0xAA) return 1;
  2304.    outp(baseaddr+7,olddata); // we don't need to restore it if it's not there
  2305.    // then check if there's a FIFO
  2306.    outp(baseaddr+2,1);
  2307.    x=inp(baseaddr+2);
  2308.    // some old-fashioned software relies on this!
  2309.    outp(baseaddr+2,0x0);
  2310.    if ((x&0x80)==0) return 2;
  2311.    if ((x&0x40)==0) return 3;
  2312.    return 4;
  2313. }
  2314.  
  2315. If it's not a 16550A, FIFO mode operation won't work, but there's no
  2316. problem in switching it on nevertheless as long as no 16550 is used and
  2317. your software is aware that there is no TX FIFO available (see below). If
  2318. your software doesn't use the FIFOs explicitly, write 0x7 to the FCR and
  2319. mask bits 3, 6 & 7 of the IIR. This does not reduce interrupt overhead but
  2320. makes transmission more reliable without changing anything for the software.
  2321. But remember that the 16550 has a bug with its FIFOs (see hardware section),
  2322. so if the function above returns 3, switch the FIFOs off.
  2323.  
  2324. Mike Surikov has provided me with an altered version of this function that
  2325. works correctly with multi-port serial adapters, too. It's available from
  2326. the ftp archive mentioned at the beginning. Look for the file
  2327. "The_Serial_Port.more03".
  2328.  
  2329. The prototype of this useful function has also been provided by Mike
  2330. Surikov; I've rewritten it from scratch though. It allows you to detect which
  2331. interrupt is used by a certain UART. There is an assembly version of Mike's
  2332. version (which can only detect intlevels 0-7) of this function as well. It's
  2333. available from the ftp archive as "The_Serial_Port.more02".
  2334.  
  2335. int detect_IRQ(unsigned base)
  2336. {
  2337.   // returns: -1 if no intlevel found, or intlevel 0-15
  2338.   char ier,mcr,imrm,imrs,maskm,masks,irqm,irqs;
  2339.  
  2340.   _asm cli;            // disable all CPU interrupts
  2341.   ier = inp(base+1);   // read IER
  2342.   outp(base+1,0);      // disable all UART ints
  2343.   while (!(inp(base+5)&0x20));  // wait for the THR to be empty
  2344.   mcr = inp(base+4);   // read MCR
  2345.   outp(base+4,0x0F);   // connect UART to irq line
  2346.   imrm = inp(0x21);    // read contents of master ICU mask register
  2347.   imrs = inp(0xA1);    // read contents of slave ICU mask register
  2348.   outp(0xA0,0x0A);     // next read access to 0xA0 reads out IRR
  2349.   outp(0x20,0x0A);     // next read access to 0x20 reads out IRR
  2350.   outp(base+1,2);      // let's generate interrupts...
  2351.   maskm = inp(0x20);   // this clears all bits except for the one
  2352.   masks = inp(0xA0);   // that corresponds to the int
  2353.   outp(base+1,0);      // drop the int line
  2354.   maskm &= ~inp(0x20); // this clears all bits except for the one
  2355.   masks &= ~inp(0xA0); // that corresponds to the int
  2356.   outp(base+1,2);      // and raise it again just to be sure...
  2357.   maskm &= inp(0x20);  // this clears all bits except for the one
  2358.   masks &= inp(0xA0);  // that corresponds to the int
  2359.   outp(0xA1,~masks);   // now let us unmask this interrupt only
  2360.   outp(0x21,~maskm);
  2361.   outp(0xA0,0x0C);     // enter polled mode; Mike Surikov reported
  2362.   outp(0x20,0x0C);     // that order is important with Pentium/PCI systems
  2363.   irqs = inp(0xA0);    // and accept the interrupt
  2364.   irqm = inp(0x20);
  2365.   inp(base+2);         // reset transmitter interrupt in UART
  2366.   outp(base+4,mcr);    // restore old value of MCR
  2367.   outp(base+1,ier);    // restore old value of IER
  2368.   if (masks) outp(0xA0,0x20);  // send an EOI to slave
  2369.   if (maskm) outp(0x20,0x20);  // send an EOI to master
  2370.   outp(0x21,imrm);     // restore old mask register contents
  2371.   outp(0xA1,imrs);
  2372.   _asm sti;
  2373.   if (irqs&0x80)       // slave interrupt occured
  2374.     return (irqs&0x07)+8;
  2375.   if (irqm&0x80)       // master interrupt occured
  2376.     return irqm&0x07;
  2377.   return -1;
  2378. }
  2379.  
  2380.  
  2381.  
  2382. Now the non-interrupt version of TX and RX.
  2383.  
  2384. Let's assume the following constants are set correctly (either by
  2385. 'CONSTANT EQU value' or by '#define CONSTANT value'). You can easily use
  2386. variables instead, but I wanted to save the extra lines for the ADD
  2387. commands then necessary... A cute trick for calculating I/O addresses in
  2388. assembly programs is this: load an index register (BX, BP, SI, or DI)
  2389. with the base address (and keep it there), then use LEA DX,[BX+offset]
  2390. before each IN/OUT instead of MOV DX,base; ADD DX,offset. It saves you
  2391. one or two cycles. :)
  2392.  
  2393.   UART_BASEADDR   the base address of the UART
  2394.   UART_BAUDRATE   the divisor value (eg. 12 for 9600 bps)
  2395.   UART_LCRVAL     the value to be written to the LCR (eg. 0x1b for 8e1)
  2396.   UART_FCRVAL     the value to be written to the FCR. Bit 0, 1 and 2 set,
  2397.                   bits 6 & 7 according to trigger level wished (see above).
  2398.                   0x87 is a good value, 0x7 establishes compatibility
  2399.                   (except that there are some bits to be masked in the IIR).
  2400.  
  2401. First thing to do is initializing the UART. This works as follows:
  2402.  
  2403. UART_init proc near
  2404.   push ax  ; we are 'clean guys'
  2405.   push dx
  2406.   mov  dx,UART_BASEADDR+3  ; LCR
  2407.   mov  al,80h  ; set DLAB
  2408.   out  dx,al
  2409.   mov  dx,UART_BASEADDR    ; divisor
  2410.   mov  ax,UART_BAUDRATE
  2411.   out  dx,ax
  2412.   mov  dx,UART_BASEADDR+3  ; LCR
  2413.   mov  al,UART_LCRVAL  ; params
  2414.   out  dx,al
  2415.   mov  dx,UART_BASEADDR+4  ; MCR
  2416.   xor  ax,ax  ; clear loopback
  2417.   out  dx,al
  2418.   ;***
  2419.   pop  dx
  2420.   pop  ax
  2421.   ret
  2422. UART_init endp
  2423.  
  2424. void UART_init()
  2425. {
  2426.    outp(UART_BASEADDR+3,0x80);
  2427.    outpw(UART_BASEADDR,UART_BAUDRATE);
  2428.    outp(UART_BASEADDR+3,UART_LCRVAL);
  2429.    outp(UART_BASEADDR+4,0);
  2430.    //***
  2431. }
  2432.  
  2433. If we wanted to use the FIFO functions of the 16550A, we'd have to add
  2434. some lines to the routines above (where the ***s are).
  2435. In assembler:
  2436.   mov  dx,UART_BASEADDR+2  ; FCR
  2437.   mov  al,UART_FCRVAL
  2438.   out  dx,al
  2439. And in C:
  2440.    outp(UART_BASEADDR+2,UART_FCRVAL);
  2441.  
  2442. Don't forget to disable the FIFO when your program exits! Some other
  2443. software may rely on this!
  2444.  
  2445. Not very complex so far, isn't it? Well, I told you so at the very
  2446. beginning, and I wanted to start easy. Now let's send a character.
  2447.  
  2448. UART_send proc near
  2449.   ; character to be sent in AL
  2450.   push dx
  2451.   push ax
  2452.   mov  dx,UART_BASEADDR+5
  2453. us_wait:
  2454.   in   al,dx  ; wait until we are allowed to write a byte to the THR
  2455.   test al,20h
  2456.   jz   us_wait
  2457.   pop  ax
  2458.   mov  dx,UART_BASEADDR
  2459.   out  dx,al  ; then write the byte
  2460.   pop  dx
  2461.   ret
  2462. UART_send endp
  2463.  
  2464. void UART_send(char character)
  2465. {
  2466.    while ((inp(UART_BASEADDR+5)&0x20)==0);
  2467.    outp(UART_BASEADDR,(int)character);
  2468. }
  2469.  
  2470. This one sends a null-terminated string.
  2471.  
  2472. UART_send_string proc near
  2473.   ; DS:SI contains a pointer to the string to be sent.
  2474.   push si
  2475.   push ax
  2476.   push dx
  2477.   cld  ; we want to read the string in its correct order
  2478. uss_loop:
  2479.   lodsb
  2480.   or   al,al  ; last character sent?
  2481.   jz   uss_end
  2482.   ;*1*
  2483.   mov  dx,UART_BASEADDR+5
  2484.   push ax
  2485. uss_wait:
  2486.   in   al,dx
  2487.   test al,20h
  2488.   jz   uss_wait
  2489.   mov  dx,UART_BASEADDR
  2490.   pop  ax
  2491.   out  dx,al
  2492.   ;*2*
  2493.   jmp  uss_loop
  2494. uss_end:
  2495.   pop  dx
  2496.   pop  ax
  2497.   pop  si
  2498.   ret
  2499. UART_send_string endp
  2500.  
  2501. void UART_send_string(char *string)
  2502. {
  2503.    int i;
  2504.    for (i=0; string[i]!=0; i++)
  2505.       {
  2506.       //*1*
  2507.       while ((inp(UART_BASEADDR+5)&0x20)==0);
  2508.       outp(UART_BASEADDR,(int)string[i]);
  2509.       //*2*
  2510.       }
  2511. }
  2512.  
  2513. Of course we could have used our already programmed function/procedure
  2514. UART_send instead of the piece of code limited by *1* and *2*, but we are
  2515. interested in high-speed code and thus save the call/ret.
  2516.  
  2517. It shouldn't be a hard nut for you to modify the above function/procedure
  2518. so that it sends a block of data rather than a null-terminated string. I'll
  2519. omit that here.
  2520.  
  2521. Note that all these routines don't make any use of the TX FIFO! If we know
  2522. for sure that it's a 16550A we're dealing with, and that its FIFOs are
  2523. enabled, we could as well write up to 16 characters whenever bit 5 (THRE)
  2524. of the LSR goes 1.
  2525.  
  2526. Now for reception. We want to program routines that do the following:
  2527.   - check if a character has been received or an error occured
  2528.   - read a character if there's one available
  2529.  
  2530. Both the C and the assembler routines return 0 (in AX) if there is
  2531. neither an error condition nor a character available. If a character is
  2532. available, Bit 8 is set and AL or the lower byte of the return value
  2533. contains the character. Bit 9 is set if we lost data (overrun), bit 10
  2534. signals a parity error, bit 11 signals a framing error, bit 12 shows if
  2535. there is a break in the data stream and bit 15 signals if there are any
  2536. errors in the FIFO (if we turned it on). The procedure/function is much
  2537. smaller than this paragraph:
  2538.  
  2539. UART_get_char proc near
  2540.   push dx
  2541.   mov  dx,UART_BASEADDR+5
  2542.   in   al,dx
  2543.   xchg al,ah
  2544.   and  ax,9f00h
  2545.   test al,1
  2546.   jz   ugc_nochar
  2547.   mov  dx,UART_BASEADDR
  2548.   in   al,dx
  2549. ugc_nochar:
  2550.   pop  dx
  2551.   ret
  2552. UART_get_char endp
  2553.  
  2554. unsigned UART_get_char()
  2555. {
  2556.    unsigned x;
  2557.    x = (inp(UART_BASEADDR+5) & 0x9f) << 8;
  2558.    if (x&0x100) x|=((unsigned)inp(UART_BASEADDR))&0xff;
  2559.    return x;
  2560. }
  2561.  
  2562. This procedure/function lets us easily keep track of what's happening
  2563. with the RxD pin. It does not provide any information on the modem status
  2564. lines! We'll program that later on.
  2565.  
  2566. If we wanted to show what's happening with the RxD pin, we'd just have to
  2567. write a routine like the following (I use a macro in the assembler version
  2568. to shorten the source code):
  2569.  
  2570. DOS_print macro pointer
  2571.   ; prints a string in the code segment
  2572.   push ax
  2573.   push ds
  2574.   push dx
  2575.   push cs
  2576.   pop  ds
  2577.   mov  dx,pointer
  2578.   mov  ah,9
  2579.   int  21h
  2580.   pop  dx
  2581.   pop  ds
  2582.   pop  ax
  2583. endm
  2584.  
  2585. UART_watch_rxd proc near
  2586. uwr_loop:
  2587.   ; check if keyboard hit; we want a possibility to break the loop
  2588.   mov  ah,1  ; Beware! Don't call INT 16h with high transmission
  2589.   int  16h   ; rates, it won't work!
  2590.   jnz  uwr_exit
  2591.   call UART_get_char
  2592.   or   ax,ax
  2593.   jz   uwr_loop
  2594.   test ah,1  ; is there a character in AL?
  2595.   jz   uwr_nodata
  2596.   push ax    ; yes, print it
  2597.   mov  dl,al ;\
  2598.   mov  ah,2  ; better use this for high rates: mov ah,0eh
  2599.   int  21h   ;/                                int 10h
  2600.   pop  ax
  2601. uwr_nodata:
  2602.   test ah,0eh ; any error at all?
  2603.   jz   uwr_loop  ; this speeds up things since errors should be rare
  2604.   test ah,2  ; overrun error?
  2605.   jz   uwr_noover
  2606.   DOS_print overrun_text
  2607. uwr_noover:
  2608.   test ah,4  ; parity error?
  2609.   jz   uwr_nopar
  2610.   DOS_print parity_text
  2611. uwr_nopar:
  2612.   test ah,8  ; framing error?
  2613.   jz   uwr_loop
  2614.   DOS_print framing_text
  2615.   jmp  uwr_loop
  2616. uwr_exit:
  2617.   ret
  2618. overrun_text    db "*** Overrun Error ***$"
  2619. parity_text     db "*** Parity Error ***$"
  2620. framing_text    db "*** Framing Error ***$"
  2621. UART_watch_rxd endp
  2622.  
  2623. void UART_watch_rxd()
  2624. {
  2625.    union {
  2626.       unsigned val;
  2627.       char character;
  2628.       } x;
  2629.    while (!kbhit()) {
  2630.       x.val=UART_get_char();
  2631.       if (!x.val) continue;  // nothing? Continue
  2632.       if (x.val&0x100) putc(x.character);  // character? Print it
  2633.       if (!(x.val&0xe00)) continue;  // any error condidion? No, continue
  2634.       if (x.val&0x200) printf("*** Overrun Error ***");
  2635.       if (x.val&0x400) printf("*** Parity Error ***");
  2636.       if (x.val&0x800) printf("*** Framing Error ***");
  2637.       }
  2638. }
  2639.  
  2640. The RX routines make use of the RX FIFO without any additional programming.
  2641.  
  2642. If you call these routines from a function/procedure as shown below,
  2643. you've got a small terminal program!
  2644.  
  2645. terminal proc near
  2646. ter_loop:
  2647.   call UART_watch_rxd  ; watch line until a key is pressed
  2648.   xor  ax,ax  ; get that key from the keyboard buffer
  2649.   int  16h
  2650.   cmp  al,27  ; is it ESC?
  2651.   jz   ter_end  ; yes, then end this function
  2652.   call UART_send  ; send the character typed if it's not ESC
  2653.   jmp  ter_loop  ; don't forget to check if data comes in
  2654. ter_end:
  2655.   ret
  2656. terminal endp
  2657.  
  2658. void terminal()
  2659. {
  2660.    int key;
  2661.    while (1)
  2662.       {
  2663.       UART_watch_rxd();
  2664.       key=getche();
  2665.       if (key==27) break;
  2666.       UART_send((char)key);
  2667.       }
  2668. }
  2669.  
  2670. These, of course, should be called from an embedding routine like the
  2671. following (the assembler routines concatenated will assemble as an .EXE
  2672. file. Put the lines 'code segment' and 'assume cs:code,ss:stack' to the
  2673. front).
  2674.  
  2675. main proc near
  2676.   call UART_init
  2677.   call terminal
  2678.   mov  ax,4c00h
  2679.   int  21h
  2680. main endp
  2681. code ends
  2682. stack segment stack 'stack'
  2683.   dw 128 dup (?)
  2684. stack ends
  2685. end main
  2686.  
  2687. void main()
  2688. {
  2689.    UART_init();
  2690.    terminal();
  2691. }
  2692.  
  2693. Here we are. Now you've got everything you need to program simple
  2694. polling UART software.
  2695.  
  2696. You know the way. Go and add functions to check if a data set is there,
  2697. then establish a connection. Don't know how? Set DTR, wait for DSR.
  2698. If you want to send, set RTS and wait for CTS before you actually transmit
  2699. data. You don't need to store old values of the MCR: this register is
  2700. readable. Just read in the data, AND/OR the bits as required and write the
  2701. byte back.
  2702.  
  2703.  
  2704. Let us now write the interrupt-driven versions of the routines. This is going
  2705. to be a bit voluminous, so I draw the scene and leave the painting to you. If
  2706. you want to implement interrupt-driven routines in a C program use either the
  2707. inline-assembler feature or link the objects together. Of course you can also
  2708. program interrupts in C (or other languages for that matter (are there
  2709. any? :)).
  2710.  
  2711. You'll find a complete program using interrupts at the end of this chapter.
  2712.  
  2713. First thing to do is initialize the UART the same way as shown above.
  2714. But there is some more work to be done before you enable the UART
  2715. interrupt: FIRST SET THE INTERRUPT VECTOR CORRECTLY! Use function 25h of
  2716. the DOS interrupt 21h. Remember to store the old value (obtained by calling
  2717. DOS interrupt 21h function 35h) and to restore this value when exiting
  2718. to DOS again. See also the note on known bugs if you've got a 8250.
  2719.  
  2720. UART_INT      EQU 0Ch  ; for COM2 / COM4 use 0bh
  2721. UART_ONMASK   EQU 11101111b  ; for COM2 / COM4 use 11110111b
  2722. UART_OFFMASK  EQU NOT UART_ONMASK
  2723. UART_IERVAL   EQU ?   ; replace ? by any value between 0h and 0fh
  2724.                       ; (dependent on which ints you want)
  2725.                       ; DON'T SET bit 1 now! (not with this kind of service
  2726.                       ; routine, that is)
  2727. UART_OLDVEC   DD  ?
  2728.  
  2729. initialize_UART_interrupt proc near
  2730.   push ds
  2731.   push es  ; first thing is to store the old interrupt
  2732.   push bx  ; vector
  2733.   mov  ax,3500h+UART_INT
  2734.   int  21h
  2735.   mov  word ptr UART_OLDVEC,bx
  2736.   mov  word ptr UART_OLDVEC+2,es
  2737.   pop  bx
  2738.   pop  es
  2739.   push cs  ; build a pointer in DS:DX
  2740.   pop  ds
  2741.   lea  dx,interrupt_service_routine
  2742.   mov  ax,2500h+UART_INT
  2743.   int  21h ; and ask DOS to set this pointer as the new interrrupt vector
  2744.   pop  ds
  2745.   mov  dx,UART_BASEADDR+4  ; MCR
  2746.   in   al,dx
  2747.   or   al,8  ; set OUT2 bit to enable interrupts
  2748.   out  dx,al
  2749.   mov  dx,UART_BASEADDR+1  ; IER
  2750.   mov  al,UART_IERVAL  ; enable the interrupts we want
  2751.   out  dx,al
  2752.   in   al,21h  ; last thing to do is unmask the int in the ICU
  2753.   and  al,UART_ONMASK
  2754.   out  21h,al
  2755.   sti  ; and free interrupts if they have been disabled
  2756.   ret
  2757. initialize_UART_interrupt endp
  2758.  
  2759. deinitialize_UART_interrupt proc near
  2760.   push ds
  2761.   lds  dx,UART_OLDVEC
  2762.   mov  ax,2500h+UART_INT
  2763.   int  21h
  2764.   pop  ds
  2765.   in   al,21h  ; mask the UART interrupt
  2766.   or   al,UART_OFFMASK
  2767.   out  21h,al
  2768.   mov  dx,UART_BASEADDR+1
  2769.   xor  al,al
  2770.   out  dx,al   ; clear all interrupt enable bits
  2771.   mov  dx,UART_BASEADDR+4
  2772.   out  dx,al   ; and disconnect the UART from the ICU
  2773.   ret
  2774. deinitialize_UART_interrupt endp
  2775.  
  2776. Now the interrupt service routine. It has to follow several rules:
  2777. first, it MUST NOT change the contents of any register of the CPU! Then it
  2778. has to tell the ICU (did I tell you that this is the interrupt control
  2779. unit? It is also called PIC Programmable Interrupt Controller) that the
  2780. interrupt is being serviced. Next thing is test which part of the UART needs
  2781. service. Let's have a look at the following procedure:
  2782.  
  2783. interupt_service_routine proc far  ; define as near if you want to link .COM
  2784.   ;*1*                             ; it doesn't matter anyway since IRET is
  2785.   push ax                          ; always a FAR command
  2786.   push cx
  2787.   push dx
  2788.   push bx
  2789.   push sp
  2790.   push bp
  2791.   push si
  2792.   push di
  2793.   ;*2*   replace the part between *1* and *2* by pusha on an 80186+ system
  2794.   push ds
  2795.   push es
  2796.   in   al,21h
  2797.   or   al,UART_OFFMASK
  2798.   out  21h,al
  2799.   mov  al,20h    ; remember: first thing to do in interrupt routines is tell
  2800.   out  20h,al    ; the ICU about the service being done. This avoids lock-up
  2801. int_loop:
  2802.   mov  dx,UART_BASEADDR+2  ; IIR
  2803.   in   al,dx  ; check IIR info
  2804.   test al,1
  2805.   jnz  int_end
  2806.   and  ax,6  ; we're interested in bit 1 & 2 (see data sheet info)
  2807.   mov  si,ax ; this is already an index! Well-devised, huh?
  2808.   call word ptr cs:int_servicetab[si]  ; ensure a near call is used...
  2809.   jmp  int_loop
  2810. int_end:
  2811.   in   al,21h
  2812.   and  al,UART_ONMASK
  2813.   out  21h,al
  2814.   pop  es
  2815.   pop  ds
  2816.   ;*3*
  2817.   pop  di
  2818.   pop  si
  2819.   pop  bp
  2820.   pop  sp
  2821.   pop  bx
  2822.   pop  dx
  2823.   pop  cx
  2824.   pop  ax
  2825.   ;*4*   *3* - *4* can be replaced by popa on an 80186+ based system
  2826.   iret
  2827. interupt_service_routine endp
  2828.  
  2829. This is the part of the service routine that does the decisions. Now we
  2830. need four different service routines to cover all four interrupt source
  2831. possibilities (EVEN IF WE DIDN'T ENABLE THEM! Let's play this safe).
  2832.  
  2833. int_servicetab    DW int_modem, int_tx, int_rx, int_status
  2834.  
  2835. int_modem proc near
  2836.   mov  dx,UART_BASE+6  ; MSR
  2837.   in   al,dx
  2838.   ; do with the info what you like; probably just ignore it...
  2839.   ; but YOU MUST READ THE MSR or you'll lock up the interrupt!
  2840.   ret
  2841. int_modem endp
  2842.  
  2843. int_tx proc near
  2844.   ; get next byte of data from a buffer or something
  2845.   ; (remember to set the segment registers correctly!)
  2846.   ; and write it to the THR (offset 0)
  2847.   ; if no more data is to be sent, disable the THRE interrupt
  2848.   ; If the FIFOs are switched on (and you've made sure it's a 16550A!), you
  2849.   ; can write up to 16 characters
  2850.  
  2851.   ; end of data to be sent?
  2852.   ; no, jump to end_int_tx
  2853.   mov  dx,UART_BASEADDR+1
  2854.   in   al,dx
  2855.   and  al,00001101b
  2856.   out  dx,al
  2857. end_int_tx:
  2858.   ret
  2859. int_tx endp
  2860.  
  2861. int_rx proc near
  2862.   mov  dx,UART_BASEADDR
  2863.   in   al,dx
  2864.   ; do with the character what you like (best write it to a
  2865.   ; FIFO buffer [not the one of the 16550A, silly! :)])
  2866.   ; the following lines speed up FIFO mode operation
  2867.   mov  dx,UART_BASEADDR+5
  2868.   in   al,dx
  2869.   test al,1
  2870.   jnz  int_rx
  2871.   ; these lines are a cure for the well-known problem of TX interrupt
  2872.   ; lock-ups when receiving and transmitting at the same time
  2873.   test al,40h
  2874.   je   dont_unlock
  2875.   call int_tx
  2876. dont_unlock:
  2877.   ret
  2878. int_rx endp
  2879.  
  2880. int_status proc near
  2881.   mov  dx,UART_BASEADDR+5
  2882.   in   al,dx
  2883.   ; do what you like. It's just important to read the LSR
  2884.   ret
  2885. int_status endp
  2886.  
  2887. How is data sent now? Write it to a FIFO buffer (that's nothing to do with
  2888. the built-in FIFOs of the 16550!) that is read by the interrupt routine.
  2889. Then set bit 1 of the IER and check if this has already started transmission.
  2890. If not, you'll have to start it by hand (just call the int_tx routine). THIS
  2891. IS DUE TO THOSE NUTTY GUYS AT BIG BLUE WHO DECIDED TO USE EDGE TRIGGERED
  2892. INTERRUPTS INSTEAD OF PROVIDING ONE SINGLE FLIP FLOP FOR THE 8253/8254!
  2893. See the "Known Problems" section for another good method of handling the
  2894. UART interrupts that avoids all these problems.
  2895.  
  2896. This procedure can be a C function, too. It is not time-critical at all.
  2897.  
  2898.   ; copy data to buffer
  2899.  
  2900.   mov  dx,UART_BASEADDR+1  ; IER
  2901.   in   al,dx
  2902.   or   al,2  ; set bit 1
  2903.   out  dx,al
  2904.   nop
  2905.   nop  ; give the UART some time to kick the interrupt...
  2906.   nop
  2907.   mov  dx,UART_BASEADDR+5  ; LSR
  2908.   cli  ; make sure no interrupts get in-between if not already running
  2909.   in   al,dx
  2910.   test al,40h  ; is there a transmission running?
  2911.   jz   dont_crank  ; yes, so don't mess it up
  2912.   call int_tx  ; no, crank it up
  2913.   sti
  2914. dont_crank:
  2915.  
  2916. Well, that's it! Your main program has to take care of the buffers,
  2917. nothing else!
  2918.  
  2919. Remember to call deinitialize_UART_interrupt before exiting to DOS! In C,
  2920. this can easily be done by adding the function to the at-exit list with
  2921. the atexit() function. You won't have to worry about the myriads of ways
  2922. your program could terminate then.
  2923.  
  2924. For those of you who prefer learning by watching rather than learning by
  2925. doing ("lazy" is such an ignorant word :-), here's the source of a
  2926. small terminal program. It can be assembled with TASM or ML without
  2927. any change. Wire together two PCs (three-wire-connection, see the
  2928. beginning of this file) and start it on each of them. You can then
  2929. type messages on both keyboards that can be viewed on both screens.
  2930. If you press F1, a large string is being sent (but not displayed on
  2931. the sender's screen). Ctrl-X terminates the program.
  2932.  
  2933.  
  2934. ----8<--------8<--------8<--------8<--------8<--------8<--------8<----
  2935.  
  2936.   ; just a small terminal program using interrupts.
  2937.   ; It's quite dumb: it uses the BIOS for screen output
  2938.   ; and keyboard input
  2939.   ; assemble and link as .EXE (just type ml name)
  2940.   ; If you have a 16550 (not a 16550A), you may lose
  2941.   ; characters since the fifos are turned on (see "Known problems
  2942.   ; with several chips")
  2943.   ; If your BIOS locks the interrupts while scrolling (some do),
  2944.   ; you may encounter data loss at high rates.
  2945.  
  2946. model small
  2947. dosseg
  2948.  
  2949. INTNUM      equ 0Ch          ; COM1; COM2: 0Bh
  2950. OFFMASK     equ 00010000b    ; COM1; COM2: 00001000b
  2951. ONMASK      equ not OFFMASK
  2952. UART_BASE   equ 3F8h         ; COM1; COM2: 2F8h
  2953. UART_RATE   equ 12           ; 9600 bps, see table in this file
  2954. UART_PARAMS equ 00000011b    ; 8n1, see tables
  2955. RXFIFOSIZE  equ 8096         ; set this to your needs
  2956. TXFIFOSIZE  equ 8096         ; dito.
  2957.                              ; the fifos must be large on slow computers
  2958.                              ; and can be small on fast ones
  2959.                              ; These have nothing to do with the 16550A's
  2960.                              ; built-in FIFOs!
  2961.  
  2962. .data
  2963. long_text  db  0dh
  2964.     db  "This is a very long test string. It serves the purpose of",0dh
  2965.     db  "demonstrating that our interrupt-driven routines are capable",0dh
  2966.     db  "of coping with pressure situations like the one we provoke",0dh
  2967.     db  "by sending large bunches of characters in each direction at",0dh
  2968.     db  "the same time. Run this test by pressing F1 at a low data",0dh
  2969.     db  "rate and a high data rate to see why serial transmission and",0dh
  2970.     db  "reception should be programmed interrupt-driven. You won't lose",0dh
  2971.     db  "a single character as long as you don't overload the fifos, no",0dh
  2972.     db  "matter how hard you try!",0dh,0
  2973.  
  2974. ds_dgroup  macro
  2975.   mov  ax,DGROUP
  2976.   mov  ds,ax
  2977.   assume  ds:DGROUP
  2978. endm
  2979.  
  2980. ds_text  macro
  2981.   push  cs
  2982.   pop   ds
  2983.   assume  ds:_TEXT
  2984. endm
  2985.  
  2986. rx_checkwrap  macro
  2987.   local rx_nowrap
  2988.   cmp  si,offset rxfifo+RXFIFOSIZE
  2989.   jb  rx_nowrap
  2990.   lea  si,rxfifo
  2991. rx_nowrap:
  2992. endm
  2993.  
  2994. tx_checkwrap  macro
  2995.   local tx_nowrap
  2996.   cmp  si,offset txfifo+TXFIFOSIZE
  2997.   jb  tx_nowrap
  2998.   lea  si,txfifo
  2999. tx_nowrap:
  3000. endm
  3001.  
  3002. .stack 256
  3003.  
  3004. .data?
  3005. old_intptr  dd  ?
  3006. rxhead      dw  ?
  3007. rxtail      dw  ?
  3008. txhead      dw  ?
  3009. txtail      dw  ?
  3010. bitxfifo    dw  1  ; size of built-in TX fifo (1 if no fifo)
  3011. rxfifo      db  RXFIFOSIZE dup (?)
  3012. txfifo      db  TXFIFOSIZE dup (?)
  3013.  
  3014. .code
  3015. start  proc far
  3016.   call  install_interrupt_handler
  3017.   call  clear_fifos
  3018.   call  clear_screen
  3019.   call  init_UART
  3020. continue:
  3021.   call  read_RX_fifo
  3022.   call  read_keyboard
  3023.   jnc  continue
  3024.   call  clean_up
  3025.   mov  ax,4c00h
  3026.   int  21h  ; return to DOS
  3027. start  endp
  3028.  
  3029. interrupt_handler  proc far
  3030.   assume  ds:nothing,es:nothing,ss:nothing,cs:_text
  3031.   push  ax
  3032.   push  cx
  3033.   push  dx  ; first save the regs we need to change
  3034.   push  ds
  3035.   push  si
  3036.   in  al,21h
  3037.   or  al,OFFMASK   ; disarm the interrupt
  3038.   out 21h,al
  3039.   mov  al,20h  ; acknowledge interrupt
  3040.   out  20h,al
  3041.  
  3042. ih_continue:
  3043.   mov  dx,UART_BASE+2
  3044.   xor  ax,ax
  3045.   in  al,dx  ; get interrupt cause
  3046.   test  al,1  ; did the UART generate the int?
  3047.   jne  ih_sep  ; no, then it's somebody else's problem
  3048.   and  al,6  ; mask bits not needed
  3049.   mov  si,ax  ; make a pointer out of it
  3050.   call  interrupt_table[si]  ; serve this int
  3051.   jmp  ih_continue  ; and look for more things to be done
  3052. ih_sep:
  3053.  
  3054.   in  al,21h
  3055.   and al,ONMASK  ; rearm the interrupt
  3056.   out 21h,al
  3057.  
  3058.   pop  si
  3059.   pop  ds
  3060.   pop  dx  ; restore regs
  3061.   pop  cx
  3062.   pop  ax
  3063.   iret
  3064. interrupt_table  dw  int_modem,int_tx,int_rx,int_status
  3065. interrupt_handler  endp
  3066.  
  3067. int_modem  proc near
  3068.   ; just clear modem status, we are not interested in it
  3069.   mov  dx,UART_BASE+6
  3070.   in  al,dx
  3071.   ret
  3072. int_modem  endp
  3073.  
  3074. int_tx  proc near
  3075.   ds_dgroup
  3076.   ; check if there's something to be sent
  3077.   mov  si,txtail
  3078.   mov  cx,bitxfifo
  3079. itx_more:
  3080.   cmp  si,txhead
  3081.   je  itx_nothing
  3082.   cld
  3083.   lodsb
  3084.   mov  dx,UART_BASE
  3085.   out  dx,al  ; write it to the THR
  3086.   ; check for wrap-around in our fifo
  3087.   tx_checkwrap
  3088.   ; send as much bytes as the chip can take when available
  3089.   loop itx_more
  3090.   jmp  itx_dontstop
  3091. itx_nothing:
  3092.   ; no more data in the fifo, so inhibit TX interrupts
  3093.   mov  dx,UART_BASE+1
  3094.   mov  al,00000001b
  3095.   out  dx,al
  3096. itx_dontstop:
  3097.   mov  txtail,si
  3098.   ret
  3099. int_tx  endp
  3100.  
  3101. int_rx  proc near
  3102.   ds_dgroup
  3103.   mov  si,rxhead
  3104. irx_more:
  3105.   mov  dx,UART_BASE
  3106.   in  al,dx
  3107.   mov  byte ptr [si],al
  3108.   inc  si
  3109.   ; check for wrap-around
  3110.   rx_checkwrap
  3111.   ; see if there are more bytes to be read
  3112.   mov  dx,UART_BASE+5
  3113.   in  al,dx
  3114.   test  al,1
  3115.   jne  irx_more
  3116.   mov  rxhead,si
  3117.   test  al,40h  ; Sometimes when sending and receiving at the
  3118.   jne  int_tx   ; same time, TX ints get lost. This is a cure.
  3119.   ret
  3120. int_rx  endp
  3121.  
  3122. int_status  proc near
  3123.   ; just clear the status ("this trivial task is left as an exercise
  3124.   ; to the student")
  3125.   mov  dx,UART_BASE+5
  3126.   in  al,dx
  3127.   ret
  3128. int_status  endp
  3129.  
  3130. read_RX_fifo  proc near
  3131.   ; see if there are bytes to be read from the fifo
  3132.   ; we read a maximum of 16 bytes, then return in order
  3133.   ; not to break keyboard control
  3134.   ds_dgroup
  3135.   cld
  3136.   mov  cx,16
  3137.   mov  si,rxtail
  3138. rx_more:
  3139.   cmp  si,rxhead
  3140.   je  rx_nodata
  3141.   lodsb
  3142.   call  output_char
  3143.   ; check for wrap-around
  3144.   rx_checkwrap
  3145.   loop  rx_more
  3146. rx_nodata:
  3147.   mov  rxtail,si
  3148.   ret
  3149. read_RX_fifo  endp
  3150.  
  3151. read_keyboard  proc near
  3152.   ds_dgroup
  3153.   ; check for keys pressed
  3154.   mov  ah,1
  3155.   int  16h
  3156.   je  rk_nokey
  3157.   xor  ax,ax
  3158.   int  16h
  3159.   cmp  ax,2d18h  ; is it Ctrl-X?
  3160.   stc
  3161.   je  rk_ctrlx
  3162.   cmp  ax,3b00h  ; is it F1?
  3163.   jne  rk_nf1
  3164.   lea  si,long_text  ; send a very long test string
  3165.   call  send_string
  3166.   jmp  rk_nokey
  3167. rk_nf1:
  3168.   ; echo the character to the screen
  3169.   call  output_char
  3170.  
  3171.   call  send_char
  3172. rk_nokey:
  3173.   clc
  3174. rk_ctrlx:
  3175.   ret
  3176. read_keyboard  endp
  3177.  
  3178.  
  3179. install_interrupt_handler  proc near
  3180.   ds_dgroup
  3181.   ; install interrupt handler first
  3182.   mov  ax,3500h+INTNUM
  3183.   int  21h
  3184.   mov  word ptr old_intptr,bx
  3185.   mov  word ptr old_intptr+2,es
  3186.   mov  ax,2500h+INTNUM
  3187.   ds_text
  3188.   lea  dx,interrupt_handler
  3189.   int  21h
  3190.   ret
  3191. install_interrupt_handler  endp
  3192.  
  3193. clear_fifos  proc near
  3194.   ds_dgroup
  3195.   ; clear fifos (not those in the 16550A, but ours)
  3196.   lea  ax,rxfifo
  3197.   mov  rxhead,ax
  3198.   mov  rxtail,ax
  3199.   lea  ax,txfifo
  3200.   mov  txhead,ax
  3201.   mov  txtail,ax
  3202.   ret
  3203. clear_fifos  endp
  3204.  
  3205. init_UART  proc near
  3206.   ; initialize the UART
  3207.   mov  dx,UART_BASE+3
  3208.   mov  al,80h
  3209.   out  dx,al  ; make DL register accessible
  3210.   mov  dx,UART_BASE
  3211.   mov  ax,UART_RATE
  3212.   out  dx,ax  ; write bps rate divisor
  3213.   mov  dx,UART_BASE+3
  3214.   mov  al,UART_PARAMS
  3215.   out  dx,al  ; write parameters
  3216.   
  3217.   ; is it a 16550A?
  3218.   mov  dx,UART_BASE+2
  3219.   in   al,dx
  3220.   and  al,11000000b
  3221.   cmp  al,11000000b
  3222.   jne  iu_nofifos
  3223.   mov  bitxfifo,16
  3224.   mov  dx,UART_BASE+2
  3225.   mov  al,11000111b
  3226.   out  dx,al  ; clear and enable the fifos if they exist
  3227. iu_nofifos:
  3228.   mov  dx,UART_BASE+1
  3229.   mov  al,00000001b  ; allow RX interrupts
  3230.   out  dx,al
  3231.   mov  dx,UART_BASE
  3232.   in  al,dx  ; clear receiver
  3233.   mov  dx,UART_BASE+5
  3234.   in  al,dx  ; clear line status
  3235.   inc  dx
  3236.   in  al,dx  ; clear modem status
  3237.   ; free interrupt in the ICU
  3238.   in  al,21h
  3239.   and  al,ONMASK
  3240.   out  21h,al
  3241.   ; and enable ints from the UART
  3242.   mov  dx,UART_BASE+4
  3243.   mov  al,00001000b
  3244.   out  dx,al
  3245.   ret
  3246. init_UART  endp
  3247.  
  3248. clear_screen  proc near
  3249.   mov  ah,0fh  ; allow all kinds of video adapters to be used
  3250.   int  10h
  3251.   cmp  al,7
  3252.   je  cs_1
  3253.   mov  al,3
  3254. cs_1:
  3255.   xor  ah,ah
  3256.   int  10h
  3257.   ret
  3258. clear_screen  endp
  3259.  
  3260. clean_up  proc near
  3261.   ds_dgroup
  3262.   ; lock int in the ICU
  3263.   in  al,21h
  3264.   or  al,OFFMASK
  3265.   out  21h,al
  3266.   xor  ax,ax
  3267.   mov  dx,UART_BASE+4  ; disconnect the UART from the int line
  3268.   out  dx,al
  3269.   mov  dx,UART_BASE+1  ; disable UART ints
  3270.   out  dx,al
  3271.   mov  dx,UART_BASE+2  ; disable the fifos (old software relies on it)
  3272.   out  dx,al
  3273.   ; restore int vector
  3274.   lds  dx,old_intptr
  3275.   mov  ax,2500h+INTNUM
  3276.   int  21h
  3277.   ret
  3278. clean_up  endp
  3279.  
  3280. output_char  proc near
  3281.   push  si
  3282.   push  ax
  3283. oc_cr:
  3284.   push  ax
  3285.   mov  ah,0eh  ; output character using BIOS TTY
  3286.   int  10h     ; it's your task to improve this
  3287.   pop  ax
  3288.   cmp  al,0dh  ; add LF after CR; change it if you don't like it
  3289.   mov  al,0ah
  3290.   je  oc_cr
  3291.   pop  ax
  3292.   pop  si
  3293.   ret
  3294. output_char  endp
  3295.  
  3296. send_char proc near
  3297.   push  si
  3298.   push  ax
  3299.   ds_dgroup
  3300.   pop  ax
  3301.   mov  si,txhead
  3302.   mov  byte ptr [si],al
  3303.   inc  si
  3304.   ; check for wrap-around
  3305.   tx_checkwrap
  3306.   mov  txhead,si
  3307.   ; test if the interrupt is running at the moment
  3308.   mov  dx,UART_BASE+5
  3309.   in  al,dx
  3310.   test  al,40h
  3311.   je  sc_dontcrank
  3312.   ; crank it up
  3313.   ; note that this might not work with some very old 8250s
  3314.   mov  dx,UART_BASE+1
  3315.   mov  al,00000011b
  3316.   out  dx,al
  3317. sc_dontcrank:
  3318.   pop  si
  3319.   ret
  3320. send_char  endp
  3321.  
  3322. send_string  proc near
  3323.   ; sends a null-terminated string pointed at by DS:SI
  3324.   ds_dgroup
  3325.   cld
  3326. ss_more:
  3327.   lodsb
  3328.   or  al,al
  3329.   je  ss_end
  3330.   call send_char
  3331.   jmp  ss_more
  3332. ss_end:
  3333.   ret
  3334. send_string  endp
  3335.  
  3336. end start
  3337.  
  3338. ---->8-------->8-------->8-------->8-------->8-------->8-------->8----
  3339.  
  3340. Stephen Warner provided me with an assembly source of a TSR program that
  3341. puts every character it receives from the serial port in the keyboard
  3342. buffer. This allows to remotely control nearly every other program; it works
  3343. with ATs and higher computers only. I decided not to add it to this file
  3344. since it doesn't show anything about programming the serial port that's
  3345. not already covered by other listings in this file. If you are interested
  3346. in it, you can obtain it from the ftp archive (it is named
  3347. "The_Serial_Port.more01"). See the beginning of this file.
  3348.  
  3349. One more thing: always remember that at 115,200 bps there is service to
  3350. be done at least every 85 microseconds! On an XT with 4.77 MHz this is
  3351. about 40 assembler commands! So forget about servicing the serial port at
  3352. this rate in high-level languages on such computers. Using a 16550A is
  3353. strongly recommended at high rates (turn on FIFOs) but not necessary
  3354. with otherwise decent hardware.
  3355.  
  3356. The interrupt service routines can be accelerated by not pushing that
  3357. much registers, and pusha and popa are fast replacements for 8 other
  3358. pushs/pops.
  3359.  
  3360.  
  3361. Well, that's the end of my short :-) summary. Don't hesitate to correct
  3362. me if I'm wrong (preferably via email) in the details (I hope not, but it's
  3363. not easy to find typographical and other errors in a text that you've
  3364. written yourself). And please help me to complete this file! If you've got
  3365. anything to add, email it to me and I'll spread it round.
  3366.  
  3367. I've received a lot of feedback from you, and I'd like to thank everybody
  3368. who encouraged me to continue the work on this file.
  3369.  
  3370.  
  3371. Yours
  3372.  
  3373.       Chris
  3374.  
  3375. P.S. You surely have noticed that English isn't my native tongue... so please
  3376. excuse everything that's not pleasant for the eye, or, even better, tell me
  3377. about it! It shouldn't be an ordeal though, at least some have assured me
  3378. so...
  3379.  
  3380.  
  3381.  
  3382. --
  3383. Chris Blum <chris@phil.uni-sb.de>  http://www.phil.uni-sb.de/~chris/
  3384.  
  3385.