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

VxWorks

开发平台:

C/C++

  1. /* ns16550Sio.c - NS 16550 UART tty driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01m,24apr02,pmr  SPR 75161: returning int from ns16550TxStartup() as required.
  8. 01l,03apr02,jnz  fixed bug at ns16550SioDrvFuncs declraation.
  9. 01k,31oct01,mdg  Corrected transmit interrtupt race condition found on 
  10.                   on MIPS Malta board with RM5261 processor. (SPR# 71830)
  11. 01j,14mar01,rcs  corrected baud rate divisor calculation formula. (SPR# 63899)
  12. 01i,17sep97,dat  fixed merge problems that caused baud rate setting to fail.
  13. 01h,06mar97,dat  SPR 7899, max baud rate set to 115200.
  14. 01g,08may97,db   added hardware options and modem control(SPRs #7570, #7082).
  15. 01f,18dec95,myz  added case IIR_TIMEOUT in ns16550Int routine.
  16. 01e,28nov95,myz  fixed bugs to work at 19200 baud or above with heavy traffic.
  17. 01d,09nov95,jdi  doc: style cleanup.
  18. 01c,02nov95,myz  undo 01b fix
  19. 01b,02nov95,p_m  added test for 960CA and 960JX around access to lcr field
  20.  in order to compile on all architectures.
  21. 01a,24oct95,myz  written from ns16550Serial.c.
  22. */
  23. /*
  24. DESCRIPTION
  25. This is the driver for the NS16552 DUART. This device includes two universal
  26. asynchronous receiver/transmitters, a baud rate generator, and a complete 
  27. modem control capability. 
  28. A NS16550_CHAN structure is used to describe the serial channel. This data 
  29. structure is defined in ns16550Sio.h.
  30. Only asynchronous serial operation is supported by this driver.
  31. The default serial settings are 8 data bits, 1 stop bit, no parity, 9600
  32. baud, and software flow control.  
  33. USAGE
  34. The BSP's sysHwInit() routine typically calls sysSerialHwInit(),
  35. which creates the NS16550_CHAN structure and initializes all the values in the 
  36. structure (except the SIO_DRV_FUNCS) before calling ns16550DevInit().
  37. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(), which
  38. connects the chips interrupts via intConnect() (either the single
  39. interrupt `ns16550Int' or the three interrupts `ns16550IntWr', `ns16550IntRd',
  40. and `ns16550IntEx').
  41. This driver handles setting of hardware options such as parity(odd, even) and
  42. number of data bits(5, 6, 7, 8). Hardware flow control is provided with the
  43. handshakes RTS/CTS. The function HUPCL(hang up on last close) is available.
  44. When hardware flow control is enabled, the signals RTS and DTR are set TRUE 
  45. and remain set until a HUPCL is performed. 
  46. INCLUDE FILES: drv/sio/ns16552Sio.h
  47. */
  48. /* includes */
  49. #include "vxWorks.h"
  50. #include "intLib.h"
  51. #include "errnoLib.h"
  52. #include "errno.h"
  53. #include "sioLib.h"
  54. #include "drv/sio/ns16552Sio.h"
  55. /* local defines       */
  56. #ifndef SIO_HUP
  57. #   define SIO_OPEN 0x100A
  58. #   define SIO_HUP 0x100B
  59. #endif
  60. /* min/max baud rate */
  61.  
  62. #define NS16550_MIN_RATE 50
  63. #define NS16550_MAX_RATE 115200
  64. #define REG(reg, pchan) 
  65.  (*(volatile UINT8 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))
  66. #define REGPTR(reg, pchan) 
  67.  ((volatile UINT8 *)((UINT32)pchan->regs + (reg * pchan->regDelta)))
  68. /* static forward declarations */
  69. LOCAL  int  ns16550CallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);
  70. LOCAL  STATUS  ns16550DummyCallback ();
  71. LOCAL  void  ns16550InitChannel (NS16550_CHAN *);
  72. LOCAL   STATUS  ns16550BaudSet (NS16550_CHAN *, UINT);
  73. LOCAL  STATUS  ns16550ModeSet (NS16550_CHAN *, UINT);
  74. LOCAL  STATUS  ns16550Ioctl (NS16550_CHAN *, int, int);
  75. LOCAL  int   ns16550TxStartup (NS16550_CHAN *);
  76. LOCAL  int  ns16550PollOutput (NS16550_CHAN *, char);
  77. LOCAL  int  ns16550PollInput (NS16550_CHAN *, char *);
  78. LOCAL  STATUS  ns16550OptsSet (NS16550_CHAN *, UINT);
  79. LOCAL  STATUS  ns16550Open (NS16550_CHAN * pChan );
  80. LOCAL  STATUS  ns16550Hup (NS16550_CHAN * pChan );
  81. /* driver functions */
  82. static SIO_DRV_FUNCS ns16550SioDrvFuncs =
  83.     {
  84.     (int (*)())ns16550Ioctl,
  85.     (int (*)())ns16550TxStartup,
  86.     (int (*)())ns16550CallbackInstall,
  87.     (int (*)())ns16550PollInput,
  88.     (int (*)(SIO_CHAN *,char))ns16550PollOutput
  89.     };
  90. /******************************************************************************
  91. *
  92. * ns16550DummyCallback - dummy callback routine.
  93. */
  94. LOCAL STATUS ns16550DummyCallback (void)
  95.     {
  96.     return (ERROR);
  97.     }
  98. /******************************************************************************
  99. *
  100. * ns16550DevInit - intialize an NS16550 channel
  101. *
  102. * This routine initializes some SIO_CHAN function pointers and then resets
  103. * the chip in a quiescent state.  Before this routine is called, the BSP
  104. * must already have initialized all the device addresses, etc. in the
  105. * NS16550_CHAN structure.
  106. *
  107. * RETURNS: N/A
  108. */
  109. void ns16550DevInit
  110.     (
  111.     NS16550_CHAN * pChan /* pointer to channel */
  112.     )
  113.     {
  114.     int oldlevel = intLock ();
  115.     /* initialize the driver function pointers in the SIO_CHAN's */
  116.     pChan->pDrvFuncs    = &ns16550SioDrvFuncs;
  117.     /* set the non BSP-specific constants */
  118.     pChan->getTxChar    = ns16550DummyCallback;
  119.     pChan->putRcvChar   = ns16550DummyCallback;
  120.     pChan->channelMode  = 0;    /* undefined */
  121.     pChan->options      = (CLOCAL | CREAD | CS8);
  122.     pChan->mcr = MCR_OUT2;
  123.     /* reset the chip */
  124.     ns16550InitChannel (pChan);
  125.     intUnlock (oldlevel);
  126.     }
  127. /*******************************************************************************
  128. *
  129. * ns16550InitChannel - initialize UART
  130. *
  131. * Initialize the number of data bits, parity and set the selected
  132. * baud rate.
  133. * Set the modem control signals if the option is selected.
  134. *
  135. * RETURNS: N/A
  136. */
  137. LOCAL void ns16550InitChannel
  138.     (
  139.     NS16550_CHAN * pChan /* pointer to channel */
  140.     )
  141.     {
  142.     /* set the requested baud rate */
  143.     ns16550BaudSet(pChan, pChan->baudRate);
  144.     /* set the options */
  145.     ns16550OptsSet(pChan, pChan->options);
  146.     }
  147. /*******************************************************************************
  148. *
  149. * ns16550OptsSet - set the serial options
  150. *
  151. * Set the channel operating mode to that specified.  All sioLib options
  152. * are supported: CLOCAL, HUPCL, CREAD, CSIZE, PARENB, and PARODD.
  153. * When the HUPCL option is enabled, a connection is closed on the last
  154. * close() call and opened on each open() call.
  155. *
  156. * Note, this routine disables the transmitter.  The calling routine
  157. * may have to re-enable it.
  158. *
  159. * RETURNS:
  160. * Returns OK to indicate success, otherwise ERROR is returned
  161. */
  162. LOCAL STATUS ns16550OptsSet
  163.     (
  164.     NS16550_CHAN * pChan, /* pointer to channel */
  165.     UINT options /* new hardware options */
  166.     )
  167.     {
  168.     FAST int     oldlevel; /* current interrupt level mask */
  169.     pChan->lcr = 0; 
  170.     pChan->mcr &= (~(MCR_RTS | MCR_DTR)); /* clear RTS and DTR bits */
  171.     
  172.     if (pChan == NULL || options & 0xffffff00)
  173. return ERROR;
  174.     switch (options & CSIZE)
  175. {
  176. case CS5:
  177.     pChan->lcr = CHAR_LEN_5; break;
  178. case CS6:
  179.     pChan->lcr = CHAR_LEN_6; break;
  180. case CS7:
  181.     pChan->lcr = CHAR_LEN_7; break;
  182. default:
  183. case CS8:
  184.     pChan->lcr = CHAR_LEN_8; break;
  185. }
  186.     if (options & STOPB)
  187. pChan->lcr |= LCR_STB;
  188.     else
  189. pChan->lcr |= ONE_STOP;
  190.     
  191.     switch (options & (PARENB | PARODD))
  192. {
  193. case PARENB|PARODD:
  194.     pChan->lcr |= LCR_PEN; break;
  195. case PARENB:
  196.     pChan->lcr |= (LCR_PEN | LCR_EPS); break;
  197. default:
  198. case 0:
  199.     pChan->lcr |= PARITY_NONE; break;
  200. }
  201.     REG(IER, pChan) = 0;
  202.     if (!(options & CLOCAL))
  203. {
  204. /* !clocal enables hardware flow control(DTR/DSR) */
  205. pChan->mcr |= (MCR_DTR | MCR_RTS);
  206.      pChan->ier &= (~TxFIFO_BIT); 
  207. pChan->ier |= IER_EMSI;    /* enable modem status interrupt */
  208. }
  209.     else
  210.         pChan->ier &= ~IER_EMSI; /* disable modem status interrupt */ 
  211.     oldlevel = intLock ();
  212.     REG(LCR, pChan) = pChan->lcr;
  213.     REG(MCR, pChan) = pChan->mcr;
  214.     /* now reset the channel mode registers */
  215.     REG(FCR, pChan) = (RxCLEAR | TxCLEAR | FIFO_ENABLE);
  216.     if (options & CREAD)  
  217. pChan->ier |= RxFIFO_BIT;
  218.     if (pChan->channelMode == SIO_MODE_INT)
  219. {
  220.         REG(IER, pChan) = pChan->ier;
  221.         }
  222.     intUnlock (oldlevel);
  223.     pChan->options = options;
  224.     return OK;
  225.     }
  226. /*******************************************************************************
  227. *
  228. * ns16550Hup - hang up the modem control lines 
  229. *
  230. * Resets the RTS and DTR signals and clears both the receiver and
  231. * transmitter sections.
  232. *
  233. * RETURNS: OK
  234. */
  235. LOCAL STATUS ns16550Hup
  236.     (
  237.     NS16550_CHAN * pChan  /* pointer to channel */
  238.     )
  239.     {
  240.     FAST int     oldlevel; /* current interrupt level mask */
  241.     oldlevel = intLock ();
  242.     pChan->mcr &= (~(MCR_RTS | MCR_DTR));
  243.     REG(MCR, pChan) = pChan->mcr;
  244.     REG(FCR, pChan) = (RxCLEAR | TxCLEAR); 
  245.     intUnlock (oldlevel);
  246.     return (OK);
  247.     }    
  248. /*******************************************************************************
  249. *
  250. * ns16550Open - Set the modem control lines 
  251. *
  252. * Set the modem control lines(RTS, DTR) TRUE if not already set.  
  253. * It also clears the receiver, transmitter and enables the fifo. 
  254. *
  255. * RETURNS: OK
  256. */
  257. LOCAL STATUS ns16550Open
  258.     (
  259.     NS16550_CHAN * pChan  /* pointer to channel */
  260.     )
  261.     {
  262.     FAST int     oldlevel; /* current interrupt level mask */
  263.     char mask;
  264.     mask = REG(MCR, pChan) & (MCR_RTS | MCR_DTR);
  265.     if (mask != (MCR_RTS | MCR_DTR)) 
  266.      {
  267.      /* RTS and DTR not set yet */
  268.      oldlevel = intLock ();
  269. /* set RTS and DTR TRUE */
  270.      pChan->mcr |= (MCR_DTR | MCR_RTS); 
  271.      REG(MCR, pChan) = pChan->mcr; 
  272.      /* clear Tx and receive and enable FIFO */
  273.         REG(FCR, pChan) = (RxCLEAR | TxCLEAR | FIFO_ENABLE);
  274.      intUnlock (oldlevel);
  275. }
  276.     return (OK);
  277.     }
  278. /******************************************************************************
  279. *
  280. * ns16550BaudSet - change baud rate for channel
  281. *
  282. * This routine sets the baud rate for the UART. The interrupts are disabled
  283. * during chip access.
  284. *
  285. * RETURNS: OK
  286. */
  287. LOCAL STATUS  ns16550BaudSet
  288.     (
  289.     NS16550_CHAN * pChan, /* pointer to channel */
  290.     UINT    baud /* requested baud rate */
  291.     )
  292.     {
  293.     int   oldlevel;
  294.     int   divisor = ((pChan->xtal + (8 * baud)) / (16 * baud));
  295.     /* disable interrupts during chip access */
  296.     oldlevel = intLock ();
  297.     /* Enable access to the divisor latches by setting DLAB in LCR. */
  298.     REG(LCR, pChan) = LCR_DLAB | pChan->lcr;
  299.     /* Set divisor latches. */
  300.     REG(DLL,pChan) = divisor;
  301.     REG(DLM,pChan) = (divisor >> 8);
  302.     /* Restore line control register */
  303.     REG(LCR, pChan) = pChan->lcr;
  304.     pChan->baudRate = baud;
  305.  
  306.     intUnlock (oldlevel);
  307.     return (OK);
  308.     }
  309. /*******************************************************************************
  310. *
  311. * ns16550ModeSet - change channel mode setting
  312. *
  313. * This driver supports both polled and interrupt modes and is capable of
  314. * switching between modes dynamically. 
  315. *
  316. * If interrupt mode is desired this routine enables the channels receiver and 
  317. * transmitter interrupts. If the modem control option is TRUE, the Tx interrupt
  318. * is disabled if the CTS signal is FALSE. It is enabled otherwise. 
  319. *
  320. * If polled mode is desired the device interrupts are disabled. 
  321. *
  322. * RETURNS:
  323. * Returns a status of OK if the mode was set else ERROR.
  324. */
  325. LOCAL STATUS ns16550ModeSet
  326.     (
  327.     NS16550_CHAN * pChan, /* pointer to channel */
  328.     UINT newMode /* mode requested */
  329.     )
  330.     {
  331.     FAST int     oldlevel; /* current interrupt level mask */
  332.     char mask;
  333.     if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
  334. return (ERROR);
  335.            
  336.     oldlevel = intLock ();
  337.     if (newMode == SIO_MODE_INT)
  338. {
  339.         /* Enable appropriate interrupts */
  340. if (pChan->options & CLOCAL) 
  341.                 REG(IER, pChan) = pChan->ier | RxFIFO_BIT | TxFIFO_BIT;
  342. else  
  343. {
  344. mask = REG(MSR, pChan) & MSR_CTS;
  345.     /* if the CTS is asserted enable Tx interrupt */
  346.     if (mask & MSR_CTS)
  347. pChan->ier |= TxFIFO_BIT;    /* enable Tx interrupt */
  348. else
  349.             pChan->ier &= (~TxFIFO_BIT); /* disable Tx interrupt */
  350. REG(IER, pChan) = pChan->ier; 
  351. }
  352. }
  353.     else
  354.         {
  355.         /* disable all ns16550 interrupts */ 
  356.         REG(IER, pChan) = 0;   
  357. }
  358.     pChan->channelMode = newMode;
  359.     intUnlock (oldlevel);
  360.     return (OK);
  361.    }
  362. /*******************************************************************************
  363. *
  364. * ns16550Ioctl - special device control
  365. *
  366. * Includes commands to get/set baud rate, mode(INT,POLL), hardware options(
  367. * parity, number of data bits), and modem control(RTS/CTS and DTR/DSR).
  368. * The ioctl command SIO_HUP is sent by ttyDrv when the last close() function 
  369. * call is made. Likewise SIO_OPEN is sent when the first open() function call
  370. * is made.
  371. *
  372. * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
  373. *          request.
  374. */
  375. LOCAL STATUS ns16550Ioctl
  376.     (
  377.     NS16550_CHAN *  pChan, /* pointer to channel */
  378.     int request, /* request code */
  379.     int         arg /* some argument */
  380.     )
  381.     {
  382.     FAST STATUS  status;
  383.     status = OK;
  384.     switch (request)
  385. {
  386. case SIO_BAUD_SET:
  387.     if (arg < NS16550_MIN_RATE || arg > NS16550_MAX_RATE)
  388. status = EIO; /* baud rate out of range */
  389.     else
  390.         status = ns16550BaudSet (pChan, arg);
  391.     break;
  392.         case SIO_BAUD_GET:
  393.             *(int *)arg = pChan->baudRate;
  394.             break; 
  395.         case SIO_MODE_SET:
  396.     status = (ns16550ModeSet (pChan, arg) == OK) ? OK : EIO;
  397.             break;          
  398.         case SIO_MODE_GET:
  399.             *(int *)arg = pChan->channelMode;
  400.             break;
  401.         case SIO_AVAIL_MODES_GET:
  402.             *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  403.             break;
  404.         case SIO_HW_OPTS_SET:
  405.          status = (ns16550OptsSet (pChan, arg) == OK) ? OK : EIO;
  406.          break;
  407.         case SIO_HW_OPTS_GET:
  408.             *(int *)arg = pChan->options;
  409.             break;
  410.         case SIO_HUP:
  411.             /* check if hupcl option is enabled */
  412.          if (pChan->options & HUPCL) 
  413.      status = ns16550Hup (pChan);
  414.             break;
  415. case SIO_OPEN:
  416.             /* check if hupcl option is enabled */
  417.          if (pChan->options & HUPCL) 
  418.      status = ns16550Open (pChan);
  419.     break;
  420.         default:
  421.             status = ENOSYS;
  422. }
  423.     return (status);
  424.     }
  425. /*******************************************************************************
  426. *
  427. * ns16550IntWr - handle a transmitter interrupt 
  428. *
  429. * This routine handles write interrupts from the UART. It reads a character
  430. * and puts it in the transmit holding register of the device for transfer.
  431. *
  432. * If there are no more characters to transmit, transmission is disabled by 
  433. * clearing the transmit interrupt enable bit in the IER(int enable register).
  434. *
  435. * RETURNS: N/A
  436. *
  437. */
  438. void ns16550IntWr 
  439.     (
  440.     NS16550_CHAN * pChan /* pointer to channel */
  441.     )
  442.     {
  443.     char           outChar;
  444.     UINT8          intStatus;
  445.     if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
  446.         REG(THR,pChan) = outChar; /* write char to Transmit Holding Reg */
  447.     else
  448.         {
  449.         pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */
  450.         REG(IER, pChan) = pChan->ier;
  451.         }
  452.     intStatus = REG(LSR, pChan);     /* read LSR to reset interrupt */
  453.     }
  454. /*******************************************************************************
  455. *
  456. * ns16550IntRd - handle a receiver interrupt 
  457. *
  458. * This routine handles read interrupts from the UART.
  459. *
  460. * RETURNS: N/A
  461. *
  462. */
  463. void ns16550IntRd 
  464.     (
  465.     NS16550_CHAN * pChan /* pointer to channel */
  466.     )
  467.     {
  468.     char   inchar;
  469.     /* read character from Receive Holding Reg. */
  470.     inchar = REG(RBR, pChan);
  471.     (*pChan->putRcvChar) (pChan->putRcvArg, inchar);
  472.     }
  473. /*******************************************************************************
  474. *
  475. * ns16550IntEx - miscellaneous interrupt processing
  476. *
  477. * This routine handles miscellaneous interrupts on the UART.
  478. * Not implemented yet.
  479. *
  480. * RETURNS: N/A
  481. *
  482. */
  483. void ns16550IntEx 
  484.     (
  485.     NS16550_CHAN *pChan /* pointer to channel */
  486.     )
  487.     {
  488.     /* Nothing for now... */
  489.     }
  490. /********************************************************************************
  491. *
  492. * ns16550Int - interrupt level processing
  493. *
  494. * This routine handles four sources of interrupts from the UART. They are
  495. * prioritized in the following order by the Interrupt Identification Register:
  496. * Receiver Line Status, Received Data Ready, Transmit Holding Register Empty
  497. * and Modem Status.
  498. *
  499. * When a modem status interrupt occurs, the transmit interrupt is enabled if
  500. * the CTS signal is TRUE.
  501. *
  502. * RETURNS: N/A
  503. *
  504. */
  505. void ns16550Int 
  506.     (
  507.     NS16550_CHAN * pChan /* pointer to channel */
  508.     )
  509.     {
  510.     FAST volatile char        intStatus;
  511.     /* read the Interrrupt Status Register (Int. Ident.) */
  512.     intStatus = (REG(IIR, pChan)) & 0x0f;
  513.     /*
  514.      * This UART chip always produces level active interrupts, and the IIR 
  515.      * only indicates the highest priority interrupt.  
  516.      * In the case that receive and transmit interrupts happened at
  517.      * the same time, we must clear both interrupt pending to prevent
  518.      * edge-triggered interrupt(output from interrupt controller) from locking
  519.      * up. One way doing it is to disable all the interrupts at the beginning
  520.      * of the ISR and enable at the end.
  521.      */
  522.     REG(IER,pChan) = 0;    /* disable interrupt */
  523.     switch (intStatus)
  524. {
  525. case IIR_RLS:
  526.             /* overrun,parity error and break interrupt */
  527.             intStatus = REG(LSR, pChan); /* read LSR to reset interrupt */
  528.     break;
  529.         case IIR_RDA:      /* received data available */
  530. case IIR_TIMEOUT: 
  531.    /*
  532.     * receiver FIFO interrupt. In some case, IIR_RDA will
  533.             * not be indicated in IIR register when there is more
  534.     * than one character in FIFO.
  535.     */
  536.             ns16550IntRd (pChan);   /* RxChar Avail */
  537.             break;
  538.         case IIR_THRE:  /* transmitter holding register ready */
  539.     {
  540.             char outChar;
  541.             if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
  542.                 REG(THR, pChan) = outChar;   /* char to Transmit Holding Reg */
  543.             else
  544.                 pChan->ier &= (~TxFIFO_BIT); /* indicates to disable Tx Int */
  545.             }
  546.             intStatus = REG(LSR, pChan);     /* read LSR to reset interrupt */
  547.             break;
  548. case IIR_MSTAT: /* modem status register */
  549.    {
  550.    char msr;
  551.    msr = REG(MSR, pChan);
  552.    /* if CTS is asserted by modem, enable tx interrupt */
  553.    if ((msr & MSR_CTS) && (msr & MSR_DCTS)) 
  554.     pChan->ier |= TxFIFO_BIT;
  555.            else
  556.             pChan->ier &= (~TxFIFO_BIT); 
  557.    }
  558.    break;
  559.         default:
  560.     break;
  561.         }
  562.     
  563.     REG(IER, pChan) = pChan->ier; /* enable interrupts accordingly */
  564.     }
  565. /*******************************************************************************
  566. *
  567. * ns16550TxStartup - transmitter startup routine
  568. *
  569. * Call interrupt level character output routine and enable interrupt if it is
  570. * in interrupt mode with no hardware flow control.
  571. * If the option for hardware flow control is enabled and CTS is set TRUE,
  572. * then the Tx interrupt is enabled.
  573. * RETURNS: OK, or ENOSYS if in polled mode.
  574. */
  575. LOCAL int ns16550TxStartup
  576.     (
  577.     NS16550_CHAN * pChan  /* pointer to channel */
  578.     )
  579.     {
  580.     char mask;
  581.     if (pChan->channelMode == SIO_MODE_INT)
  582. {
  583. if (pChan->options & CLOCAL)
  584. {
  585. /* No modem control */
  586. pChan->ier |= TxFIFO_BIT;
  587.   REG(IER,pChan) = pChan->ier; 
  588. }
  589. else
  590. {
  591. mask = REG(MSR, pChan) & MSR_CTS;
  592.     /* if the CTS is asserted enable Tx interrupt */
  593.     if (mask & MSR_CTS)
  594. pChan->ier |= TxFIFO_BIT;    /* enable Tx interrupt */
  595. else
  596.             pChan->ier &= (~TxFIFO_BIT); /* disable Tx interrupt */
  597. REG(IER, pChan) = pChan->ier; 
  598. }
  599. return (OK);
  600. }
  601.     else
  602. {
  603.         return (ENOSYS);
  604. }
  605.     }
  606. /******************************************************************************
  607. *
  608. * ns16550PollOutput - output a character in polled mode.
  609. *
  610. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  611. * if the output buffer if full.
  612. */
  613. LOCAL int ns16550PollOutput
  614.     (
  615.     NS16550_CHAN *  pChan, /* pointer to channel */
  616.     char            outChar /* char to send */
  617.     )
  618.     {
  619.     char pollStatus = REG(LSR, pChan);
  620.     char msr = REG(MSR, pChan);
  621.     /* is the transmitter ready to accept a character? */
  622.     if ((pollStatus & LSR_THRE) == 0x00)
  623.         return (EAGAIN);
  624.     if (!(pChan->options & CLOCAL))  /* modem flow control ? */
  625.      {
  626.      if (msr & MSR_CTS)
  627.      REG(THR, pChan) = outChar;
  628. else
  629. return (EAGAIN);
  630. }
  631.     else
  632.      REG(THR, pChan) = outChar;       /* transmit character */
  633.     return (OK);
  634.     }
  635. /******************************************************************************
  636. *
  637. * ns16550PollInput - poll the device for input.
  638. *
  639. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  640. * if the input buffer if empty.
  641. */
  642. LOCAL int ns16550PollInput
  643.     (
  644.     NS16550_CHAN *  pChan, /* pointer to channel */
  645.     char *          pChar  /* pointer to char */
  646.     )
  647.     {
  648.     char pollStatus = REG(LSR, pChan);
  649.     if ((pollStatus & LSR_DR) == 0x00)
  650.         return (EAGAIN);
  651.     /* got a character */
  652.     *pChar = REG(RBR, pChan);
  653.     return (OK);
  654.     }
  655. /******************************************************************************
  656. *
  657. * ns16550CallbackInstall - install ISR callbacks to get/put chars.
  658. *
  659. * This routine installs the callback functions for the driver
  660. *
  661. * RETURNS: OK on success or ENOSYS on unsupported callback type.
  662. */
  663. LOCAL int ns16550CallbackInstall
  664.     (
  665.     SIO_CHAN *  pSioChan, /* pointer to device to control */
  666.     int         callbackType, /* callback type(tx or receive) */
  667.     STATUS      (*callback)(), /* pointer to callback function */
  668.     void *      callbackArg /* callback function argument */
  669.     )
  670.     {
  671.     NS16550_CHAN * pChan = (NS16550_CHAN *)pSioChan;
  672.     switch (callbackType)
  673.         {
  674.         case SIO_CALLBACK_GET_TX_CHAR:
  675.             pChan->getTxChar    = callback;
  676.             pChan->getTxArg     = callbackArg;
  677.             return (OK);
  678.         case SIO_CALLBACK_PUT_RCV_CHAR:
  679.             pChan->putRcvChar   = callback;
  680.             pChan->putRcvArg    = callbackArg;
  681.             return (OK);
  682.         default:
  683.             return (ENOSYS);
  684.         }
  685.     }