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

VxWorks

开发平台:

C/C++

  1. /* cd2400Serial.c - CL-CD2400 MPCC tty driver */
  2. /* Copyright 1984-1992 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,20nov96,dds  SPR 5438: Added interrupt locking to tyCoStartup () routine.
  8. 01n,30nov92,jdi  doc tweak; NOMANUAL for tyCoIntRx(), tyCoIntTx(), tyCoInt()
  9.  - SPR 1808.
  10. 01m,28oct92,caf  tweaked tyCoDevCreate() documentation.
  11. 01l,25sep92,ccc  added LOCAL forward declarations.
  12. 01k,09sep92,gae  doc tweaks.
  13. 01j,01sep92,ccc  changed name to cd2400Serial.c.
  14. 01i,18jul92,smb  Changed errno.h to errnoLib.h.
  15. 01h,16jun92,ccc  created from 01g version of mv167 tyCoDrv, ansified.
  16. 01g,26may92,rrr  the tree shuffle
  17. 01f,14oct91,ccc  changed VOID to void.
  18.  changed copyright notice.
  19. 01e,18aug91,jdi  documentation cleanup.
  20. 01d,15aug91,ccc  documentation changes.
  21. 01c,12aug91,ccc  delinted.
  22. 01b,30jul91,ccc  fixed IRQ vector for channels, removed tyCoResetChannel().
  23.  selected channel in tyCoIoctl().
  24. 01a,14jun91,ccc  written, by modifying 01e of the mv147 version.
  25. */
  26. /*
  27. DESCRIPTION
  28. This is the driver for the Cirus Logic CD2400 MPCC.  It uses the SCC's in
  29. asynchronous mode only.
  30. USER-CALLABLE ROUTINES
  31. Most of the routines in this driver are accessible only through the I/O
  32. system.  Two routines, however, must be called directly:  tyCoDrv() to
  33. initialize the driver, and tyCoDevCreate() to create devices.
  34. Before the driver can be used, it must be initialized by calling tyCoDrv().
  35. This routine should be called exactly once, before any reads, writes, or
  36. calls to tyCoDevCreate().  Normally, it is called from usrRoot() in usrConfig.c.
  37. Before a terminal can be used, it must be created using tyCoDevCreate().
  38. Each port to be used should have exactly one device associated with it by
  39. calling this routine.
  40. IOCTL FUNCTIONS
  41. This driver responds to the same ioctl() codes as a normal tty driver; for
  42. more information, see the manual entry for tyLib.  The available baud rates
  43. are:  50, 110, 150, 300, 600, 1200, 2400, 3600, 4800, 7200, 9600,
  44. 19200, and 38400.
  45. SEE ALSO
  46. tyLib
  47. */
  48. #include "vxWorks.h"
  49. #include "iv.h"
  50. #include "ioLib.h"
  51. #include "iosLib.h"
  52. #include "tyLib.h"
  53. #include "intLib.h"
  54. #include "errnoLib.h"
  55. #include "drv/serial/cd2400.h"
  56. #define DEFAULT_BAUD 9600
  57. IMPORT TY_CO_DEV tyCoDv []; /* device descriptors */
  58. LOCAL int tyCoDrvNum; /* driver number assigned to this driver */
  59. typedef struct /* BAUD */
  60.     {
  61.     int rate; /* baud rate */
  62.     char timeConstant; /* time constant */
  63.     char tcor; /* transmit clock option register value */
  64.     char rcor; /* receive clock option register value */
  65.     } BAUD;
  66. LOCAL BAUD baudTable [] =
  67.     {
  68.      {    50, ((BAUD_CLK_FREQ / 2048) /   50) - 1, TCOR_CLK4, RCOR_CLK4 },
  69.      {   110, ((BAUD_CLK_FREQ / 2048) /  110) - 1, TCOR_CLK4, RCOR_CLK4 },
  70.      {   150, ((BAUD_CLK_FREQ / 2048) /  150) - 1, TCOR_CLK4, RCOR_CLK4 },
  71.      {   300, ((BAUD_CLK_FREQ /  512) /  300) - 1, TCOR_CLK3, RCOR_CLK3 },
  72.      {   600, ((BAUD_CLK_FREQ /  512) /  600) - 1, TCOR_CLK3, RCOR_CLK3 },
  73.      {  1200, ((BAUD_CLK_FREQ /  128) / 1200) - 1, TCOR_CLK2, RCOR_CLK2 },
  74.      {  2400, ((BAUD_CLK_FREQ /  128) / 2400) - 1, TCOR_CLK2, RCOR_CLK2 },
  75.      {  3600, ((BAUD_CLK_FREQ /   32) / 3600) - 1, TCOR_CLK1, RCOR_CLK1 },
  76.      {  4800, ((BAUD_CLK_FREQ /   32) / 4800) - 1, TCOR_CLK1, RCOR_CLK1 },
  77.      {  7200, ((BAUD_CLK_FREQ /   32) / 7200) - 1, TCOR_CLK1, RCOR_CLK1 },
  78.      {  9600, ((BAUD_CLK_FREQ /   32) / 9600) - 1, TCOR_CLK1, RCOR_CLK1 },
  79.      { 19200, ((BAUD_CLK_FREQ /    8) /19200) - 1, TCOR_CLK0, RCOR_CLK0 },
  80.      { 38400, ((BAUD_CLK_FREQ /    8) /38400) - 1, TCOR_CLK0, RCOR_CLK0 }
  81.     };
  82. /* forward declarations */
  83. LOCAL void      tyCoHrdInit ();
  84. LOCAL void      tyCoInitChannel ();
  85. LOCAL STATUS    tyCoIoctl ();
  86. LOCAL int tyCoOpen ();
  87. LOCAL void tyCoStartup ();
  88. /*******************************************************************************
  89. *
  90. * tyCoDrv - tty driver initialization routine
  91. *
  92. * This routine initializes the serial driver, sets up interrupt vectors, and
  93. * performs hardware initialization of the serial ports.
  94. *
  95. * This routine should be called exactly once, before any reads, writes, or
  96. * calls to tyCoDevCreate().  Normally, it is called by usrRoot() is
  97. * usrConfig.c.
  98. *
  99. * RETURNS: OK, or ERROR if the driver cannot be installed.
  100. */
  101. STATUS tyCoDrv (void)
  102.     {
  103.     /* check if driver already installed */
  104.     if (tyCoDrvNum > 0)
  105. return (OK);
  106.     tyCoHrdInit (); /* init hardware */
  107.     tyCoDrvNum = iosDrvInstall (tyCoOpen, (FUNCPTR) NULL, tyCoOpen,
  108. (FUNCPTR) NULL, tyRead, tyWrite, tyCoIoctl);
  109.     return (tyCoDrvNum == ERROR ? ERROR : OK);
  110.     }
  111. /*******************************************************************************
  112. *
  113. * tyCoDevCreate - create a device for an on-board serial port
  114. *
  115. * This routine creates a device on a specified serial port.  Each port
  116. * to be used should have exactly one device associated with it by calling
  117. * this routine.
  118. *
  119. * For instance, to create the device "/tyCo/0", with buffer sizes of 512 bytes,
  120. * the proper call would be:
  121. * .CS
  122. *     tyCoDevCreate ("/tyCo/0", 0, 512, 512);
  123. * .CE
  124. *
  125. * RETURNS: OK, or ERROR if the driver is not installed or the channel is
  126. * invalid.
  127. */
  128. STATUS tyCoDevCreate
  129.     (
  130.     char *      name,           /* name to use for this device      */
  131.     FAST int    channel,        /* physical channel for this device */
  132.     int         rdBufSize,      /* read buffer size, in bytes       */
  133.     int         wrtBufSize      /* write buffer size, in bytes      */
  134.     )
  135.     {
  136.     FAST TY_CO_DEV *pTyCoDv;
  137.     if (tyCoDrvNum <= 0)
  138. {
  139. errnoSet (S_ioLib_NO_DRIVER);
  140. return (ERROR);
  141. }
  142.     /* if this doesn't represent a valid channel, don't do it */
  143.     if (channel < 0 || channel >= tyCoDv [0].numChannels)
  144. return (ERROR);
  145.     pTyCoDv = &tyCoDv [channel];
  146.     /* if there is a device already on this channel, don't do it */
  147.     if (pTyCoDv->created)
  148. return (ERROR);
  149.     /* initialize the ty descriptor */
  150.     if (tyDevInit (&pTyCoDv->tyDev, rdBufSize, wrtBufSize,
  151.    (FUNCPTR) tyCoStartup) != OK)
  152. {
  153. return (ERROR);
  154. }
  155.     /* initialize the channel hardware */
  156.     tyCoInitChannel (channel); /* init single channel */
  157.     /* mark the device as created, and add the device to the I/O system */
  158.     pTyCoDv->created = TRUE;
  159.     return (iosDevAdd (&pTyCoDv->tyDev.devHdr, name, tyCoDrvNum));
  160.     }
  161. /*******************************************************************************
  162. *
  163. * tyCoHrdInit - initialize the USART
  164. */
  165. LOCAL void tyCoHrdInit (void)
  166.     {
  167.     FAST int   oldlevel; /* current interrupt level mask */
  168.     oldlevel = intLock (); /* disable interrupts during init */
  169.     while (*MPCC_CCR)
  170. ; /* make sure no outstanding commands */
  171.     *MPCC_CCR = CCR_RESET_ALL; /* reset chip */
  172.     while (*MPCC_CCR)
  173. ; /* make sure we are done */
  174.     while (*MPCC_GFRCR == 0)
  175. ; /* wait for it to be non-zero */
  176.     *MPCC_TPR = 0x0a; /* Timer Peroid Register */
  177.     *MPCC_PILR1 = 0x00; /* Priority Interrupt Level Register */
  178.     *MPCC_PILR2 = 0x02; /* Priority Interrupt Level Register */
  179.     *MPCC_PILR3 = 0x03; /* Priority Interrupt Level Register */
  180.     intUnlock (oldlevel);
  181.     }
  182. /*******************************************************************************
  183. *
  184. * tyCoInitChannel - initialize a single channel
  185. */
  186. LOCAL void tyCoInitChannel
  187.     (
  188.     int channel
  189.     )
  190.     {
  191.     FAST TY_CO_DEV *pTyCoDv = &tyCoDv [channel];
  192.     FAST int        oldlevel; /* current interrupt level mask */
  193.     oldlevel = intLock (); /* disable interrupts during init */
  194.     /* initialize registers */
  195.     *MPCC_CAR  = pTyCoDv->chan_num;
  196.     *MPCC_LIVR = pTyCoDv->int_vec;
  197.     *MPCC_COR1 = COR1_NO_PARITY |
  198.  COR1_8BITS;
  199.     *MPCC_COR2 = 0x00;
  200.     *MPCC_COR3 = COR3_1STOP_BIT;
  201.     *MPCC_COR4 = 0x00; /* no modem control for now */
  202.     *MPCC_COR5 = 0x00; /* no modem control for now */
  203.     *MPCC_COR6 = COR6_NORMAL_CR_NL |
  204.  COR6_BRK_EXCEPTION |
  205.  COR6_PARITY_EXCEPTION;
  206.     *MPCC_COR7 = COR7_NORMAL_CR_NL;
  207.     *MPCC_CMR = CMR_RX_INTERRUPT |
  208. CMR_TX_INTERRUPT |
  209. CMR_ASYNC_MODE;
  210.     *MPCC_TBPR = BPR_9600;
  211.     *MPCC_TCOR = TCOR_CLK1;
  212.     *MPCC_RBPR = BPR_9600;
  213.     *MPCC_RCOR = RCOR_CLK1;
  214.     *MPCC_CPSR = CPSR_CRC_V41;
  215.     *MPCC_SCHR1 = 0x00;
  216.     *MPCC_SCHR2 = 0x00;
  217.     *MPCC_SCHR3 = 0x00; /* Special Char Reg 3 */
  218.     *MPCC_SCHR4 = 0x00; /* Special Char Reg 4 */
  219.     *MPCC_SCRL = 0x00; /* Special Char Range Low */
  220.     *MPCC_SCRH = 0x00; /* Special Char Range High */
  221.     *MPCC_RTPRL = 0x01; /* set timeout high - ONLY DMA mode */
  222.     *MPCC_RTPRH = 0x00; /* so this should not be used for now */
  223.     while (*MPCC_CCR)
  224. ; /* make sure no outstanding commands */
  225.     *MPCC_CCR = CCR_INIT_CHANNEL;
  226.     while (*MPCC_CCR)
  227. ; /* make sure we are done */
  228.     *MPCC_CCR = CCR_ENABLE_TRANS |
  229. CCR_ENABLE_REC; /* enable Tx and Rx */
  230.     while (*MPCC_CCR)
  231. ;
  232.     *MPCC_IER = IER_RXDATA |
  233. IER_TXEMPTY;
  234.     *MPCC_MSVRDTR = MSVR_DTR;
  235.     *MPCC_MSVRRTS = MSVR_RTS;
  236.     intUnlock (oldlevel);
  237.     }
  238. /*******************************************************************************
  239. *
  240. * tyCoOpen - open file to USART
  241. */
  242. LOCAL int tyCoOpen
  243.     (
  244.     TY_CO_DEV *pTyCoDv,
  245.     char      *name,
  246.     int        mode
  247.     )
  248.     {
  249.     return ((int) pTyCoDv);
  250.     }
  251. /*******************************************************************************
  252. *
  253. * tyCoIoctl - special device control
  254. *
  255. * This routine handles FIOBAUDRATE requests and passes all others to tyIoctl.
  256. *
  257. * RETURNS: OK or ERROR if invalid baud rate, or whatever tyIoctl returns.
  258. */
  259. LOCAL STATUS tyCoIoctl
  260.     (
  261.     TY_CO_DEV *pTyCoDv, /* device to control */
  262.     int        request, /* request code      */
  263.     int        arg /* some argument     */
  264.     )
  265.     {
  266.     FAST int     oldlevel; /* current interrupt level mask */
  267.     int  ix;
  268.     FAST STATUS  status;
  269.     switch (request)
  270. {
  271. case FIOBAUDRATE:
  272.     status = ERROR; /* baud rate out of range */
  273.     /* disable interrupts during chip access */
  274.     oldlevel = intLock ();
  275.     *MPCC_CAR = pTyCoDv->chan_num;      /* set up channel */
  276.     for (ix = 0; ix < NELEMENTS (baudTable); ix++)
  277. {
  278. if (baudTable [ix].rate == arg)
  279.     {
  280.     *MPCC_TBPR = baudTable [ix].timeConstant;
  281.     *MPCC_TCOR = baudTable [ix].tcor;
  282.     *MPCC_RBPR = baudTable [ix].timeConstant;
  283.     *MPCC_RCOR = baudTable [ix].rcor;
  284.     status = OK;
  285.     break;
  286.     }
  287. }
  288.     intUnlock (oldlevel);
  289.     break;
  290. default:
  291.     status = tyIoctl (&pTyCoDv->tyDev, request, arg);
  292.     break;
  293. }
  294.     return (status);
  295.     }
  296. /*******************************************************************************
  297. *
  298. * tyCoIntRx - interrupt level processing for Receive Data Interrupt
  299. *
  300. * This routine handles the interrupts for all channels for a Receive
  301. * Data Interrupt.
  302. *
  303. * NOMANUAL
  304. */
  305. void tyCoIntRx
  306.     (
  307.     FAST TY_CO_DEV  *pTyCoDv
  308.     )
  309.     {
  310.     if (pTyCoDv->created)
  311. {
  312. tyIRd (&pTyCoDv->tyDev, *MPCC_RDR); /* read char */
  313. *MPCC_REOIR = EOIR_TRANSFER;
  314. /* write to register to clear interrupt */
  315. }
  316.     else
  317. *MPCC_REOIR = EOIR_NO_TRANSFER; /* just clear interrupt */
  318.     }
  319. /*******************************************************************************
  320. *
  321. * tyCoIntTx - interrupt level processing
  322. *
  323. * This routine handles all interrupts from the MPCC.
  324. * We determine from the paramter which channel interrupted us.
  325. * Then from the status register we know what kind of interrupt.
  326. *
  327. * NOMANUAL
  328. */
  329. void tyCoIntTx
  330.     (
  331.     FAST TY_CO_DEV  *pTyCoDv
  332.     )
  333.     {
  334.     char       outChar;
  335.     /* Tx Buffer Empty */
  336.     if (pTyCoDv->created && (tyITx (&pTyCoDv->tyDev, &outChar) == OK))
  337. {
  338. *MPCC_TDR = outChar;
  339. *MPCC_TEOIR = EOIR_TRANSFER;
  340. }
  341.     else
  342. {
  343. /* no more chars to xmit now.  reset the tx int,
  344.  * so the SCC doesn't keep interrupting us. */
  345. *MPCC_IER &= ~(IER_TXEMPTY | IER_TXDATA);
  346. *MPCC_TEOIR = EOIR_NO_TRANSFER;
  347. }
  348.     }
  349. /*******************************************************************************
  350. *
  351. * tyCoInt - interrupt level processing for special interrupts
  352. *
  353. * NOMANUAL
  354. */
  355. void tyCoInt
  356.     (
  357.     FAST TY_CO_DEV  *pTyCoDv
  358.     )
  359.     {
  360.     *MPCC_REOIR = EOIR_NO_TRANSFER; /* just clear interrupt */
  361.     }
  362. /*******************************************************************************
  363. *
  364. * tyCoStartup - transmitter startup routine
  365. *
  366. * Call interrupt level character output routine.
  367. */
  368. LOCAL void tyCoStartup
  369.     (
  370.     TY_CO_DEV *pTyCoDv /* ty device to start up */
  371.     )
  372.     {
  373.     int oldLevel;
  374.     oldLevel = intLock ();
  375.     *MPCC_CAR = pTyCoDv->chan_num; /* set up channel */
  376.     /* only need to enable interrupt */
  377.     *MPCC_IER = IER_TXEMPTY |
  378. IER_TXDATA |
  379. IER_RXDATA;
  380.     intUnlock (oldLevel);
  381.     }