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

VxWorks

开发平台:

C/C++

  1. /* ambaSio.c - ARM AMBA UART tty driver */
  2. /* Copyright 1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01d,04dec97,jpd  updated doc'n to latest standards. Fix max/min baud setting.
  8. 01c,13oct97,jpd  modified comments/documentation.
  9. 01b,26sep97,jpd  modified in line with errata, removed debugging code.
  10. 01a,18sep97,jpd  created from st1550Sio.c version 01d.
  11. */
  12. /*
  13. DESCRIPTION
  14. This is the device driver for the Advanced RISC Machines (ARM) AMBA
  15. UART. This is a generic design of UART used within a number of chips
  16. containing (or for use with) ARM CPUs such as in the Digital Semiconductor
  17. 21285 chip as used in the EBSA-285 BSP.
  18. This design contains a universal asynchronous receiver/transmitter, a
  19. baud-rate generator, and an InfraRed Data Association (IrDa) Serial
  20. InfraRed (SiR) protocol encoder. The Sir encoder is not supported by
  21. this driver. The UART contains two 16-entry deep FIFOs for receive and
  22. transmit: if a framing, overrun or parity error occurs during
  23. reception, the appropriate error bits are stored in the receive FIFO
  24. along with the received data. The FIFOs can be programmed to be one
  25. byte deep only, like a conventional UART with double buffering, but the
  26. only mode of operation supported is with the FIFOs enabled.
  27. The UART design does not support the modem control output signals: DTR,
  28. RI and RTS. Moreover, the implementation in the 21285 chip does not
  29. support the modem control inputs: DCD, CTS and DSR.
  30. The UART design can generate four interrupts: Rx, Tx, modem status
  31. change and a UART disabled interrupt (which is asserted when a start
  32. bit is detected on the receive line when the UART is disabled). The
  33. implementation in the 21285 chip has only two interrupts: Rx and Tx,
  34. but the Rx interrupt is a combination of the normal Rx interrupt status
  35. and the UART disabled interrupt status.
  36. Only asynchronous serial operation is supported by the UART which
  37. supports 5 to 8 bit bit word lengths with or without parity and with
  38. one or two stop bits. The only serial word format supported by the
  39. driver is 8 data bits, 1 stop bit, no parity,  The default baud rate is
  40. determined by the BSP by filling in the AMBA_CHAN structure before
  41. calling ambaDevInit().
  42. The exact baud rates supported by this driver will depend on the
  43. crystal fitted (and consequently the input clock to the baud-rate
  44. generator), but in general, baud rates from about 300 to about 115200
  45. are possible.
  46. In theory, any number of UART channels could be implemented within a
  47. chip. This driver has been designed to cope with an arbitrary number of
  48. channels, but at the time of writing, has only ever been tested with
  49. one channel.
  50. .SH DATA STRUCTURES
  51. An AMBA_CHAN data structure is used to describe each channel, this
  52. structure is described in h/drv/sio/ambaSio.h.
  53. .SH CALLBACKS
  54. Servicing a "transmitter ready" interrupt involves making a callback to
  55. a higher level library in order to get a character to transmit.  By
  56. default, this driver installs dummy callback routines which do nothing.
  57. A higher layer library that wants to use this driver (e.g. ttyDrv)
  58. will install its own callback routine using the SIO_INSTALL_CALLBACK
  59. ioctl command.  Likewise, a receiver interrupt handler makes a callback
  60. to pass the character to the higher layer library.
  61.  
  62. .SH MODES
  63. This driver supports both polled and interrupt modes.
  64. .SH USAGE
  65. The driver is typically only called by the BSP. The directly callable
  66. routines in this modules are ambaDevInit(), ambaIntTx() and
  67. ambaIntRx().
  68. The BSP's sysHwInit() routine typically calls sysSerialHwInit(), which
  69. initialises the hardware-specific fields in the AMBA_CHAN structure
  70. (e.g. register I/O addresses etc) before calling ambaDevInit() which
  71. resets the device and installs the driver function pointers.  After
  72. this the UART will be enabled and ready to generate interrupts, but
  73. those interrupts will be disabled in the interrupt controller.
  74. The following example shows the first parts of the initialisation:
  75. .CS
  76. #include "drv/sio/ambaSio.h"
  77. LOCAL AMBA_CHAN ambaChan[N_AMBA_UART_CHANS];
  78. void sysSerialHwInit (void)
  79.     {
  80.     int i;
  81.     for (i = 0; i < N_AMBA_UART_CHANS; i++)
  82. {
  83. ambaChan[i].regs = devParas[i].baseAdrs;
  84. ambaChan[i].baudRate = CONSOLE_BAUD_RATE;
  85. ambaChan[i].xtal = UART_XTAL_FREQ; 
  86. ambaChan[i].levelRx = devParas[i].intLevelRx;
  87. ambaChan[i].levelTx = devParas[i].intLevelTx;
  88. /@
  89.  * Initialise driver functions, getTxChar, putRcvChar and
  90.  * channelMode, then initialise UART
  91.  @/
  92. ambaDevInit(&ambaChan[i]);
  93. }
  94.     }
  95. .CE
  96. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(),
  97. which connects the chips interrupts via intConnect() (the two
  98. interrupts `ambaIntTx' and `ambaIntRx') and enables those interrupts,
  99. as shown in the following example:
  100. .CS
  101. void sysSerialHwInit2 (void)
  102.     {
  103.     /@ connect and enable Rx interrupt @/
  104.     (void) intConnect (INUM_TO_IVEC(devParas[0].vectorRx),
  105.        ambaIntRx, (int) &ambaChan[0]);
  106.     intEnable (devParas[0].intLevelRx);
  107.     /@ connect Tx interrupt @/
  108.     (void) intConnect (INUM_TO_IVEC(devParas[0].vectorTx),
  109.        ambaIntTx, (int) &ambaChan[0]);
  110.     /@
  111.      * There is no point in enabling the Tx interrupt, as it will
  112.      * interrupt immediately and then be disabled.
  113.      @/
  114.     }
  115. .CE
  116. .SH BSP
  117. By convention all the BSP-specific serial initialisation is performed
  118. in a file called sysSerial.c, which is #include'ed by sysLib.c.
  119. sysSerial.c implements at least four functions, sysSerialHwInit()
  120. sysSerialHwInit2(), sysSerialChanGet(), and sysSerialReset(). The first
  121. two have been described above, the others work as follows:
  122. sysSerialChanGet is called by usrRoot to get the serial channel
  123. descriptor associated with a serial channel number. The routine takes a
  124. single parameter which is a channel number ranging between zero and
  125. NUM_TTY. It returns a pointer to the corresponding channel descriptor,
  126. SIO_CHAN *, which is just the address of the AMBA_CHAN structure.
  127.  
  128. sysSerialReset is called from sysToMonitor() and should reset the
  129. serial devices to an inactive state (prevent them from generating any
  130. interrupts).
  131. .SH INCLUDE FILES:
  132. drv/sio/ambaSio.h sioLib.h
  133. .SH SEE ALSO:
  134. .I "Advanced RISC Machines AMBA UART (AP13) Data Sheet,"
  135. .I "Digital Semiconductor 21285 Core Logic for SA-110 Microprocessor Data
  136. Sheet,"
  137. .I "Digital Semiconductor EBSA-285 Evaluation Board Reference Manual."
  138. */
  139. #include "vxWorks.h"
  140. #include "intLib.h"
  141. #include "errnoLib.h"
  142. #include "errno.h"
  143. #include "sioLib.h"
  144. #include "drv/sio/ambaSio.h"
  145. /* local defines  */
  146. #ifndef AMBA_UART_REG_READ
  147. #define AMBA_UART_REG_READ(pChan, reg, result) 
  148. result = (*(volatile UINT32 *)((UINT32)pChan->regs + reg))
  149. #endif
  150. #ifndef AMBA_UART_REG_WRITE
  151. #define AMBA_UART_REG_WRITE(pChan, reg, data) 
  152. (*(volatile UINT32 *)((UINT32)pChan->regs + reg)) = (data)
  153. #endif
  154. /* locals */
  155. /* function prototypes */
  156. LOCAL STATUS ambaDummyCallback (void);
  157. LOCAL void ambaInitChannel (AMBA_CHAN * pChan);
  158. LOCAL STATUS ambaIoctl (SIO_CHAN * pSioChan, int request, int arg);
  159. LOCAL int ambaTxStartup (SIO_CHAN * pSioChan);
  160. LOCAL int ambaCallbackInstall (SIO_CHAN * pSioChan, int callbackType,
  161.        STATUS (*callback)(), void * callbackArg);
  162. LOCAL int ambaPollInput (SIO_CHAN * pSioChan, char *);
  163. LOCAL int ambaPollOutput (SIO_CHAN * pSioChan, char);
  164. /* driver functions */
  165. LOCAL SIO_DRV_FUNCS ambaSioDrvFuncs =
  166.     {
  167.     (int (*)())ambaIoctl,
  168.     ambaTxStartup,
  169.     ambaCallbackInstall,
  170.     ambaPollInput,
  171.     ambaPollOutput
  172.     };
  173. /*******************************************************************************
  174. *
  175. * ambaDummyCallback - dummy callback routine.
  176. *
  177. * RETURNS: ERROR, always.
  178. */
  179. LOCAL STATUS ambaDummyCallback (void)
  180.     {
  181.     return ERROR;
  182.     }
  183. /*******************************************************************************
  184. *
  185. * ambaDevInit - initialise an AMBA channel
  186. *
  187. * This routine initialises some SIO_CHAN function pointers and then resets
  188. * the chip to a quiescent state.  Before this routine is called, the BSP
  189. * must already have initialised all the device addresses, etc. in the
  190. * AMBA_CHAN structure.
  191. *
  192. * RETURNS: N/A
  193. */
  194. void ambaDevInit
  195.     (
  196.     AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
  197.     )
  198.     {
  199.     int oldlevel = intLock();
  200.     /* initialise the driver function pointers in the SIO_CHAN */
  201.     pChan->sio.pDrvFuncs = &ambaSioDrvFuncs;
  202.     /* set the non BSP-specific constants */
  203.     pChan->getTxChar = ambaDummyCallback;
  204.     pChan->putRcvChar = ambaDummyCallback;
  205.     pChan->channelMode = 0;    /* undefined */
  206.     /* initialise the chip */
  207.     ambaInitChannel (pChan);
  208.     intUnlock (oldlevel);
  209.     }
  210. /*******************************************************************************
  211. *
  212. * ambaInitChannel - initialise UART
  213. *
  214. * This routine performs hardware initialisation of the UART channel.
  215. *
  216. * RETURNS: N/A
  217. */
  218. LOCAL void ambaInitChannel
  219.     (
  220.     AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
  221.     )
  222.     {
  223.     int i;
  224.     UINT32 discard;
  225.     /* Fill Tx FIFO with nulls (data sheet specifies this) */
  226.     for (i = 0; i < 16; i++)
  227. AMBA_UART_REG_WRITE(pChan, UARTDR, 0);
  228.     /* Program UART control register */
  229.     AMBA_UART_REG_WRITE(pChan, UARTCON, 0);
  230.     AMBA_UART_REG_WRITE(pChan, UARTCON, UART_ENABLE);
  231.     /* Set baud rate divisor */
  232.     AMBA_UART_REG_WRITE(pChan, L_UBRLCR,
  233.     (pChan->xtal / (16 * pChan->baudRate) - 1) & 0xFF);
  234.     AMBA_UART_REG_WRITE(pChan, M_UBRLCR,
  235.     ((pChan->xtal / (16 * pChan->baudRate) - 1) >> 8) & 0xF);
  236.     /*
  237.      * Set word format, enable FIFOs: set 8 bits, 1 stop bit, no parity.
  238.      * This also latches the writes to the two (sub)registers above.
  239.      */
  240.     AMBA_UART_REG_WRITE(pChan, H_UBRLCR,
  241. (UINT8)(WORD_LEN_8 | ONE_STOP | PARITY_NONE | FIFO_ENABLE));
  242.  
  243.     /* Clear Rx FIFO (data sheet specifies this) */
  244.     for (i = 0; i < 16; i++)
  245. AMBA_UART_REG_READ(pChan, RXSTAT, discard);
  246.     }
  247. /*******************************************************************************
  248. *
  249. * ambaIoctl - special device control
  250. *
  251. * This routine handles the IOCTL messages from the user.
  252. *
  253. * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
  254. * request.
  255. */
  256. LOCAL STATUS ambaIoctl
  257.     (
  258.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  259.     int request, /* request code */
  260.     int arg /* some argument */
  261.     )
  262.     {
  263.     int oldlevel; /* current interrupt level mask */
  264.     STATUS status; /* status to return */
  265.     UINT32 brd; /* baud rate divisor */
  266.     AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
  267.     status = OK; /* preset to return OK */
  268.     switch (request)
  269. {
  270. case SIO_BAUD_SET:
  271.     /*
  272.      * Set the baud rate. Return EIO for an invalid baud rate, or
  273.      * OK on success.
  274.      */
  275.     /*
  276.      * baudrate divisor must be non-zero and must fit in a 12-bit
  277.      * register.
  278.      */
  279.     brd = (pChan->xtal/(16*arg)) - 1; /* calculate baudrate divisor */
  280.     if ((brd < 1) || (brd > 0xFFF))
  281. {
  282. status = EIO; /* baud rate out of range */
  283. break;
  284. }
  285.     /* disable interrupts during chip access */
  286.     oldlevel = intLock ();
  287.     /* Set baud rate divisor in UART */
  288.     AMBA_UART_REG_WRITE(pChan, L_UBRLCR, brd & 0xFF);
  289.     AMBA_UART_REG_WRITE(pChan, M_UBRLCR, (brd >> 8) & 0xF);
  290.     /*
  291.      * Set word format, enable FIFOs: set 8 bits, 1 stop bit, no parity.
  292.      * This also latches the writes to the two (sub)registers above.
  293.      */
  294.     AMBA_UART_REG_WRITE(pChan, H_UBRLCR,
  295. (UINT8)(WORD_LEN_8 | ONE_STOP | PARITY_NONE | FIFO_ENABLE));
  296.     pChan->baudRate = arg;
  297.  
  298.     intUnlock (oldlevel);
  299.     break;
  300. case SIO_BAUD_GET:
  301.     /* Get the baud rate and return OK */
  302.     *(int *)arg = pChan->baudRate;
  303.     break; 
  304. case SIO_MODE_SET:
  305.     /*
  306.      * Set the mode (e.g., to interrupt or polled). Return OK
  307.      * or EIO for an unknown or unsupported mode.
  308.      */
  309.     if ((arg != SIO_MODE_POLL) && (arg != SIO_MODE_INT))
  310. {
  311. status = EIO;
  312. break;
  313. }
  314.    
  315.     oldlevel = intLock ();
  316.     if (arg == SIO_MODE_INT)
  317. {
  318. /* Enable appropriate interrupts */
  319. intEnable (pChan->levelRx);
  320. /*
  321.  * There is no point in enabling the Tx interrupt, as it
  322.  * will interrupt immediately and be disabled.
  323.  */  
  324. }
  325.     else
  326. {
  327. /* Disable the interrupts */ 
  328. intDisable (pChan->levelRx);
  329. intDisable (pChan->levelTx);
  330. }
  331.     pChan->channelMode = arg;
  332.     intUnlock (oldlevel);
  333.     break;     
  334. case SIO_MODE_GET:
  335.     /* Get the current mode and return OK */
  336.     *(int *)arg = pChan->channelMode;
  337.     break;
  338. case SIO_AVAIL_MODES_GET:
  339.     /* Get the available modes and return OK */
  340.     *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  341.     break;
  342. case SIO_HW_OPTS_SET:
  343.     /*
  344.      * Optional command to set the hardware options (as defined
  345.      * in sioLib.h).
  346.      * Return OK, or ENOSYS if this command is not implemented.
  347.      * Note: several hardware options are specified at once.
  348.      * This routine should set as many as it can and then return
  349.      * OK. The SIO_HW_OPTS_GET is used to find out which options
  350.      * were actually set.
  351.      */
  352. case SIO_HW_OPTS_GET:
  353.     /*
  354.      * Optional command to get the hardware options (as defined
  355.      * in sioLib.h). Return OK or ENOSYS if this command is not
  356.      * implemented.  Note: if this command is unimplemented, it
  357.      * will be assumed that the driver options are CREAD | CS8
  358.      * (e.g., eight data bits, one stop bit, no parity, ints enabled).
  359.      */
  360. default:
  361.     status = ENOSYS;
  362. }
  363.     return status;
  364.     }
  365. /*******************************************************************************
  366. *
  367. * ambaIntTx - handle a transmitter interrupt 
  368. *
  369. * This routine handles write interrupts from the UART.
  370. *
  371. * RETURNS: N/A
  372. */
  373. void ambaIntTx 
  374.     (
  375.     AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
  376.     )
  377.     {
  378.     char outChar;
  379.     if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
  380. /* write char. to Transmit Holding Reg. */
  381. AMBA_UART_REG_WRITE(pChan, UARTDR, outChar);
  382.     else
  383. intDisable (pChan->levelTx);
  384.     }
  385. /*****************************************************************************
  386. *
  387. * ambaIntRx - handle a receiver interrupt 
  388. *
  389. * This routine handles read interrupts from the UART.
  390. *
  391. * RETURNS: N/A
  392. */
  393. void ambaIntRx
  394.     (
  395.     AMBA_CHAN * pChan /* ptr to AMBA_CHAN describing this channel */
  396.     )
  397.     {
  398.     char inchar;
  399.     /* read character from Receive Holding Reg. */
  400.     AMBA_UART_REG_READ(pChan, UARTDR, inchar);
  401.     (*pChan->putRcvChar) (pChan->putRcvArg, inchar);
  402.     }
  403. /*******************************************************************************
  404. *
  405. * ambaTxStartup - transmitter startup routine
  406. *
  407. * Enable interrupt so that interrupt-level char output routine will be called.
  408. *
  409. * RETURNS: OK on success, ENOSYS if the device is polled-only, or
  410. * EIO on hardware error.
  411. */
  412. LOCAL int ambaTxStartup
  413.     (
  414.     SIO_CHAN * pSioChan /* ptr to SIO_CHAN describing this channel */
  415.     )
  416.     {
  417.     AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
  418.     if (pChan->channelMode == SIO_MODE_INT)
  419. {
  420. intEnable (pChan->levelTx);
  421. return OK;
  422. }
  423.     else
  424. return ENOSYS;
  425.     }
  426. /******************************************************************************
  427. *
  428. * ambaPollOutput - output a character in polled mode.
  429. *
  430. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  431. * if the output buffer is full, ENOSYS if the device is interrupt-only.
  432. */
  433. LOCAL int ambaPollOutput
  434.     (
  435.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  436.     char outChar  /* char to output */
  437.     )
  438.     {
  439.     AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
  440.     FAST UINT32 pollStatus;
  441.     AMBA_UART_REG_READ(pChan, UARTFLG, pollStatus);
  442.     /* is the transmitter ready to accept a character? */
  443.     if ((pollStatus & FLG_UTXFF) != 0x00)
  444. return EAGAIN;
  445.     /* write out the character */
  446.     AMBA_UART_REG_WRITE(pChan, UARTDR, outChar); /* transmit character */
  447.     return OK;
  448.     }
  449. /******************************************************************************
  450. *
  451. * ambaPollInput - poll the device for input.
  452. *
  453. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  454. * if the input buffer is empty, ENOSYS if the device is interrupt-only.
  455. */
  456. LOCAL int ambaPollInput
  457.     (
  458.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  459.     char * thisChar /* pointer to where to return character */
  460.     )
  461.     {
  462.     AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
  463.     FAST UINT32 pollStatus;
  464.     AMBA_UART_REG_READ(pChan, UARTFLG, pollStatus);
  465.     if ((pollStatus & FLG_URXFE) != 0x00)
  466. return EAGAIN;
  467.     /* got a character */
  468.     AMBA_UART_REG_READ(pChan, UARTDR, *thisChar);
  469.     return OK;
  470.     }
  471. /******************************************************************************
  472. *
  473. * ambaCallbackInstall - install ISR callbacks to get/put chars.
  474. *
  475. * This routine installs interrupt callbacks for transmitting characters
  476. * and receiving characters.
  477. *
  478. * RETURNS: OK on success, or ENOSYS for an unsupported callback type.
  479. *
  480. */
  481. LOCAL int ambaCallbackInstall
  482.     (
  483.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  484.     int callbackType, /* type of callback */
  485.     STATUS (*callback)(), /* callback */
  486.     void * callbackArg /* parameter to callback */
  487.  
  488.     )
  489.     {
  490.     AMBA_CHAN * pChan = (AMBA_CHAN *)pSioChan;
  491.     switch (callbackType)
  492. {
  493. case SIO_CALLBACK_GET_TX_CHAR:
  494.     pChan->getTxChar = callback;
  495.     pChan->getTxArg = callbackArg;
  496.     return OK;
  497. case SIO_CALLBACK_PUT_RCV_CHAR:
  498.     pChan->putRcvChar = callback;
  499.     pChan->putRcvArg = callbackArg;
  500.     return OK;
  501. default:
  502.     return ENOSYS;
  503. }
  504.     }