COMM.CPP
上传用户:xr_qian
上传日期:2007-01-05
资源大小:443k
文件大小:31k
源码类别:

通讯/手机编程

开发平台:

DOS

  1. // ******************************************************************** //
  2. //                                                                      //
  3. //      COMM.CPP                                                        //
  4. //      Copyright (c) 1993, Michael Holmes and Bob Flanders             //
  5. //      C++ Communication Utilities                                     //
  6. //                                                                      //
  7. //      Chapter 7: Receiving a FAX                                      //
  8. //      Last changed in chapter 7                                       //
  9. //                                                                      //
  10. //      This file contains the functions to implement the basic         //
  11. //      communications class and facilities.  Each instance of the      //
  12. //      Comm class will control a single communications port.           //
  13. //                                                                      //
  14. // ******************************************************************** //
  15. class Comm
  16.     {
  17.     public:
  18.         Comm(int b,                         // define a comm instance
  19.              int i,                         //   base addr, interrupt
  20.              int d,                         //   baud rate divisor
  21.              int l,                         //   line control setting
  22.              int fc = 0,                    //   flow control flag
  23.              UINT si = 3200,                //   input queue size
  24.              UINT so = 1500);               //   and output queue size
  25.         UINT Read(char *c,                  // read a character from queue
  26.                   char *m,                  // ..and get modem status reg
  27.                   char *l),                 //   and line status register
  28.              Set8n(void),                   // set 8 data bits, no parity
  29.              ICount(void),                  // get depth of input queue
  30.              OCount(void),                  // ..or output queue
  31.              IFree(void),                   // free space in input queue
  32.              OFree(void);                   // ..or output queue
  33.         int  Modem(void),                   // rtn modem status register
  34.              ModemChanged(void),            // rtn TRUE if msr changed
  35.              IFlow(void),                   // rtn input flow ctrl status
  36.              IEmpty(void),                  // rtn TRUE if input queue
  37.              OEmpty(void);                  // ..or output queue empty
  38.         long GetSpeed(void);                // rtn current speed in bps
  39.         void SetSpeed(int d),               // set up port's divisor
  40.              SetBPS(long s),                // set up port's speed
  41.              SetLine(int l),                // ..and line control register
  42.              Write(int c),                  // write a character
  43.              Write(char *s),                // ..or a string of characters
  44.              Write(char *s, int l),         // ..or a block of characters
  45.              IClear(void),                  // clear input queue
  46.              OClear(void),                  // ..and output queue
  47.              DTR(long t = 1500L),           // lower DTR temporarily
  48.              RTS(int),                      // RTS signal control
  49.              IntRoutine(void);              // interrupt service routine
  50.        ~Comm();                             // destructor
  51.     private:
  52.         UINT base,                          // base port address
  53.              irq,                           // interrupt number
  54.              divisor,                       // baud rate divisor
  55.              line,                          // initial line control
  56.              i_size,                        // input buffer size
  57.              o_size,                        // output buffer size
  58.              i_start,                       // flow ctl restart limit
  59.              i_stop,                        // ..and upper stop limit
  60.              i_count,                       // characters in input queue
  61.              o_count,                       // ..and output queue
  62.              Deque(void);                   // deque an output queue char
  63.         char *i_buf,                        // input buffer
  64.              *i_get,                        // ..and nxt user get location
  65.              *i_put,                        // ..and nxt comm put location
  66.              *i_limit,                      // ..and last location
  67.              *i_last,                       // ..and last i_put location
  68.              i_of,                          // ..and input overflow flag
  69.              *o_buf,                        // output buffer
  70.              *o_get,                        // ..and nxt comm get location
  71.              *o_put,                        // ..and nxt user put location
  72.              *o_limit,                      // ..and last location
  73.              msr_changed,                   // msr changed flag
  74.              int_msr,                       // last interrupt msr
  75.              int_lsr,                       // ..and last interrupt lsr
  76.              fifo,                          // 16550 flag
  77.              flow,                          // flow control enable flag
  78.              o_flow,                        // output flow controlled flag
  79.              i_flow,                        // input flow controlled flag
  80.              empty_trans;                   // empty transmitter flag
  81.         void InstallInt(void),              // install interrupt svc rtn
  82.              DeInstallInt(void),            // de-install interrupt rtn
  83.              SetLimits(void),               // set up flow ctl limits
  84.              CheckFifo(void),               // set up fifo flags
  85.              Queue(int c,                   // queue char to input queue
  86.                    int m,                   //   saving modem status reg
  87.                    int l),                  //   and line status register
  88.              interrupt (*old_comm)(...);    // old comm interrupt pointer
  89.     };
  90. extern
  91. Comm   *comm;                               // current Comm instance
  92. void    interrupt far comm_int(...);        // comm interrupt routine
  93. /* ******************************************************************** *
  94.  *
  95.  *  Comm -- define communications port instance
  96.  *
  97.  * ******************************************************************** */
  98. Comm::Comm(int b,                           // comm port base address
  99.            int i,                           // interrupt number
  100.            int d,                           // baud rate divisor
  101.            int l,                           // line control setting
  102.            int fc,                          // flow control flag
  103.            UINT si,                         // input queue size
  104.            UINT so)                         // output queue size
  105. {
  106. UINT    max_size = 64535U / 3;              // max number of input chars
  107. base = b;                                   // set up instance base addr
  108. irq = i;                                    // ..interrupt request
  109. o_size = so;                                // ..output buffer size
  110. flow = fc;                                  // ..flow control flag
  111. CheckFifo();                                // ..fifo flag if available
  112. SetSpeed(d);                                // ..line speed
  113. SetLine(l);                                 // ..line format
  114. if (si < 512)                               // q. less than .5k of buffer?
  115.     si = 512;                               // a. yes .. set to minimum
  116. if (si > max_size)                          // q. greater than maximum?
  117.     si = max_size;                          // a. yes .. set to max size
  118. if (so < 256)                               // q. really small output buf?
  119.     so = 256;                               // a. yes .. set to minimum
  120. i_size = si;                                // save input buffer size
  121. empty_trans = 1;                            // ..set empty transmitter flag
  122. msr_changed = 1;                            // ..set msr changed flag
  123. o_flow = i_flow = 0;                        // ..clear active flags
  124. o_count = i_count = 0;                      // ..and current queue counts
  125. i_buf = i_get = i_put =                     // allocate input buffer
  126.             new char[i_size * 3];           // ..for data, lsr and msr
  127. i_limit = i_buf + (i_size - 1) * 3;         // ..set limit address
  128. memset(i_buf, 0, i_size * 3);               // ..and clear area to nulls
  129. o_buf = o_get = o_put = new char[o_size];   // allocate output buffer
  130. o_limit = o_buf + o_size - 1;               // ..set limit address
  131. memset(o_buf, 0, o_size);                   // ..and clear area to nulls
  132. SetLimits();                                // set up flow ctl limits
  133. InstallInt();                               // ..and interrupt routine
  134. int_msr = IN(MSR);                          // set up initial MSR
  135. }
  136. /* ******************************************************************** *
  137.  *
  138.  *  SetLimits -- set up receive buffer flow control limits
  139.  *
  140.  *  This routine sets up the flow control limits for receive
  141.  *  operations.  Flow control will be asserted when the buffer
  142.  *  reaches a point when there is not enough room to receive
  143.  *  a second worth of data in the input buffer.  Flow control will
  144.  *  be de-asserted when 50% of the upper limit is read by the
  145.  *  application.
  146.  *
  147.  * ******************************************************************** */
  148. void    Comm::SetLimits(void)
  149. {
  150. i_stop = (UINT) (115200L / 10) / divisor;   // get 1 second in characters
  151. if (i_stop > i_size)                        // q. limit too high?
  152.     i_stop = i_size / 2;                    // a. yes .. set at half
  153.  else
  154.     i_stop = i_size - i_stop;               // else .. set limit point
  155. i_start = i_stop / 2;                       // set restart point at 50%
  156. }
  157. /* ******************************************************************** *
  158.  *
  159.  *  CheckFifo -- if UART is a 16550, set FIFO variable to true
  160.  *
  161.  * ******************************************************************** */
  162. void    Comm::CheckFifo(void)
  163. {
  164. fifo = 0;                                   // assume standard uart
  165. OUT(FCR, 0xcf);                             // try to enable FIFOs
  166. if ((IN(IIR) & 0xc0) != 0xc0)               // q. FIFO bits found?
  167.     return;                                 // a. no .. just return
  168. OUT(FCR, 0);                                // turn off FIFOs
  169. fifo = 1;                                   // set fifo available flag
  170. }
  171. /* ******************************************************************** *
  172.  *
  173.  *  SetSpeed -- set up port baud rate divisor
  174.  *
  175.  * ******************************************************************** */
  176. void    Comm::SetSpeed(int d)               // baud rate divisor
  177. {
  178. divisor = d;                                // save divisor for later
  179. OUT(IER, 0);                                // clear interrupts enable
  180. if (fifo)                                   // q. is UART a 16550 chip?
  181.     OUT(FCR, FCR_16550);                    // a. yes .. enable fifo
  182. IN(LSR);                                    // read/reset line status reg
  183. IN(MSR);                                    // ..and modem status register
  184. IN(IIR);                                    // ..and interrupt id register
  185. IN(RBR);                                    // ..and receive buffer reg
  186. __asm   cli                                 // stop interrupts
  187. OUT(LCR, IN(LCR) | LCR_DLAB);               // set divisor latch bit
  188. OUT(DLM, d >> 8);                           // out msb portion of divisor
  189. OUT(DLL, d & 0xff);                         // ..then the lsb portion
  190. OUT(LCR, IN(LCR) & ~LCR_DLAB);              // clear divisor latch bit
  191. OUT(MCR, MCR_DO);                           // enable DTR, OUT2 and RTS
  192. __asm   sti                                 // ..and interrupts
  193. OUT(IER, IER_RBF | IER_TBE | IER_MSI);      // then enable UART interrupts
  194. }
  195. /* ******************************************************************** *
  196.  *
  197.  *  SetBPS -- set port's speed
  198.  *
  199.  * ******************************************************************** */
  200. void    Comm::SetBPS(long s)                // speed in BPS
  201. {
  202. SetSpeed((int)(115200L / s));               // calc and set divisor
  203. }
  204. /* ******************************************************************** *
  205.  *
  206.  *  GetSpeed -- retrieve current port speed
  207.  *
  208.  * ******************************************************************** */
  209. long   Comm::GetSpeed(void)
  210. {
  211. return((long) (115200L / (long) divisor));  // return current speed
  212. }
  213. /* ******************************************************************** *
  214.  *
  215.  *  SetLine -- set up port's line control register
  216.  *
  217.  * ******************************************************************** */
  218. void    Comm::SetLine(int l)                // new line control setting
  219. {
  220. line = l & ~LCR_DLAB;                       // save new value in instance
  221. OUT(LCR, line);                             // ..and write new LCR
  222. }
  223. /* ******************************************************************** *
  224.  *
  225.  *  Set8n -- set 8 data bits, no parity
  226.  *
  227.  * ******************************************************************** */
  228. UINT    Comm::Set8n(void)
  229. {
  230. UINT    oldline;                            // old LCR value
  231. oldline = IN(LCR);                          // get the current LCR value
  232. line = ((oldline & LCR_STOP) | LCR_WLEN);   // setup 8 databits, no parity
  233. OUT(LCR, line);                             // ..and write new LCR
  234. return(oldline);                            // return old LCR value
  235. }
  236. /* ******************************************************************** *
  237.  *
  238.  *  InstallInt -- install interrupt service routine
  239.  *
  240.  * ******************************************************************** */
  241. void    Comm::InstallInt(void)
  242. {
  243. int     mask;                               // interrupt mask
  244. old_comm = getvect(irq + 8);                // save old comm interrupt rtn
  245. comm = this;                                // ..save instance address
  246. setvect(irq + 8, comm_int);                 // ..establish new routine
  247. mask = inportb(I8259M);                     // get current interrupt mask
  248. mask &= ~(1 << irq);                        // determine new mask
  249. outportb(I8259M, mask);                     // ..and put in place
  250. }
  251. /* ******************************************************************** *
  252.  *
  253.  *  DeInstallInt -- de-install interrupt service routine
  254.  *
  255.  * ******************************************************************** */
  256. void    Comm::DeInstallInt(void)
  257. {
  258. int     mask;                               // interrupt mask
  259. OUT(IER, 0);                                // disable UART interrupt
  260. OUT(FCR, 0);                                // ..and fifo, if available
  261. setvect(irq + 8, old_comm);                 // re-establish old comm rtn
  262. mask = inportb(I8259M);                     // get current interrupt mask
  263. mask |= (1 << irq);                         // determine new mask
  264. outportb(I8259M, mask);                     // ..and turn off comm int
  265. }
  266. /* ******************************************************************** *
  267.  *
  268.  *  ModemChanged -- returns TRUE if the modem status register changed
  269.  *
  270.  * ******************************************************************** */
  271. int     Comm::ModemChanged(void)
  272. {
  273. int     rtn;                                // return value
  274. rtn = msr_changed;                          // get current status
  275. msr_changed = 0;                            // ..and clear flag
  276. return(rtn);                                // ..and return current status
  277. }
  278. /* ******************************************************************** *
  279.  *
  280.  *  Modem -- returns the modem status register
  281.  *
  282.  * ******************************************************************** */
  283. int     Comm::Modem(void)
  284. {
  285. return(int_msr);                            // return last modem status
  286. }
  287. /* ******************************************************************** *
  288.  *
  289.  *  IFlow -- return status of input flow control
  290.  *
  291.  * ******************************************************************** */
  292. int     Comm::IFlow(void)
  293. {
  294. return(i_flow);                             // rtn TRUE if input flow
  295.                                             // ..has been restricted
  296. }
  297. /* ******************************************************************** **
  298.  *
  299.  *  Read -- read a character, the msr and lsr from the port's input queue
  300.  *
  301.  *  Returns: -1 = input queue was empty
  302.  *            0 = character returned
  303.  *            n = number of characters overflowed buffer
  304.  *
  305.  * ******************************************************************** */
  306. UINT    Comm::Read(char *c,                 // queued character
  307.                    char *m,                 // modem status register
  308.                    char *l)                 // line status register
  309. {
  310. if (i_count == 0)                           // q. input queue empty?
  311.     return(-1);                             // a. yes .. return w/err code
  312. *c = *i_get++;                              // get char from input queue
  313. *m = *i_get++;                              // ..then get modem status
  314. *l = *i_get++;                              // ..then get line status
  315. i_count--;                                  // ..finally decrement count
  316. if (i_get > i_limit)                        // q. reached end of buffer?
  317.     i_get = i_buf;                          // a. yes .. set to beginning
  318. if (i_flow && (ICount() <= i_start))        // q. port need restarting?
  319.     RTS(1);                                 // a. yes .. raise RTS line
  320. return(((UCHAR) *l == 0xff) ?               // return with character or
  321.                     ((*m << 8) + *c) : 0);  // ..with overflow count
  322.                                             // ..based on lsr flag
  323. }
  324. /* ******************************************************************** **
  325.  *
  326.  *  IEmpty -- return TRUE if input queue is empty
  327.  *
  328.  * ******************************************************************** */
  329. int     Comm::IEmpty(void)
  330. {
  331. return((i_count == 0) &&                    // TRUE if queue empty
  332.             ((UCHAR) i_put[2] != 0xff));    // ..and not in overflow
  333. }
  334. /* ******************************************************************** **
  335.  *
  336.  *  OEmpty -- return TRUE if output queue empty
  337.  *
  338.  * ******************************************************************** */
  339. int     Comm::OEmpty(void)
  340. {
  341. return(o_count == 0);                       // TRUE if queue empty
  342. }
  343. /* ******************************************************************** **
  344.  *
  345.  *  ICount -- get depth of the input queue
  346.  *
  347.  * ******************************************************************** */
  348. UINT    Comm::ICount(void)
  349. {
  350. return(i_count);                            // return nbr in queue
  351. }
  352. /* ******************************************************************** **
  353.  *
  354.  *  OCount -- get depth of the output queue
  355.  *
  356.  * ******************************************************************** */
  357. UINT    Comm::OCount(void)
  358. {
  359. return(o_count);                            // return nbr in queue
  360. }
  361. /* ******************************************************************** **
  362.  *
  363.  *  IFree -- get free space in input queue
  364.  *
  365.  * ******************************************************************** */
  366. UINT    Comm::IFree(void)
  367. {
  368. return(i_size - i_count);                   // buffer size less in-use
  369. }
  370. /* ******************************************************************** **
  371.  *
  372.  *  OFree -- get free space in output queue
  373.  *
  374.  * ******************************************************************** */
  375. UINT    Comm::OFree(void)
  376. {
  377. return(o_size - o_count);                   // buffer size less in-use
  378. }
  379. /* ******************************************************************** **
  380.  *
  381.  *  Write -- write a character to the output queue
  382.  *
  383.  * ******************************************************************** */
  384. void    Comm::Write(int c)                  // character to queue up
  385. {
  386. while (NOT OFree())                         // q. room in output queue?
  387.     ;                                       // a. no .. wait a bit
  388. *o_put++ = c;                               // put char into output queue
  389. if (empty_trans)                            // q. pump need priming?
  390.     {                                       // a. yes .. try to do output
  391.     empty_trans = 0;                        // clear empty tranmitter flag
  392.     o_count++;                              // ..and count character
  393.     if ((NOT flow || IN(MSR) & MSR_CTS)     // q. output flow satisfied?
  394.                 && (c = Deque()) != -1)     // ..and queue not empty?
  395.         OUT(THR, c);                        // a. yes .. send char to port
  396.     }
  397.  else
  398.     o_count++;                              // else .. count characters
  399. if (o_put > o_limit)                        // q. reach end of buffer?
  400.     o_put = o_buf;                          // a. yes .. set to beginning
  401. }
  402. /* ******************************************************************** *
  403.  *
  404.  *  Write -- write a string of characters to output queue
  405.  *
  406.  * ******************************************************************** */
  407. void    Comm::Write(char *s)                // string of chars to output
  408. {
  409. for (; *s;)                                 // for each char in the string
  410.     Write(*s++);                            // write to the output queue
  411. }
  412. /* ******************************************************************** *
  413.  *
  414.  *  Write -- write a block of characters to output queue
  415.  *
  416.  * ******************************************************************** */
  417. void    Comm::Write(char *s,                // block of chars to output
  418.                     int  l)                 // length of block
  419. {
  420. for (; l--;)                                // for each char in the block
  421.     Write(*s++);                            // write to the output queue
  422. }
  423. /* ******************************************************************** **
  424.  *
  425.  *    IClear -- clear input queue of unread characters
  426.  *
  427.  * ******************************************************************** */
  428. void    Comm::IClear(void)
  429. {
  430. __asm   cli                                 // stop interrupts
  431. i_get = i_put = i_buf;                      // reset buffer pointers
  432. i_count = 0;                                // ..and queue count
  433. __asm   sti                                 // ..and re-enable interrupts
  434. }
  435. /* ******************************************************************** **
  436.  *
  437.  *    OClear -- clear output queue of unsent characters
  438.  *
  439.  * ******************************************************************** */
  440. void    Comm::OClear(void)
  441. {
  442. __asm   cli                                 // stop interrupts
  443. o_get = o_put = o_buf;                      // reset buffer pointers
  444. o_count = 0;                                // ..and queue count
  445. __asm   sti                                 // ..and re-enable interrupts
  446. }
  447. /* ******************************************************************** *
  448.  *
  449.  *  Queue -- put a character into the input queue
  450.  *
  451.  * ******************************************************************** */
  452. void    Comm::Queue(int c,                  // character to store
  453.                    int m,                   // modem status register
  454.                    int l)                   // line status register
  455. {
  456. if (flow && (ICount() >= i_stop) &&         // q. flow control needed?
  457.             NOT i_flow)                     // ..and not already on
  458.     RTS(0);                                 // a. yes .. clear RTS line
  459. switch (IFree())                            // based on avail queue space
  460.     {
  461.     case 0:                                 // full input queue
  462.         if (i_of)                           // q. in overflow?
  463.             {                               // a. yes .. count lost chars
  464.             if (*(UINT *) i_last < 65534U)  // q. within lost count range?
  465.                 (*(UINT *) i_last)++;       // a. yes .. tally another one
  466.             }
  467.          else
  468.             {
  469.             i_of = 1;                       // set overflow flag
  470.             *(UINT *) i_last = 2;           // init counter to 2
  471.             i_last[2] = 0xff;               // ..and set error flag in lsr
  472.             }
  473.         break;                              // ..and return to caller
  474.     case 1:                                 // almost full
  475.         i_last = i_put;                     // save last saved addr
  476.         i_of = 0;                           // clear overflow flag
  477.     default:                                // from empty to almost full
  478.         i_count++;                          // count characters in queue
  479.         *i_put++ = c;                       // save character in queue
  480.         *i_put++ = m;                       // ..and modem status register
  481.         *i_put++ = l;                       // ..and line status register
  482.         if (i_put > i_limit)                // q. reach end of buffer?
  483.             i_put = i_buf;                  // a. yes .. set to beginning
  484.     }
  485. }
  486. /* ******************************************************************** *
  487.  *
  488.  *  Deque -- get a character from the output queue
  489.  *
  490.  * ******************************************************************** */
  491. UINT    Comm::Deque(void)
  492. {
  493. char    c;                                  // work character
  494. if (o_count == 0)                           // q. output queue empty?
  495.     return(-1);                             // a. yes .. rtn empty handed
  496. c = *o_get++;                               // get char from output queue
  497. o_count--;                                  // show character being removed
  498. if (o_get > o_limit)                        // q. reached end of buffer?
  499.     o_get = o_buf;                          // a. yes .. set to beginning
  500. return(c & 0xff);                           // ..and rtn with char to send
  501. }
  502. /* ******************************************************************** **
  503.  *
  504.  *    ~Comm -- destructor
  505.  *
  506.  * ******************************************************************** */
  507. Comm::~Comm(void)
  508. {
  509. OUT(MCR, 0);                                // take down DTR and RTS
  510. DeInstallInt();                             // remove interrupt service
  511. delete i_buf;                               // free input
  512. delete o_buf;                               // ..and output queues
  513. }
  514. /* ******************************************************************** *
  515.  *
  516.  *  DTR -- cycle DTR modem signal
  517.  *
  518.  * ******************************************************************** */
  519. void    Comm::DTR(long t)                   // time to hold DTR low
  520. {
  521. OUT(MCR, MCR_DO & ~MCR_DTR);                // set off DTR control line
  522. wait_ms(t);                                 // wait a little bit
  523. OUT(MCR, MCR_DO);                           // ..and restore DTR
  524. }
  525. /* ******************************************************************** *
  526.  *
  527.  *  RTS -- control RTS modem signal
  528.  *
  529.  * ******************************************************************** */
  530. void    Comm::RTS(int f)                    // RTS enable/disable flag
  531. {
  532. OUT(MCR, MCR_DO - (f ? 0 : MCR_RTS));       // set mcr register
  533. i_flow = NOT f;                             // ..and set flow ctl'd flag
  534. }
  535. /* ******************************************************************** **
  536.  *
  537.  *    IntRoutine -- communications port interrupt service routine
  538.  *
  539.  * ******************************************************************** */
  540. void    Comm::IntRoutine(void)
  541. {
  542. int     c,                                  // output character
  543.         cnt,                                // loop counter
  544.         first_cycle;                        // first cycle flag
  545. char    iir,                                // interrupt id register
  546.         lsr;                                // working line status reg
  547. while (((iir = IN(IIR)) & IIR_PEND) == 0)   // while there is work to do
  548.     {
  549.     switch (iir & IIR_II)                   // handle each interrupt
  550.         {
  551.         case IIR_MSI:                       // modem status interrupt
  552.             msr_changed = 1;                // set msr changed flag
  553.             if ((int_msr = IN(MSR)) &       // q. modem status register
  554.                         MSR_CTS)            // ..ready for transmits?
  555.                 {
  556.                 if (o_flow ||               // q. flow controlled?
  557.                         IN(LSR) & LSR_THRE) // ..or transmitter empty?
  558.                     {
  559.                     o_flow = 0;             // a. yes .. clear flag
  560.                     if ((c = Deque()) == -1)// q. output queue empty?
  561.                         empty_trans = 1;    // a. yes .. set flag
  562.                      else
  563.                         OUT(THR, c);        // else .. put out a character
  564.                     }
  565.                 }
  566.             continue;                       // ..and check next interrupt
  567.         case IIR_LSI:                       // line status interrupt
  568.             int_lsr = IN(LSR);              // read line status register
  569.             continue;                       // ..and check again
  570.         case IIR_TBE:                       // transmitter buffer empty
  571.             cnt = fifo ? 15 : 1;            // set up output fifo size
  572.             first_cycle = 1;                // ..and first cycle flag
  573.             for (; cnt--;)                  // loop outputing characters
  574.                 {
  575.                 if (flow &&                 // q. flow control enabled
  576.                     NOT (IN(MSR) & MSR_CTS))// ..and receiver not ready?
  577.                     {
  578.                     o_flow = first_cycle;   // a. yes .. show flow ctl'd
  579.                                             // ..if nothing went out
  580.                     break;                  // ..and check next interrupt
  581.                     }
  582.                 if ((c = Deque()) == -1)    // q. output queue empty?
  583.                     {
  584.                     empty_trans = 1;        // a. yes .. set flag
  585.                     break;                  // ..and exit this loop
  586.                     }
  587.                 OUT(THR, c);                // put out another character
  588.                 first_cycle = 0;            // ..and clear flag
  589.                 }
  590.             continue;                       // ..and check again
  591.         case IIR_RBF:                       // receiver buffer full
  592.             while ((lsr = IN(LSR)) & LSR_DR)// while data is available
  593.                 Queue(IN(RBR), int_msr,     // ..get and store
  594.                         lsr);               // ..in the input queue
  595.             continue;                       // check for next interrupt
  596.         }
  597.     }
  598. __asm   mov     al, EOI                     // al = end of interrupt cmd
  599. __asm   out     I8259, al                   // send EOI to int controller
  600. }
  601. /* ******************************************************************** *
  602.  *
  603.  *  comm_int() -- communications port interrupt service routine header
  604.  *
  605.  * ******************************************************************** */
  606. #pragma option -O2-b-e                      // no global reg allocation
  607.                                             // ..or dead code elimination
  608. void    interrupt far comm_int(...)
  609. {
  610. __asm   sti                                 // re-enable interrupts
  611. comm->IntRoutine();                         // use object's interrupt rtn
  612. }