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

VxWorks

开发平台:

C/C++

  1. /* am85c30Serial.c - Am85C30 ESCC (Enhanced Serial Communications Controller)
  2.                      tty driver*/
  3. /* Copyright 1984-1993 Wind River Systems, Inc. */
  4. #include "copyright_wrs.h"
  5. /*
  6. modification history
  7. --------------------
  8. 01c,27apr95,tpr  inverted RX and TX text in tyCoInt().
  9. 01b,11mar94,pme  changed dedines to defines.
  10. 01a,02dec93,pad  written, by modifying 01n of the z8530 version.
  11. */
  12. /*
  13. DESCRIPTION
  14. This is the driver for the Am85C30 ESCC (Enhanced Serial Communications
  15. Controller).
  16. It uses the ESCCs in asynchronous mode only.
  17. USER-CALLABLE ROUTINES
  18. Most of the routines in this driver are accessible only through the I/O
  19. system.  Two routines, however, must be called directly: tyCoDrv() to
  20. initialize the driver, and tyCoDevCreate() to create devices.
  21. Before the driver can be used, it must be initialized by calling tyCoDrv().
  22. This routine should be called exactly once, before any reads, writes, or
  23. calls to tyCoDevCreate().  Normally, it is called by usrRoot() in usrConfig.c.
  24. Before a terminal can be used, it must be created using tyCoDevCreate().
  25. Each port to be used should have exactly one device associated with it by
  26. calling this routine.
  27. IOCTL FUNCTIONS
  28. This driver responds to the same ioctl() codes as a normal tty driver; for
  29. more information, see the manual entry for tyLib.  Available baud rates
  30. range from 50 to 38400.
  31. SEE ALSO
  32. tyLib
  33. */
  34. /* includes */
  35. #include "vxWorks.h"
  36. #include "iv.h"
  37. #include "ioLib.h"
  38. #include "iosLib.h"
  39. #include "tyLib.h"
  40. #include "intLib.h"
  41. #include "errnoLib.h"
  42. #include "drv/serial/am85c30.h"
  43. /* defines */
  44. #define DEFAULT_BAUD 9600
  45. /* externals */
  46. IMPORT TY_CO_DEV tyCoDv []; /* device descriptors */
  47. IMPORT int delayCount; /* used in SCC_DELAY */
  48. /* locals */
  49. LOCAL int tyCoDrvNum; /* driver number assigned to this driver */
  50. /* forward declarations */
  51. LOCAL void   tyCoStartup (TY_CO_DEV * pTyCoDv);
  52. LOCAL int    tyCoOpen (TY_CO_DEV * pTyCoDv, char * name, int mode);
  53. LOCAL STATUS tyCoIoctl (TY_CO_DEV * pTyCoDv, int request, int arg);
  54. LOCAL void   tyCoHrdInit (void);
  55. LOCAL void   tyCoInitChannel (int channel);
  56. LOCAL void   tyCoResetChannel (int channel);
  57. /*******************************************************************************
  58. *
  59. * tyCoDrv - initialize the tty driver
  60. *
  61. * This routine initializes the serial driver, sets up interrupt vectors, and
  62. * 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 by 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.     (void) intConnect (INUM_TO_IVEC (INT_NUM_SCC), tyCoInt, 0);
  81.     return (tyCoDrvNum == ERROR ? ERROR : OK);
  82.     }
  83. /*******************************************************************************
  84. *
  85. * tyCoDevCreate - create a device for an on-board serial port
  86. *
  87. * This routine creates a device on a specified serial port.  Each port
  88. * to be used should have exactly one device associated with it by calling
  89. * this routine.
  90. *
  91. * For instance, to create the device "/tyCo/0", with buffer sizes of 512 bytes,
  92. * the proper call would be:
  93. * .CS
  94. *     tyCoDevCreate ("/tyCo/0", 0, 512, 512);
  95. * .CE
  96. *
  97. * RETURNS: OK, or ERROR if the driver is not installed, the channel is
  98. * invalid, or the device already exists.
  99. *
  100. * SEE ALSO: tyCoDrv()
  101. */
  102. STATUS tyCoDevCreate
  103.     (
  104.     char * name,           /* name to use for this device      */
  105.     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.     TY_CO_DEV * pTyCoDv;
  111.     if (tyCoDrvNum <= 0)
  112. {
  113. errnoSet (S_ioLib_NO_DRIVER);
  114. return (ERROR);
  115. }
  116.     /* if this doesn't represent a valid channel, don't do it */
  117.     if (channel < 0 || channel >= tyCoDv [0].numChannels)
  118. return (ERROR);
  119.     pTyCoDv = &tyCoDv [channel];
  120.     /* if there is a device already on this channel, don't do it */
  121.     if (pTyCoDv->created)
  122. return (ERROR);
  123.     /* initialize the ty descriptor */
  124.     if (tyDevInit (&pTyCoDv->tyDev, rdBufSize, wrtBufSize,
  125.    (FUNCPTR) tyCoStartup) != OK)
  126. {
  127. return (ERROR);
  128. }
  129.     /* initialize the channel hardware */
  130.     tyCoInitChannel (channel);
  131.     /* mark the device as created, and add the device to the I/O system */
  132.     pTyCoDv->created = TRUE;
  133.     return (iosDevAdd (&pTyCoDv->tyDev.devHdr, name, tyCoDrvNum));
  134.     }
  135. /*******************************************************************************
  136. *
  137. * tyCoHrdInit - initialize the USART
  138. */
  139. LOCAL void tyCoHrdInit (void)
  140.     {
  141.     int oldlevel; /* current interrupt level mask */
  142.     int ix;
  143.     oldlevel = intLock (); /* disable interrupts during init */
  144.     for (ix=0; ix < tyCoDv [0].numChannels; ix++)
  145. tyCoResetChannel (ix); /* reset channel */
  146.     intUnlock (oldlevel);
  147.     }
  148. /********************************************************************************
  149. * tyCoResetChannel - reset a single channel
  150. */
  151. LOCAL void tyCoResetChannel
  152.     (
  153.     int channel
  154.     )
  155.     {
  156.     volatile char * cr = tyCoDv [channel].cr; /* SCC control reg adr */
  157.     int zero = 0;
  158.     *cr = zero; /* SCC_WR0_NULL_CODE sync the state machine */
  159.     SCC_DELAY;
  160.     *cr = zero; /* SCC_WR0_NULL_CODE sync the state machine */
  161.     SCC_DELAY;
  162.     *cr = SCC_WR0_ERR_RST;
  163.     SCC_DELAY;
  164.     *cr = SCC_WR0_RST_INT;
  165.     SCC_DELAY;
  166.     *cr = SCC_WR0_SEL_WR9;      /* write register 9 - master int ctrl */
  167.     SCC_DELAY;
  168.     *cr = ((channel % 2) == 0) ?
  169.         SCC_WR9_CH_A_RST :      /* reset channel A */
  170.         SCC_WR9_CH_B_RST;       /* reset channel B */
  171.     SCC_DELAY; SCC_DELAY; SCC_DELAY; SCC_DELAY; SCC_DELAY; SCC_DELAY; 
  172.     SCC_DELAY; SCC_DELAY; SCC_DELAY; SCC_DELAY; SCC_DELAY; SCC_DELAY;
  173.     }
  174. /*******************************************************************************
  175. *
  176. * tyCoInitChannel - initialize a single channel
  177. */
  178. LOCAL void tyCoInitChannel
  179.     (
  180.     int channel
  181.     )
  182.     {
  183.     TY_CO_DEV * pTyCoDv = &tyCoDv [channel];
  184.     volatile char * cr = pTyCoDv->cr; /* SCC control reg adr */
  185.     int baudConstant;
  186.     int oldlevel; /* current interrupt level mask */
  187.     int zero = 0;
  188.     oldlevel = intLock (); /* disable interrupts during init */
  189.     /* initialize registers */
  190.     *cr = SCC_WR0_RST_TX_UND; /* reset transmit underrun */
  191.     SCC_DELAY;
  192.     *cr = SCC_WR0_SEL_WR4;              /* write reg 4 - misc parms and modes */
  193.     SCC_DELAY;
  194.     *cr = SCC_WR4_1_STOP | SCC_WR4_16_CLOCK;
  195.     SCC_DELAY;
  196.     *cr = SCC_WR0_SEL_WR1;
  197.     SCC_DELAY;
  198.     *cr = 0; /* no DMA */
  199.     SCC_DELAY;
  200.     *cr = SCC_WR0_SEL_WR2;
  201.     SCC_DELAY;
  202.     *cr = 0; /* no vector */
  203.     SCC_DELAY;
  204.     *cr = SCC_WR0_SEL_WR3; /* write reg 3 - receive params */
  205.     SCC_DELAY;
  206.     *cr = SCC_WR3_RX_8_BITS;
  207.     SCC_DELAY;
  208.     *cr = SCC_WR0_SEL_WR5; /* tx params */
  209.     SCC_DELAY;
  210.     *cr = SCC_WR5_TX_8_BITS;
  211.     SCC_DELAY;
  212.     *cr = SCC_WR0_SEL_WR6; /* no sync mode */
  213.     SCC_DELAY;
  214.     *cr = zero;
  215.     SCC_DELAY;
  216.     *cr = SCC_WR0_SEL_WR7; /* no sync mode */
  217.     SCC_DELAY;
  218.     *cr = zero;
  219.     SCC_DELAY;
  220.     *cr = SCC_WR0_SEL_WR9; /* no interrupt acknowledge */
  221.     SCC_DELAY;
  222.     *cr = SCC_WR9_NV;
  223.     SCC_DELAY;
  224.     *cr = SCC_WR0_SEL_WR10; /* misc tx/rx control */
  225.     SCC_DELAY;
  226.     *cr = zero; /* clear sync, loop, poll */
  227.     SCC_DELAY;
  228.     *cr = SCC_WR0_SEL_WR11; /* clock mode */
  229.     SCC_DELAY;
  230.     *cr = pTyCoDv->clockModeWR11;
  231.     SCC_DELAY;
  232.     /* Calculate the baud rate constant for the default baud rate
  233.      * from the input clock frequency.  This assumes that the
  234.      * divide-by-16 bit is set (done in WR4 above).
  235.      */
  236.     baudConstant = ((pTyCoDv->baudFreq / 32) / DEFAULT_BAUD) - 2;
  237.     *cr = SCC_WR0_SEL_WR12; /* LSB of baud constant */
  238.     SCC_DELAY;
  239.     *cr = (char) baudConstant; /* write LSB */
  240.     SCC_DELAY;
  241.     *cr = SCC_WR0_SEL_WR13; /* MSB of baud constant */
  242.     SCC_DELAY;
  243.     *cr = (char) (baudConstant >> 8); /* write MSB */
  244.     SCC_DELAY;
  245.     *cr = SCC_WR0_SEL_WR14; /* clock source : BRG */
  246.     SCC_DELAY;
  247.     *cr = pTyCoDv->clockModeWR14;
  248.     SCC_DELAY;
  249.     *cr = SCC_WR0_SEL_WR3; /* write reg 3 - receive params */
  250.     SCC_DELAY;
  251.     *cr = SCC_WR3_RX_8_BITS | SCC_WR3_RX_EN;
  252.     SCC_DELAY;
  253.     *cr = SCC_WR0_SEL_WR5; /* tx params */
  254.     SCC_DELAY;
  255.     *cr = SCC_WR5_TX_8_BITS | SCC_WR5_TX_EN | SCC_WR5_DTR | SCC_WR5_RTS;
  256.     SCC_DELAY;
  257.     *cr = SCC_WR0_SEL_WR15; /* external/status interrupt control */
  258.     SCC_DELAY;
  259.     *cr = zero;
  260.     SCC_DELAY;
  261.     *cr = SCC_WR0_RST_INT; /* reset external interrupts */
  262.     SCC_DELAY;
  263.     *cr = SCC_WR0_SEL_WR1; /* int and xfer mode */
  264.     SCC_DELAY;
  265.     *cr = SCC_WR1_INT_ALL_RX | SCC_WR1_TX_INT_EN;
  266.     SCC_DELAY;
  267.     *cr = SCC_WR0_SEL_WR9; /* master interrupt control */
  268.     SCC_DELAY;
  269.     *cr = SCC_WR9_MIE | pTyCoDv->intType; /* enable interrupts */
  270.     SCC_DELAY;
  271.     *cr = zero; /* reset SCC register counter */
  272.     SCC_DELAY;
  273.     intUnlock (oldlevel);
  274.     }
  275. /*******************************************************************************
  276. *
  277. * tyCoOpen - open file to USART
  278. */
  279. LOCAL int tyCoOpen
  280.     (
  281.     TY_CO_DEV * pTyCoDv,
  282.     char      * name,
  283.     int         mode
  284.     )
  285.     {
  286.     return ((int) pTyCoDv);
  287.     }
  288. /*******************************************************************************
  289. *
  290. * tyCoIoctl - special device control
  291. *
  292. * This routine handles FIOBAUDRATE requests and passes all others to tyIoctl().
  293. *
  294. * RETURNS: OK, or ERROR if invalid baud rate, or whatever tyIoctl() returns.
  295. */
  296. LOCAL STATUS tyCoIoctl
  297.     (
  298.     TY_CO_DEV * pTyCoDv, /* device to control */
  299.     int         request, /* request code */
  300.     int         arg /* some argument */
  301.     )
  302.     {
  303.     int oldlevel; /* current interrupt level mask */
  304.     int baudConstant;
  305.     STATUS status;
  306.     volatile char * cr; /* SCC control reg adr */
  307.     switch (request)
  308. {
  309. case FIOBAUDRATE:
  310.     if (arg < 50 || arg > 38400)
  311.         {
  312. status = ERROR; /* baud rate out of range */
  313. break;
  314.         }
  315.     /* Calculate the baud rate constant for the new baud rate
  316.      * from the input clock frequency.  This assumes that the
  317.      * divide-by-16 bit is set in the Am85C30 WR4 register (done
  318.      * in tyCoInitChannel).
  319.      */
  320.     baudConstant = ((pTyCoDv->baudFreq / 32) / arg) - 2;
  321.     cr = pTyCoDv->cr;
  322.     /* disable interrupts during chip access */
  323.     oldlevel = intLock ();
  324.     *cr = SCC_WR0_SEL_WR12; /* LSB of baud constant */
  325.     SCC_DELAY;
  326.     *cr = (char)baudConstant; /* write LSB */
  327.     SCC_DELAY;
  328.     *cr = SCC_WR0_SEL_WR13; /* MSB of baud constant */
  329.     SCC_DELAY;
  330.     *cr = (char)(baudConstant >> 8); /* write MSB */
  331.     SCC_DELAY;
  332.     intUnlock (oldlevel);
  333.     status = OK;
  334.     break;
  335. default:
  336.     status = tyIoctl (&pTyCoDv->tyDev, request, arg);
  337.     break;
  338. }
  339.     return (status);
  340.     }
  341. /*******************************************************************************
  342. *
  343. * tyCoIntWr - interrupt level processing
  344. *
  345. * This routine handles write interrupts from the SCC.
  346. *
  347. * RETURNS: N/A
  348. *
  349. * NOMANUAL
  350. */
  351. void tyCoIntWr
  352.     (
  353.     int channel /* interrupting serial channel */
  354.     )
  355.     {
  356.     char outChar;
  357.     TY_CO_DEV * pTyCoDv = &tyCoDv [channel];
  358.     volatile char * cr = pTyCoDv->cr;
  359.     if (pTyCoDv->created && tyITx (&pTyCoDv->tyDev, &outChar) == OK)
  360. {
  361. *pTyCoDv->dr = outChar;
  362. }
  363.     else
  364. {
  365. /* no more chars to xmit now.  reset the tx int,
  366.  * so the SCC does not keep interrupting.
  367.  */
  368. *cr = SCC_WR0_RST_TX_INT;
  369. SCC_DELAY;
  370. }
  371.     *cr = SCC_WR0_RST_HI_IUS; /* end the interrupt acknowledge */
  372.     SCC_DELAY;
  373.     }
  374. /*****************************************************************************
  375. *
  376. * tyCoIntRd - interrupt level input processing
  377. *
  378. * This routine handles read interrupts from the SCC
  379. *
  380. * RETURNS: N/A
  381. *
  382. * NOMANUAL
  383. */
  384. void tyCoIntRd
  385.     (
  386.     int channel /* interrupting serial channel */
  387.     )
  388.     {
  389.     TY_CO_DEV * pTyCoDv = &tyCoDv [channel];
  390.     volatile char * cr = pTyCoDv->cr;
  391.     char inchar;
  392.     inchar = *pTyCoDv->dr;
  393.     if (pTyCoDv->created)
  394. tyIRd (&pTyCoDv->tyDev, inchar);
  395.     *cr = SCC_WR0_RST_HI_IUS; /* reset the interrupt in the Am85C30 */
  396.     SCC_DELAY;
  397.     }
  398. /**********************************************************************
  399. *
  400. * tyCoIntEx - miscellaneous interrupt processing
  401. *
  402. * This routine handles miscellaneous interrupts on the SCC
  403. *
  404. * RETURNS: N/A
  405. *
  406. * NOMANUAL
  407. */
  408. void tyCoIntEx
  409.     (
  410.     int channel /* interrupting serial channel */
  411.     )
  412.     {
  413.     TY_CO_DEV * pTyCoDv = &tyCoDv [channel];
  414.     volatile char * cr = pTyCoDv->cr;
  415.     *cr = SCC_WR0_ERR_RST; /* reset errors */
  416.     SCC_DELAY;
  417.     *cr = SCC_WR0_RST_HI_IUS; /* reset the interrupt in the Am85C30 */
  418.     SCC_DELAY;
  419.     }
  420. /********************************************************************************
  421. * tyCoInt - interrupt level processing
  422. *
  423. * This routine handles interrupts from both of the SCCs.
  424. * We determine from the parameter which SCC interrupted, then look at
  425. * the code to find out which channel and what kind of interrupt.
  426. *
  427. * NOMANUAL
  428. */
  429. void tyCoInt
  430.     (
  431.     int sccNum
  432.     )
  433.     {
  434.     volatile char * cr;
  435.     char intStatus;
  436.     TY_CO_DEV * pTyCoDv;
  437.     char outChar;
  438.     /* We need to find out which channel interrupted.  We need to read
  439.      * the B channel of the interrupting SCC to find out which channel
  440.      * really interrupted.  Note that things are set up so that the A
  441.      * channel is channel 0, even though on the chip it is the one with
  442.      * the higher address
  443.      */  
  444.     pTyCoDv = &tyCoDv [(sccNum * 2) + 1];
  445.     cr = pTyCoDv->cr;
  446.     SCC_DELAY;
  447.     *cr = SCC_WR0_SEL_WR2;                      /* read reg 2 */
  448.     SCC_DELAY;
  449.     intStatus = *cr;
  450.     if ((intStatus & 0x08) != 0)
  451.         {                               /* the A channel interrupted */
  452.         --pTyCoDv;
  453.         cr = pTyCoDv->cr;
  454.         }
  455.     switch (intStatus & 0x06)
  456.         {
  457.         case 0x04:                      /* RxChar Avail */
  458.             if (pTyCoDv->created)
  459.                 tyIRd (&pTyCoDv->tyDev, *pTyCoDv->dr);
  460.             SCC_DELAY;
  461.             break;
  462.  
  463.         case 0x00:                      /* Tx Buffer Empty */
  464.             if (pTyCoDv->created && (tyITx (&pTyCoDv->tyDev, &outChar) == OK))
  465.                 *pTyCoDv->dr = outChar;
  466.             else
  467.                 {
  468.                 /* no more chars to xmit now.  reset the tx int,
  469.                  * so the SCC doesn't keep interrupting us.
  470.  */
  471.  
  472.                 *cr = SCC_WR0_RST_TX_INT;
  473.                 }
  474.             SCC_DELAY;
  475.             break;
  476.  
  477.         case 0x02:                      /* External Status Change */
  478.             *cr = SCC_WR0_ERR_RST;
  479.             SCC_DELAY;
  480.             outChar = *pTyCoDv->dr;          /* throw away char */
  481.             break;
  482.  
  483.         case 0x06:                      /* Special receive condition */
  484.             *cr = SCC_WR0_ERR_RST;
  485.             SCC_DELAY;
  486.             break;                      /* ignore */
  487.  
  488.         }
  489.  
  490.     *cr = SCC_WR0_RST_HI_IUS;   /* Reset the Highest interrupt in the AM85C30 */
  491.     SCC_DELAY;
  492.     }
  493. /*******************************************************************************
  494. *
  495. * tyCoStartup - transmitter startup routine
  496. *
  497. * Call interrupt level character output routine.
  498. */
  499. LOCAL void tyCoStartup
  500.     (
  501.     TY_CO_DEV * pTyCoDv  /* ty device to start up */
  502.     )
  503.     {
  504.     char outChar;
  505.     if (tyITx (&pTyCoDv->tyDev, &outChar) == OK)
  506. *pTyCoDv->dr = outChar;
  507.     }