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

VxWorks

开发平台:

C/C++

  1. /* ns16550Serial.c - NS 16550 UART tty driver */
  2. /* Copyright 1994-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01d,19nov96,dat  fixed SPR 5381, args to tyCoInitUart(), coding stds.
  8. 01c,22aug95,kkk  undo 01b changes
  9.             kvk  fixed a serial bug which hangs the board on fast serial input.
  10. 01,07aug95,kkk  fix warnings for I960 (spr#4177)
  11. 01a,27jun94,snc  written.
  12. */
  13. /*
  14. DESCRIPTION
  15. This is the device driver for the ns16550 UART.  Enjoy!
  16. USER-CALLABLE_ROUTINES
  17. Most of the routines in this driver are accessible only through the I/O
  18. system.  Two routines, however, must be called directly:  tyCoDrv() to
  19. initialize the driver, and tyCoDevCreate() to create logical devices.
  20. Before the driver can be used, it must be initialized by calling tyCoDrv().
  21. This routine should be called exactly once, before any reads, writes, or
  22. calls to tyCoDevCreate().  Normally, it is called by usrRoot() in usrConfig.c.
  23. Before a terminal can be used, it must be created using tyCoDevCreate().
  24. Each port to be used should have exactly one device associated with it by
  25. calling this routine.
  26. IOCTL FUNCTIONS
  27. This driver responds to the same ioctl() codes as a normal tty driver; for
  28. more information, see the manual entry for tyLib.  Available baud rates
  29. range from 50 to 38400.
  30. SEE ALSO
  31. tyLib
  32. */
  33. #include "vxWorks.h"
  34. #include "iv.h"
  35. #include "ioLib.h"
  36. #include "iosLib.h"
  37. #include "tyLib.h"
  38. #include "intLib.h"
  39. #include "errnoLib.h"
  40. #include "drv/serial/ns16552.h"
  41. #define DEFAULT_BAUD 9600
  42. IMPORT TY_CO_DEV tyCoDv []; /* device descriptors */
  43. LOCAL int tyCoDrvNum; /* driver number assigned to this driver */
  44. /* function prototypes */
  45. LOCAL void tyCoStartup ();
  46. LOCAL int tyCoOpen ();
  47. LOCAL STATUS tyCoIoctl ();
  48. LOCAL void tyCoInitUart ();
  49. #define UART_DELTA          4           /* register address boundaries */
  50. #define XTAL                1843200
  51. /******************************************************************************
  52. *
  53. * InReg - reads a register from the 16550 UART
  54. *
  55. * Note: UART_DELTA must be defined to be the number of bytes between
  56. * adjacent UART registers
  57. */
  58. UINT8 InReg
  59.     (
  60.     int reg,
  61.     UINT8 *base_addr /* Base address of UART device */
  62.     )
  63.     {
  64.     UINT8 val;
  65.     val = *(UINT8 *)((UINT32)base_addr + (reg*UART_DELTA));
  66.     return val;
  67.     }
  68. /******************************************************************************
  69. *
  70. * OutReg - reads a register from the 16550 UART
  71. *
  72. * Note: UART_DELTA must be defined to be the number of bytes between
  73. * adjacent UART registers
  74. */
  75. void OutReg
  76.     (
  77.     int reg,
  78.     UINT8 val,
  79.     UINT8 *base_addr /* Base address of UART device */
  80.     )
  81.     {
  82.     *(UINT8 *)((UINT32)base_addr + (reg*UART_DELTA)) = val;
  83.     }
  84. /*******************************************************************************
  85. *
  86. * tyCoDrv - initialize the tty driver
  87. *
  88. * This routine initializes the serial driver, sets up interrupt vectors, and
  89. * performs hardware initialization of the serial ports.
  90. *
  91. * This routine should be called exactly once, before any reads, writes, or
  92. * calls to tyCoDevCreate().  Normally, it is called by usrRoot() in
  93. * usrConfig.c.
  94. *
  95. * RETURNS:  OK, or ERROR if the driver cannot be installed.
  96. *
  97. * SEE ALSO:  tyCoDevCreate()
  98. */
  99. STATUS tyCoDrv (void)
  100.     {
  101.     /* check if driver already installed */
  102.     if (tyCoDrvNum > 0)
  103. return (OK);
  104.     tyCoDrvNum = iosDrvInstall (tyCoOpen, (FUNCPTR) NULL, tyCoOpen,
  105. (FUNCPTR) NULL, tyRead, tyWrite, tyCoIoctl);
  106.     return (tyCoDrvNum == ERROR ? ERROR : OK);
  107.     }
  108. /*******************************************************************************
  109. *
  110. * tyCoDevCreate - create a device for an on-board serial port
  111. *
  112. * This routine creates a device on a specified serial port.  Each port
  113. * to be used should have exactly one device associated with it by calling
  114. * this routine.
  115. *
  116. * For instance, to create the device "/tyCo/0", with buffer sizes of 512 bytes,
  117. * the proper call would be:
  118. * .CS
  119. * tyCoDevCreate ("/tyCo/0", 512, 512);
  120. * .CE
  121. *
  122. * RETURNS:  OK, or ERROR if the driver is not installed,
  123. * or the device already exists.
  124. *
  125. * SEE ALSO: tyCoDrv()
  126. */
  127. STATUS tyCoDevCreate
  128.     (
  129.     char * name, /* name to use for this device     */
  130.     FAST int channel, /* physical channel for this device */
  131.     int rdBufSize, /* read buffer size, in bytes     */
  132.     int wrtBufSize /* write buffer size, in bytes     */
  133.     )
  134.     {
  135.     FAST TY_CO_DEV *pTyCoDv;
  136.     if (tyCoDrvNum <= 0)
  137. {
  138. errnoSet (S_ioLib_NO_DRIVER);
  139. return (ERROR);
  140. }
  141.     pTyCoDv = &tyCoDv[channel];
  142.     /* If there is a device already, don't create one */
  143.     if (pTyCoDv->created)
  144. return (ERROR);
  145.     /* Initialize the ty descriptor */
  146.     if (tyDevInit (&pTyCoDv->tyDev, rdBufSize, wrtBufSize,
  147. (FUNCPTR) tyCoStartup) != OK)
  148. {
  149. return (ERROR);
  150. }
  151.     /* Initialize the hardware */
  152.     tyCoInitUart (channel);
  153.     /* Mark the device as created, and add the device to the I/O system */
  154.     pTyCoDv->created = TRUE;
  155.     return (iosDevAdd (&pTyCoDv->tyDev.devHdr, name, tyCoDrvNum));
  156.     }
  157. /*******************************************************************************
  158. *
  159. * tyCoInitUart - initialize UART
  160. *
  161. * Reconfigure the UART; 8 data bits, 1 stop bit, no parity.
  162. */
  163. LOCAL void tyCoInitUart
  164.     (
  165.     int channel
  166.     )
  167.     {
  168.     FAST TY_CO_DEV *pTyCoDv;
  169.     FAST int        oldlevel; /* current interrupt level mask */
  170.     pTyCoDv = &tyCoDv[channel];
  171.     oldlevel = intLock (); /* disable interrupts during init */
  172.     /* Configure Port -  Set 8 bits, 1 stop bit, no parity. */
  173.     pTyCoDv->lcr = (UINT8)(CHAR_LEN_8 | ONE_STOP | PARITY_NONE);
  174.     OutReg(LCR, pTyCoDv->lcr, pTyCoDv->regs);
  175.     /* Reset/Enable the FIFOs */
  176.     OutReg(FCR, RxCLEAR | TxCLEAR, pTyCoDv->regs);
  177.  
  178.     /* Enable access to the divisor latches by setting DLAB in LCR. */
  179.     OutReg(LCR, LCR_DLAB | pTyCoDv->lcr, pTyCoDv->regs);
  180.     /* Set divisor latches. */
  181.     OutReg(DLL, XTAL/(16*DEFAULT_BAUD), pTyCoDv->regs);
  182.     OutReg(DLM, (XTAL/(16*DEFAULT_BAUD)) >> 8, pTyCoDv->regs);
  183.     /* Restore line control register */
  184.     OutReg(LCR, pTyCoDv->lcr, pTyCoDv->regs);
  185.     /* Make a copy since register is not readable */
  186.     pTyCoDv->ier = (UINT8)(RxFIFO_BIT | TxFIFO_BIT); 
  187.     /* Enable appropriate interrupts */
  188.     OutReg(IER, pTyCoDv->ier, pTyCoDv->regs);
  189.     intUnlock (oldlevel);
  190.     }
  191. /*******************************************************************************
  192. *
  193. * tyCoOpen - open file to UART
  194. *
  195. * RETURNS: Ptr to device structure.
  196. */
  197. LOCAL int tyCoOpen
  198.     (
  199.     TY_CO_DEV *pTyCoDv,
  200.     char      *name,
  201.     int        mode
  202.     )
  203.     {
  204.     return ((int) pTyCoDv);
  205.     }
  206. /*******************************************************************************
  207. *
  208. * tyCoIoctl - special device control
  209. *
  210. * This routine handles FIOBAUDRATE requests and passes all others to tyIoctl().
  211. *
  212. * RETURNS: OK, or ERROR if invalid baud rate, or whatever tyIoctl() returns.
  213. */
  214. LOCAL STATUS tyCoIoctl
  215.     (
  216.     TY_CO_DEV *pTyCoDv, /* device to control */
  217.     int        request, /* request code */
  218.     int        arg /* some argument */
  219.     )
  220.     {
  221.     FAST int     oldlevel; /* current interrupt level mask */
  222.     FAST STATUS  status;
  223.     status = 0;
  224.     switch (request)
  225. {
  226. case FIOBAUDRATE:
  227.     if (arg < 50 || arg > 38400)
  228.         {
  229. status = ERROR; /* baud rate out of range */
  230. break;
  231.         }
  232.     /* disable interrupts during chip access */
  233.     oldlevel = intLock ();
  234.          /* Enable access to the divisor latches by setting DLAB in LCR. */
  235.          OutReg(LCR, LCR_DLAB | pTyCoDv->lcr, pTyCoDv->regs);
  236.  
  237.          /* Set divisor latches. */
  238.          OutReg(DLL, XTAL/(16*arg), pTyCoDv->regs);
  239.          OutReg(DLM, (XTAL/(16*arg)) >> 8, pTyCoDv->regs);
  240.  
  241.          /* Restore line control register */
  242.          OutReg(LCR, pTyCoDv->lcr, pTyCoDv->regs);
  243.  
  244.     intUnlock (oldlevel);
  245.     status = OK;
  246.     break;
  247. default:
  248.     status = tyIoctl (&pTyCoDv->tyDev, request, arg);
  249.     break;
  250. }
  251.     return (status);
  252.     }
  253. /*******************************************************************************
  254. *
  255. * tyCoIntWr - interrupt level processing
  256. *
  257. * This routine handles write interrupts from the UART.
  258. *
  259. * RETURNS: N/A
  260. *
  261. * NOMANUAL
  262. */
  263. void tyCoIntWr (int channel)
  264.     {
  265.     char            outChar;
  266.     FAST TY_CO_DEV *pTyCoDv = &tyCoDv[channel];
  267.     if (pTyCoDv->created && (tyITx (&pTyCoDv->tyDev, &outChar) == OK))
  268. {
  269. /* write char. to Transmit Holding Reg. */
  270. OutReg(THR, outChar, pTyCoDv->regs);
  271. }
  272.     }
  273. /*****************************************************************************
  274. *
  275. * tyCoIntRd - interrupt level input processing
  276. *
  277. * This routine handles read interrupts from the UART
  278. *
  279. * RETURNS: N/A
  280. *
  281. * NOMANUAL
  282. */
  283. void tyCoIntRd (int channel)
  284.     {
  285.     FAST TY_CO_DEV *pTyCoDv = &tyCoDv[channel];
  286.     char            inchar;
  287.     /* read character from Receive Holding Reg. */
  288.     inchar = InReg(RBR, pTyCoDv->regs);
  289.     if (pTyCoDv->created)
  290. tyIRd (&pTyCoDv->tyDev, inchar);
  291.     }
  292. /**********************************************************************
  293. *
  294. * tyCoIntEx - miscellaneous interrupt processing
  295. *
  296. * This routine handles miscellaneous interrupts on the UART
  297. *
  298. * RETURNS: N/A
  299. *
  300. * NOMANUAL
  301. */
  302. void tyCoIntEx (int channel)
  303.     {
  304.     FAST TY_CO_DEV *pTyCoDv;
  305.     pTyCoDv = &tyCoDv[channel];
  306.     /* Nothing for now... */
  307.     }
  308. /********************************************************************************
  309. * tyCoInt - interrupt level processing
  310. *
  311. * This routine handles interrupts from the UART.
  312. *
  313. * NOMANUAL
  314. */
  315. void tyCoInt
  316.     (
  317.     int channel /* unused parameter */
  318.     )
  319.     {
  320.     FAST char        intStatus;
  321.     FAST TY_CO_DEV  *pTyCoDv;
  322.     pTyCoDv = &tyCoDv[channel];
  323.     /* read the Interrrupt Status Register (Int. Ident.) */
  324.     intStatus = InReg(IIR, pTyCoDv->regs);
  325.     switch (intStatus & 0x0f)
  326.         {
  327. case 0x00: /* Modem Status Reg. */
  328.     tyCoIntEx(channel);
  329.     break;
  330. case 0x01: /* No Interrupt Pending */
  331.     break;
  332.         case 0x02:                      /* Tx Holding Reg. Empty */
  333.     tyCoIntWr(channel);
  334.             break;
  335.  
  336.         case 0x04:                      /* RxChar Avail */
  337.     tyCoIntRd(channel);
  338.             break;
  339.  
  340.         case 0x06:                      /* Rx. Line Status Change */
  341.     tyCoIntEx(channel);
  342.             break;
  343. case 0x0c: /* Receive Data Timeout */
  344.     tyCoIntEx(channel);
  345.     break;
  346.         }
  347.     }
  348. /*******************************************************************************
  349. *
  350. * tyCoStartup - transmitter startup routine
  351. *
  352. * Call interrupt level character output routine and enable interrupt!
  353. */
  354. LOCAL void tyCoStartup
  355.     (
  356.     TY_CO_DEV *pTyCoDv  /* ty device to start up */
  357.     )
  358.     {
  359.     char outChar;
  360.     if (tyITx (&pTyCoDv->tyDev, &outChar) == OK)
  361. {
  362. OutReg(THR,outChar, pTyCoDv->regs); /* transmit character */
  363. }
  364.     }