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

VxWorks

开发平台:

C/C++

  1. /* ppc860Sio.c - Motorola MPC800 SMC UART serial driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01c,24apr02,pmr  SPR 75161: returning int from ppc860Startup().
  8. 01b,06nov96,tpr  removed DEBUG code.
  9. 01c,08nov96,dgp  doc: final formatting
  10. 01b,28oct96,tam  fixed typo error to build man pages. 
  11. 01a,14apr96,cah  adapted from m68360.c and updated for SMC part
  12. */
  13. /*
  14. DESCRIPTION
  15. This is the driver for the SMCs in the internal Communications Processor (CP)
  16. of the Motorola MPC68860/68821.  This driver only supports the SMCs in 
  17. asynchronous UART mode.
  18. USAGE
  19. A PPC800SMC_CHAN structure is used to describe the chip.
  20. The BSP's sysHwInit() routine typically calls sysSerialHwInit(),
  21. which initializes all the values in the PPC860SMC_CHAN structure (except
  22. the SIO_DRV_FUNCS) before calling ppc860DevInit().
  23. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2() which
  24. connects the chip's interrupts via intConnect().
  25. INCLUDE FILES: drv/sio/ppc860Sio.h
  26. */
  27. /* includes */
  28. #include "vxWorks.h"
  29. #include "intLib.h"
  30. #include "errno.h"
  31. #include "sioLib.h"
  32. #include "drv/multi/ppc860Siu.h"
  33. #include "drv/multi/ppc860Cpm.h"
  34. #include "drv/sio/ppc860Sio.h"
  35. /* defines */
  36. #define DEFAULT_BAUD 9600
  37. /* forward declarations */
  38. static STATUS ppc860Ioctl (PPC860SMC_CHAN *pChan,int request,int arg);
  39. static void   ppc860ResetChannel (PPC860SMC_CHAN *pChan);
  40. static int    ppc860PollOutput (SIO_CHAN *,char);
  41. static int    ppc860PollInput (SIO_CHAN *,char *);
  42. static int    ppc860Startup (PPC860SMC_CHAN *);
  43. static int    ppc860CallbackInstall (SIO_CHAN *, int, STATUS (*)(), void *);
  44. /* local driver function table */
  45. static SIO_DRV_FUNCS ppc860SioDrvFuncs =
  46.     {
  47.     (int (*)()) ppc860Ioctl,
  48.     (int (*)()) ppc860Startup,
  49.     (int (*)()) ppc860CallbackInstall,
  50.     (int (*)()) ppc860PollInput,
  51.     (int (*)(SIO_CHAN *,char)) ppc860PollOutput
  52.     };
  53. /*******************************************************************************
  54. *
  55. * ppc860DevInit - initialize the SMC
  56. *
  57. * This routine is called to initialize the chip to a quiescent state.
  58. * Note that the `smcNum' field of PPC860SMC_CHAN must be either 1 or 2.
  59. */
  60. void ppc860DevInit
  61.     (
  62.     PPC860SMC_CHAN *pChan
  63.     )
  64.     {
  65.     /* masks off this SMC's interrupt. */
  66.     * CIMR(pChan->regBase) &= (~(CIMR_SMC1 >> (pChan->uart.smcNum - 1)));
  67.     pChan->baudRate  = DEFAULT_BAUD;
  68.     pChan->pDrvFuncs = &ppc860SioDrvFuncs;
  69.     }
  70. /*******************************************************************************
  71. *
  72. * ppc860ResetChannel - initialize the SMC
  73. */
  74. static void ppc860ResetChannel 
  75.     (
  76.     PPC860SMC_CHAN *pChan
  77.     )
  78.     {
  79.     int smc; /* the SMC number being initialized */
  80.     int baud; /* the baud rate generator being used */
  81.     int frame;
  82.     int oldlevel = intLock (); /* lock interrupts */ 
  83.     smc  = pChan->uart.smcNum - 1; /* get SMC number */
  84.     baud = pChan->bgrNum - 1; /* get BRG number */
  85.     pChan->uart.intMask = CIMR_SMC1 >> smc;
  86.     /* set up SMC as NMSI, select Baud Rate Generator */
  87.     switch( baud ) 
  88. {
  89. default: /* default to BRG1 */
  90. case 0: 
  91.     * SIMODE(pChan->regBase) |= (SIMODE_SMC1CS_BRG1 << (16 * smc));
  92.     break;
  93. case 1: 
  94.     * SIMODE(pChan->regBase) |= (SIMODE_SMC1CS_BRG2 << (16 * smc));
  95.     break;
  96. case 2: 
  97.     * SIMODE(pChan->regBase) |= (SIMODE_SMC1CS_BRG3 << (16 * smc));
  98.     break;
  99. case 3: 
  100.     * SIMODE(pChan->regBase) |= (SIMODE_SMC1CS_BRG4 << (16 * smc));
  101.     break;
  102.         }
  103.  
  104.     /* reset baud rate generator, wait for reset to clear... */
  105.  
  106.     *pChan->pBaud |= BRGC_RST;
  107.     while (*pChan->pBaud & BRGC_RST);
  108.     ppc860Ioctl (pChan, SIO_BAUD_SET, pChan->baudRate);
  109.     /* set up transmit buffer descriptors */
  110.     pChan->uart.txBdBase = (SMC_BUF *) (pChan->regBase +
  111.  ((UINT32) pChan->uart.txBdBase ));
  112.     pChan->uart.pSmc->param.tbase = (UINT16) ((UINT32) pChan->uart.txBdBase);
  113.     pChan->uart.pSmc->param.tbptr = (UINT16) ((UINT32) pChan->uart.txBdBase);
  114.     pChan->uart.txBdNext = 0;
  115.     /* initialize each transmit buffer descriptor */
  116.     for (frame = 0; frame < pChan->uart.txBdNum; frame++)
  117.         {
  118.         pChan->uart.txBdBase[frame].statusMode = BD_TX_INTERRUPT_BIT;
  119.         pChan->uart.txBdBase[frame].dataPointer = pChan->uart.txBufBase +
  120.                                                 (frame * pChan->uart.txBufSize);
  121.         }
  122.     /* set the last BD to wrap to the first */
  123.     pChan->uart.txBdBase[(frame - 1)].statusMode |= BD_TX_WRAP_BIT;
  124.     /* set up receive buffer descriptors */
  125.     pChan->uart.rxBdBase = (SMC_BUF *) (pChan->regBase +
  126.          ((UINT32) pChan->uart.rxBdBase ));
  127.     pChan->uart.pSmc->param.rbase = (UINT16) ((UINT32) pChan->uart.rxBdBase);
  128.     pChan->uart.pSmc->param.rbptr = (UINT16) ((UINT32) pChan->uart.rxBdBase);
  129.     pChan->uart.rxBdNext = 0;
  130.     /* initialize each receive buffer descriptor */
  131.     for (frame = 0; frame < pChan->uart.rxBdNum; frame++)
  132.         {
  133.         pChan->uart.rxBdBase[frame].statusMode = BD_RX_EMPTY_BIT |
  134.  BD_RX_INTERRUPT_BIT;
  135.         pChan->uart.rxBdBase[frame].dataLength = 1; /* char oriented */
  136.         pChan->uart.rxBdBase[frame].dataPointer = pChan->uart.rxBufBase + frame;
  137.         }
  138.     /* set the last BD to wrap to the first */
  139.     pChan->uart.rxBdBase[(frame - 1)].statusMode |= BD_RX_WRAP_BIT;
  140.     /* set SMC attributes to standard UART mode */
  141.     pChan->uart.pSmcReg->smcmr = SMCMR_STD_MODE;
  142.     /* initialize parameter RAM area for this SMC */
  143.     pChan->uart.pSmc->param.rfcr   = 0x18; /* supervisor data access */
  144.     pChan->uart.pSmc->param.tfcr   = 0x18; /* supervisor data access */
  145.     pChan->uart.pSmc->param.mrblr  = 0x1; /* one character rx buffers */
  146.     pChan->uart.pSmc->param.maxidl = 0x0; /* no idle features */
  147.     pChan->uart.pSmc->param.brkln  = 0x0; /* no breaks received yet */
  148.     pChan->uart.pSmc->param.brkec  = 0x0; /* zero break condition ctr */
  149.     pChan->uart.pSmc->param.brkcr  = 0x1; /* xmit 1 BRK on stop */
  150.     /* clear all events */
  151.     pChan->uart.pSmcReg->smce = SMCE_ALL_EVENTS;
  152.     /* enables the transmitter and receiver  */
  153.     pChan->uart.pSmcReg->smcmr |= SMCMR_TEN | SMCMR_REN;
  154.     /* unmask interrupt (Tx, Rx only) */
  155.     pChan->uart.pSmcReg->smcm  = SMCM_TX_MSK | SMCM_RX_MSK;
  156.     *CIMR(pChan->regBase) |= pChan->uart.intMask;
  157.     intUnlock (oldlevel); /* UNLOCK INTERRUPTS */
  158.     }
  159. /*******************************************************************************
  160. *
  161. * ppc860Ioctl - special device control
  162. *
  163. * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
  164. *          request.
  165. *
  166. */
  167. LOCAL STATUS ppc860Ioctl
  168.     (
  169.     PPC860SMC_CHAN * pChan, /* device to control */
  170.     int request, /* request code */
  171.     int arg /* some argument */
  172.     )
  173.     {
  174.     int baudRate;
  175.     int  oldlevel;
  176.     STATUS  status = OK;
  177.     switch (request)
  178. {
  179. case SIO_BAUD_SET:
  180.             if (arg >=  50 && arg <= 38400) /* could go higher... */
  181. {
  182. /* calculate proper counter value, then enable BRG */
  183. baudRate = (pChan->clockRate + (8 * arg)) / (16 * arg);
  184. if (--baudRate > 0xfff)
  185.     *pChan->pBaud = (BRGC_CD_MSK &
  186.     (((baudRate + 8) / 16) << BRGC_CD_SHIFT)) | BRGC_EN |
  187.     BRGC_DIV16;
  188.                 else
  189.                     *pChan->pBaud = (BRGC_CD_MSK & 
  190. (baudRate << 1)) | BRGC_EN;
  191.                 pChan->baudRate = arg;
  192. }
  193.             else
  194.         status = EIO;
  195.     break;
  196.     
  197. case SIO_BAUD_GET:
  198.     * (int *) arg = pChan->baudRate;
  199.     break;
  200. case SIO_MODE_SET:
  201.             if (!((int) arg == SIO_MODE_POLL || (int) arg == SIO_MODE_INT))
  202.                 {
  203.                 status = EIO;
  204.                 break;
  205.                 }
  206.             /* lock interrupt  */
  207.             oldlevel = intLock();
  208.             /* initialize channel on first MODE_SET */
  209.             if (!pChan->channelMode)
  210.                 ppc860ResetChannel(pChan);
  211.             /*
  212.              * if switching from POLL to INT mode, wait for all characters to
  213.              * clear the output pins
  214.              */
  215.             if ((pChan->channelMode == SIO_MODE_POLL) && (arg == SIO_MODE_INT))
  216.                 {
  217. int i;
  218.                 for (i=0; i < pChan->uart.txBdNum; i++)
  219.                     while (pChan->uart.txBdBase
  220.                            [(pChan->uart.txBdNext + i) % pChan->uart.txBdNum].
  221.                            statusMode & BD_TX_READY_BIT);
  222.                 }
  223.             if (arg == SIO_MODE_INT)
  224. {
  225.                 * CISR(pChan->regBase) = pChan->uart.intMask;
  226. /* reset the SMC's interrupt status bit */
  227. * CIMR(pChan->regBase) |= pChan->uart.intMask;
  228. /* enable this SMC's interrupt  */
  229. pChan->uart.pSmcReg->smce = SMCE_RX;
  230. /* reset the receiver status bit */ 
  231.                 pChan->uart.pSmcReg->smcm = SMCM_RX_MSK | SMCM_TX_MSK;
  232. /* enables receive and transmit interrupts */
  233. }
  234.             else
  235. {
  236.                 pChan->uart.pSmcReg->smcm = 0;
  237. /* mask off the receive and transmit intrs */
  238. * CIMR(pChan->regBase) &= (~(pChan->uart.intMask));
  239. /* mask off this SMC's interrupt */ 
  240.                 }
  241.             pChan->channelMode = arg;
  242.             intUnlock(oldlevel);
  243.             break;
  244.         case SIO_MODE_GET:
  245.             * (int *) arg = pChan->channelMode;
  246.     break;
  247.         case SIO_AVAIL_MODES_GET:
  248.             *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  249.     break;
  250. default:
  251.     status = ENOSYS;
  252. }
  253.     return (status);
  254.     }
  255. /*******************************************************************************
  256. *
  257. * ppc860Int - handle an SMC interrupt
  258. *
  259. * This routine is called to handle SMC interrupts.
  260. */
  261. void ppc860Int
  262.     (
  263.     PPC860SMC_CHAN *pChan
  264.     )
  265.     {
  266.     char outChar;
  267.     FAST UINT16 dataLen = 0;
  268.     /* check for a receive event */
  269.     if (pChan->uart.pSmcReg->smce & SMCE_RX)
  270. {
  271.         pChan->uart.pSmcReg->smce = SMCE_RX;
  272. while (!(pChan->uart.rxBdBase [pChan->uart.rxBdNext].statusMode &
  273.  BD_RX_EMPTY_BIT))
  274.     {
  275.     /* process all filled receive buffers */
  276.     outChar = pChan->uart.rxBdBase[pChan->uart.rxBdNext].dataPointer[0];
  277.             pChan->uart.rxBdBase[pChan->uart.rxBdNext].statusMode |=
  278.                 BD_RX_EMPTY_BIT;
  279.             /* incr BD count */
  280.             pChan->uart.rxBdNext = (pChan->uart.rxBdNext + 1) %
  281.                                   pChan->uart.rxBdNum;
  282.             /* acknowledge interrupt ??? multiple events ??? */
  283.             pChan->uart.pSmcReg->smce = SMCE_RX;
  284.     (*pChan->putRcvChar) (pChan->putRcvArg,outChar);
  285.     if (pChan->channelMode == SIO_MODE_POLL)
  286. break;
  287.     }
  288. }
  289.     /* check for a transmit event and if a character needs to be output */
  290.     if ((pChan->uart.pSmcReg->smce & SMCE_TX) &&
  291.         (pChan->channelMode != SIO_MODE_POLL))
  292. {
  293.         pChan->uart.pSmcReg->smce = SMCE_TX;
  294.     
  295.         if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) == OK)
  296.     {
  297.     do
  298.         {
  299.         pChan->uart.txBdBase[pChan->uart.txBdNext].dataPointer[dataLen++]
  300.     = outChar;
  301.                 if (pChan->channelMode == SIO_MODE_POLL)
  302.                     break;
  303.         }
  304.     while ((dataLen < pChan->uart.txBufSize) &&
  305.                    ((*pChan->getTxChar) (pChan->getTxArg, &outChar)
  306.        == OK));
  307.     pChan->uart.txBdBase[pChan->uart.txBdNext].dataLength = dataLen;
  308.             /* acknowledge interrupt */
  309.             pChan->uart.pSmcReg->smce = SMCE_TX;
  310.     /* send transmit buffer */
  311.     pChan->uart.txBdBase[pChan->uart.txBdNext].statusMode |=
  312.         BD_TX_READY_BIT;
  313.     /* incr BD count */
  314.       pChan->uart.txBdNext = (pChan->uart.txBdNext+ 1) %
  315. pChan->uart.txBdNum;
  316.     }
  317. }
  318.     /* acknowledge all other interrupts - ignore events */
  319.     pChan->uart.pSmcReg->smce = (pChan->uart.pSmcReg->smce & 
  320. ~(SMCE_RX | SMCE_TX));
  321.     * CISR(pChan->regBase) = pChan->uart.intMask;
  322.     }
  323. /*******************************************************************************
  324. *
  325. * ppc860Startup - transmitter startup routine
  326. */
  327. static int ppc860Startup
  328.     (
  329.     PPC860SMC_CHAN *pChan /* ty device to start up */
  330.     )
  331.     {
  332.     char outChar;
  333.     FAST UINT16 dataLen = 0;
  334.     if (pChan->channelMode == SIO_MODE_POLL)
  335. return (ENOSYS);
  336.     /* check if buffer is ready and if a character needs to be output */
  337.     if ((!(pChan->uart.txBdBase[pChan->uart.txBdNext].statusMode &
  338.    BD_TX_READY_BIT)) &&
  339.         ((*pChan->getTxChar) (pChan->getTxArg, &outChar) == OK))
  340. {
  341. do
  342.     {
  343.     pChan->uart.txBdBase[pChan->uart.txBdNext].dataPointer[dataLen++] =
  344. outChar;
  345.     }
  346. while ((dataLen < pChan->uart.txBufSize) &&
  347.                ((*pChan->getTxChar) (pChan->getTxArg, &outChar) == OK));
  348.         /* fill buffer */
  349. /* send transmit buffer */
  350. pChan->uart.txBdBase[pChan->uart.txBdNext].dataLength  = dataLen;
  351. pChan->uart.txBdBase[pChan->uart.txBdNext].statusMode |=
  352.     BD_TX_READY_BIT;
  353. /* incr BD count */
  354.         pChan->uart.txBdNext = (pChan->uart.txBdNext + 1) % pChan->uart.txBdNum;
  355. }
  356.     return (OK);
  357.     }
  358. /******************************************************************************
  359. *
  360. * ppc860PollInput - poll the device for input.
  361. *
  362. * RETURNS: OK if a character arrived, ERROR on device error, EAGAIN
  363. *          if the input buffer is empty.
  364. */
  365. static int ppc860PollInput
  366.     (
  367.     SIO_CHAN * pSioChan,
  368.     char * thisChar
  369.     )
  370.     {
  371.     PPC860SMC_CHAN * pChan = (PPC860SMC_CHAN *) pSioChan;
  372.     if (!(pChan->uart.pSmcReg->smce & SMCE_RX))
  373.         return (EAGAIN); 
  374.     if (pChan->uart.rxBdBase[pChan->uart.rxBdNext].statusMode & BD_RX_EMPTY_BIT)
  375.         return (EAGAIN);
  376.     /* get a character */
  377.     *thisChar = pChan->uart.rxBdBase[pChan->uart.rxBdNext].dataPointer[0];
  378.     /* set the empty bit */
  379.     pChan->uart.rxBdBase[pChan->uart.rxBdNext].statusMode |= BD_RX_EMPTY_BIT;
  380.     /* incr BD count */
  381.     pChan->uart.rxBdNext = (pChan->uart.rxBdNext + 1) % pChan->uart.rxBdNum;
  382.     /* only clear RX event if no more characters are ready */
  383.     if (pChan->uart.rxBdBase[pChan->uart.rxBdNext].statusMode & BD_RX_EMPTY_BIT)
  384.         pChan->uart.pSmcReg->smce = SMCE_RX;
  385.     return (OK);
  386.     }
  387. /******************************************************************************
  388. *
  389. * ppc860PollOutput - output a character in polled mode.
  390. *
  391. * RETURNS: OK if a character arrived, ERROR on device error, EAGAIN
  392. *          if the output buffer if full.
  393. */
  394. static int ppc860PollOutput
  395.     (
  396.     SIO_CHAN * pSioChan,
  397.     char outChar
  398.     )
  399.     {
  400.     PPC860SMC_CHAN * pChan = (PPC860SMC_CHAN *) pSioChan;
  401.     int i;
  402.     /* wait a bit for the last character to get out */
  403.     /* because the PPC604 is a very fast processor */
  404.     /* ???  make the 10000 value a #define */
  405.     i = 0;
  406.     while( (i<10000) && (pChan->uart.txBdBase[pChan->uart.txBdNext].statusMode &
  407. BD_TX_READY_BIT) )
  408. {
  409. i = i + 1;    
  410. }
  411.     /* is the transmitter ready to accept a character? */
  412.     /* if still not, we have a problem */
  413.     if (pChan->uart.txBdBase[pChan->uart.txBdNext].statusMode &
  414. BD_TX_READY_BIT)
  415. return(EAGAIN);
  416.     /* reset the transmitter status bit */
  417.     pChan->uart.pSmcReg->smce = SMCE_TX;
  418.     /* write out the character */
  419.     pChan->uart.txBdBase[pChan->uart.txBdNext].dataPointer[0] = outChar;
  420.     pChan->uart.txBdBase[pChan->uart.txBdNext].dataLength  = 1;
  421.     /* send transmit buffer */
  422.     pChan->uart.txBdBase[pChan->uart.txBdNext].statusMode |= BD_TX_READY_BIT;
  423.     pChan->uart.txBdNext = (pChan->uart.txBdNext + 1) % pChan->uart.txBdNum;
  424.     return (OK);
  425.     }
  426. /******************************************************************************
  427. *
  428. * ppc860CallbackInstall - install ISR callbacks to get put chars.
  429. *
  430. */
  431. static int ppc860CallbackInstall
  432.     (
  433.     SIO_CHAN * pSioChan,
  434.     int callbackType,
  435.     STATUS (* callback)(),
  436.     void * callbackArg
  437.     )
  438.     {
  439.     PPC860SMC_CHAN * pChan = (PPC860SMC_CHAN *) pSioChan;
  440.     switch (callbackType)
  441.         {
  442.         case SIO_CALLBACK_GET_TX_CHAR:
  443.             pChan->getTxChar    = callback;
  444.             pChan->getTxArg     = callbackArg;
  445.             return (OK);
  446.     break;
  447.         case SIO_CALLBACK_PUT_RCV_CHAR:
  448.             pChan->putRcvChar   = callback;
  449.             pChan->putRcvArg    = callbackArg;
  450.             return (OK);
  451.     break;
  452.         default:
  453.             return (ENOSYS);
  454.         }
  455.     }