i8250Sio.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:23k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* i8250Sio.c - I8250 serial driver */
  2. /* Copyright 1984-2000 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01k,05dec00,dat  merge from sustaining branch to tor2_0_x
  8. 01j,20nov00,pai  enabled receiver buffer full interrupt from UART in
  9.                  i8250Startup() (SPR 32443).
  10. 01i,06oct99,pai  account for PC87307 hardware anomaly in i8250Int() (SPR 26117).
  11. 01h,26oct98,dbt  call i8250InitChannel() in i8250HrdInit() rather than in
  12.                  i8250ModeSet(). (SPR #22349).
  13. 01g,23may97,db   added hardware options and modem control(SPR #7542).
  14.                  fixed bugs reported in SPRs 9404, 9223.
  15. 01f,12oct95,dgf  added bauds > 38k
  16. 01e,03aug95,myz  fixed the warning messages
  17. 01d,12jul95,myz  fixed the baud rate problem.
  18. 01c,20jun95,ms   fixed comments for mangen.
  19. 01b,15jun95,ms   updated for new driver structure
  20. 01a,15mar95,myz  written (using i8250Serial.c + the VxMon polled driver).
  21. */
  22. /*
  23. DESCRIPTION
  24. This is the driver for the Intel 8250 UART Chip used on the PC 386.
  25. It uses the SCCs in asynchronous mode only.
  26. USAGE
  27. An I8250_CHAN structure is used to describe the chip.
  28. The BSP's sysHwInit() routine typically calls sysSerialHwInit()
  29. which initializes all the register values in the I8250_CHAN structure
  30. (except the SIO_DRV_FUNCS) before calling i8250HrdInit().
  31. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2() which
  32. connects the chips interrupt handler (i8250Int) via intConnect().
  33. IOCTL FUNCTIONS
  34. This driver responds to all the same ioctl() codes as a normal serial driver;
  35. for more information, see the comments in sioLib.h.  As initialized, the
  36. available baud rates are 110, 300, 600, 1200, 2400, 4800, 9600, 19200, and
  37. 38400.
  38. This driver handles setting of hardware options such as parity(odd, even) and
  39. number of data bits(5, 6, 7, 8). Hardware flow control is provided with the
  40. handshakes RTS/CTS. The function HUPCL(hang up on last close) is available.
  41. INCLUDE FILES: drv/sio/i8250Sio.h
  42. */
  43. #include "vxWorks.h"
  44. #include "iv.h"
  45. #include "intLib.h"
  46. #include "errnoLib.h"
  47. #include "drv/sio/i8250Sio.h"
  48. /* defines */
  49. /* This value is used to specify the maximum number of times i8250Int()
  50.  * routine will read the 8250 Interrupt Identification Register before
  51.  * returning.  This value should optimally be derived from the BRDR.
  52.  */
  53. #define I8250_IIR_READ_MAX          40
  54. #ifndef I8250_DEFAULT_BAUD
  55. #   define  I8250_DEFAULT_BAUD      9600
  56. #endif
  57. #ifndef SIO_HUP
  58. #   define SIO_OPEN     0x100A
  59. #   define SIO_HUP      0x100B
  60. #endif
  61. /* locals */
  62. /* baudTable is a table of the available baud rates, and the values to write
  63.  * to the UART's baud rate divisor {high, low} register. the formula is
  64.  * 1843200(source) / (16 * baudrate)
  65.  */
  66. static BAUD baudTable [] =
  67.     {
  68.     {50, 2304}, {75, 1536}, {110, 1047}, {134, 857}, {150, 768},
  69.     {300, 384}, {600, 192}, {1200, 96}, {2000, 58}, {2400, 48},
  70.     {3600,32}, {4800, 24}, {7200,16}, {9600, 12}, {19200, 6}, {38400, 3},
  71.     {57600, 2}, {115200, 1}
  72.     };
  73. static SIO_DRV_FUNCS i8250SioDrvFuncs;
  74. /* forward declarations */
  75. LOCAL   void    i8250InitChannel (I8250_CHAN *);
  76. LOCAL   int     i8250Ioctl(I8250_CHAN *, int, int);
  77. LOCAL   int     i8250Startup(I8250_CHAN *pChan);
  78. LOCAL   int     i8250PRxChar (I8250_CHAN *pChan, char *ch);
  79. LOCAL   int     i8250PTxChar(I8250_CHAN *pChan, char ch);
  80. LOCAL   STATUS  i8250OptsSet (I8250_CHAN *, UINT);
  81. LOCAL   STATUS  i8250ModeSet (I8250_CHAN *, UINT);
  82. LOCAL   STATUS  i8250BaudSet (I8250_CHAN *, UINT);
  83. /******************************************************************************
  84. *
  85. * i8250CallbackInstall - install ISR callbacks to get put chars.
  86. *
  87. * This routine installs the callback functions for the driver
  88. *
  89. * RETURNS: OK on success or ENOSYS on unsupported callback type.
  90. */ 
  91. static int i8250CallbackInstall
  92.     (
  93.     SIO_CHAN *  pSioChan,
  94.     int         callbackType,
  95.     STATUS      (*callback)(),
  96.     void *      callbackArg
  97.     )
  98.     {
  99.     I8250_CHAN * pChan = (I8250_CHAN *)pSioChan;
  100.     switch (callbackType)
  101.         {
  102.         case SIO_CALLBACK_GET_TX_CHAR:
  103.             pChan->getTxChar    = callback;
  104.             pChan->getTxArg     = callbackArg;
  105.             return (OK);
  106.         case SIO_CALLBACK_PUT_RCV_CHAR:
  107.             pChan->putRcvChar   = callback;
  108.             pChan->putRcvArg    = callbackArg;
  109.             return (OK);
  110.         default:
  111.             return (ENOSYS);
  112.         }
  113.     }
  114. /******************************************************************************
  115. *
  116. * i8250HrdInit - initialize the chip
  117. *
  118. * This routine is called to reset the chip in a quiescent state.
  119. * RETURNS: N/A
  120. */
  121. void i8250HrdInit
  122.     (
  123.     I8250_CHAN *  pChan         /* pointer to device */
  124.     )
  125.     {
  126.     if (i8250SioDrvFuncs.ioctl == NULL)
  127.         {
  128.         i8250SioDrvFuncs.ioctl          = (int (*)())i8250Ioctl;
  129.         i8250SioDrvFuncs.txStartup      = (int (*)())i8250Startup;
  130.         i8250SioDrvFuncs.callbackInstall = i8250CallbackInstall;
  131.         i8250SioDrvFuncs.pollInput      = (int (*)())i8250PRxChar;
  132.         i8250SioDrvFuncs.pollOutput     = (int (*)(SIO_CHAN *,char))i8250PTxChar;
  133.         }
  134.     pChan->pDrvFuncs = &i8250SioDrvFuncs;
  135.     i8250InitChannel(pChan);    /* reset the channel */
  136.     }
  137. /*******************************************************************************
  138. *
  139. * i8250InitChannel  - initialize a single channel
  140. */
  141. static void i8250InitChannel
  142.     (
  143.     I8250_CHAN *  pChan         /* pointer to device */
  144.     )
  145.     {
  146.     int oldLevel;
  147.     oldLevel = intLock ();
  148.     /* set channel baud rate */
  149.     (void) i8250BaudSet(pChan, I8250_DEFAULT_BAUD);
  150.     /* 8 data bits, 1 stop bit, no parity */
  151.     (*pChan->outByte) (pChan->lcr, (I8250_LCR_CS8 | I8250_LCR_1_STB));
  152.     (*pChan->outByte) (pChan->mdc, (I8250_MCR_RTS | I8250_MCR_DTR | 
  153.                                         I8250_MCR_OUT2));
  154.     (*pChan->inByte) (pChan->data);     /* clear the port */
  155.     /* disable interrupts  */
  156.     (*pChan->outByte) (pChan->ier, 0x0);
  157.     pChan->options = (CLOCAL | CREAD | CS8);
  158.     intUnlock (oldLevel);
  159.     }
  160. /*******************************************************************************
  161. *
  162. * i8250Hup - hang up the modem control lines 
  163. *
  164. * Resets the RTS and DTR signals.
  165. *
  166. * RETURNS: OK
  167. */
  168. LOCAL STATUS i8250Hup
  169.     (
  170.     I8250_CHAN * pChan          /* pointer to channel */
  171.     )
  172.     {
  173.     FAST int     oldlevel;      /* current interrupt level mask */
  174.     oldlevel = intLock ();
  175.     (*pChan->outByte) (pChan->mdc, I8250_MCR_OUT2);
  176.     intUnlock (oldlevel);
  177.     return (OK);
  178.     }    
  179. /*******************************************************************************
  180. *
  181. * i8250Open - Set the modem control lines 
  182. *
  183. * Set the modem control lines(RTS, DTR) TRUE if not already set.  
  184. * It also clears the receiver. 
  185. *
  186. * RETURNS: OK
  187. */
  188. LOCAL STATUS i8250Open
  189.     (
  190.     I8250_CHAN * pChan          /* pointer to channel */
  191.     )
  192.     {
  193.     FAST int     oldlevel;      /* current interrupt level mask */
  194.     char mask;
  195.     /* read modem control register */
  196.     mask = ((*pChan->inByte) (pChan->mdc)) & (I8250_MCR_RTS | I8250_MCR_DTR);
  197.     if (mask != (I8250_MCR_RTS | I8250_MCR_DTR)) 
  198.         {
  199.         /* RTS and DTR not set yet */
  200.         oldlevel = intLock ();
  201.         /* set RTS and DTR TRUE */
  202.         (*pChan->outByte) (pChan->mdc, (I8250_MCR_RTS | I8250_MCR_DTR | 
  203.                                         I8250_MCR_OUT2));
  204.         intUnlock (oldlevel);
  205.         }
  206.     return (OK);
  207.     }
  208. /******************************************************************************
  209. *
  210. * i8250BaudSet - change baud rate for channel
  211. *
  212. * This routine sets the baud rate for the UART. The interrupts are disabled
  213. * during chip access.
  214. *
  215. * RETURNS: OK to indicate success, otherwise ERROR is returned
  216. */
  217. LOCAL STATUS  i8250BaudSet
  218.     (
  219.     I8250_CHAN *   pChan,       /* pointer to channel */
  220.     UINT           baud         /* requested baud rate */
  221.     )
  222.     {
  223.     int         oldlevel;
  224.     STATUS      status;
  225.     FAST        int     ix;
  226.     UINT8       lcr;
  227.     /* disable interrupts during chip access */
  228.     oldlevel = intLock ();
  229.     status = ERROR;
  230.     for (ix = 0; ix < NELEMENTS (baudTable); ix++)
  231.         {
  232.         if (baudTable [ix].rate == baud)        /* lookup baud rate value */
  233.             {
  234.             lcr = (*pChan->inByte) (pChan->lcr);   
  235.             (*pChan->outByte) (pChan->lcr, (char)(I8250_LCR_DLAB | lcr));
  236.             (*pChan->outByte) (pChan->brdh, MSB (baudTable[ix].preset));
  237.             (*pChan->outByte) (pChan->brdl, LSB (baudTable[ix].preset));
  238.             (*pChan->outByte) (pChan->lcr, lcr);
  239.             status = OK;
  240.             break;
  241.             }
  242.         }
  243.     intUnlock(oldlevel);
  244.     return (status);
  245.     }
  246. /*******************************************************************************
  247. *
  248. * i8250ModeSet - change channel mode setting
  249. *
  250. * This driver supports both polled and interrupt modes and is capable of
  251. * switching between modes dynamically. 
  252. *
  253. * If interrupt mode is desired this routine enables the channels receiver and 
  254. * transmitter interrupts. If the modem control option is TRUE, the Tx interrupt
  255. * is disabled if the CTS signal is FALSE. It is enabled otherwise. 
  256. *
  257. * If polled mode is desired the device interrupts are disabled. 
  258. *
  259. * RETURNS:
  260. * Returns a status of OK if the mode was set else ERROR.
  261. */
  262. LOCAL STATUS i8250ModeSet
  263.     (
  264.     I8250_CHAN * pChan,         /* pointer to channel */
  265.     UINT        newMode         /* mode requested */
  266.     )
  267.     {
  268.     FAST int     oldlevel;      /* current interrupt level mask */
  269.     char ier, mask;
  270.     if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
  271.         return (ERROR);
  272.     oldlevel = intLock();
  273.            
  274.     if (newMode == SIO_MODE_POLL)
  275.         ier = 0x00;
  276.     else  
  277.         {
  278.         if (pChan->options & CLOCAL) 
  279.             ier = I8250_IER_RXRDY;
  280.         else  
  281.             {
  282.             mask = ((*pChan->inByte) (pChan->msr)) & I8250_MSR_CTS;
  283.             /* if the CTS is asserted enable Tx interrupt */
  284.             if (mask & I8250_MSR_CTS)
  285.                 ier = (I8250_IER_TBE | I8250_IER_MSI);
  286.             else
  287.                 ier = (I8250_IER_MSI);
  288.             }   
  289.         }
  290.     (*pChan->outByte) (pChan->ier, ier);
  291.             
  292.     pChan->channelMode = newMode;  
  293.           
  294.     intUnlock(oldlevel);
  295.     return (OK);
  296.     }
  297. /*******************************************************************************
  298. *
  299. * i8250OptsSet - set the serial options
  300. *
  301. * Set the channel operating mode to that specified.  All sioLib options
  302. * are supported: CLOCAL, HUPCL, CREAD, CSIZE, PARENB, and PARODD.
  303. *
  304. * RETURNS:
  305. * Returns OK to indicate success, otherwise ERROR is returned
  306. */
  307. LOCAL STATUS i8250OptsSet
  308.     (
  309.     I8250_CHAN * pChan,         /* pointer to channel */
  310.     UINT options                /* new hardware options */
  311.     )
  312.     {
  313.     FAST int     oldlevel;              /* current interrupt level mask */
  314.     char lcr = 0; 
  315.     char mcr = I8250_MCR_OUT2;
  316.     char ier;
  317.     char mask;
  318.     ier = (*pChan->inByte) (pChan->ier);
  319.     if (pChan == NULL || options & 0xffffff00)
  320.         return ERROR;
  321.     switch (options & CSIZE)
  322.         {
  323.         case CS5:
  324.             lcr = I8250_LCR_CS5; break;
  325.         case CS6:
  326.             lcr = I8250_LCR_CS6; break;
  327.         case CS7:
  328.             lcr = I8250_LCR_CS7; break;
  329.         default:
  330.         case CS8:
  331.             lcr = I8250_LCR_CS8; break;
  332.         }
  333.     if (options & STOPB)
  334.         lcr |= I8250_LCR_2_STB;
  335.     else
  336.         lcr |= I8250_LCR_1_STB;
  337.     
  338.     switch (options & (PARENB | PARODD))
  339.         {
  340.         case PARENB|PARODD:
  341.             lcr |= I8250_LCR_PEN; break;
  342.         case PARENB:
  343.             lcr |= (I8250_LCR_PEN | I8250_LCR_EPS); break;
  344.         default:
  345.         case 0:
  346.             lcr |= I8250_LCR_PDIS; break;
  347.         }
  348.     (*pChan->outByte) (pChan->ier, 0x00);
  349.     if (!(options & CLOCAL))
  350.         {
  351.         /* !clocal enables hardware flow control(DTR/DSR) */
  352.         mcr |= (I8250_MCR_DTR | I8250_MCR_RTS);
  353.         ier |= I8250_IER_MSI;    /* enable modem status interrupt */
  354.         mask = ((*pChan->inByte) (pChan->msr)) & I8250_MSR_CTS;
  355.         /* if the CTS is asserted enable Tx interrupt */
  356.         if (mask & I8250_MSR_CTS)
  357.                 ier |= I8250_IER_TBE;
  358.         else
  359.                 ier &= (~I8250_IER_TBE); 
  360.         }
  361.     else 
  362.         ier &= ~I8250_IER_MSI; /* disable modem status interrupt */ 
  363.     oldlevel = intLock ();
  364.     (*pChan->outByte) (pChan->lcr, lcr);
  365.     (*pChan->outByte) (pChan->mdc, mcr);
  366.     /* now clear the port */
  367.     (*pChan->inByte) (pChan->data);
  368.     if (options & CREAD)  
  369.         ier |= I8250_IER_RXRDY;
  370.     if (pChan->channelMode == SIO_MODE_INT)
  371.         {
  372.         (*pChan->outByte) (pChan->ier, ier);
  373.         }
  374.     intUnlock (oldlevel);
  375.     pChan->options = options;
  376.     return OK;
  377.     }
  378. /*******************************************************************************
  379. *
  380. * i8250Ioctl - special device control
  381. *
  382. * Includes commands to get/set baud rate, mode(INT, POLL), hardware options(
  383. * parity, number of data bits), and modem control(RTS/CTS and DTR/DSR).
  384. * The ioctl commands SIO_HUP and SIO_OPEN are implemented to provide the 
  385. * HUPCL( hang up on last close) function.
  386. *
  387. * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
  388. *          request.
  389. */
  390. static int i8250Ioctl
  391.     (
  392.     I8250_CHAN *  pChan,        /* device to control */
  393.     int request,                /* request code */
  394.     int arg                     /* some argument */
  395.     )
  396.     {
  397.     int ix;
  398.     int baudH;
  399.     int baudL;
  400.     int oldlevel;
  401.     UINT8 lcr;
  402.     int status = OK;
  403.     switch (request)
  404.         {
  405.         case SIO_BAUD_SET:
  406.             status = (i8250BaudSet(pChan, arg) == OK) ? OK : EIO;
  407.             break;
  408.         case SIO_BAUD_GET:
  409.             
  410.             oldlevel = intLock();
  411.             status = EIO;
  412.             lcr = (*pChan->inByte) (pChan->lcr);
  413.             (*pChan->outByte) (pChan->lcr, (char)(I8250_LCR_DLAB | lcr));
  414.             baudH = (*pChan->inByte)(pChan->brdh);
  415.             baudL = (*pChan->inByte)(pChan->brdl);
  416.             (*pChan->outByte) (pChan->lcr, lcr);
  417.             for (ix = 0; ix < NELEMENTS (baudTable); ix++)
  418.                 {
  419.                 if ( baudH  == MSB (baudTable[ix].preset) &&
  420.                      baudL  == LSB (baudTable[ix].preset) )
  421.                     {
  422.                     *(int *)arg = baudTable[ix].rate;
  423.                     status = OK;
  424.                     }
  425.                 }
  426.             intUnlock(oldlevel);
  427.             break;
  428.         case SIO_MODE_SET:
  429.             status = (i8250ModeSet (pChan, arg) == OK) ? OK : EIO;
  430.             break;
  431.         case SIO_MODE_GET:
  432.             *(int *)arg = pChan->channelMode;
  433.             return (OK);
  434.         case SIO_AVAIL_MODES_GET:
  435.             *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  436.             return (OK);
  437.         case SIO_HW_OPTS_SET:
  438.             status = (i8250OptsSet (pChan, arg) == OK) ? OK : EIO;
  439.             break;
  440.         case SIO_HW_OPTS_GET:
  441.             *(int *)arg = pChan->options;
  442.             break;
  443.         case SIO_HUP:
  444.             /* check if hupcl option is enabled */
  445.             if (pChan->options & HUPCL) 
  446.                 status = i8250Hup (pChan);
  447.             break;
  448.         
  449.         case SIO_OPEN:
  450.             /* check if hupcl option is enabled */
  451.             if (pChan->options & HUPCL) 
  452.                 status = i8250Open (pChan);
  453.             break;
  454.         default:
  455.             status = ENOSYS;
  456.             break;
  457.         }
  458.     return (status);
  459.     }
  460. /*******************************************************************************
  461. *
  462. * i8250Int - handle a receiver/transmitter interrupt
  463. *
  464. * This routine handles four sources of interrupts from the UART.  If there is
  465. * another character to be transmitted, the character is sent.  When a modem
  466. * status interrupt occurs, the transmit interrupt is enabled if the CTS signal
  467. * is TRUE.
  468. *
  469. * INTERNAL
  470. * The UART interrupts are prioritized in the following order by the Interrupt
  471. * Identification Register:
  472. *
  473. *     Bit 2    bit 1    bit 0    Priority        Interrupt ID
  474. *     -------------------------------------------------------
  475. *     0        0        1        none            none
  476. *     1        1        0        0               serialization error or BREAK
  477. *     1        0        0        1               received data
  478. *     0        1        0        2               transmitter buffer empty
  479. *     0        0        0        3               RS-232 input
  480. *
  481. * In the table, priority level 0 is the highest priority.  These priorities
  482. * are not typically configurable via software.  The interrupt is expressed as
  483. * a two-bit integer.  Bit 0, the pending bit, is negative logic - a value 0
  484. * means that an interrupt is pending.
  485. *
  486. * When nested interrupts occur, the second interrupt is identified in the
  487. * Interrupt Identification Register (IIR) as soon as the first interrupt is
  488. * cleared. Therefore, the interrupt service routine must continue to read IIR
  489. * until bit-0 is 1.
  490. *
  491. * When the 8250 generates an interrupt, all interrupts with an equal or
  492. * lower priority are locked out until the current interrupt has been cleared.
  493. * The operation required to clear an interrupt varies according to the source.
  494. * The actions typically required to clear an interrupt are as follows:
  495. *
  496. *    Source of interrupt                Response required to reset
  497. *    ---------------------------------------------------------------------
  498. *    receiver error or BREAK            read serialization status register
  499. *    received data                      read data from receiver register
  500. *    transmit buffer empty              write to the transmitter or read
  501. *                                       the interrupt ID register
  502. *    RS-232 input                       read the RS-232 status register
  503. *
  504. * In response to an empty transmit buffer (TBE), the interrupt can be
  505. * cleared by writing a byte to the transmitter buffer register.  It can
  506. * also be cleared by reading the interrupt identification register.
  507. *
  508. * Failure to clear all interrupts before returning will leave an interrupt
  509. * pending and prevent the UART from generating further interrupt requests
  510. * to the CPU.
  511. *
  512. * RETURNS: N/A
  513. */
  514. void i8250Int
  515.     (
  516.     I8250_CHAN  *  pChan
  517.     )
  518.     {
  519.     char outChar;       /* store a byte for transmission */
  520.     char interruptID;   /* store contents of interrupt ID register */
  521.     char lineStatus;    /* store contents of line status register */
  522.     char ier;           /* store contents of interrupt enable register */
  523.     int  ix = 0;        /* allows us to return just in case IP never clears */
  524.     ier = (*pChan->inByte) (pChan->ier);
  525.     /* service UART interrupts until IP bit set or read counter expires */
  526.     FOREVER
  527.         {
  528.         interruptID = ((*pChan->inByte)(pChan->iid) & I8250_IIR_MASK);
  529.         if ((interruptID == I8250_IIR_IP) || (++ix > I8250_IIR_READ_MAX))
  530.             {
  531.             break;  /* interrupt cleared or loop counter expired */ 
  532.             }
  533.         /* filter possible anomalous interrupt ID from PC87307VUL (SPR 26117) */
  534.         interruptID &= 0x06;  /* clear odd-bit to find interrupt ID */
  535.         if (interruptID == I8250_IIR_SEOB)
  536.             {
  537.             lineStatus = (*pChan->inByte) (pChan->lst);
  538.             }
  539.         else if (interruptID == I8250_IIR_RBRF)
  540.             {
  541.             if (pChan->putRcvChar != NULL)
  542.                 (*pChan->putRcvChar)(pChan->putRcvArg,
  543.                                (*pChan->inByte) (pChan->data));
  544.             else
  545.                 (*pChan->inByte) (pChan->data);
  546.             }
  547.         else if (interruptID == I8250_IIR_THRE)
  548.             {
  549.             if ((pChan->getTxChar != NULL) &&
  550.                 (*pChan->getTxChar) (pChan->getTxArg, &outChar) == OK
  551.                )
  552.                 {
  553.                 (*pChan->outByte) (pChan->data, outChar);
  554.                 }
  555.             /* There are no bytes available for transmission.  Reading
  556.              * the IIR at the top of this loop will clear the interrupt.
  557.              */
  558.             }
  559.         else if (interruptID == I8250_IIR_MSTAT) /* modem status register */
  560.             {
  561.             char msr = (*(pChan)->inByte) (pChan->msr);
  562.             /* (|=) ... DON'T CLOBBER BITS ALREADY SET IN THE IER */
  563.             ier |= (I8250_IER_RXRDY | I8250_IER_MSI);
  564.             /* if CTS is asserted by modem, enable tx interrupt */
  565.             if ((msr & I8250_MSR_CTS) && (msr & I8250_MSR_DCTS))
  566.                 {
  567.                 (*pChan->outByte) (pChan->ier, (I8250_IER_TBE | ier));
  568.                 }
  569.             else  /* turn off TBE interrupt until CTS from modem */
  570.                 {
  571.                 (*pChan->outByte) (pChan->ier, (ier & (~I8250_IER_TBE)));
  572.                 }
  573.             }
  574.         }  /* FOREVER */
  575.     }
  576. /*******************************************************************************
  577. *
  578. * i8250Startup - transmitter startup routine
  579. *
  580. * Call interrupt level character output routine and enable interrupt if it is
  581. * in interrupt mode with no hardware flow control.
  582. * If the option for hardware flow control is enabled and CTS is set TRUE,
  583. * then the Tx interrupt is enabled.
  584. *
  585. * RETURNS: OK
  586. */
  587. LOCAL int i8250Startup
  588.     (
  589.     I8250_CHAN *  pChan         /* tty device to start up */
  590.     )
  591.     {
  592.     char  ier = I8250_IER_RXRDY;
  593.     char  mask;
  594.     if (pChan->channelMode == SIO_MODE_INT)
  595.         {
  596.         if (pChan->options & CLOCAL)
  597.             {
  598.             /* No modem control */
  599.             ier |= I8250_IER_TBE;
  600.             }
  601.         else
  602.             {
  603.             mask = ((*pChan->inByte) (pChan->msr)) & I8250_MSR_CTS;
  604.             /* if the CTS is asserted enable Tx interrupt */
  605.             if (mask & I8250_MSR_CTS)
  606.                 ier |= (I8250_IER_TBE | I8250_IER_MSI);
  607.             else
  608.                 ier |= (I8250_IER_MSI);
  609.             }
  610.         (*pChan->outByte) (pChan->ier, ier);
  611.         }
  612.     return (OK);
  613.     }
  614. /******************************************************************************
  615. *
  616. * i8250PRxChar - poll the device for input.
  617. *
  618. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  619. * if the input buffer if empty.
  620. */
  621. LOCAL int i8250PRxChar
  622.     (
  623.     I8250_CHAN *    pChan,      /* pointer to channel */
  624.     char *          pChar       /* pointer to char */
  625.     )
  626.     {
  627.     char pollStatus;
  628.     pollStatus = ( *(pChan)->inByte) (pChan->lst);
  629.     if ((pollStatus & I8250_LSR_RXRDY) == 0x00)
  630.         return (EAGAIN);
  631.     /* got a character */
  632.     *pChar = ( *(pChan)->inByte) (pChan->data);
  633.     return (OK);
  634.     }
  635. /******************************************************************************
  636. *
  637. * i8250PTxChar - output a character in polled mode.
  638. * Checks if the transmitter is empty. If empty, a character is written to
  639. * the data register. 
  640. *
  641. * If the hardware flow control is enabled the handshake signal CTS has to be
  642. * asserted in order to send a character.
  643. *
  644. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  645. * if the output buffer if full.
  646. */
  647. LOCAL int i8250PTxChar
  648.     (
  649.     I8250_CHAN *  pChan,        /* pointer to channel */
  650.     char          outChar       /* char to send */
  651.     )
  652.     {
  653.     char pollStatus;
  654.     char msr;
  655.     pollStatus = ( *(pChan)->inByte) (pChan->lst);
  656.     msr = (*(pChan)->inByte) (pChan->msr);
  657.     /* is the transmitter ready to accept a character? */
  658.     if ((pollStatus & I8250_LSR_TEMT) == 0x00)
  659.         return (EAGAIN);
  660.     if (!(pChan->options & CLOCAL))      /* modem flow control ? */
  661.         {
  662.         if (msr & I8250_MSR_CTS)
  663.             (*(pChan)->outByte) ((pChan)->data, outChar);
  664.         else
  665.             return (EAGAIN);
  666.         }
  667.     else
  668.         (*(pChan)->outByte) ((pChan)->data, outChar);
  669.     return (OK);
  670.     }