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