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

VxWorks

开发平台:

C/C++

  1. /* shSciSio.c - Hitachi SH SCI (Serial Communications Interface) driver */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01i,02nov01,zl   corrected NULL usage and callback declaration.
  7. 01h,16nov00,zl   make BRR=0 invalid for baud rate setting.
  8. 01g,24aug99,zl   set initial baud rate
  9. 01f,01apr99,hk   fix for receive overruns in polled mode.
  10. 01e,30may98,jmb  Add support for more data formats.
  11. 01d,22mar97,hk   changed to import sysBaudTable[].
  12. 01c,10mar97,hk   renamed as shSciSio.c from shSio.c. changed function names to
  13.                  shSciAbc(). deleted casting for shSioDrvFuncs' members.
  14.                  changed SH_DUSART to SCI_CHAN and made CPU conditional simple.
  15.                  added SH704X support. fixed shSciIoctl() return value.
  16.                  changed baud-rate save value to arg from brr in shSciIoctl().
  17.                  also saved default baud-rate in shSciDevInit().
  18. 01b,07mar97,hk   fixed shDevInit() to set SIO_MODE_POLL for reboot failure.
  19. 01a,16dec96,kn   derived from templateSio.c.
  20. */
  21. /*
  22. DESCRIPTION
  23. This is the driver for the Hitachi SH series on-chip SCI (Serial Communication
  24. Interface).  It uses the SCI in asynchronous mode only.
  25. USAGE
  26. A SCI_CHAN structure is used to describe the chip. 
  27. The BSP's sysHwInit() routine typically calls sysSerialHwInit()
  28. which initializes all the values in the SCI_CHAN structure (except
  29. the SIO_DRV_FUNCS) before calling shSciDevInit().
  30. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2(), which
  31. connects the chips interrupts via intConnect(). 
  32. INCLUDE FILES: drv/sio/shSciSio.h sioLib.h
  33. */
  34. #include "vxWorks.h"
  35. #include "sioLib.h"
  36. #include "intLib.h"
  37. #include "errnoLib.h"
  38. #include "drv/sio/shSciSio.h"
  39. /* external data */
  40. IMPORT SCI_BAUD sysBaudTable[]; /* BSP specific baud-rate constants */
  41. /* forward static declarations */
  42. static int shSciTxStartup (SIO_CHAN * pSioChan);
  43. static int shSciCallbackInstall (SIO_CHAN * pSioChan, int callbackType,
  44.  STATUS (*callback)(void *, ...), 
  45.  void * callbackArg);
  46. static int shSciPollOutput (SIO_CHAN * pSioChan, char outChar);
  47. static int shSciPollInput (SIO_CHAN * pSioChan, char * thisChar);
  48. static int shSciIoctl (SIO_CHAN * pSioChan, int request, void * arg);
  49. LOCAL STATUS shSciOptsSet (SCI_CHAN * pChan, UINT options);
  50. static STATUS dummyCallback (void);
  51. /* local variables */
  52. static SIO_DRV_FUNCS shSioDrvFuncs =
  53.     {
  54.     shSciIoctl,
  55.     shSciTxStartup,
  56.     shSciCallbackInstall,
  57.     shSciPollInput,
  58.     shSciPollOutput
  59.     };
  60. #define SSC_DELAY 100000
  61. /******************************************************************************
  62. *
  63. * shSciDevInit - initialize a on-chip serial communication interface
  64. *
  65. * This routine initializes the driver
  66. * function pointers and then resets the chip in a quiescent state.
  67. * The BSP must have already initialized all the device addresses and the
  68. * baudFreq fields in the SCI_CHAN structure before passing it to
  69. * this routine.
  70. *
  71. * RETURNS: N/A
  72. */
  73. void shSciDevInit
  74.     (
  75.     SCI_CHAN * pChan
  76.     )
  77.     {
  78.     /* initialize a channel's driver function pointers */
  79.     pChan->pDrvFuncs = &shSioDrvFuncs;
  80.     /* install dummy driver callbacks */
  81.     pChan->getTxChar  = dummyCallback;
  82.     pChan->putRcvChar = dummyCallback;
  83.     
  84.     /* reset the chip to 8-none-1, no interrupts enabled */
  85.     *(pChan->scr) = (UINT8) 0;
  86.     *(pChan->smr) = (UINT8)(SCI_SMR_ASYNC | SCI_SMR_8_BITS |
  87.     SCI_SMR_PAR_DIS | SCI_SMR_1_STOP | SCI_SMR_MP_DIS);
  88.     pChan->options = CS8; /* 8-bit, no parity, one stop bit */
  89.     /* set initial baud rate */
  90.     shSciIoctl ((SIO_CHAN *)pChan, SIO_BAUD_SET, (void *)pChan->baud);
  91.     /* setting polled mode is one way to make the device quiet */
  92.     shSciIoctl ((SIO_CHAN *)pChan, SIO_MODE_SET, (void *)SIO_MODE_POLL);
  93.     }
  94. /******************************************************************************
  95. *
  96. * shSciIntRcv - handle a channel's receive-character interrupt.
  97. *
  98. * RETURNS: N/A
  99. */ 
  100. void shSciIntRcv
  101.     (
  102.     SCI_CHAN * pChan /* channel generating the interrupt */
  103.     )
  104.     {
  105.     volatile UINT8 ssr = *(pChan->ssr);
  106.     /*
  107.      * Grab the input character from the chip and hand it off via a
  108.      * callback. For chips with input FIFO's it is more efficient
  109.      * to empty the entire FIFO here.
  110.      */
  111.     if (ssr & SCI_SSR_RDRF)
  112. {
  113. char inChar = *(pChan->rdr); /* grab the character */
  114. *(pChan->ssr) = ssr & (UINT8)~SCI_SSR_RDRF;    /* int acknowledge */
  115. (*(pChan->putRcvChar)) (pChan->putRcvArg, inChar);     /* hand it off */
  116. }
  117.     }
  118. /******************************************************************************
  119. *
  120. * shSciIntTx - handle a channels transmitter-ready interrupt.
  121. *
  122. * RETURNS: N/A
  123. */ 
  124. void shSciIntTx
  125.     (
  126.     SCI_CHAN * pChan /* channel generating the interrupt */
  127.     )
  128.     {
  129.     volatile UINT8 ssr = *(pChan->ssr);
  130.     /*
  131.      * If there's a character to transmit then write it out, else reset
  132.      * the transmitter. For chips with output FIFO's it is more efficient
  133.      * to fill the entire FIFO here.
  134.      */
  135.     if (ssr & SCI_SSR_TDRE)
  136. {
  137. char outChar;
  138. if ((*(pChan->getTxChar)) (pChan->getTxArg, &outChar) != ERROR)
  139.     {
  140.     *(pChan->tdr) = outChar;
  141.     *(pChan->ssr) = ssr & (UINT8)~SCI_SSR_TDRE;    /* int acknowledge */
  142.     }
  143. else
  144.     {
  145.     /* no more chars to xmit now.  reset the tx int,
  146.      * so the SCI does not keep interrupting.
  147.      */
  148.     *(pChan->scr) &= (UINT8)~SCI_SCR_TIE;
  149.     }
  150. }
  151.     }
  152. /******************************************************************************
  153. *
  154. * shSciIntErr - handle a channel's error interrupt.
  155. *
  156. * RETURNS: N/A
  157. */ 
  158. void shSciIntErr
  159.     (
  160.     SCI_CHAN * pChan         /* channel generating the interrupt */
  161.     )
  162.     {
  163.     volatile UINT8 ssr;
  164.     ssr = *(pChan->ssr);
  165.     *(pChan->ssr) = (UINT8) 0; /* reset errors */
  166.     }
  167. /******************************************************************************
  168. *
  169. * shSciTxStartup - start the interrupt transmitter.
  170. *
  171. * RETURNS: OK on success, ENOSYS if the device is polled-only, or
  172. *          EIO on hardware error.
  173. */
  174. static int shSciTxStartup
  175.     (
  176.     SIO_CHAN * pSioChan /* channel to start */
  177.     )
  178.     {
  179.     SCI_CHAN * pChan = (SCI_CHAN *)pSioChan;
  180.     *(pChan->scr) |= (UINT8)SCI_SCR_TIE; /* only need to enable int */
  181.     return (OK);
  182.     }
  183. /******************************************************************************
  184. *
  185. * shSciCallbackInstall - install ISR callbacks to get/put chars.
  186. *
  187. * This driver allows interrupt callbacks for transmitting characters
  188. * and receiving characters. In general, drivers may support other
  189. * types of callbacks too.
  190. *
  191. * RETURNS: OK on success, or ENOSYS for an unsupported callback type.
  192. */ 
  193. static int shSciCallbackInstall
  194.     (
  195.     SIO_CHAN * pSioChan, /* channel */
  196.     int        callbackType, /* type of callback */
  197.     STATUS     (*callback)(void *, ...), /* callback */
  198.     void *     callbackArg /* parameter to callback */
  199.     )
  200.     {
  201.     SCI_CHAN * pChan = (SCI_CHAN *)pSioChan;
  202.     switch (callbackType)
  203. {
  204. case SIO_CALLBACK_GET_TX_CHAR:
  205.     pChan->getTxChar = (STATUS (*)(void *, char *))callback;
  206.     pChan->getTxArg = callbackArg;
  207.     return (OK);
  208. case SIO_CALLBACK_PUT_RCV_CHAR:
  209.     pChan->putRcvChar = (STATUS (*)(void *, char *))callback;
  210.     pChan->putRcvArg = callbackArg;
  211.     return (OK);
  212. default:
  213.     return (ENOSYS);
  214. }
  215.     }
  216. /******************************************************************************
  217. *
  218. * shSciPollOutput - output a character in polled mode.
  219. *
  220. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  221. *    if the output buffer if full. ENOSYS if the device is
  222. *          interrupt-only.
  223. */
  224. static int shSciPollOutput
  225.     (
  226.     SIO_CHAN * pSioChan,
  227.     char outChar
  228.     )
  229.     {
  230.     SCI_CHAN * pChan = (SCI_CHAN *)pSioChan;
  231.     volatile UINT8 ssr = *(pChan->ssr );
  232.     /* is the transmitter ready to accept a character? */
  233.     if ((ssr & (UINT8)SCI_SSR_TDRE) == 0x00)
  234. return (EAGAIN);
  235.     /* write out the character */
  236.     *(pChan->tdr) = outChar;
  237.     *pChan->ssr = ssr & (UINT8)~SCI_SSR_TDRE;
  238.     return (OK);
  239.     }
  240. /******************************************************************************
  241. *
  242. * shSciPollInput - poll the device for input.
  243. *
  244. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  245. *    if the input buffer if empty, ENOSYS if the device is
  246. *          interrupt-only.
  247. */
  248. static int shSciPollInput
  249.     (
  250.     SIO_CHAN * pSioChan,
  251.     char * thisChar /* where to put the input character */
  252.     )
  253.     {
  254.     SCI_CHAN * pChan = (SCI_CHAN *)pSioChan;
  255.     volatile UINT8 ssr = *(pChan->ssr);
  256.     /* If a receive overrun condition is set, the SCI does not receive
  257.      * any more characters.  Since it is likely to happen in polling
  258.      * mode, we have to check and clear the overrun status.
  259.      */
  260.     if (ssr & SCI_SSR_ORER)
  261.        *(pChan->ssr) = ssr & (UINT8)~SCI_SSR_ORER;
  262.     if ((ssr & SCI_SSR_RDRF) == 0x00)
  263. return (EAGAIN);
  264.     /* got a character */
  265.     *thisChar = *(pChan->rdr);
  266.     *pChan->ssr = ssr & (UINT8)~SCI_SSR_RDRF;
  267.     return (OK);
  268.     }
  269. /******************************************************************************
  270. *
  271. * shSciModeSet - toggle between interrupt and polled mode.
  272. *
  273. * RETURNS: OK on success, EIO on unsupported mode.
  274. */
  275. static int shSciModeSet
  276.     (
  277.     SCI_CHAN * pChan, /* channel */
  278.     uint_t newMode /* new mode */
  279.     )
  280.     {
  281.     int oldlevel;
  282.     if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))
  283. return (EIO);
  284.     oldlevel = intLock (); /* LOCK INTERRUPTS */
  285.     pChan->mode = newMode; /* set the new mode */
  286.     
  287.     if (pChan->mode == SIO_MODE_INT)
  288. *(pChan->scr) = (UINT8)(SCI_SCR_RIE | SCI_SCR_TXE | SCI_SCR_RXE);
  289.     else
  290. *(pChan->scr) = (UINT8)(SCI_SCR_TXE | SCI_SCR_RXE);
  291.     intUnlock (oldlevel); /* UNLOCK INTERRUPTS */
  292.     return (OK);
  293.     }
  294. /*******************************************************************************
  295. *
  296. * shSciIoctl - special device control
  297. *
  298. * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
  299. *          request.
  300. */
  301. static int shSciIoctl
  302.     (
  303.     SIO_CHAN * pSioChan, /* channel to control */
  304.     int        request, /* request code */
  305.     void *     someArg /* some argument */
  306.     )
  307.     {
  308.     SCI_CHAN * pChan = (SCI_CHAN *)pSioChan;
  309.     int        oldlevel, delay;
  310.     UINT8      oldScr, cks, brr;
  311.     STATUS     result;
  312.     int        arg = (int)someArg;
  313.     switch (request)
  314. {
  315. case SIO_BAUD_SET:
  316.     /*
  317.      * Set the baud rate. Return EIO for an invalid baud rate, or
  318.      * OK on success.
  319.      */
  320.     {
  321.     int ix, status;
  322.     for (status = EIO, cks = 0, brr = 0,
  323.  ix = 0; sysBaudTable[ix].rate != 0; ix++)
  324. {
  325. if (sysBaudTable[ix].rate == arg)
  326.     {
  327.     cks = sysBaudTable[ix].cksVal; /* clock select bits */
  328.     brr = sysBaudTable[ix].brrVal; /* bit rate */
  329.     status = OK;
  330.     break;
  331.     }
  332. }
  333.     if (status == EIO) return (status);
  334.     /* 
  335.      * Although the zero value for BRR may be aceptable in rare 
  336.      * occasions, we use it as invalid value - for example when the
  337.      * calculated value overflows (larger than 255).
  338.      */
  339.     if (brr == 0) return (EIO);
  340.     }
  341.     oldlevel = intLock (); /* LOCK INTERRUPTS */
  342.     oldScr = *(pChan->scr); /* save old scr */
  343.     *(pChan->scr) = (UINT8) 0;
  344.     *(pChan->smr) = (UINT8)((*(pChan->smr) & SCI_SMR_CKS_MASK) | cks);
  345.     *(pChan->brr) = (UINT8)brr;
  346.     pChan->baud   = arg;
  347.     for (delay = 0; delay < (SSC_DELAY / arg); delay++)
  348. delay = delay; /* spin wheels for a moment */
  349.     
  350.     *(pChan->scr) = oldScr; /* restore scr */
  351.     intUnlock (oldlevel); /* UNLOCK INTERRUPTS */
  352.     return (OK);
  353. case SIO_BAUD_GET:
  354.     /* Get the baud rate and return OK */
  355.     *(int *)arg = pChan->baud;
  356.     return (OK);
  357. case SIO_MODE_SET:
  358.     /*
  359.      * Set the mode (e.g., to interrupt or polled). Return OK
  360.      * or EIO for an unknown or unsupported mode.
  361.      */
  362.     return (shSciModeSet (pChan, arg));
  363. case SIO_MODE_GET:
  364.     /*
  365.      * Get the current mode and return OK.
  366.      */
  367.     *(int *)arg = pChan->mode;
  368.     return (OK);
  369. case SIO_AVAIL_MODES_GET:
  370.     /*
  371.      * Get the available modes and return OK.
  372.      */
  373.     *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  374.     return (OK);
  375.         case SIO_HW_OPTS_SET:
  376.             /* change options, then set mode to restart chip correctly */
  377.             result =  shSciOptsSet (pChan, arg);
  378.             if (pChan->baud)
  379.         for (delay = 0; delay < (SSC_DELAY / pChan->baud); delay++)
  380.     delay = delay; /* spin wheels for a moment */
  381.             shSciModeSet (pChan, pChan->mode);
  382.             return (result);
  383.         case SIO_HW_OPTS_GET:
  384.             *(int *)arg = pChan->options;
  385.             return (OK);
  386. default:
  387.     return (ENOSYS);
  388. }
  389.     }
  390. /*******************************************************************************
  391. *
  392. * dummyCallback - dummy callback routine.
  393. *
  394. * RETURNS: ERROR.
  395. */
  396. STATUS dummyCallback (void)
  397.     {
  398.     return (ERROR);
  399.     }
  400. /*******************************************************************************
  401. *
  402. * shSciOptsSet - set the serial options
  403. *
  404. * Set the channel operating mode to that specified.  These sioLib options
  405. * are supported: CSIZE (CS7 and CS8), PARENB, and PARODD.
  406. *
  407. * The unsupported options are CREAD and CLOCAL.  CLOCAL is ignored because
  408. * SCI does not have hardware flow control.  CREAD is also ignored.  The
  409. * routine to turn on serial I/O is shSciModeSet().
  410. *
  411. * Note, this routine disables all serial interrupts.  To re-enable
  412. * serial communication, the caller should use shSciModeSet().
  413. *
  414. * RETURNS:
  415. * Returns OK to indicate success.  ERROR is returned if a bad arg is
  416. * detected. ENOSYS is returned for an unsupported option.
  417. */
  418. LOCAL STATUS shSciOptsSet
  419.     (
  420.     SCI_CHAN * pChan,  /* ptr to channel */
  421.     UINT options /* new hardware options */
  422.     )
  423.     {
  424.     /*  Retain last two bits of serial mode register.  These form the
  425.      *  peripheral clock divisor.
  426.      */
  427.     UINT8 smrValue = *(pChan->smr) & 0x3;
  428.     int lvl;
  429.     if (pChan == NULL)
  430. return (ERROR);
  431.     /* Set the data format.  SCI supports even/odd parity, 1/2 stop bits,
  432.      * and 7/8 bit characters.
  433.      */
  434.     switch (options & CSIZE)
  435. {
  436. case CS5: 
  437. case CS6:
  438.             return (ENOSYS); 
  439.             break;
  440. case CS7:
  441.     smrValue |= SCI_SMR_7_BITS;  /* 7-bit data */
  442.             break;
  443. case CS8:
  444. default:
  445.     smrValue &=  ~SCI_SMR_7_BITS;  /* 8-bit data */
  446.     break;
  447. }
  448.     if (options & STOPB)
  449. smrValue |=   SCI_SMR_2_STOP;    /* 2 stop bits */
  450.     else
  451. smrValue &=  ~SCI_SMR_2_STOP;   /* 1 stop bit */
  452.     switch (options & (PARENB|PARODD))
  453. {
  454. case (PARENB|PARODD):
  455. case PARODD:
  456.     smrValue |= SCI_SMR_PAR_EN;          /* parity enabled */
  457.     smrValue |= SCI_SMR_PAR_ODD;         /* parity odd */
  458.             break; 
  459. case PARENB:
  460.     smrValue |= SCI_SMR_PAR_EN;          /* parity enabled */
  461.     smrValue &= ~SCI_SMR_PAR_ODD;        /* parity even */
  462.             break;
  463. default:
  464. case 0:
  465.     smrValue &= ~SCI_SMR_PAR_EN;         /* parity disabled */
  466.             break;
  467. }
  468.     lvl = intLock (); /* LOCK INTERRUPTS */
  469.     /* 
  470.      *  Set the hardware registers
  471.      */
  472.     *(pChan->scr) &= 0x03; /* Disable xmit, receiver, and all interrupts */
  473.     *(pChan->smr) = smrValue; /* Reset data format */
  474.     *(pChan->scr) |= (SCI_SCR_TXE | SCI_SCR_RXE);  /* Turn on xmit, recv */
  475.     intUnlock (lvl); /* UNLOCK INTERRUPTS */
  476.     pChan->options = options;
  477.     return (OK);
  478.     }