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

VxWorks

开发平台:

C/C++

  1. /* lptDrv.c - parallel chip device driver for the IBM-PC LPT */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01m,01apr01,rcs  used LPT_DATA_RES, LPT_STAT_RES, and LPT_CTRL_RES macros
  7.                  exclusively and set the default spacing to 1 SPR# 65937
  8. 01l,23mar01,sru  register spacing now provided in LPT_RESOURCE SPR# 65937
  9. 01k,15mar01,dat  SPR 28847/65275, disable interrupt after each character
  10. 01j,21nov00,jkf  SPR#62266 T3 doc update
  11. 01i,26oct00,jkf  SPR 35546, removed unused IMPORT sysIntLevel().
  12. 01h,04jan00,dat  SPR 29875, using SEM_ID in structures.
  13. 01g,06oct98,jmp  doc: cleanup.
  14. 01f,03jun98,hdn  removed spurious interrupt handling from lptIntr().
  15. 01e,18oct96,hdn  re-written.
  16. 01d,14jun95,hdn  removed function declarations defined in sysLib.h.
  17. 01c,24jan95,jdi  doc cleanup.
  18. 01b,20nov94,kdl  fixed typo in man page.
  19. 01a,13oct94,hdn  written.
  20. */
  21. /*
  22. DESCRIPTION
  23. This is the basic driver for the LPT used on the IBM-PC.  If the 
  24. component INCLUDE_LPT is enabled, the driver initializes the LPT 
  25. port on the PC.
  26. USER-CALLABLE ROUTINES
  27. Most of the routines in this driver are accessible only through the I/O
  28. system.  However, two routines must be called directly:  lptDrv() to
  29. initialize the driver, and lptDevCreate() to create devices.
  30. There are one other callable routines:  lptShow() to show statistics.
  31. The argument to lptShow() is a channel number, 0 to 2.
  32. Before the driver can be used, it must be initialized by calling lptDrv().
  33. This routine should be called exactly once, before any reads, writes, or
  34. calls to lptDevCreate().  Normally, it is called from usrRoot() in
  35. usrConfig.c.  The first argument to lptDrv() is a number of channels,
  36. 0 to 2.  The second argument is a pointer to the resource table.
  37. Definitions of members of the resource table structure are:
  38. .CS
  39.     int  ioBase;         /@ IO base address @/
  40.     int  intVector;      /@ interrupt vector @/
  41.     int  intLevel;       /@ interrupt level @/
  42.     BOOL autofeed;       /@ TRUE if enable autofeed @/
  43.     int  busyWait;       /@ loop count for BUSY wait @/
  44.     int  strobeWait;     /@ loop count for STROBE wait @/
  45.     int  retryCnt;       /@ retry count @/
  46.     int  timeout;        /@ timeout second for syncSem @/
  47. .CE
  48. IOCTL FUNCTIONS
  49. This driver responds to two functions: LPT_SETCONTROL and LPT_GETSTATUS.
  50. The argument for LPT_SETCONTROL is a value of the control register.
  51. The argument for LPT_GETSTATUS is a integer pointer where a value of the
  52. status register is stored.
  53. SEE ALSO:
  54. .pG "I/O System"
  55. */
  56. #include "vxWorks.h"
  57. #include "taskLib.h"
  58. #include "blkIo.h"
  59. #include "ioLib.h"
  60. #include "iosLib.h"
  61. #include "memLib.h"
  62. #include "stdlib.h"
  63. #include "errnoLib.h"
  64. #include "stdio.h"
  65. #include "string.h"
  66. #include "intLib.h"
  67. #include "iv.h"
  68. #include "wdLib.h"
  69. #include "sysLib.h"
  70. #include "sys/fcntlcom.h"
  71. #include "drv/parallel/lptDrv.h"
  72. /* imports */
  73. IMPORT UINT sysStrayIntCount;
  74. /* globals */
  75. LPT_DEV lptDev [N_LPT_CHANNELS];
  76. /* locals */
  77. LOCAL int lptDrvNum; /* driver number assigned to this driver */
  78. /* forward declarations */
  79. LOCAL int lptOpen (LPT_DEV *pDev, char *name, int mode);
  80. LOCAL int lptRead (LPT_DEV *pDev, char *pBuf, int size);
  81. LOCAL int lptWrite (LPT_DEV *pDev, char *pBuf, int size);
  82. LOCAL STATUS lptIoctl (LPT_DEV *pDev, int function, int arg);
  83. LOCAL void lptIntr (LPT_DEV *pDev);
  84. LOCAL void lptInit (LPT_DEV *pDev);
  85. /*******************************************************************************
  86. *
  87. * lptDrv - initialize the LPT driver
  88. *
  89. * This routine initializes the LPT driver, sets up interrupt vectors,
  90. * and performs hardware initialization of the LPT ports.
  91. *
  92. * This routine should be called exactly once, before any reads, writes,
  93. * or calls to lptDevCreate().  Normally, it is called by usrRoot()
  94. * in usrConfig.c.
  95. *
  96. * RETURNS: OK, or ERROR if the driver cannot be installed.
  97. *
  98. * SEE ALSO: lptDevCreate()
  99. */
  100. STATUS lptDrv 
  101.     (
  102.     int channels, /* LPT channels */
  103.     LPT_RESOURCE *pResource /* LPT resources */
  104.     )
  105.     {
  106.     int ix;
  107.     LPT_DEV *pDev;
  108.     /* check if driver already installed */
  109.     if (lptDrvNum > 0)
  110. return (OK);
  111.     
  112.     if (channels > N_LPT_CHANNELS)
  113. return (ERROR);
  114.     for (ix=0; ix < channels; ix++, pResource++)
  115. {
  116. pDev = &lptDev[ix];
  117. pDev->created = FALSE;
  118. pDev->autofeed = pResource->autofeed;
  119. pDev->inservice = FALSE;
  120.         if (pResource->regDelta == 0) 
  121.    pResource->regDelta = 1; 
  122.         pDev->data = LPT_DATA_RES (pResource);
  123.         pDev->stat = LPT_STAT_RES (pResource);
  124.         pDev->ctrl = LPT_CTRL_RES (pResource);
  125. pDev->intCnt = 0;
  126. pDev->retryCnt = pResource->retryCnt;
  127. pDev->busyWait = pResource->busyWait;
  128. pDev->strobeWait = pResource->strobeWait;
  129. pDev->timeout = pResource->timeout;
  130. pDev->intLevel = pResource->intLevel;
  131.      pDev->syncSem = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
  132.      pDev->muteSem = semMCreate (SEM_Q_PRIORITY | SEM_DELETE_SAFE |
  133.   SEM_INVERSION_SAFE);
  134.      (void) intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pResource->intVector),
  135.            (VOIDFUNCPTR)lptIntr, (int)pDev);
  136.      sysIntEnablePIC (pDev->intLevel); /* unmask the interrupt */
  137. lptInit (&lptDev[ix]);
  138. }
  139.     lptDrvNum = iosDrvInstall (lptOpen, (FUNCPTR) NULL, lptOpen,
  140.        (FUNCPTR) NULL, lptRead, lptWrite, lptIoctl);
  141.     return (lptDrvNum == ERROR ? ERROR : OK);
  142.     }
  143. /*******************************************************************************
  144. *
  145. * lptDevCreate - create a device for an LPT port
  146. *
  147. * This routine creates a device for a specified LPT port.  Each port
  148. * to be used should have exactly one device associated with it by calling
  149. * this routine.
  150. *
  151. * For instance, to create the device `/lpt/0', the proper call would be:
  152. * .CS
  153. *     lptDevCreate ("/lpt/0", 0);
  154. * .CE
  155. *
  156. * RETURNS: OK, or ERROR if the driver is not installed, the channel is
  157. * invalid, or the device already exists.
  158. *
  159. * SEE ALSO: lptDrv()
  160. */
  161. STATUS lptDevCreate
  162.     (
  163.     char *name, /* name to use for this device */
  164.     int channel /* physical channel for this device (0 - 2) */
  165.     )
  166.     {
  167.     if (channel >= N_LPT_CHANNELS)
  168. return (ERROR);
  169.     if (lptDrvNum <= 0)
  170. {
  171. errnoSet (S_ioLib_NO_DRIVER);
  172. return (ERROR);
  173. }
  174.     /* if this device already exists, don't create it */
  175.     if (lptDev[channel].created)
  176. return (ERROR);
  177.     /* mark the device as created, and add the device to the I/O system */
  178.     lptDev[channel].created = TRUE;
  179.     return (iosDevAdd (&lptDev[channel].devHdr, name, lptDrvNum));
  180.     }
  181. /*******************************************************************************
  182. *
  183. * lptOpen - open file to LPT
  184. *
  185. * ARGSUSED1
  186. */
  187. LOCAL int lptOpen
  188.     (
  189.     LPT_DEV *pDev,
  190.     char    *name,
  191.     int     mode
  192.     )
  193.     {
  194.     return ((int) pDev);
  195.     }
  196. /*******************************************************************************
  197. *
  198. * lptRead - read from the port.
  199. *
  200. * Read from the port.
  201. *
  202. * RETURNS: ERROR.
  203. */
  204. LOCAL int lptRead
  205.     (
  206.     LPT_DEV *pDev,
  207.     char    *pBuf,
  208.     int     size
  209.     )
  210.     {
  211.     return (ERROR); /* XXX would be supported in next release */
  212.     }
  213. /*******************************************************************************
  214. *
  215. * lptWrite - write to the port.
  216. *
  217. * Write to the port.
  218. *
  219. * RETURNS: The number of bytes written, or ERROR if the command didn't succeed.
  220. */
  221. LOCAL int lptWrite
  222.     (
  223.     LPT_DEV *pDev,
  224.     char    *pBuf,
  225.     int     size
  226.     )
  227.     {
  228.     int byteCnt = 0;
  229.     BOOL giveup = FALSE;
  230.     int retry;
  231.     int wait;
  232.     if (size == 0)
  233. return (size);
  234.     
  235.     semTake (pDev->muteSem, WAIT_FOREVER);
  236.     retry = 0;
  237.     while ((sysInByte (pDev->stat) & S_MASK) != 
  238.    (S_SELECT | S_NODERR | S_NOBUSY))
  239. {
  240. if (retry++ > pDev->retryCnt)
  241.     {
  242.     if (giveup)
  243. {
  244.         errnoSet (S_ioLib_DEVICE_ERROR);
  245.         semGive (pDev->muteSem);
  246.         return (ERROR);
  247. }
  248.     else
  249. {
  250. lptInit (pDev);
  251. giveup = TRUE;
  252. }
  253.     }
  254.         wait = 0;
  255. while (wait != pDev->busyWait)
  256.     wait++;
  257. }
  258.     
  259.     retry = 0;
  260.     do {
  261.         wait  = 0;
  262. sysOutByte (pDev->data, *pBuf);
  263. while (wait != pDev->strobeWait)
  264.     wait++;
  265. sysOutByte (pDev->ctrl, sysInByte (pDev->ctrl) | C_STROBE | C_ENABLE);
  266. while (wait)
  267.     wait--;
  268. sysOutByte (pDev->ctrl, sysInByte (pDev->ctrl) & ~C_STROBE);
  269. if (semTake (pDev->syncSem, pDev->timeout * sysClkRateGet ()) == ERROR)
  270.     {
  271.     if (retry++ > pDev->retryCnt)
  272. {
  273. errnoSet (S_ioLib_DEVICE_ERROR);
  274. semGive (pDev->muteSem);
  275. return (ERROR);
  276. }
  277.     }
  278. else
  279.     {
  280.     pBuf++;
  281.     byteCnt++;
  282.     }
  283. } while (byteCnt < size);
  284.     semGive (pDev->muteSem);
  285.     return (size);
  286.     }
  287. /*******************************************************************************
  288. *
  289. * lptIoctl - special device control
  290. *
  291. * This routine handles LPT_SETCONTROL and LPT_GETSTATUS requests.
  292. *
  293. * RETURNS: OK or ERROR if invalid request.
  294. */
  295. LOCAL STATUS lptIoctl
  296.     (
  297.     LPT_DEV *pDev, /* device to control */
  298.     int function, /* request code */
  299.     int arg /* some argument */
  300.     )
  301.     {
  302.     int status = OK;
  303.     semTake (pDev->muteSem, WAIT_FOREVER);
  304.     switch (function)
  305. {
  306. case LPT_SETCONTROL:
  307.          sysOutByte (pDev->ctrl, arg);
  308.     break;
  309. case LPT_GETSTATUS:
  310.          *(int *)arg = sysInByte (pDev->stat);
  311.     break;
  312. default:
  313.     (void) errnoSet (S_ioLib_UNKNOWN_REQUEST);
  314.     status = ERROR;
  315.     break;
  316. }
  317.     semGive (pDev->muteSem);
  318.     return (status);
  319.     }
  320. /*******************************************************************************
  321. *
  322. * lptIntr - handle an interrupt
  323. *
  324. * This routine gets called to handle interrupts.
  325. * If there is another character to be transmitted, it sends it.  If
  326. * not, or if a device has never been created for this channel, just
  327. * return.
  328. *
  329. * Disables interrupts after each character.  This protects the system
  330. * against continuous interrupts when printer is not connected, or interrupt
  331. * controller is not programmed correctly (level versus edge detect).
  332. */
  333. LOCAL void lptIntr
  334.     (
  335.     LPT_DEV *pDev
  336.     )
  337.     {
  338.     pDev->inservice = TRUE;
  339.     pDev->intCnt++;
  340.     semGive (pDev->syncSem);
  341.     pDev->inservice = FALSE;
  342.     sysOutByte (pDev->ctrl, sysInByte (pDev->ctrl) & ~C_ENABLE);  
  343.     }
  344. /*******************************************************************************
  345. *
  346. * lptInit - initialize the specified LPT port
  347. *
  348. * initialize the specified LPT port.
  349. */
  350. LOCAL void lptInit
  351.     (
  352.     LPT_DEV *pDev
  353.     )
  354.     {
  355.     sysOutByte (pDev->ctrl, 0); /* init */
  356.     taskDelay (sysClkRateGet () >> 3); /* hold min 50 mili sec */
  357.     if (pDev->autofeed)
  358.         sysOutByte (pDev->ctrl, C_NOINIT | C_SELECT | C_AUTOFEED);
  359.     else
  360.         sysOutByte (pDev->ctrl, C_NOINIT | C_SELECT);
  361.     }
  362. /*******************************************************************************
  363. *
  364. * lptShow - show LPT statistics
  365. *
  366. * This routine shows statistics for a specified LPT port.
  367. *
  368. * RETURNS: N/A
  369. */
  370. void lptShow
  371.     (
  372.     UINT channel /* channel (0 - 2) */
  373.     )
  374.     {
  375.     LPT_DEV *pDev = &lptDev[channel];
  376.     if (channel > N_LPT_CHANNELS)
  377. return;
  378.     printf ("controlReg        = 0x%xn", sysInByte (pDev->ctrl));
  379.     printf ("statusReg         = 0x%xn", sysInByte (pDev->stat));
  380.     printf ("created           = %sn",   pDev->created ? "TRUE" : "FALSE");
  381.     printf ("autofeed          = %sn",   pDev->autofeed ? "TRUE" : "FALSE");
  382.     printf ("inservice         = %sn",   pDev->inservice ? "TRUE" : "FALSE");
  383.     printf ("normalInt         = %dn",   pDev->intCnt);
  384.     printf ("defaultInt        = %dn",   sysStrayIntCount);
  385.     printf ("retryCnt          = %dn",   pDev->retryCnt);
  386.     printf ("busyWait   (loop) = %dn",   pDev->busyWait);
  387.     printf ("strobeWait (loop) = %dn",   pDev->strobeWait);
  388.     printf ("timeout    (sec)  = %dn",   pDev->timeout);
  389.     printf ("intLevel   (IRQ)  = %dn",   pDev->intLevel);
  390.     }