ns16550SioBE.c
上传用户:yuanda199
上传日期:2022-06-26
资源大小:412k
文件大小:22k
源码类别:

VxWorks

开发平台:

C/C++

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