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

VxWorks

开发平台:

C/C++

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