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

VxWorks

开发平台:

C/C++

  1. /* i8250Serial.c - I8250 tty driver */
  2. /* Copyright 1984-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01p,18nov96,db  put missing brackets in if-else statement(SPR #7411).
  8. 01m,25jan95,vin  removed magic numbers, replaced with macros.
  9. 01n,15aug95,hdn  added support for i386ex, and cleanup.
  10. 01m,14jun95,hdn  removed function declarations defined in sysLib.h.
  11. 01l,06jun94,hdn  doc cleanup for 5.1.1 FCS.
  12. 01k,22apr94,hdn  add a support for 38400.
  13.  changed a description mentioned PC_KBD_TYPE.
  14. 01j,30mar94,hdn  changed PC_CONSOLE tty number from 0,1 to 2,3.
  15. 01i,17feb94,hdn  moved TY_CO_DEV structure from sysLib.c.
  16. 01h,20oct93,vin  included support for keyboard and vga drivers
  17. 01g,12oct93,hdn  added sysIntEnablePIC(), sysIntDisablePIC().
  18. 01f,16jun93,hdn  renamed to i8250Serial.c.
  19. 01e,21apr93,hdn  fixed a bug in tyCoInt.
  20. 01d,09apr93,jdi  doc cleanup.
  21. 01c,07apr93,hdn  renamed compaq to pc.
  22. 01b,19oct92,hdn  supported nested interrupt.
  23. 01a,15may92,hdn  written based on frc386 version.
  24. */
  25. /*
  26. DESCRIPTION
  27. This is the driver for the Intel 8250 UART Chip used on the PC 386.
  28. If the macro INCLUDE_PC_CONSOLE is defined then this driver also
  29. initializes the keyboard and VGA console devices on the PC.
  30. If INCLUDE_PC_CONSOLE is defined then the keyboard and VGA consoles
  31. are created first. Depending on the definition of PC_KBD_TYPE in config.h
  32. the corresponding keyboard driver is included.
  33. USER-CALLABLE ROUTINES
  34. Most of the routines in this driver are accessible only through the I/O
  35. system.  Two routines, however, must be called directly:  tyCoDrv() to
  36. initialize the driver, and tyCoDevCreate() to create devices.
  37. Before the driver can be used, it must be initialized by calling tyCoDrv().
  38. This routine should be called exactly once, before any reads, writes, or
  39. calls to tyCoDevCreate().  Normally, it is called from usrRoot() in
  40. usrConfig.c.
  41. Before a terminal can be used, it must be created, using tyCoDevCreate().
  42. Each port to be used should have exactly one device associated with it
  43. by calling this routine.
  44. IOCTL FUNCTIONS
  45. This driver responds to all the same ioctl() codes as a normal tty driver;
  46. for more information, see the manual entry for tyLib.  As initialized, the
  47. available baud rates are 110, 300, 600, 1200, 2400, 4800, 9600, 19200, and
  48. 38400.
  49. SEE ALSO: tyLib
  50. */
  51. #include "vxWorks.h"
  52. #include "iv.h"
  53. #include "ioLib.h"
  54. #include "iosLib.h"
  55. #include "tyLib.h"
  56. #include "intLib.h"
  57. #include "errnoLib.h"
  58. #include "sysLib.h"
  59. #include "config.h"
  60. /* globals */
  61. TY_CO_DEV tyCoDv [N_UART_CHANNELS] =
  62.     {
  63.     {{{{NULL}}}, FALSE,
  64.      UART_LCR(COM1_BASE_ADR),
  65.      UART_LST(COM1_BASE_ADR),
  66.      UART_MDC(COM1_BASE_ADR),
  67.      UART_MSR(COM1_BASE_ADR),
  68.      UART_IER(COM1_BASE_ADR),
  69.      UART_IID(COM1_BASE_ADR),
  70.      UART_BRDL(COM1_BASE_ADR),
  71.      UART_BRDH(COM1_BASE_ADR),
  72.      UART_RDR(COM1_BASE_ADR)},
  73.     {{{{NULL}}}, FALSE,
  74.      UART_LCR(COM2_BASE_ADR),
  75.      UART_LST(COM2_BASE_ADR),
  76.      UART_MDC(COM2_BASE_ADR),
  77.      UART_MSR(COM2_BASE_ADR),
  78.      UART_IER(COM2_BASE_ADR),
  79.      UART_IID(COM2_BASE_ADR),
  80.      UART_BRDL(COM2_BASE_ADR),
  81.      UART_BRDH(COM2_BASE_ADR),
  82.      UART_RDR(COM2_BASE_ADR)},
  83.     };
  84. /* locals */
  85. /* baudTable is a table of the available baud rates, and the values to write
  86.  * to the UART's baud rate divisor {high, low} register. the formula is
  87.  * 1843200(source) / (16 * baudrate)
  88.  */
  89. LOCAL BAUD baudTable [] =
  90.     {
  91.     {50, 2304}, {75, 1536}, {110, 1047}, {134, 857}, {150, 768},
  92.     {300, 384}, {600, 192}, {1200, 96}, {2000, 58}, {2400, 48},
  93.     {3600,32}, {4800, 24}, {7200,16}, {9600, 12}, {19200, 6}, {38400, 3} 
  94.     };
  95. LOCAL int tyCoDrvNum; /* driver number assigned to this driver */
  96. /* forward declarations */
  97. LOCAL void tyCoStartup (TY_CO_DEV *pTyCoDv);
  98. LOCAL int tyCoOpen (TY_CO_DEV *pTyCoDv, char *name, int mode);
  99. LOCAL STATUS tyCoIoctl (TY_CO_DEV *pTyCoDv, int request, int arg);
  100. LOCAL void tyCoHrdInit (void);
  101. #ifdef INCLUDE_PC_CONSOLE /* if key board and VGA console needed */
  102. #include "serial/pcConsole.c"
  103. #include "serial/m6845Vga.c"
  104. #if (PC_KBD_TYPE == PC_PS2_101_KBD) /* 101 KEY PS/2                 */
  105. #include "serial/i8042Kbd.c"
  106. #else
  107. #include "serial/i8048Kbd.c" /* 83 KEY PC/PCXT/PORTABLE      */
  108. #endif /* (PC_KBD_TYPE == PC_XT_83_KBD) */
  109. #endif /* INCLUDE_PC_CONSOLE */
  110. /*******************************************************************************
  111. *
  112. * tyCoDrv - initialize the tty driver
  113. *
  114. * This routine initializes the serial driver, sets up interrupt vectors,
  115. * and performs hardware initialization of the serial ports.
  116. *
  117. * This routine should be called exactly once, before any reads, writes,
  118. * or calls to tyCoDevCreate().  Normally, it is called by usrRoot()
  119. * in usrConfig.c.
  120. *
  121. * RETURNS: OK or ERROR if the driver cannot be installed.
  122. *
  123. * SEE ALSO: tyCoDevCreate()
  124. */
  125. STATUS tyCoDrv (void)
  126.     {
  127.     /* check if driver already installed */
  128. #ifdef INCLUDE_PC_CONSOLE
  129.     if (pcConDrv () == ERROR)
  130.        return (ERROR);
  131. #endif 
  132.     if (tyCoDrvNum > 0)
  133. return (OK);
  134.     tyCoHrdInit ();
  135.     tyCoDrvNum = iosDrvInstall (tyCoOpen, (FUNCPTR) NULL, tyCoOpen,
  136. (FUNCPTR) NULL, tyRead, tyWrite, tyCoIoctl);
  137.     return (tyCoDrvNum == ERROR ? ERROR : OK);
  138.     }
  139. /*******************************************************************************
  140. *
  141. * tyCoDevCreate - create a device for an on-board serial port
  142. *
  143. * This routine creates a device for a specified serial port.  Each port
  144. * to be used should have exactly one device associated with it by calling
  145. * this routine.
  146. *
  147. * For instance, to create the device "/tyCo/0", with buffer sizes of 512
  148. * bytes, the proper call would be:
  149. * .CS
  150. *     tyCoDevCreate ("/tyCo/0", 0, 512, 512);
  151. * .CE
  152. *
  153. * RETURNS: OK, or ERROR if the driver is not installed, the channel is
  154. * invalid, or the device already exists.
  155. *
  156. * SEE ALSO: tyCoDrv()
  157. */
  158. STATUS tyCoDevCreate
  159.     (
  160.     char *name, /* name to use for this device */
  161.     FAST int channel, /* physical channel for this device (0 only) */
  162.     int rdBufSize, /* read buffer size, in bytes */
  163.     int wrtBufSize /* write buffer size, in bytes */
  164.     )
  165.     {
  166.     TY_CO_DEV *pTyCoDv = &tyCoDv[channel];
  167.     if (channel >= N_UART_CHANNELS)
  168. {
  169. #ifdef INCLUDE_PC_CONSOLE
  170.         channel -= N_UART_CHANNELS;
  171.         if (channel < N_VIRTUAL_CONSOLES)
  172.     return (pcConDevCreate (name, channel, rdBufSize, wrtBufSize));
  173. #endif /* INCLUDE_PC_CONSOLE */
  174. return (ERROR);
  175. }
  176.     if (tyCoDrvNum <= 0)
  177. {
  178. errnoSet (S_ioLib_NO_DRIVER);
  179. return (ERROR);
  180. }
  181.     /* if this device already exists, don't create it */
  182.     if (pTyCoDv->created)
  183. return (ERROR);
  184.     if (tyDevInit (&pTyCoDv->tyDev, rdBufSize, wrtBufSize, 
  185. (FUNCPTR)tyCoStartup) != OK)
  186. {
  187. return (ERROR);
  188. }
  189. #ifndef TY_CO_POLL
  190.     /* enable the receiver and receiver error */
  191.     sysOutByte (pTyCoDv->ier, 0x01);
  192.     if (channel == 0)
  193. {
  194. sysOutByte (UART_IER (COM1_BASE_ADR), I8250_IER_RDI_ENBL);
  195. sysIntEnablePIC (COM1_INT_LVL);
  196. }
  197.     else
  198. {
  199. sysOutByte (UART_IER (COM2_BASE_ADR), I8250_IER_RDI_ENBL);
  200. sysIntEnablePIC (COM2_INT_LVL);
  201. }
  202. #endif /* TY_CO_POLL XXX */
  203.     /* mark the device as created, and add the device to the I/O system */
  204.     pTyCoDv->created = TRUE;
  205.     return (iosDevAdd (&pTyCoDv->tyDev.devHdr, name, tyCoDrvNum));
  206.     }
  207. /*******************************************************************************
  208. *
  209. * tyCoHrdInit - initialize the UART
  210. */
  211. LOCAL void tyCoHrdInit (void)
  212.     {
  213.     int oldLevel = intLock ();
  214.     TY_CO_DEV *pTyCoDv;
  215.     int ix;
  216.     for (ix = 0; ix < N_UART_CHANNELS; ix++)
  217. {
  218. pTyCoDv = &tyCoDv[ix];
  219. /* initialization 9600 baud */
  220. sysOutByte (pTyCoDv->ier,  0x00);
  221. sysOutByte (pTyCoDv->mdc,  0x00);
  222. sysInByte  (pTyCoDv->iid);
  223. sysInByte  (pTyCoDv->lst);
  224. sysInByte  (pTyCoDv->msr);
  225. sysOutByte (pTyCoDv->lcr,  0x80);
  226. sysOutByte (pTyCoDv->brdl, 0x0c);
  227. sysOutByte (pTyCoDv->brdh, 0x00);
  228. /* 8 data bits, 1 stop bit, no parity */
  229. sysOutByte (pTyCoDv->lcr, 0x03);
  230. /* enable the receiver and transmitter */
  231. sysOutByte (pTyCoDv->mdc, 0x0b);
  232. }
  233.     sysOutByte (UART_LCR (COM1_BASE_ADR),(I8250_LCR_WRD8 | I8250_LCR_DLAB));
  234.     sysOutByte (UART_BRDL (COM1_BASE_ADR), BAUD_9600_LSB);
  235.     sysOutByte (UART_BRDH (COM1_BASE_ADR), BAUD_9600_MSB);
  236.     sysOutByte (UART_LCR (COM1_BASE_ADR), (I8250_LCR_WRD8 | I8250_LCR_SB1));
  237.     sysOutByte (UART_MDC (COM1_BASE_ADR), (I8250_MCR_OUT2 | 
  238.    I8250_MCR_RTS  | 
  239.    I8250_MCR_DTR));
  240.     sysOutByte (UART_LCR (COM2_BASE_ADR), (I8250_LCR_WRD8 | I8250_LCR_DLAB));
  241.     sysOutByte (UART_BRDL (COM2_BASE_ADR), BAUD_9600_LSB);
  242.     sysOutByte (UART_BRDH (COM2_BASE_ADR), BAUD_9600_MSB);
  243.     sysOutByte (UART_LCR (COM2_BASE_ADR), (I8250_LCR_WRD8 | I8250_LCR_SB1));
  244.     sysOutByte (UART_MDC (COM2_BASE_ADR), (I8250_MCR_OUT2 |
  245.    I8250_MCR_RTS  | 
  246.    I8250_MCR_DTR));
  247.     /* all interrupts are masked out: the receiver interrupt will be enabled
  248.      * in the tyCoDevCreate 
  249.      */
  250.     intUnlock (oldLevel);
  251.     } 
  252. /*******************************************************************************
  253. *
  254. * tyCoOpen - open file to UART
  255. *
  256. * ARGSUSED1
  257. */
  258. LOCAL int tyCoOpen
  259.     (
  260.     TY_CO_DEV *pTyCoDv,
  261.     char *name,
  262.     int mode
  263.     )
  264.     {
  265.     return ((int) pTyCoDv);
  266.     }
  267. /*******************************************************************************
  268. *
  269. * tyCoIoctl - special device control
  270. *
  271. * This routine handles FIOBAUDRATE requests and passes all others to tyIoctl.
  272. *
  273. * RETURNS: OK or ERROR if invalid baud rate, or whatever tyIoctl returns.
  274. */
  275. LOCAL STATUS tyCoIoctl
  276.     (
  277.     TY_CO_DEV *pTyCoDv, /* device to control */
  278.     int request, /* request code */
  279.     int arg /* some argument */
  280.     )
  281.     {
  282.     int ix;
  283.     int status;
  284.     switch (request)
  285. {
  286. case FIOBAUDRATE:
  287.     status = ERROR;
  288.     for (ix = 0; ix < NELEMENTS (baudTable); ix++)
  289. {
  290. if (baudTable [ix].rate == arg) /* lookup baud rate value */
  291.     {
  292.          sysOutByte (pTyCoDv->lcr,I8250_LCR_DLAB | I8250_LCR_WRD8);
  293.          sysOutByte (pTyCoDv->lcr, 0x80);
  294.          sysOutByte (pTyCoDv->brdh, MSB (baudTable[ix].preset));
  295.          sysOutByte (pTyCoDv->brdl, LSB (baudTable[ix].preset));
  296.          sysOutByte (pTyCoDv->lcr, I8250_LCR_WRD8);
  297.     status = OK;
  298.     break;
  299.     }
  300. }
  301.     break;
  302. default:
  303.     status = tyIoctl (&pTyCoDv->tyDev, request, arg);
  304.     break;
  305. }
  306.     return (status);
  307.     }
  308. /*******************************************************************************
  309. *
  310. * tyCoInt - handle a receiver/transmitter interrupt
  311. *
  312. * This routine gets called to handle interrupts.
  313. * If there is another character to be transmitted, it sends it.  If
  314. * not, or if a device has never been created for this channel, just
  315. * disable the interrupt.
  316. */
  317. void tyCoInt
  318.     (
  319.     TY_CO_DEV *pTyCoDv
  320.     )
  321.     {
  322.     char outChar;
  323.     char interruptID;
  324.     char lineStatus;
  325.     int ix = 0;
  326.     interruptID = sysInByte (pTyCoDv->iid);
  327.     do {
  328. interruptID &= I8250_IIR_RLS;
  329.         if (interruptID == I8250_IIR_RLS)
  330.             lineStatus = sysInByte (pTyCoDv->lst);
  331.         else if (interruptID == I8250_IIR_RD)
  332.     {
  333.             if (pTyCoDv->created)
  334.         tyIRd (&pTyCoDv->tyDev, sysInByte (pTyCoDv->data));
  335.     else
  336.         sysInByte (pTyCoDv->data);
  337.     }
  338.         else if (interruptID == I8250_IIR_THR)
  339.     {
  340.             if ((pTyCoDv->created && tyITx (&pTyCoDv->tyDev, &outChar)) == OK)
  341.         sysOutByte (pTyCoDv->data, outChar);
  342.             else
  343.         sysOutByte (pTyCoDv->ier, I8250_IER_RDI_ENBL);
  344.     }
  345.         interruptID = sysInByte (pTyCoDv->iid);
  346. } while (((interruptID & I8250_IIR_PIMASK) == I8250_IIR_PI) && 
  347.  (ix++ < 10));
  348.     }
  349. /*******************************************************************************
  350. *
  351. * tyCoStartup - transmitter startup routine
  352. *
  353. * Call interrupt level character output routine.
  354. */
  355. LOCAL void tyCoStartup
  356.     (
  357.     TY_CO_DEV *pTyCoDv /* tty device to start up */
  358.     )
  359.     {
  360.     char  outChar;
  361.     char  lsrReg;
  362.     static int  charCount = 0;
  363.     /* enable the transmitter and it should interrupt to write the next char */
  364.     if (tyITx (&pTyCoDv->tyDev, &outChar) == OK)
  365. sysOutByte (pTyCoDv->data, outChar);
  366.     sysOutByte (pTyCoDv->ier, (I8250_IER_THR_ENBL | I8250_IER_RDI_ENBL));
  367.     }