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

VxWorks

开发平台:

C/C++

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