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

VxWorks

开发平台:

C/C++

  1. /* nvr4101SIUSio.c - NEC VR4101 SIU UART tty driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01b,24apr02,pmr  SPR 75161: returning int from nvr4101SIUTxStartup() as
  8.                  required.
  9. 01a,11jun97,sru  written.
  10. */
  11. /*
  12. DESCRIPTION
  13. This is the device driver for the nvr4101 UART.
  14. USAGE
  15. A NVR4101_CHAN data structure is used to describe the SIU.
  16. The BSP's sysHwInit() routine typically calls sysSerialHwInit(), which
  17. should pass a pointer to an uninitialized NVR4101_CHAN structure to
  18. nvr4101SIUDevInit().  The BSP's sysHwInit2() routine typically calls
  19. sysSerialHwInit2(), which connects the chip's interrupts via
  20. intConnect().
  21. INCLUDE FILES: drv/sio/nvr4101SIUSio.h
  22. */
  23. #include "vxWorks.h"
  24. #include "intLib.h"
  25. #include "logLib.h"
  26. #include "errnoLib.h"
  27. #include "errno.h"
  28. #include "sioLib.h"
  29. #include "memLib.h"
  30. #include "stdlib.h"
  31. #include "drv/multi/nvr4101.h"
  32. #include "drv/sio/nvr4101SIUSio.h"
  33. /* local defines */
  34. #define RX_INT_SOURCES (VR4101_ICU_SIU_RXG | /* 1-char reception end */ 
  35. VR4101_ICU_SIU_RXE | /* rx DMA 2-page end */ 
  36. VR4101_ICU_SIU_RXI) /* rx DMA 1-page end */
  37. #define TX_INT_SOURCES (VR4101_ICU_SIU_TXI |  /* tx DMA 1-page end */ 
  38. VR4101_ICU_SIU_TXE) /* tx DMA 2-page end */
  39. /* min/max baud rate */
  40. #define NVR4101_MIN_RATE 1200
  41. #define NVR4101_MAX_RATE 115200
  42. typedef struct /* BAUD */
  43.     {
  44.     int rate;        /* baud rate */
  45.     int cntl;        /* control bits */
  46.     } BAUD;
  47. LOCAL BAUD baudTable [] =
  48.     {
  49.     {   1200, 0},
  50.     {   2400, 1},
  51.     {   4800, 2},
  52.     {   9600, 3},
  53.     {  19200, 4},
  54.     {  38400, 5},
  55.     {  57600, 6},
  56.     { 115200, 7}
  57.     };
  58. LOCAL char txrxBuf [3 * DMA_PAGE_SIZE];
  59. /* function prototypes */
  60. LOCAL int nvr4101SIUCallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);
  61. LOCAL STATUS nvr4101SIUDummyCallback ();
  62. LOCAL void nvr4101SIUInitChannel (NVR4101_SIU_CHAN *);
  63. LOCAL STATUS nvr4101SIUIoctl (NVR4101_SIU_CHAN *, int, int);
  64. LOCAL int nvr4101SIUTxStartup (NVR4101_SIU_CHAN *);
  65. LOCAL int nvr4101SIUPollOutput (NVR4101_SIU_CHAN *, char);
  66. LOCAL int nvr4101SIUPollInput (NVR4101_SIU_CHAN *, char *);
  67. LOCAL void nvr4101SIUIntMask ();
  68. LOCAL void nvr4101SIUIntUnmask ();
  69. LOCAL UINT16 nvr4101SIUCharToTxWord (char outChar);
  70. LOCAL char nvr4101SIURxWordToChar (UINT16 inWord);
  71. LOCAL void nvr4101SIUTxOutput (NVR4101_SIU_CHAN *pChan, char outChar);
  72. /* driver functions */
  73. LOCAL SIO_DRV_FUNCS nvr4101SIUSioDrvFuncs =
  74.     {
  75.     (int (*)())nvr4101SIUIoctl,
  76.     (int (*)())nvr4101SIUTxStartup,
  77.     (int (*)())nvr4101SIUCallbackInstall,
  78.     (int (*)())nvr4101SIUPollInput,
  79.     (int (*)(SIO_CHAN *,char))nvr4101SIUPollOutput
  80.     };
  81. /******************************************************************************
  82. *
  83. * nvr4101SIUDummyCallback - dummy callback routine.
  84. */
  85. LOCAL STATUS nvr4101SIUDummyCallback (void)
  86.     {
  87.     return (ERROR);
  88.     }
  89. /******************************************************************************
  90. *
  91. * nvr4101SIUDevInit - initialization of the NVR4101SIU SIU.
  92. *
  93. * This routine initializes some SIO_CHAN function pointers and then resets
  94. * the chip in a quiescent state.  No initialization of the NVR4101_SIU_CHAN
  95. * structure is required before this routine is called.
  96. *
  97. * RETURNS: N/A
  98. */
  99. void nvr4101SIUDevInit
  100.     (
  101.     NVR4101_SIU_CHAN * pChan
  102.     )
  103.     {
  104.     int oldlevel;
  105.     oldlevel = intLock ();
  106.     /* initialize the driver function pointers in the SIO_CHAN's */
  107.     pChan->sio.pDrvFuncs = &nvr4101SIUSioDrvFuncs;
  108.     pChan->getTxChar = nvr4101SIUDummyCallback;
  109.     pChan->putRcvChar = nvr4101SIUDummyCallback;
  110.     /* set the SIU state variables */
  111.     pChan->txActive = FALSE;
  112.     pChan->channelMode = -1;  /* so ioctl will notice first change */
  113.     /* construct pointers to rx/tx buffers aligned with DMA boundaries */
  114.     pChan->pTxBuf = (char *) ROUND_UP ((int) txrxBuf, DMA_PAGE_SIZE);
  115.     pChan->pTxBuf = (char *) K0_TO_K1 (pChan->pTxBuf);
  116.     pChan->pRxBuf = pChan->pTxBuf + DMA_PAGE_SIZE;
  117.     /* construct pointers to the 2nd-to-last word in each buffer */
  118.     pChan->pTxWord = ((UINT16 *) (pChan->pTxBuf + DMA_PAGE_SIZE)) - 2;
  119.     pChan->pRxWord = ((UINT16 *) (pChan->pRxBuf + DMA_PAGE_SIZE)) - 2;
  120.     /* make the last word a word of all stop bits */
  121.     pChan->pTxWord[1] = ~0;
  122.     pChan->pTxWord[1] = ~0;
  123.     /* reset the SIU */
  124.     nvr4101SIUInitChannel (pChan);
  125.     intUnlock (oldlevel);
  126.     }
  127. /*******************************************************************************
  128. *
  129. * nvr4101SIUInitChannel - initialize UART
  130. *
  131. * RETURNS: N/A.
  132. */
  133. LOCAL void nvr4101SIUInitChannel
  134.     (
  135.     NVR4101_SIU_CHAN *pChan
  136.     )
  137.     {
  138.     UINT32 rxAdr;
  139.     /* enable SIU clock from within the CIU subsystem */
  140.     *VR4101_CMUCLKMSK |= VR4101_MSKSIU;
  141.     /* forcibly reset the SIU */
  142.     *VR4101_SIUCNTREG |= VR4101_SIU_SRST;
  143.     /* 
  144.      * Set transmit length of 1 start bit, 8 data bits, 1 stop bit, 
  145.      * no parity. (1+8+1 = 10).  The receive length is identical,
  146.      * except that the stop bit is not included in the calculation,
  147.      * so the receive length is one less than the transmit length. 
  148.      */
  149.     *VR4101_SIUDLENGTHREG = (10 << VR4101_SIU_TX_CHAR_WIDTH_SHIFT) |
  150.                             (9 << VR4101_SIU_RX_CHAR_WIDTH_SHIFT) |
  151.             VR4101_SIU_STOP_BITS_1;
  152.     /*
  153.      * Select RS232 mode, and set transmit and receive DMA stop 
  154.      * addresses at page 1 boundary.
  155.      */
  156.     *VR4101_SIUCNTREG = VR4101_SIU_RS232_MODE |
  157.        VR4101_SIU_RSP | VR4101_SIU_TSP;
  158.     /* Confirm that DTR and RTS are high. */
  159.     *VR4101_SIURS232CREG = VR4101_SIU_DTR | VR4101_SIU_RTS;
  160.     /* Set receive DMA address pointer */
  161.     rxAdr = K0_TO_K1 (pChan->pRxWord);
  162.     *VR4101_SRXDMAADRLREG = (UINT16) rxAdr;
  163.     *VR4101_SRXDMAADRHREG = (UINT16) (rxAdr >> 16);
  164.     /* enable the receiver */
  165.     *VR4101_SIUCNTREG |= VR4101_SIU_RXE;
  166.     /* 
  167.      * unmask the desired interrupts.  Note that the SIU summary interrupt
  168.      * bit within the VR4101_ICU_MSYSINTREG register is _not_ enabled
  169.      * by this driver.  This allows other parts of the BSP to
  170.      * selectively enable or disable the entire SIU using the summary bit, 
  171.      * and hides the details of the specific unmasked SIU interrupts within 
  172.      * this driver. 
  173.      */
  174.     nvr4101SIUIntUnmask ();
  175.     }
  176. /*******************************************************************************
  177. *
  178. * nvr4101SIUIoctl - special device control
  179. *
  180. * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
  181. *          request.
  182. */
  183. LOCAL STATUS nvr4101SIUIoctl
  184.     (
  185.     NVR4101_SIU_CHAN *pChan, /* device to control */
  186.     int        request, /* request code */
  187.     int        arg /* some argument */
  188.     )
  189.     {
  190.     int    oldlevel;
  191.     STATUS status;
  192.     int i;
  193.     status = OK;
  194.     switch (request)
  195. {
  196. case SIO_BAUD_SET:
  197.             status = EIO;  /* assume baud rate out of range */
  198.             for (i = 0; i < NELEMENTS (baudTable); i++)
  199.                 {
  200.                 if (baudTable [i].rate == (int)arg)
  201.                     {
  202.     pChan->baudRate = arg;
  203.     oldlevel = intLock ();
  204.     *VR4101_SIUBAUDSELREG = baudTable [i].cntl;
  205.     intUnlock (oldlevel);
  206.                     status = OK;
  207.                     break;
  208.                     }
  209.         }
  210.     break;
  211.         case SIO_BAUD_GET:
  212.             *(int *)arg = pChan->baudRate;
  213.             break; 
  214.         case SIO_MODE_SET:
  215.             if ((arg != SIO_MODE_POLL) && (arg != SIO_MODE_INT))
  216.                 {
  217.                 status = EIO;
  218.                 break;
  219.                 }
  220.            
  221.     if (arg != pChan->channelMode)
  222. {
  223. if (arg == SIO_MODE_INT)
  224.     {
  225.     /* clear all pending interrupts */
  226.     *VR4101_SIUINTREG = TX_INT_SOURCES | RX_INT_SOURCES;
  227.     /* mark that we're not awaiting xmit interrupt */
  228.     pChan->txActive = FALSE;
  229.     /* Enable appropriate interrupts */
  230.     nvr4101SIUIntUnmask ();
  231.     }
  232. else
  233.     {
  234.     /* Disable the interrupts */ 
  235.     
  236.     nvr4101SIUIntMask ();
  237.     }
  238. pChan->channelMode = arg;
  239. }
  240.             break;          
  241.         case SIO_MODE_GET:
  242.             *(int *)arg = pChan->channelMode;
  243.             break;
  244.         case SIO_AVAIL_MODES_GET:
  245.             *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  246.             break;
  247.         case SIO_HW_OPTS_SET:
  248.         case SIO_HW_OPTS_GET:
  249.         default:
  250.             status = ENOSYS;
  251. }
  252.     return (status);
  253.     }
  254. /********************************************************************************
  255. * nvr4101SIUInt - interrupt level processing
  256. *
  257. * This routine handles interrupts from the SIU.
  258. *
  259. * RETURNS: N/A
  260. */
  261. void nvr4101SIUInt
  262.     (
  263.     NVR4101_SIU_CHAN *pChan
  264.     )
  265.     {
  266.     UINT16  statusReg;
  267.     char outChar;
  268.     /* get status from the SIU (not ICU) subsystem.  */
  269.     statusReg = *VR4101_SIUINTREG;
  270.     /* write status value back out to clear the various sources */
  271.     *VR4101_SIUINTREG = statusReg;
  272.     /* handle receiver interrupt */
  273.     if (statusReg & RX_INT_SOURCES)
  274. {
  275. (*pChan->putRcvChar) (pChan->putRcvArg, 
  276.       nvr4101SIURxWordToChar (*VR4101_SIURXDATREG));
  277. }
  278.     /* handle transmitter interrupt */
  279.     if (statusReg & TX_INT_SOURCES)
  280. {
  281. /* Disable the sequencer */
  282. *VR4101_SIUCNTREG &= ~VR4101_SIU_TXE;
  283. if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)
  284.     {
  285.     /* transmit the next character */
  286.     nvr4101SIUTxOutput (pChan, outChar);
  287.     }
  288. else
  289.     {
  290.     /* note that TxStartup will need to generate next character */
  291.     pChan->txActive = FALSE;
  292.     }
  293. }
  294.     }
  295. /*******************************************************************************
  296. *
  297. * nvr4101SIUTxStartup - transmitter startup routine.
  298. *
  299. * This routine is called to restart data output.  the VR4101 does not
  300. * provide a mechanism to regenerate a transmit interrupt, so this
  301. * function needs to perform the work involved in setting up the data
  302. * transmission.
  303. *
  304. * RETURNS: OK, or ENOSYS if in polled mode.
  305. */
  306. LOCAL int nvr4101SIUTxStartup
  307.     (
  308.     NVR4101_SIU_CHAN *pChan 
  309.     )
  310.     {
  311.     char outChar;
  312.     int oldLevel;
  313.     if (pChan->channelMode == SIO_MODE_INT)
  314. {
  315. oldLevel = intLock ();
  316. /* ignore request if expecting transmitter interrupt */
  317. if (pChan->txActive)
  318.     {
  319.     intUnlock (oldLevel);
  320.     return (OK);
  321.     }
  322. /* mark that we've started transmission */
  323. pChan->txActive = TRUE;
  324. intUnlock (oldLevel);
  325. /* initiate transmission of the next character */
  326. (void) (*pChan->getTxChar) (pChan->getTxArg, &outChar);
  327. nvr4101SIUTxOutput (pChan, outChar);
  328. return (OK);
  329. }
  330.     else
  331. {
  332. return (ENOSYS);
  333. }
  334.     }
  335. /******************************************************************************
  336. *
  337. * nvr4101SIUTxOutput - Transmit requested character.
  338. * This function sets up the transmitter to send the requested character.
  339. *
  340. * RETURNS: N/A
  341. */
  342. LOCAL void nvr4101SIUTxOutput
  343.     (
  344.     NVR4101_SIU_CHAN *pChan,
  345.     char outChar
  346.     )
  347.     {
  348.     UINT32 txAdr;
  349.     /* encode the character, and place in the output buffer */
  350.     *pChan->pTxWord = nvr4101SIUCharToTxWord (outChar);
  351.     
  352.     /* write the buffer address to the the DMA address registers. */
  353.     
  354.     txAdr = K0_TO_K1 (pChan->pTxWord);
  355.     *VR4101_STXDMAADRLREG = (UINT16) txAdr;
  356.     *VR4101_STXDMAADRHREG = (UINT16) (txAdr >> 16);
  357.     /* start the transmit sequencer */
  358.     *VR4101_SIUCNTREG |= VR4101_SIU_TXE;
  359.     }
  360. /******************************************************************************
  361. *
  362. * nvr4101SIUPollOutput - output a character in polled mode.
  363. *
  364. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  365. *          if the output buffer if full.
  366. */
  367. LOCAL int nvr4101SIUPollOutput
  368.     (
  369.     NVR4101_SIU_CHAN *  pChan,
  370.     char            outChar
  371.     )
  372.     {
  373.     /* if haven't gotten DMA interrupt, we're still transmitting */
  374.     if (pChan->txActive && 
  375. ((*VR4101_SIUINTREG & TX_INT_SOURCES) == 0))
  376. return (EAGAIN);
  377.     /* mark that we're starting transmission */
  378.     pChan->txActive = TRUE;
  379.     /* clear the interrupt bits */
  380.     *VR4101_SIUINTREG = TX_INT_SOURCES;
  381.     /* disable the sequencer */
  382.     *VR4101_SIUCNTREG &= ~VR4101_SIU_TXE;
  383.     /* ok to send the character */
  384.     nvr4101SIUTxOutput (pChan, outChar);
  385.     return (OK);
  386.     }
  387. /******************************************************************************
  388. *
  389. * nvr4101SIUPollInput - poll the device for input.
  390. *
  391. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  392. *          if the input buffer if empty.
  393. */
  394. LOCAL int nvr4101SIUPollInput
  395.     (
  396.     NVR4101_SIU_CHAN *  pChan,
  397.     char *          thisChar
  398.     )
  399.     {
  400.     /* if no receiver interrupt, no character */
  401.     if (!(*VR4101_SIUINTREG & RX_INT_SOURCES))
  402. return (EAGAIN);
  403.     /* clear the interrupt */
  404.     *VR4101_SIUINTREG = RX_INT_SOURCES;
  405.     /* read the character */
  406.     *thisChar = nvr4101SIURxWordToChar (*VR4101_SIURXDATREG);
  407.     return (OK);
  408.     }
  409. /******************************************************************************
  410. *
  411. * nvr4101SIUCallbackInstall - install ISR callbacks to get/put chars.
  412. */
  413. LOCAL int nvr4101SIUCallbackInstall
  414.     (
  415.     SIO_CHAN *  pSioChan,
  416.     int         callbackType,
  417.     STATUS      (*callback)(),
  418.     void *      callbackArg
  419.     )
  420.     {
  421.     NVR4101_SIU_CHAN * pChan = (NVR4101_SIU_CHAN *) pSioChan;
  422.     switch (callbackType)
  423.         {
  424.         case SIO_CALLBACK_GET_TX_CHAR:
  425.             pChan->getTxChar    = callback;
  426.             pChan->getTxArg     = callbackArg;
  427.             return (OK);
  428.         case SIO_CALLBACK_PUT_RCV_CHAR:
  429.             pChan->putRcvChar   = callback;
  430.             pChan->putRcvArg    = callbackArg;
  431.             return (OK);
  432.         default:
  433.             return (ENOSYS);
  434.         }
  435.     }
  436. /******************************************************************************
  437. *
  438. * nvr4101SIUIntMask - Mask interrupts from the SIU.
  439. * This function masks all possible interrupts from the SIU subsystem.
  440. *
  441. * RETURNS: N/A
  442. */
  443. void nvr4101SIUIntMask()
  444.     {
  445.     int oldLevel;
  446.     oldLevel = intLock ();
  447.     *VR4101_ICU_MSIUINTREG &= ~(RX_INT_SOURCES | TX_INT_SOURCES);
  448.     intUnlock (oldLevel);
  449.     }
  450. /******************************************************************************
  451. *
  452. * nvr4101SIUIntUnmask - Unmask interrupts from the SIU.
  453. * This function unmasks all desired interrupts from the SIU subsystem.
  454. *
  455. * RETURNS: N/A
  456. */
  457. void nvr4101SIUIntUnmask()
  458.     {
  459.     int oldLevel;
  460.     oldLevel = intLock ();
  461.     *VR4101_ICU_MSIUINTREG |= (RX_INT_SOURCES | TX_INT_SOURCES);
  462.     intUnlock (oldLevel);
  463.     }
  464. /******************************************************************************
  465. *
  466. * nvr4101SIUCharToTxWord - Translate character to output word format.
  467. * This routine performs the bit manipulations required to convert 
  468. * a character into the output word format required by the SIU.  
  469. * This routine only supports 8-bit word lengths, two stop bits
  470. * and no parity.
  471. *
  472. * RETURNS: The translated output character.
  473. */
  474. UINT16 nvr4101SIUCharToTxWord
  475.     (
  476.     char outChar
  477.     )
  478.     {
  479.     /* char --> [1][char][0] */
  480.     return ((0x100 | (UINT16) outChar) << 1);
  481.     }
  482. /******************************************************************************
  483. *
  484. * nvr4101SIURxWordToChar - Extract character from received word.
  485. * This function performs the bit manipulations required to extract
  486. * the received character from its encoded word.  This routine only
  487. * supports 8-bit word lengths, one stop bit and no parity.
  488. *
  489. * RETURNS: The received character.
  490. */
  491. LOCAL char nvr4101SIURxWordToChar
  492.     (
  493.     UINT16 inWord
  494.     )
  495.     {
  496.     return (char) (inWord >> 8);
  497.     }