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

VxWorks

开发平台:

C/C++

  1. /* m68360Serial.c - Motorola MC68360 SCC UART tty driver */
  2. /* Copyright 1984-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01e,28may96,dat  fixed SPR #5526, #3689, #3517
  8. 01d,12nov93,dzb  fixed event race condition in tyCoInt() (SPR #2632).
  9. 01c,05oct93,dzb  tweaks for abstraction of SCC_DEV.  removed CP init call.
  10. 01b,23aug93,dzb  tweaked to accept multiple NMSI settings.
  11. 01a,22jul93,dzb  derived from version 01l of serial/m68302Serial.c.
  12. */
  13. /*
  14. DESCRIPTION
  15. This is the driver for the SCC's in the internal Communications Processor (CP)
  16. of the Motorola MC68360.  This driver only supports the SCC's in asynchronous
  17. UART mode.
  18. USER-CALLABLE ROUTINES
  19. Most of the routines in this driver are accessible only through the I/O
  20. system.  Two routines, however, must be called directly:  tyCoDrv() to
  21. initialize the driver, and tyCoDevCreate() to create devices.
  22. Before the driver can be used, it must be initialized by calling the
  23. routine tyCoDrv().  This routine should be called exactly once, before any
  24. reads, writes, or calls to tyCoDevCreate().  Normally, it is called from
  25. usrRoot() in usrConfig.c.
  26. Before a terminal can be used, it must be created using tyCoDevCreate().
  27. Each port to be used should have exactly one device associated with it by
  28. calling this routine.
  29. IOCTL FUNCTIONS
  30. This driver responds to the same ioctl() codes as a normal tty driver; for
  31. more information, see the manual entry for tyLib.  Available baud
  32. rates range from 50 to 38400.
  33. SEE ALSO
  34. tyLib
  35. */
  36. /* includes */
  37. #include "vxWorks.h"
  38. #include "iosLib.h"
  39. #include "memLib.h"
  40. #include "tyLib.h"
  41. #include "iv.h"
  42. #include "intLib.h"
  43. #include "errnoLib.h"
  44. #include "drv/multi/m68360.h"
  45. /* defines */
  46. #define DEFAULT_BAUD 9600
  47. /* globals */
  48. IMPORT TY_CO_DEV tyCoDv []; /* device descriptors */
  49. /* locals */
  50. LOCAL int tyCoDrvNum; /* driver number assigned to this driver */
  51. /* forward declarations */
  52. LOCAL void tyCoStartup ();
  53. LOCAL int tyCoOpen ();
  54. LOCAL STATUS tyCoIoctl ();
  55. void tyCoInt ();
  56. LOCAL void tyCoHrdInit ();
  57. /*******************************************************************************
  58. *
  59. * tyCoDrv - initialize the tty driver
  60. *
  61. * This routine initializes the serial driver, sets up interrupt vectors,
  62. * and performs hardware initialization of the serial ports.
  63. *
  64. * This routine should be called exactly once, before any reads, writes, or
  65. * calls to tyCoDevCreate().  Normally, it is called from usrRoot() in
  66. * usrConfig.c.
  67. *
  68. * RETURNS: OK, or ERROR if the driver cannot be installed.
  69. *
  70. * SEE ALSO: tyCoDevCreate()
  71. */
  72. STATUS tyCoDrv (void)
  73.     {
  74.     /* check if driver already installed */
  75.     if (tyCoDrvNum > 0)
  76. return (OK);
  77.     tyCoHrdInit ();
  78.     tyCoDrvNum = iosDrvInstall (tyCoOpen, (FUNCPTR) NULL, tyCoOpen,
  79. (FUNCPTR) NULL, tyRead, tyWrite, tyCoIoctl);
  80.     return (tyCoDrvNum == ERROR ? ERROR : OK);
  81.     }
  82. /*******************************************************************************
  83. *
  84. * tyCoDevCreate - create a device for an on-board serial port
  85. *
  86. * This routine creates a device on a specified serial port.  Each port
  87. * to be used should have exactly one device associated with it by calling
  88. * this routine.
  89. *
  90. * For instance, to create the device "/tyCo/0", with buffer sizes of 512 bytes,
  91. * the proper call would be:
  92. * .CS
  93. *    tyCoDevCreate ("/tyCo/0", 0, 512, 512);
  94. * .CE
  95. *
  96. * RETURNS:
  97. * OK, or ERROR if the driver is not installed, the channel is invalid, or
  98. * the device already exists.
  99. *
  100. * SEE ALSO: tyCoDrv()
  101. */
  102. STATUS tyCoDevCreate
  103.     (
  104.     char *      name,           /* name to use for this device      */
  105.     FAST int    channel,        /* physical channel for this device */
  106.     int         rdBufSize,      /* read buffer size, in bytes       */
  107.     int         wrtBufSize      /* write buffer size, in bytes      */
  108.     )
  109.     {
  110.     if (tyCoDrvNum <= 0)
  111. {
  112. errnoSet (S_ioLib_NO_DRIVER);
  113. return (ERROR);
  114. }
  115.     /* if this doesn't represent a valid channel, don't do it */
  116.     if (channel < 0 || channel >= tyCoDv [0].numChannels)
  117.         return (ERROR);
  118.     /* if this device already exists, don't create it */
  119.     if (tyCoDv[channel].created )
  120. return (ERROR);
  121.     if (tyDevInit (&tyCoDv[channel].tyDev, rdBufSize, wrtBufSize,
  122.    (FUNCPTR) tyCoStartup)!= OK)
  123. return (ERROR);
  124.     /* enable the receiver and transmitter of the channel's SCC */
  125.     tyCoDv[channel].uart.pSccReg->gsmrl |= SCC_GSMRL_ENR | SCC_GSMRL_ENT;
  126.     /* mark the device as created, and add the device to the I/O system */
  127.     tyCoDv[channel].created = TRUE;
  128.     return (iosDevAdd (&tyCoDv[channel].tyDev.devHdr, name, tyCoDrvNum));
  129.     }
  130. /*******************************************************************************
  131. *
  132. * tyCoHrdInit - initialize the SCC
  133. */
  134. LOCAL void tyCoHrdInit (void)
  135.     {
  136.     int scc; /* the SCC number being initialized */
  137.     int baud; /* the baud rate generator being used */
  138.     int channel;
  139.     int frame;
  140.     TY_CO_DEV *pDv;
  141.     int oldlevel = intLock (); /* LOCK INTERRUPTS */
  142.  
  143.     for (channel = 0; channel < tyCoDv[0].numChannels; channel ++)
  144. {
  145. pDv = &tyCoDv[channel]; /* pDv points to device */
  146.         scc = pDv->uart.sccNum - 1; /* get SCC number */
  147.         baud = pDv->bgrNum - 1; /* get BRG number */
  148.         /* set up relevant addresses in the serial descriptor */
  149.         pDv->uart.pScc = (SCC *) ((UINT32) M360_DPR_SCC1(pDv->regBase) +
  150.                                   (scc * 0x100));
  151.         pDv->uart.pSccReg = (SCC_REG *) ((UINT32) M360_CPM_GSMR_L1(pDv->regBase)
  152.  + (scc * 0x20));
  153.         pDv->pBaud = (UINT32 *) (M360_CPM_BRGC1(pDv->regBase) + baud);
  154.         pDv->uart.intMask = CPIC_CIXR_SCC4 << (3 - scc);
  155.         /* set up SCC as NMSI */
  156.  
  157.         *M360_CPM_SICR(pDv->regBase) |= (UINT32) (baud << (scc << 3));
  158.         *M360_CPM_SICR(pDv->regBase) |= (UINT32) ((baud << 3) << (scc << 3));
  159.  
  160.         /* reset baud rate generator */
  161.  
  162.         *pDv->pBaud |= BRG_CR_RST;
  163.         while (*pDv->pBaud & BRG_CR_RST);
  164.         /* set BRG at default baud rate */
  165.         tyCoIoctl (pDv, FIOBAUDRATE, DEFAULT_BAUD);
  166.         /* set up transmit buffer descriptors */
  167.         pDv->uart.txBdBase = (SCC_BUF *) (pDv->regBase +
  168.  ((UINT32) pDv->uart.txBdBase & 0xfff));
  169.         pDv->uart.pScc->param.tbase = (UINT16) ((UINT32) pDv->uart.txBdBase &
  170. 0xfff);
  171.         pDv->uart.pScc->param.tbptr = (UINT16) ((UINT32) pDv->uart.txBdBase &
  172. 0xfff);
  173.         pDv->uart.txBdNext = 0;
  174.         /* initialize each transmit buffer descriptor */
  175. for (frame = 0; frame < pDv->uart.txBdNum; frame++)
  176.             {
  177.     pDv->uart.txBdBase[frame].statusMode = SCC_UART_TX_BD_INT;
  178.     pDv->uart.txBdBase[frame].dataPointer = pDv->uart.txBufBase +
  179.                 (frame * pDv->uart.txBufSize);
  180.             }
  181. /* set the last BD to wrap to the first */
  182. pDv->uart.txBdBase[(frame - 1)].statusMode |= SCC_UART_TX_BD_WRAP;
  183.         /* set up receive buffer descriptors */
  184.         pDv->uart.rxBdBase = (SCC_BUF *) (pDv->regBase +
  185.          ((UINT32) pDv->uart.rxBdBase & 0xfff));
  186.         pDv->uart.pScc->param.rbase = (UINT16) ((UINT32) pDv->uart.rxBdBase &
  187. 0xfff);
  188.         pDv->uart.pScc->param.rbptr = (UINT16) ((UINT32) pDv->uart.rxBdBase &
  189. 0xfff);
  190.         pDv->uart.rxBdNext = 0;
  191.         /* initialize each receive buffer descriptor */
  192. for (frame = 0; frame < pDv->uart.rxBdNum; frame++)
  193.     {
  194.     pDv->uart.rxBdBase[frame].statusMode = SCC_UART_RX_BD_EMPTY |
  195.                                                    SCC_UART_RX_BD_INT;
  196.     pDv->uart.rxBdBase[frame].dataLength = 1; /* char oriented */
  197.     pDv->uart.rxBdBase[frame].dataPointer = pDv->uart.rxBufBase + frame;
  198.     }
  199. /* set the last BD to wrap to the first */
  200. pDv->uart.rxBdBase[(frame - 1)].statusMode |= SCC_UART_TX_BD_WRAP;
  201. /* set SCC attributes to UART mode */
  202. pDv->uart.pSccReg->gsmrl = SCC_GSMRL_RDCR_X16 | SCC_GSMRL_TDCR_X16 |
  203.    SCC_GSMRL_UART;
  204. pDv->uart.pSccReg->gsmrh = SCC_GSMRH_RFW      | SCC_GSMRH_TFL;
  205.         pDv->uart.pSccReg->psmr  = SCC_UART_PSMR_FLC  | SCC_UART_PSMR_CL_8BIT;
  206. pDv->uart.pSccReg->dsr  = 0x7e7e; /* no fractional stop bits */
  207. pDv->uart.pScc->param.rfcr  = 0x18; /* supervisor data access */
  208. pDv->uart.pScc->param.tfcr  = 0x18; /* supervisor data access */
  209. pDv->uart.pScc->param.mrblr = 0x1; /* one character rx buffers */
  210. /* initialize parameter the SCC RAM */
  211.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->maxIdl      = 0x0;
  212.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->brkcr       = 0x1;
  213.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->parec       = 0x0;
  214.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->frmer       = 0x0;
  215.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->nosec       = 0x0;
  216.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->brkec       = 0x0;
  217.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->uaddr1      = 0x0;
  218.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->uaddr2      = 0x0;
  219.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->toseq       = 0x0;
  220.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character1  = 0x8000;
  221.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character2  = 0x8000;
  222.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character3  = 0x8000;
  223.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character4  = 0x8000;
  224.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character5  = 0x8000;
  225.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character6  = 0x8000;
  226.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character7  = 0x8000;
  227.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->character8  = 0x8000;
  228.         ((SCC_UART_PROTO *)pDv->uart.pScc->prot)->rccm        = 0x8000;
  229. pDv->uart.pSccReg->scce = 0xffff; /* clr events */
  230.         /* unmask interrupt */
  231. pDv->uart.pSccReg->sccm = SCC_UART_SCCX_RX | SCC_UART_SCCX_TX;
  232.         *M360_CPM_CIMR(pDv->regBase) |= pDv->uart.intMask;
  233. }
  234.     intUnlock (oldlevel); /* UNLOCK INTERRUPTS */
  235.     }
  236. /*******************************************************************************
  237. *
  238. * tyCoOpen - open file to SCC
  239. */
  240. LOCAL int tyCoOpen
  241.     (
  242.     TY_CO_DEV *pTyCoDv,
  243.     char *name,
  244.     int mode
  245.     )
  246.     {
  247.     return ((int) pTyCoDv);
  248.     }
  249. /*******************************************************************************
  250. *
  251. * tyCoIoctl - special device control
  252. *
  253. * This routine handles FIOBAUDRATE requests and passes all others to tyIoctl().
  254. *
  255. * RETURNS: OK or ERROR if invalid baud rate, or whatever tyIoctl() returns.
  256. */
  257. LOCAL STATUS tyCoIoctl
  258.     (
  259.     TY_CO_DEV *pTyCoDv, /* device to control */
  260.     int request, /* request code */
  261.     int arg /* some argument */
  262.     )
  263.     {
  264.     int baudRate;
  265.     STATUS status = OK;
  266.     switch (request)
  267. {
  268. case FIOBAUDRATE:
  269.             if (arg >=  50 && arg <= 38400) /* could go higher... */
  270. {
  271. /* calculate proper counter value, then enable BRG */
  272.                 baudRate = (pTyCoDv->clockRate / (16 * arg)) - 1;
  273. if (baudRate > 0xfff)
  274.                     *pTyCoDv->pBaud = (BRG_CR_CD & ((baudRate / 16) << 1)) |
  275.        BRG_CR_EN | BRG_CR_DIV16;
  276.                 else
  277.                     *pTyCoDv->pBaud = (BRG_CR_CD & (baudRate << 1)) |
  278.        BRG_CR_EN;
  279. }
  280.             else
  281.         status = ERROR;
  282.     break;
  283. /* pass all other requests to tyIoctl() */
  284. default:
  285.     status = tyIoctl (&pTyCoDv->tyDev, request, arg);
  286.     break;
  287. }
  288.     return (status);
  289.     }
  290. /*******************************************************************************
  291. *
  292. * tyCoInt - handle a SCC interrupt
  293. *
  294. * This routine gets called to handle SCC interrupts.
  295. *
  296. * NOMANUAL
  297. */
  298. void tyCoInt
  299.     (
  300.     TY_CO_DEV *pDv
  301.     )
  302.     {
  303.     char outChar;
  304.     FAST UINT16 dataLen = 0;
  305.     int event;
  306.     if (!pDv->created)
  307. {
  308.         pDv->uart.pSccReg->scce = 0xffff; /* acknowledge interrupt */
  309.         *M360_CPM_CISR(pDv->regBase) = pDv->uart.intMask;
  310. return;
  311. }
  312.     /* get event bits and acknowledge them */
  313.     event = pDv->uart.pSccReg->scce;
  314.     pDv->uart.pSccReg->scce = event;
  315.     /* check for a receive event */
  316.     if (event & SCC_UART_SCCX_RX)
  317. {
  318. while (!(pDv->uart.rxBdBase[pDv->uart.rxBdNext].statusMode &
  319.  SCC_UART_RX_BD_EMPTY))
  320.     {
  321.     /* process all filled receive buffers */
  322.     tyIRd (&pDv->tyDev,
  323.                    pDv->uart.rxBdBase[pDv->uart.rxBdNext].dataPointer[0]);
  324.     pDv->uart.rxBdBase[pDv->uart.rxBdNext].statusMode |=
  325. SCC_UART_RX_BD_EMPTY;
  326.     /* incr BD count */
  327.     pDv->uart.rxBdNext = (pDv->uart.rxBdNext + 1) % pDv->uart.rxBdNum;
  328.     }
  329. }
  330.     /* check for a transmit event and if a character needs to be output */
  331.     if (event & SCC_UART_SCCX_TX)
  332. {
  333.         if (tyITx (&pDv->tyDev, &outChar) == OK)
  334.     {
  335.     do
  336.         {
  337.         pDv->uart.txBdBase[pDv->uart.txBdNext].dataPointer[dataLen++] =
  338.                     outChar;
  339.         }
  340.     while ((dataLen < pDv->uart.txBufSize) &&
  341.                    (tyITx (&pDv->tyDev, &outChar) == OK));
  342.     pDv->uart.txBdBase[pDv->uart.txBdNext].dataLength  = dataLen;
  343.     /* send transmit buffer */
  344.     pDv->uart.txBdBase[pDv->uart.txBdNext].statusMode |=
  345.         SCC_UART_TX_BD_READY;
  346.     /* incr BD count */
  347.       pDv->uart.txBdNext = (pDv->uart.txBdNext + 1) % pDv->uart.txBdNum;
  348.     }
  349. }
  350.     *M360_CPM_CISR(pDv->regBase) = pDv->uart.intMask;
  351.     }
  352. /*******************************************************************************
  353. *
  354. * tyCoStartup - transmitter startup routine
  355. */
  356. LOCAL void tyCoStartup
  357.     (
  358.     TY_CO_DEV *pDv /* ty device to start up */
  359.     )
  360.     {
  361.     char outChar;
  362.     FAST UINT16 dataLen = 0;
  363.     /* check if buffer is ready and if a character needs to be output */
  364.     if ((!(pDv->uart.txBdBase[pDv->uart.txBdNext].statusMode &
  365.    SCC_UART_TX_BD_READY)) &&
  366.         (tyITx (&pDv->tyDev, &outChar) == OK))
  367. {
  368. do
  369.     {
  370.     pDv->uart.txBdBase[pDv->uart.txBdNext].dataPointer[dataLen++] =
  371. outChar;
  372.     }
  373. while ((dataLen < pDv->uart.txBufSize) &&
  374.                (tyITx (&pDv->tyDev, &outChar) == OK)); /* fill buffer */
  375. /* send transmit buffer */
  376. pDv->uart.txBdBase[pDv->uart.txBdNext].dataLength  = dataLen;
  377. pDv->uart.txBdBase[pDv->uart.txBdNext].statusMode |=
  378.     SCC_UART_TX_BD_READY;
  379. /* incr BD count */
  380.         pDv->uart.txBdNext = (pDv->uart.txBdNext + 1) % pDv->uart.txBdNum;
  381. }
  382.     }