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

VxWorks

开发平台:

C/C++

  1. /* sa1100Sio.c - Digital Semiconductor SA-1100 UART tty driver */
  2. /* Copyright 1998 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01a,22jan98,jpd  created from ambaSio.c version 01d.
  8. */
  9. /*
  10. DESCRIPTION
  11. This is the device driver for the Digital Semiconductor SA-1100 UARTs.
  12. This chip contains 5 serial ports, but only ports 1 and 3 are usable as
  13. UARTs, the others support Universal Serial Bus (USB), SDLC, IrDA
  14. Infrared Communications Port (ICP) and Multimedia Communications Port
  15. (MCP)/Synchronous Serial Port (SSP).
  16. The UARTs are identical in design.  They contain a universal
  17. asynchronous receiver/transmitter, and a baud-rate generator, The UARTs
  18. contain an 8-entry, 8-bit FIFO to buffer outgoing data and a 12-entry
  19. 11-bit FIFO to buffer incoming data.  If a framing, overrun or parity
  20. error occurs during reception, the appropriate error bits are stored in
  21. the receive FIFO along with the received data.  The only mode of
  22. operation supported is with the FIFOs enabled.
  23. The UART design does not support modem control input or output signals
  24. e.g. DTR, RI, RTS, DCD, CTS and DSR.
  25. An interrupt is generated when a framing, parity or receiver overrun
  26. error is present within the bottom four entries of the receive FIFO,
  27. when the transmit FIFO is half-empty or receive FIFO is one- to
  28. two-thirds full, when a begin and end of break is detected on the
  29. receiver, and when the receive FIFO is partially full and the receiver
  30. is idle for three or more frame periods.
  31. Only asynchronous serial operation is supported by the UARTs which
  32. supports 7 or 8 bit word lengths with or without parity and with one or
  33. two stop bits. The only serial word format supported by the driver is 8
  34. data bits, 1 stop bit, no parity,  The default baud rate is determined
  35. by the BSP by filling in the SA1100_CHAN structure before calling
  36. sa1100DevInit().
  37. The UART supports baud rates from 56.24 to 230.4 kbps.
  38. .SH DATA STRUCTURES
  39. An SA1100_CHAN data structure is used to describe each channel, this
  40. structure is described in h/drv/sio/sa1100Sio.h.
  41. .SH CALLBACKS
  42. Servicing a "transmitter ready" interrupt involves making a callback to
  43. a higher level library in order to get a character to transmit.  By
  44. default, this driver installs dummy callback routines which do nothing.
  45. A higher layer library that wants to use this driver (e.g. ttyDrv)
  46. will install its own callback routine using the SIO_INSTALL_CALLBACK
  47. ioctl command.  Likewise, a receiver interrupt handler makes a callback
  48. to pass the character to the higher layer library.
  49.  
  50. .SH MODES
  51. This driver supports both polled and interrupt modes.
  52. .SH USAGE
  53. The driver is typically only called by the BSP. The directly callable
  54. routines in this modules are sa1100DevInit(), and sa1100Int().
  55. The BSP's sysHwInit() routine typically calls sysSerialHwInit(), which
  56. initialises the hardware-specific fields in the SA1100_CHAN structure
  57. (e.g. register I/O addresses etc) before calling sa1100DevInit() which
  58. resets the device and installs the driver function pointers.  After
  59. this the UART will be enabled and ready to generate interrupts, but
  60. those interrupts will be disabled in the interrupt controller.
  61. The following example shows the first parts of the initialisation:
  62. .CS
  63. #include "drv/sio/sa1100Sio.h"
  64. LOCAL SA1100_CHAN sa1100Chan[N_SA1100_UART_CHANS];
  65. void sysSerialHwInit (void)
  66.     {
  67.     int i;
  68.     for (i = 0; i < N_SA1100_UART_CHANNELS; i++)
  69. {
  70. sa1100Chan[i].regs = devParas[i].baseAdrs;
  71. sa1100Chan[i].baudRate = CONSOLE_BAUD_RATE;
  72. sa1100Chan[i].xtal = UART_XTAL_FREQ; 
  73. sa1100Chan[i].level = devParas[i].intLevel;
  74. /@ set up GPIO pins and UART pin reassignment @/
  75. ...
  76. /@
  77.  * Initialise driver functions, getTxChar, putRcvChar
  78.  * and channelMode and initialise UART
  79.  @/
  80. sa1100DevInit(&sa1100Chan[i]);
  81. }
  82.     }
  83. .CE
  84. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(),
  85. which connects the chips interrupts via intConnect() and enables those
  86. interrupts, as shown in the following example:
  87. .CS
  88. void sysSerialHwInit2 (void)
  89.     {
  90.     int i;
  91.     for (i = 0; i < N_SA1100_UART_CHANNELS; i++)
  92. {
  93. /@ connect and enable interrupts @/
  94. (void)intConnect (INUM_TO_IVEC(devParas[i].vector),
  95. sa1100Int, (int) &sa1100Chan[i]);
  96. intEnable (devParas[i].intLevel);
  97. }
  98.     }
  99. .CE
  100. .SH BSP
  101. By convention all the BSP-specific serial initialisation is performed
  102. in a file called sysSerial.c, which is #include'ed by sysLib.c.
  103. sysSerial.c implements at least four functions, sysSerialHwInit()
  104. sysSerialHwInit2(), sysSerialChanGet(), and sysSerialReset(). The first
  105. two have been described above, the others work as follows:
  106. sysSerialChanGet is called by usrRoot to get the serial channel
  107. descriptor associated with a serial channel number. The routine takes a
  108. single parameter which is a channel number ranging between zero and
  109. NUM_TTY. It returns a pointer to the corresponding channel descriptor,
  110. SIO_CHAN *, which is just the address of the SA1100_CHAN structure.
  111.  
  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/sa1100Sio.h sioLib.h
  117. .SH SEE ALSO:
  118. .I Digital StrongARM SA-1100 Portable Communications Microcontroller, Data
  119. Sheet,
  120. .I Digital Semiconductor StrongARM SA-1100 Microprocessor Evaluation Platform,
  121. User's Guide
  122. */
  123. #include "vxWorks.h"
  124. #include "intLib.h"
  125. #include "errnoLib.h"
  126. #include "errno.h"
  127. #include "sioLib.h"
  128. #include "drv/sio/sa1100Sio.h"
  129. /* local defines  */
  130. #ifndef SA1100_UART_REG_READ
  131. #define SA1100_UART_REG_READ(pChan, reg, result) 
  132. ((result) = (*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg))))
  133. #endif
  134. #ifndef SA1100_UART_REG_WRITE
  135. #define SA1100_UART_REG_WRITE(pChan, reg, data) 
  136. ((*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg))) = (data))
  137. #endif
  138. /* locals */
  139. /* function prototypes */
  140. LOCAL STATUS sa1100DummyCallback (void);
  141. LOCAL void sa1100InitChannel (SA1100_CHAN * pChan);
  142. LOCAL STATUS sa1100Ioctl (SIO_CHAN * pSioChan, int request, int arg);
  143. LOCAL int sa1100TxStartup (SIO_CHAN * pSioChan);
  144. LOCAL int sa1100CallbackInstall (SIO_CHAN * pSioChan, int callbackType,
  145.        STATUS (*callback)(), void * callbackArg);
  146. LOCAL int sa1100PollInput (SIO_CHAN * pSioChan, char *);
  147. LOCAL int sa1100PollOutput (SIO_CHAN * pSioChan, char);
  148. /* driver functions */
  149. LOCAL SIO_DRV_FUNCS sa1100SioDrvFuncs =
  150.     {
  151.     (int (*)())sa1100Ioctl,
  152.     sa1100TxStartup,
  153.     sa1100CallbackInstall,
  154.     sa1100PollInput,
  155.     sa1100PollOutput
  156.     };
  157. /*******************************************************************************
  158. *
  159. * sa1100DummyCallback - dummy callback routine.
  160. *
  161. * RETURNS: ERROR, always.
  162. */
  163. LOCAL STATUS sa1100DummyCallback (void)
  164.     {
  165.     return ERROR;
  166.     }
  167. /*******************************************************************************
  168. *
  169. * sa1100DevInit - initialise an SA1100 channel
  170. *
  171. * This routine initialises some SIO_CHAN function pointers and then resets
  172. * the chip to a quiescent state.  Before this routine is called, the BSP
  173. * must already have initialised all the device addresses, etc. in the
  174. * SA1100_CHAN structure.
  175. *
  176. * RETURNS: N/A
  177. */
  178. void sa1100DevInit
  179.     (
  180.     SA1100_CHAN * pChan /* ptr to SA1100_CHAN describing this channel */
  181.     )
  182.     {
  183.     int oldlevel = intLock();
  184.     /* initialise the driver function pointers in the SIO_CHAN */
  185.     pChan->sio.pDrvFuncs = &sa1100SioDrvFuncs;
  186.     /* set the non BSP-specific constants */
  187.     pChan->getTxChar = sa1100DummyCallback;
  188.     pChan->putRcvChar = sa1100DummyCallback;
  189.     pChan->channelMode = 0;    /* am undefined mode */
  190.     /* initialise the chip */
  191.     sa1100InitChannel (pChan);
  192.     intUnlock (oldlevel);
  193.     return;
  194.     }
  195. /*******************************************************************************
  196. *
  197. * sa1100InitChannel - initialise UART
  198. *
  199. * This routine performs hardware initialisation of the UART channel.
  200. *
  201. * RETURNS: N/A
  202. */
  203. LOCAL void sa1100InitChannel
  204.     (
  205.     SA1100_CHAN * pChan /* ptr to SA1100_CHAN describing this channel */
  206.     )
  207.     {
  208.     UINT32 brd;
  209.     /* Disable UART so can set line speed */
  210.     SA1100_UART_REG_WRITE (pChan, UTCR3, 0);
  211.     /* Clear Status Register sticky bits */
  212.     SA1100_UART_REG_WRITE (pChan, UTSR0, 0xFF);
  213.     /* Set word format: set 8 bits, 1 stop bit, no parity. */
  214.     SA1100_UART_REG_WRITE (pChan, UTCR0, (WORD_LEN_8 | ONE_STOP | PARITY_NONE));
  215.     /* Set baud rate divisor */
  216.     brd = (pChan->xtal / (16 * pChan->baudRate)) - 1;
  217.     SA1100_UART_REG_WRITE (pChan, UTCR1, (brd >> 8) & 0xF);
  218.     SA1100_UART_REG_WRITE (pChan, UTCR2, brd & 0xFF);
  219.     /* Enable UART and rx and tx interrupts */
  220.     SA1100_UART_REG_WRITE (pChan, UTCR3,
  221.    UTCR3_RXE | UTCR3_TXE | UTCR3_RIM | UTCR3_TIM);
  222.     }
  223. /*******************************************************************************
  224. *
  225. * sa1100Ioctl - special device control
  226. *
  227. * This routine handles the IOCTL messages from the user.
  228. *
  229. * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
  230. * request.
  231. */
  232. LOCAL STATUS sa1100Ioctl
  233.     (
  234.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  235.     int request, /* request code */
  236.     int arg /* some argument */
  237.     )
  238.     {
  239.     int oldlevel; /* current interrupt level mask */
  240.     STATUS status; /* status to return */
  241.     UINT32 brd; /* baud rate divisor */
  242.     UINT32  cr3;
  243.     SA1100_CHAN * pChan = (SA1100_CHAN *)pSioChan;
  244.     status = OK; /* preset to return OK */
  245.     switch (request)
  246. {
  247. case SIO_BAUD_SET:
  248.     /*
  249.      * Set the baud rate. Return EIO for an invalid baud rate, or
  250.      * OK on success.
  251.      *
  252.      * Calculate the baud rate divisor: it must be non-zero and must
  253.      * fit in a 12-bit register.
  254.      */
  255.     brd = (pChan->xtal / (16 * arg)) - 1;
  256.     if (brd & ~0xFFF)
  257. {
  258. status = EIO; /* baud rate out of range */
  259. break;
  260. }
  261.     /* disable interrupts during chip access */
  262.     oldlevel = intLock ();
  263.     SA1100_UART_REG_READ (pChan, UTCR3, cr3); /* save current cr3 */
  264.     SA1100_UART_REG_WRITE (pChan, UTCR3, 0); /* disable UART */
  265.     /* Set baud rate divisor in UART */
  266.     SA1100_UART_REG_WRITE (pChan, UTCR1, (brd >> 8) & 0xF);
  267.     SA1100_UART_REG_WRITE (pChan, UTCR2, brd & 0xFF);
  268.     /* reenable UART and any enabled interrupts */
  269.     SA1100_UART_REG_WRITE (pChan, UTCR3, cr3);
  270.     pChan->baudRate = arg;
  271.  
  272.     intUnlock (oldlevel);
  273.     break;
  274. case SIO_BAUD_GET:
  275.     /* Get the baud rate and return OK */
  276.     *(int *)arg = pChan->baudRate;
  277.     break; 
  278. case SIO_MODE_SET:
  279.     /*
  280.      * Set the mode (e.g., to interrupt or polled). Return OK
  281.      * or EIO for an unknown or unsupported mode.
  282.      */
  283.     if ((arg != SIO_MODE_POLL) && (arg != SIO_MODE_INT))
  284. {
  285. status = EIO;
  286. break;
  287. }
  288.    
  289.     oldlevel = intLock ();
  290.     if (arg == SIO_MODE_INT)
  291. {
  292. /* Enable appropriate interrupt */
  293. intEnable (pChan->level);
  294. }
  295.     else
  296. {
  297. /* Disable the interrupt */ 
  298. intDisable (pChan->level);
  299. }
  300.     pChan->channelMode = arg;
  301.     intUnlock (oldlevel);
  302.     break;     
  303. case SIO_MODE_GET:
  304.     /* Get the current mode and return OK */
  305.     *(int *)arg = pChan->channelMode;
  306.     break;
  307. case SIO_AVAIL_MODES_GET:
  308.     /* Get the available modes and return OK */
  309.     *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  310.     break;
  311. case SIO_HW_OPTS_SET:
  312.     /*
  313.      * Optional command to set the hardware options (as defined
  314.      * in sioLib.h).
  315.      * Return OK, or ENOSYS if this command is not implemented.
  316.      * Note: several hardware options are specified at once.
  317.      * This routine should set as many as it can and then return
  318.      * OK. The SIO_HW_OPTS_GET is used to find out which options
  319.      * were actually set.
  320.      */
  321. case SIO_HW_OPTS_GET:
  322.     /*
  323.      * Optional command to get the hardware options (as defined
  324.      * in sioLib.h). Return OK or ENOSYS if this command is not
  325.      * implemented.  Note: if this command is unimplemented, it
  326.      * will be assumed that the driver options are CREAD | CS8
  327.      * (e.g., eight data bits, one stop bit, no parity, ints enabled).
  328.      */
  329. default:
  330.     status = ENOSYS;
  331. }
  332.     return status;
  333.     }
  334. /*******************************************************************************
  335. *
  336. * sa1100Int - handle an interrupt
  337. *
  338. * This routine handles interrupts from the UART.
  339. *
  340. * RETURNS: N/A
  341. */
  342.  
  343. void sa1100Int
  344.     (
  345.     SA1100_CHAN *       pChan   /* ptr to SA1100_CHAN describing this channel */
  346.     )
  347.     {
  348.     UINT32 ch; /* Possible char to be in/output */
  349.     UINT32 statusReg0; /* Status from UART */
  350.     UINT32 statusReg1; /* Status from UART */
  351.     int gotOne;
  352.     /* read status registers */
  353.     SA1100_UART_REG_READ (pChan, UTSR0, statusReg0);
  354.     SA1100_UART_REG_READ (pChan, UTSR1, statusReg1);
  355.     /* clear sticky interrupts */
  356.     SA1100_UART_REG_WRITE (pChan, UTSR0, UTSR0_RID | UTSR0_RBB | UTSR0_REB);
  357.     /*
  358.      * loop, removing characters from the rx FIFO (other Sio drivers do this
  359.      * so it must be OK)
  360.      */
  361.     while (statusReg1 & UTSR1_RNE)    /* data? */
  362. {
  363. SA1100_UART_REG_READ (pChan, UTDR, ch);    /* read character */
  364. (*pChan->putRcvChar) (pChan->putRcvArg, (char)ch); /* pass it on */
  365. SA1100_UART_REG_READ (pChan, UTSR1, statusReg1);   /* update status */
  366. }
  367.     /*
  368.      * if tx FIFO is interrupting, loop, writing characters to the FIFO
  369.      * until the FIFO is full or there are no more characters to transmit
  370.      */
  371.     if (statusReg0 & UTSR0_TFS) /* tx FIFO needs filling? */
  372. {
  373. do
  374.     {
  375.     gotOne = (*pChan->getTxChar) (pChan->getTxArg, &ch) != ERROR;
  376.     if (gotOne)
  377. SA1100_UART_REG_WRITE(pChan, UTDR, ch & 0xFF);  /* tx char */
  378.     SA1100_UART_REG_READ (pChan, UTSR1, statusReg1); /* get status */
  379.     }
  380. while (gotOne && (statusReg1 & UTSR1_TNF)); /* while not full */
  381. if (!gotOne)
  382.     {
  383.     /* no more chars to send - disable transmitter interrupts */
  384.     SA1100_UART_REG_READ (pChan, UTCR3, ch);
  385.     ch &= ~UTCR3_TIM;
  386.     SA1100_UART_REG_WRITE (pChan, UTCR3, ch);
  387.     }
  388. }
  389.     }
  390. /*******************************************************************************
  391. *
  392. * sa1100TxStartup - transmitter startup routine
  393. *
  394. * Call interrupt level char output routine and enable interrupt
  395. *
  396. * RETURNS: OK on success, ENOSYS if the device is polled-only, or
  397. * EIO on hardware error.
  398. */
  399. LOCAL int sa1100TxStartup
  400.     (
  401.     SIO_CHAN * pSioChan /* ptr to SIO_CHAN describing this channel */
  402.     )
  403.     {
  404.     UINT32 cr3;
  405.     SA1100_CHAN * pChan = (SA1100_CHAN *)pSioChan;
  406.     if (pChan->channelMode == SIO_MODE_INT)
  407. {
  408. /* Enable Transmitter interrupts */
  409. SA1100_UART_REG_READ (pChan, UTCR3, cr3);
  410. cr3 |= UTCR3_TIM;
  411. SA1100_UART_REG_WRITE (pChan, UTCR3, cr3);
  412. return OK;
  413. }
  414.     else
  415. return ENOSYS;
  416.     }
  417. /******************************************************************************
  418. *
  419. * sa1100PollOutput - output a character in polled mode.
  420. *
  421. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  422. * if the output buffer is full, ENOSYS if the device is interrupt-only.
  423. */
  424. LOCAL int sa1100PollOutput
  425.     (
  426.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  427.     char outChar  /* char to output */
  428.     )
  429.     {
  430.     SA1100_CHAN * pChan = (SA1100_CHAN *)pSioChan;
  431.     UINT32 pollStatus;
  432.     SA1100_UART_REG_READ (pChan, UTSR1, pollStatus);
  433.     /* is the transmitter ready to accept a character? */
  434.     if ((pollStatus & UTSR1_TNF) == 0x00)
  435. return EAGAIN;
  436.     /* write out the character */
  437.     SA1100_UART_REG_WRITE (pChan, UTDR, outChar); /* transmit character */
  438.     return OK;
  439.     }
  440. /******************************************************************************
  441. *
  442. * sa1100PollInput - poll the device for input.
  443. *
  444. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  445. * if the input buffer is empty, ENOSYS if the device is interrupt-only.
  446. */
  447. LOCAL int sa1100PollInput
  448.     (
  449.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  450.     char * thisChar /* pointer to where to return character */
  451.     )
  452.     {
  453.     SA1100_CHAN * pChan = (SA1100_CHAN *)pSioChan;
  454.     UINT32 pollStatus;
  455.     SA1100_UART_REG_READ (pChan, UTSR1, pollStatus);
  456.     if ((pollStatus & UTSR1_RNE) == 0x00)
  457. return EAGAIN;
  458.     /* got a character */
  459.     SA1100_UART_REG_READ (pChan, UTDR, *thisChar);
  460.     return OK;
  461.     }
  462. /******************************************************************************
  463. *
  464. * sa1100CallbackInstall - install ISR callbacks to get/put chars.
  465. *
  466. * This routine installs interrupt callbacks for transmitting characters
  467. * and receiving characters.
  468. *
  469. * RETURNS: OK on success, or ENOSYS for an unsupported callback type.
  470. *
  471. */
  472. LOCAL int sa1100CallbackInstall
  473.     (
  474.     SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */
  475.     int callbackType, /* type of callback */
  476.     STATUS (*callback)(), /* callback */
  477.     void * callbackArg /* parameter to callback */
  478.  
  479.     )
  480.     {
  481.     SA1100_CHAN * pChan = (SA1100_CHAN *)pSioChan;
  482.     switch (callbackType)
  483. {
  484. case SIO_CALLBACK_GET_TX_CHAR:
  485.     pChan->getTxChar = callback;
  486.     pChan->getTxArg = callbackArg;
  487.     return OK;
  488. case SIO_CALLBACK_PUT_RCV_CHAR:
  489.     pChan->putRcvChar = callback;
  490.     pChan->putRcvArg = callbackArg;
  491.     return OK;
  492. default:
  493.     return ENOSYS;
  494. }
  495.     }