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

VxWorks

开发平台:

C/C++

  1. /* st16552Sio.c - ST 16C552 DUART tty driver */
  2. /* Copyright 1984-1999 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01h,30jun99,jpd  improved interrupt efficiency with FIFOs (SPR #27952).
  8. 01g,23jul98,cdp  added ARM big-endian support.
  9. 01f,04dec97,jpd  updated to latest standards. Fix max/min baud setting.
  10. 01e,03oct97,jpd  Expanded comments/documentation.
  11. 01d,04apr97,jpd  Added multiplexed interrupt handler.
  12. 01c,18feb97,jpd  Tidied comments/documentation.
  13. 01b,03dec96,jpd  Added case IIR_TIMEOUT in st16550Int routine as per change
  14.  to version 01f of ns16550Sio.c
  15. 01a,18jul96,jpd  Created from ns1550Sio.c version 01e, by adding setting of
  16.  INT bit in MCR in InitChannel().
  17. */
  18. /*
  19. DESCRIPTION
  20. This is the device driver for the Startech ST16C552 DUART, similar, but
  21. not quite identical to the National Semiconductor 16550 UART.
  22. The chip is a dual universal asynchronous receiver/transmitter with 16
  23. byte transmit and receive FIFOs and a programmable baud-rate
  24. generator. Full modem control capability is included and control over
  25. the four interrupts that can be generated: Tx, Rx, Line status, and
  26. modem status.  Only the Rx and Tx interrupts are used by this driver.
  27. The FIFOs are enabled for both Tx and Rx by this driver.
  28. Only asynchronous serial operation is supported by the UART which
  29. supports 5 to 8 bit bit word lengths with or without parity and with
  30. one or two stop bits. The only serial word format supported by the
  31. driver is 8 data bits, 1 stop bit, no parity,  The default baud rate is
  32. determined by the BSP by filling in the ST16552_CHAN structure before
  33. calling st16552DevInit().
  34. The exact baud rates supported by this driver will depend on the
  35. crystal fitted (and consequently the input clock to the baud-rate
  36. generator), but in general, baud rates from about 50 to about 115200
  37. are possible.
  38. .SH DATA STRUCTURES
  39. An ST16552_CHAN data structure is used to describe the two channels of
  40. the chip and, if necessary, an ST16552_MUX structure is used to
  41. describe the multiplexing of the interrupts for the two channels of the
  42. DUART.  These structures are described in h/drv/sio/st16552Sio.h.
  43. .SH CALLBACKS
  44. Servicing a "transmitter ready" interrupt involves making a callback to
  45. a higher level library in order to get a character to transmit.  By
  46. default, this driver installs dummy callback routines which do nothing.
  47. A higher layer library that wants to use this driver (e.g. ttyDrv)
  48. will install its own callback routine using the SIO_INSTALL_CALLBACK
  49. ioctl command.  Likewise, a receiver interrupt handler makes a callback
  50. to pass the character to the higher layer library.
  51. .SH MODES
  52. This driver supports both polled and interrupt modes.
  53. .SH USAGE
  54. The driver is typically only called by the BSP. The directly callable
  55. routines in this module are st16552DevInit(), st16552Int(),
  56. st16552IntRd(), st16552IntWr(), and st16552MuxInt.
  57. The BSP's sysHwInit() routine typically calls sysSerialHwInit(), which
  58. initialises all the hardware-specific values in the ST16552_CHAN
  59. structure before calling st16552DevInit() which resets the device and
  60. installs the driver function pointers. After this the UART will be
  61. enabled and ready to generate interrupts, but those interrupts will be
  62. disabled in the interrupt controller.
  63. The following example shows the first parts of the initialisation:
  64. .CS
  65. #include "drv/sio/st16552Sio.h"
  66. LOCAL ST16552_CHAN st16552Chan[N_16552_CHANNELS];
  67. void sysSerialHwInit (void)
  68.     {
  69.     int i;
  70.     for (i = 0; i < N_16552_CHANNELS; i++)
  71. {
  72. st16552Chan[i].regDelta = devParas[i].regSpace;
  73. st16552Chan[i].regs = devParas[i].baseAdrs;
  74. st16552Chan[i].baudRate = CONSOLE_BAUD_RATE;
  75. st16552Chan[i].xtal = UART_XTAL_FREQ;
  76. st16552Chan[i].level = devParas[i].intLevel;
  77. /@
  78.  * Initialise driver functions, getTxChar, putRcvChar and
  79.  * channelMode and init UART.
  80.  @/
  81. st16552DevInit(&st16552Chan[i]);
  82. }
  83.     }
  84. .CE
  85. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(),
  86. which connects the chips interrupts via intConnect() (either the single
  87. interrupt `st16552Int', the three interrupts `st16552IntWr',
  88. `st16552IntRd', and `st16552IntEx', or the multiplexed interrupt
  89. handler `st16552MuxInt' which will cope with both channels of a DUART
  90. producing the same interrupt). It then enables those interrupts in the
  91. interrupt controller as shown in the following example:
  92. .CS
  93. void sysSerialHwInit2 (void)
  94.     {
  95.     /@ Connect the multiplexed interrupt handler @/
  96.     (void) intConnect (INUM_TO_IVEC(devParas[0].vector),
  97. st16552MuxInt, (int) &st16552Mux);
  98.     intEnable (devParas[0].intLevel);
  99.     }
  100. .CE
  101. .SH BSP
  102. By convention all the BSP-specific serial initialisation is performed
  103. in a file called sysSerial.c, which is #include'ed by sysLib.c.
  104. sysSerial.c implements at least four functions, sysSerialHwInit()
  105. sysSerialHwInit2(), sysSerialChanGet(), and sysSerialReset(). The first
  106. two have been described above, the others work as follows:
  107. sysSerialChanGet is called by usrRoot to get the serial channel
  108. descriptor associated with a serial channel number. The routine takes a
  109. single parameter which is a channel number ranging between zero and
  110. NUM_TTY. It returns a pointer to the corresponding channel descriptor,
  111. SIO_CHAN *, which is just the address of the ST16552_CHAN strucure.
  112. sysSerialReset is called from sysToMonitor() and should reset the
  113. serial devices to an inactive state (prevent them from generating any
  114. interrupts).
  115. .SH INCLUDE FILES:
  116. drv/sio/st16552Sio.h sioLib.h
  117. SEE ALSO:
  118. .I "Startech ST16C552 Data Sheet"
  119. */
  120. #include "vxWorks.h"
  121. #include "intLib.h"
  122. #include "errnoLib.h"
  123. #include "errno.h"
  124. #include "sioLib.h"
  125. #include "drv/sio/st16552Sio.h"
  126. /* local defines  */
  127. #ifndef ST16552_REG_READ
  128. #if (CPU_FAMILY == ARM) && (_BYTE_ORDER == _BIG_ENDIAN)
  129. #define ST16552_REG_READ(pChan, reg, result) 
  130. result = 
  131.     (*(volatile UINT8 *)(3+(UINT32)pChan->regs + (reg*pChan->regDelta)))
  132. #else
  133. #define ST16552_REG_READ(pChan, reg, result) 
  134. result = 
  135.     (*(volatile UINT8 *)((UINT32)pChan->regs + (reg*pChan->regDelta)))
  136. #endif /* _BYTE_ORDER == _BIG_ENDIAN */
  137. #endif /* ifndef ST16552_REG_READ */
  138. #ifndef ST16552_REG_WRITE
  139. #define ST16552_REG_WRITE(pChan, reg, data) 
  140. (*(volatile UINT8 *)((UINT32)pChan->regs + (reg*pChan->regDelta))) = 
  141. (data)
  142. #endif
  143. /* locals */
  144. LOCAL BOOL multiplexed = FALSE; /* whether int from mux-ed handler */
  145. LOCAL char intStatus;
  146. /* function prototypes */
  147. LOCAL STATUS st16552DummyCallback ();
  148. LOCAL void st16552InitChannel (ST16552_CHAN *);
  149. LOCAL STATUS st16552Ioctl (SIO_CHAN * pSioChan, int request, int arg);
  150. LOCAL int st16552TxStartup (SIO_CHAN * pSioChan);
  151. LOCAL int st16552CallbackInstall (SIO_CHAN * pSioChan, int callbackType,
  152.        STATUS (*callback)(), void * callbackArg);
  153. LOCAL int st16552PollInput (SIO_CHAN * pSioChan, char *);
  154. LOCAL int st16552PollOutput (SIO_CHAN * pSioChan, char);
  155. /* driver functions */
  156. LOCAL SIO_DRV_FUNCS st16552SioDrvFuncs =
  157.     {
  158.     (int (*)())st16552Ioctl,
  159.     st16552TxStartup,
  160.     st16552CallbackInstall,
  161.     st16552PollInput,
  162.     st16552PollOutput
  163.     };
  164. /*******************************************************************************
  165. *
  166. * st16552DummyCallback - dummy callback routine.
  167. *
  168. * RETURNS: ERROR, always.
  169. */
  170. LOCAL STATUS st16552DummyCallback (void)
  171.     {
  172.     return ERROR;
  173.     }
  174. /*******************************************************************************
  175. *
  176. * st16552DevInit - initialise an ST16552 channel
  177. *
  178. * This routine initialises some SIO_CHAN function pointers and then resets
  179. * the chip in a quiescent state.  Before this routine is called, the BSP
  180. * must already have initialised all the device addresses, etc. in the
  181. * ST16552_CHAN structure.
  182. *
  183. * RETURNS: N/A
  184. */
  185. void st16552DevInit
  186.     (
  187.     ST16552_CHAN * pChan
  188.     )
  189.     {
  190.     int oldlevel = intLock();
  191.     /* initialise the driver function pointers in the SIO_CHAN */
  192.     pChan->sio.pDrvFuncs = &st16552SioDrvFuncs;
  193.     /* set the non BSP-specific constants */
  194.     pChan->getTxChar = st16552DummyCallback;
  195.     pChan->putRcvChar = st16552DummyCallback;
  196.     pChan->channelMode = 0;    /* undefined */
  197.     /* reset the chip */
  198.     st16552InitChannel(pChan);
  199.     intUnlock(oldlevel);
  200.     }
  201. /*******************************************************************************
  202. *
  203. * st16552InitChannel - initialise UART
  204. *
  205. * This routine performs hardware initialisation of the UART channel.
  206. *
  207. * RETURNS: N/A
  208. */
  209. LOCAL void st16552InitChannel
  210.     (
  211.     ST16552_CHAN * pChan /* ptr to ST16552 struct describing channel */
  212.     )
  213.     {
  214.     /* Configure Port -  Set 8 bits, 1 stop bit, no parity. */
  215.     /* keep soft copy */
  216.     pChan->lcr = (UINT8)(CHAR_LEN_8 | ONE_STOP | PARITY_NONE);
  217.     /* Set Line Control Register */
  218.     ST16552_REG_WRITE(pChan, LCR, pChan->lcr);
  219.     /* Reset/Enable the FIFOs */
  220.     ST16552_REG_WRITE(pChan, FCR, RxCLEAR | TxCLEAR | FIFO_ENABLE);
  221.     /* Enable access to the divisor latches by setting DLAB in LCR. */
  222.     ST16552_REG_WRITE(pChan, LCR, LCR_DLAB | pChan->lcr);
  223.     /* Set divisor latches to set baud rate */
  224.     ST16552_REG_WRITE(pChan, DLL,  pChan->xtal/(16*pChan->baudRate));
  225.     ST16552_REG_WRITE(pChan, DLM, (pChan->xtal/(16*pChan->baudRate)) >> 8);
  226.     /* Restore Line Control Register */
  227.     ST16552_REG_WRITE(pChan, LCR, pChan->lcr);
  228.     /*
  229.      * This appears to be different from the NS 16550, which defines Bit 3 to
  230.      * be a general purpose output. The ST 16552 datasheet defines it to set
  231.      * the INT output pin from tri-state to normal active mode. If this is not
  232.      * done, then no interrupts are generated, at least on the ARM PID7T
  233.      * board.
  234.      */
  235.     /* Set INT output pin to normal/active operating mode and assert DTR */
  236.     ST16552_REG_WRITE(pChan, MCR, MCR_INT | MCR_DTR);
  237.     /* Make a copy of Interrupt Enable Register */
  238.     pChan->ier = (UINT8)(RxFIFO_BIT | TxFIFO_BIT);
  239.     /* Disable interrupts */
  240.     ST16552_REG_WRITE(pChan, IER, 0);
  241.     }
  242. /*******************************************************************************
  243. *
  244. * st16552Ioctl - special device control
  245. *
  246. * This routine handles the IOCTL messages from the user.
  247. *
  248. * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
  249. * request.
  250. */
  251. LOCAL STATUS st16552Ioctl
  252.     (
  253.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  254.     int request,  /* request code */
  255.     int arg   /* some argument */
  256.     )
  257.     {
  258.     int  oldlevel; /* current interrupt level mask */
  259.     STATUS status;   /* status to return */
  260.     ST16552_CHAN * pChan = (ST16552_CHAN *)pSioChan;
  261.     UINT32 brd;   /* baud rate divisor */
  262.     status = OK; /* preset to return OK */
  263.     switch (request)
  264. {
  265. case SIO_BAUD_SET:
  266.     /*
  267.      * Set the baud rate. Return EIO for an invalid baud rate, or
  268.      * OK on success.
  269.      *
  270.      * baudrate divisor must be non-zero and must fit in a 16-bit
  271.      * register.
  272.      */
  273.     brd = pChan->xtal/(16*arg); /* calculate baudrate divisor */
  274.     if ((brd < 1) || (brd > 0xFFFF))
  275.      {
  276.      status = EIO; /* baud rate out of range */
  277.      break;
  278.      }
  279.     /* disable interrupts during chip access */
  280.     oldlevel = intLock ();
  281.     /* Enable access to the divisor latches by setting DLAB in LCR. */
  282.     ST16552_REG_WRITE(pChan, LCR, LCR_DLAB | pChan->lcr);
  283.     /* Set divisor latches. */
  284.     ST16552_REG_WRITE(pChan, DLL, brd);
  285.     ST16552_REG_WRITE(pChan, DLM, brd >> 8);
  286.     /* Restore Line Control Register */
  287.     ST16552_REG_WRITE(pChan, LCR, pChan->lcr);
  288.     pChan->baudRate = arg;
  289.     intUnlock (oldlevel);
  290.     break;
  291. case SIO_BAUD_GET:
  292.     *(int *)arg = pChan->baudRate;
  293.     break;
  294. case SIO_MODE_SET:
  295.     if ((arg != SIO_MODE_POLL) && (arg != SIO_MODE_INT))
  296. {
  297. status = EIO;
  298. break;
  299. }
  300.     oldlevel = intLock ();
  301.     if (arg == SIO_MODE_INT)
  302. {
  303. /* Enable appropriate interrupts */
  304. ST16552_REG_WRITE(pChan,
  305. IER, pChan->ier | RxFIFO_BIT | TxFIFO_BIT);
  306. }
  307.     else
  308. {
  309. /* Disable the interrupts */
  310. ST16552_REG_WRITE(pChan, IER, 0);
  311. }
  312.     pChan->channelMode = arg;
  313.     intUnlock(oldlevel);
  314.     break;
  315. case SIO_MODE_GET:
  316.     *(int *)arg = pChan->channelMode;
  317.     break;
  318. case SIO_AVAIL_MODES_GET:
  319.     *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  320.     break;
  321. case SIO_HW_OPTS_SET:
  322. case SIO_HW_OPTS_GET:
  323. default:
  324.     status = ENOSYS;
  325. }
  326.     return status;
  327.     }
  328. /*******************************************************************************
  329. *
  330. * st16552IntWr - handle a transmitter interrupt
  331. *
  332. * This routine handles write interrupts from the UART.
  333. *
  334. * RETURNS: N/A
  335. */
  336. void st16552IntWr
  337.     (
  338.     ST16552_CHAN * pChan /* ptr to struct describing channel */
  339.     )
  340.     {
  341.     char outChar;
  342.     BOOL gotOne;
  343.     UINT32 status;
  344.     do
  345.      {
  346. /* get a character to send, if available */
  347. gotOne = (*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR;
  348. if (gotOne) /* there was one, so send it */
  349.     ST16552_REG_WRITE(pChan, THR, outChar); /* write char to THR */
  350. ST16552_REG_READ(pChan, LSR, status); /* read status */
  351. }
  352.     while (gotOne && ((status & LSR_THRE) != 0));
  353.     if (!gotOne)
  354. {
  355. /* no more chars to send, disable Tx interrupt */
  356. pChan->ier &= (~TxFIFO_BIT); /* update copy */
  357. ST16552_REG_WRITE(pChan, IER, pChan->ier); /* disable Tx int */
  358. }
  359.     return;
  360.     }
  361. /*****************************************************************************
  362. *
  363. * st16552IntRd - handle a receiver interrupt
  364. *
  365. * This routine handles read interrupts from the UART.
  366. *
  367. * RETURNS: N/A
  368. */
  369. void st16552IntRd
  370.     (
  371.     ST16552_CHAN * pChan /* ptr to struct describing channel */
  372.     )
  373.     {
  374.     char inchar;
  375.     UINT32 status;
  376.     do
  377. {
  378. /* read character from Receive Holding Reg. */
  379. ST16552_REG_READ(pChan, RBR, inchar);
  380. /* send it on to upper level, via installed callback */
  381. (*pChan->putRcvChar) (pChan->putRcvArg, inchar);
  382. ST16552_REG_READ(pChan, LSR, status); /* read status, more chars? */
  383. }
  384.     while ((status & LSR_DR) != 0);
  385.     return;
  386.     }
  387. /**********************************************************************
  388. *
  389. * st16552IntEx - miscellaneous interrupt processing
  390. *
  391. * This routine handles miscellaneous interrupts on the UART.
  392. *
  393. * RETURNS: N/A
  394. */
  395. void st16552IntEx
  396.     (
  397.     ST16552_CHAN * pChan /* ptr to struct describing channel */
  398.     )
  399.     {
  400.     /* Nothing for now... */
  401.     }
  402. /******************************************************************************
  403. *
  404. * st16552Int - interrupt level processing
  405. *
  406. * This routine handles interrupts from the UART.
  407. *
  408. * RETURNS: N/A
  409. */
  410. void st16552Int
  411.     (
  412.     ST16552_CHAN * pChan /* ptr to struct describing channel */
  413.     )
  414.     {
  415.     /*
  416.      * If this routine has been called from the multiplexed interrupt
  417.      * handler, then we have already read the Interrupt Status Register,
  418.      * and must not read it again, else this routine has been installled
  419.      * directly using intConnect() and we must now read the Interrupt
  420.      * Status Register (or Interrupt Identification Register).
  421.      */
  422.      if (!multiplexed)
  423.  {
  424.  ST16552_REG_READ(pChan, IIR, intStatus);
  425.  intStatus &= 0x0F;
  426.  }
  427.     /*
  428.      * This UART chip always produces level active interrupts, and the IIR
  429.      * only indicates the highest priority interrupt.
  430.      * In the case that receive and transmit interrupts happened at
  431.      * the same time, we must clear both interrupt pending to prevent
  432.      * edge-triggered interrupt(output from interrupt controller) from locking
  433.      * up. One way doing it is to disable all the interrupts at the beginning
  434.      * of the ISR and enable at the end.
  435.      */
  436.     ST16552_REG_WRITE(pChan, IER, 0); /* disable interrupts */
  437.     switch (intStatus)
  438. {
  439. case IIR_RLS:
  440.     /*
  441.      * overrun, parity error and break interrupt:
  442.      *
  443.      * read LSR to reset interrupt
  444.      */
  445.     ST16552_REG_READ(pChan, LSR, intStatus);
  446.     break;
  447. case IIR_RDA:
  448.     /* received data available: FALL THROUGH to timeout */
  449. case IIR_TIMEOUT:
  450.     /*
  451.      * receiver FIFO interrupt. In some cases, IIR_RDA
  452.      * will not be indicated in IIR register when there
  453.      * is more than one char. in FIFO.
  454.      */
  455.     st16552IntRd (pChan); /* at least one RxChar available */
  456.     break;
  457. case IIR_THRE:
  458.     st16552IntWr (pChan); /* can transmit at least one char */
  459.     break;
  460. default:
  461.     break;
  462. }
  463.     ST16552_REG_WRITE(pChan, IER, pChan->ier); /* enable ints accordingly */
  464.     }
  465. /******************************************************************************
  466. *
  467. * st16552MuxInt - multiplexed interrupt level processing
  468. *
  469. * This routine handles multiplexed interrupts from the DUART. It assumes that
  470. * channels 0 and 1 are connected so that they produce the same interrupt.
  471. *
  472. * RETURNS: N/A
  473. */
  474. void st16552MuxInt
  475.     (
  476.     ST16552_MUX * pMux /* ptr to struct describing multiplexed chans */
  477.     )
  478.     {
  479.     ST16552_CHAN * pChan;
  480.     /* get pointer to structure for channel to examine first */
  481.     pChan = &(pMux->pChan[pMux->nextChan]);
  482.     /*
  483.      * Step on the next channel to examine: use round-robin for which to
  484.      * examine first.
  485.      */
  486.     if (pMux->nextChan == 0)
  487. pMux->nextChan = 1;
  488.     else
  489. pMux->nextChan = 0;
  490.     /*
  491.      * Let the st16552Int() routine know it is called from here, not direct
  492.      * from intConnect().
  493.      */
  494.     multiplexed = TRUE;
  495.     /* check Interrupt Status Register for this channel */
  496.     ST16552_REG_READ(pChan, IIR, intStatus);
  497.     intStatus &= 0x0F;
  498.     if ((intStatus & 0x01) == 0)
  499. {
  500. /* Call int handler if int active */
  501. st16552Int (pChan);
  502. }
  503.     else
  504. {
  505. /* step on again */
  506. pChan = &pMux->pChan[pMux->nextChan];
  507. if (pMux->nextChan == 0)
  508.     pMux->nextChan = 1;
  509. else
  510.     pMux->nextChan = 0;
  511. /* get interrupt status for next channel */
  512. ST16552_REG_READ(pChan, IIR, intStatus);
  513. intStatus &= 0x0F;
  514. /* and call interrupt handler if active */
  515. if ((intStatus & 0x01) == 0)
  516.     st16552Int (pChan);
  517. }
  518.     multiplexed = FALSE;
  519.     return;
  520.     }
  521. /*******************************************************************************
  522. *
  523. * st16552TxStartup - transmitter startup routine
  524. *
  525. * Call interrupt level character output routine and enable interrupt!
  526. *
  527. * RETURNS: OK on success, ENOSYS if the device is polled-only, or
  528. * EIO on hardware error.
  529. */
  530. LOCAL int st16552TxStartup
  531.     (
  532.     SIO_CHAN * pSioChan  /* ptr to SIO_CHAN describing this channel */
  533.     )
  534.     {
  535.     ST16552_CHAN * pChan = (ST16552_CHAN *)pSioChan;
  536.     if (pChan->channelMode == SIO_MODE_INT)
  537. {
  538. pChan->ier |= TxFIFO_BIT;
  539. ST16552_REG_WRITE(pChan, IER, pChan->ier);
  540. return OK;
  541. }
  542.     else
  543. return ENOSYS;
  544.     }
  545. /******************************************************************************
  546. *
  547. * st16552PollOutput - output a character in polled mode.
  548. *
  549. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  550. * if the output buffer is full, ENOSYS if the device is interrupt-only.
  551. */
  552. LOCAL int st16552PollOutput
  553.     (
  554.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  555.     char outChar   /* char to be output */
  556.     )
  557.     {
  558.     ST16552_CHAN * pChan = (ST16552_CHAN *)pSioChan;
  559.     char pollStatus;
  560.     ST16552_REG_READ(pChan, LSR, pollStatus);
  561.     /* is the transmitter ready to accept a character? */
  562.     if ((pollStatus & LSR_THRE) == 0x00)
  563. return EAGAIN;
  564.     /* write out the character */
  565.     ST16552_REG_WRITE(pChan, THR, outChar); /* transmit character */
  566.     return OK;
  567.     }
  568. /******************************************************************************
  569. *
  570. * st16552PollInput - poll the device for input.
  571. *
  572. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  573. * if the input buffer is empty, ENOSYS if the device is interrupt-only.
  574. */
  575. LOCAL int st16552PollInput
  576.     (
  577.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  578.     char * thisChar  /* ptr to where to return character */
  579.     )
  580.     {
  581.     ST16552_CHAN * pChan = (ST16552_CHAN *)pSioChan;
  582.     char pollStatus;
  583.     ST16552_REG_READ(pChan, LSR, pollStatus);
  584.     if ((pollStatus & LSR_DR) == 0x00)
  585. return EAGAIN;
  586.     /* got a character */
  587.     ST16552_REG_READ(pChan, RBR, *thisChar);
  588.     return OK;
  589.     }
  590. /******************************************************************************
  591. *
  592. * st16552CallbackInstall - install ISR callbacks to get/put chars.
  593. *
  594. * This routine installs interrupt callbacks for transmitting characters
  595. * and receiving characters.
  596. *
  597. * RETURNS: OK on success, or ENOSYS for an unsupported callback type.
  598. */
  599. LOCAL int st16552CallbackInstall
  600.     (
  601.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  602.     int callbackType, /* type of callback */
  603.     STATUS (*callback)(), /* callback */
  604.     void * callbackArg /* parameter to callback */
  605.     )
  606.     {
  607.     ST16552_CHAN * pChan = (ST16552_CHAN *)pSioChan;
  608.     switch (callbackType)
  609. {
  610. case SIO_CALLBACK_GET_TX_CHAR:
  611.     pChan->getTxChar = callback;
  612.     pChan->getTxArg = callbackArg;
  613.     return OK;
  614. case SIO_CALLBACK_PUT_RCV_CHAR:
  615.     pChan->putRcvChar = callback;
  616.     pChan->putRcvArg = callbackArg;
  617.     return OK;
  618. default:
  619.     return ENOSYS;
  620. }
  621.     }