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

VxWorks

开发平台:

C/C++

  1. /* wdbVisionDrv.c - Wind River Vision Driver */
  2. /* Copyright 1988-2002 Wind River Systems Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01e,29nov01,g_h  Cleaning for T2.2
  7. 01d,05may01,g_h  rename to wdbVisionDrv.c and cleaning
  8. 01c,09apr01,rnr  Changed to generic driver that calls different IO packages
  9. 01b,07feb01,g_h  renaming module name and cleaning
  10. 01a,07may97,est  Adapted from memdrv.c
  11. */
  12. /*
  13. DESCRIPTION
  14. This driver provides a Vision Communications Channel
  15. between the I/O system and a host. The system requires an Wind River
  16. background mode emulator equiped with a TGTCONS Transparent
  17. Mode.
  18. USER-CALLABLE ROUTINES
  19. Most of the routines in this driver are accessible only through the I/O
  20. system.  Two routines, however, must be called directly:  visionDriverInit() to 
  21. initialize the driver, and visionDriverCreate() to create devices.
  22. Before using the driver, it must be initialized by calling vDriverInit().
  23. This routine should be called only once, before any reads, writes, or 
  24. visionDriverCreate() calls.  
  25. The use and functions provided by the driver vary depending on the 
  26. target microprocessor: ColdFire, PowerPC, ARM, XSCALE, MIPS and SH. 
  27. IOCTL
  28. The memory driver responds to the ioctl() codes
  29. SEE ALSO:
  30. .pG "I/O System"
  31. */
  32. /* includes */
  33. #include "vxWorks.h"
  34. #include "ioLib.h"
  35. #include "iosLib.h"
  36. #include "memLib.h"
  37. #include "cacheLib.h"
  38. #include "errnoLib.h"
  39. #include "string.h"
  40. #include "stdlib.h"
  41. #include "stdio.h"
  42. #include "taskLib.h"
  43. #include "configAll.h"
  44. #include "drv/wdb/vision/wdbVisionDrvIF.h"
  45. #include "drv/wdb/vision/wdbVisionDrv.h"
  46. /* defines */
  47. #undef VISION_DEBUG_VERSION     /* undef for released version */     
  48. /* externals */
  49. #if defined (INCLUDE_WDB_COMM_VTMD)
  50. IMPORT VDR_ULONG  tmdLowLevelIOInit (V_DRIVER_INTERFACE *pInterfaceData);
  51. #endif /* (INCLUDE_WDB_COMM_VTMD) */
  52. IMPORT VDR_ULONG visionLowLevelIOInit (V_DRIVER_INTERFACE *pInterfaceData);
  53. /* locals */
  54. LOCAL int vDrivNum  = 0; /* driver number          */
  55. LOCAL int vDrivOpen = 0; /* number of open devices */
  56. #if defined (INCLUDE_WDB_COMM_VTMD)
  57. LOCAL VDR_INIT_PTR pIOEntryRoutine = (VDR_INIT_PTR) tmdLowLevelIOInit; /* visionTMD I/O subsystem entry  */
  58. #else 
  59. LOCAL VDR_INIT_PTR pIOEntryRoutine = NULL;
  60. #endif /* (INCLUDE_WDB_COMM_VTMD) */
  61. /* forward declarations */
  62. int visionDriverOpen (VDRIV_DEV *pFd, char *pName, int mode);
  63. int visionDriverRead (VDRIV_DEV *pFd, char *pBuffer ,int maxbytes);
  64. int visionDriverWrite (VDRIV_DEV *pFd, char *pBuffer, int nbytes);
  65. int visionDriverIoctl (VDRIV_DEV *pFd, int function, int arg);
  66. int visionDriverClose (VDRIV_DEV *pFd);
  67. LOCAL void visionDrvPollTask (VDRIV_DEV *pFd);
  68. LOCAL int  visionPoll (VDRIV_DEV *pFd);
  69. LOCAL int  visionStartPollTask (VDRIV_DEV *pFd, int priority);
  70. LOCAL int  visionFillRxQueue (VDRIV_DEV *pFd);
  71. LOCAL int visionInitQueue (volatile VISION_QUEUE *pQueue, int size);
  72. LOCAL int visionBytesInQueue (volatile VISION_QUEUE *pQueue);
  73. LOCAL int visionAddToQueue (volatile VISION_QUEUE *pQueue, char *pDt, int sz);
  74. LOCAL int visionRemoveFromQueue (volatile VISION_QUEUE *pQueue, char *pDt, int sz);
  75. LOCAL int visionFlushQueue (volatile VISION_QUEUE *pQueue);
  76. LOCAL int visionSpaceInQueue (volatile VISION_QUEUE *pQueue);
  77. /***************************************************************************
  78. *
  79. * visionDriverInit - install Wind River Vision Driver
  80. *
  81. * This routine initializes the driver.  It must be called first,
  82. * before any other routine in the driver.
  83. *
  84. * RETURNS: OK, or ERROR if the I/O system cannot install the driver.
  85. */
  86. int visionDriverInit
  87.     (
  88.     void 
  89.     )
  90.     {
  91.     /* Exit if driver has already been installed */ 
  92.     if (vDrivNum > 0)
  93.         {
  94.         return (OK);
  95.         }
  96.     vDrivNum = iosDrvInstall(visionDriverOpen,
  97.                              (FUNCPTR) NULL,
  98.                              visionDriverOpen,
  99.                              visionDriverClose,
  100.                              visionDriverRead,
  101.                              visionDriverWrite,
  102.                              visionDriverIoctl);
  103.     vDrivOpen = (vDrivNum == ERROR) ? 0 : 1;
  104.     return ((vDrivNum == ERROR) ? ERROR : OK);
  105.     }
  106. /***************************************************************************
  107. *
  108. * visionDriverCreate - create an instance of Wind River Virtual Mode Driver. 
  109. *
  110. * This routine create an instance of Wind River Virtual Mode Driver
  111. *   
  112. * RETURNS: OK, ERROR/errno
  113. *
  114. * NOTE: currently only a single device is supported
  115. */
  116. int visionDriverCreate
  117.     (  
  118.     char *pName,         
  119.     int   opMode,
  120.     int   blockMode,
  121.     int   bufferMode,
  122.     int   taskDelay,
  123.     int   taskPriority
  124.     )
  125.     {
  126.     VDRIV_DEV *pFd      = (VDRIV_DEV*)NULL;
  127.     VDR_ULONG  ioStatus = VDR_FAILURE;
  128.     
  129.     /* sanity check on taskDelay and taskPriority */
  130.     if ((taskDelay < 0) || (taskDelay > VISION_MAX_PTASK_DELAY))
  131. {
  132.         return (ERROR);
  133.         }
  134.     if ((taskPriority < VISION_MIN_PTASK_PRIOR) || 
  135.         (taskPriority > VISION_MAX_PTASK_PRIOR))
  136.         {
  137. return(ERROR);
  138.         }
  139.     /*
  140.      *   If device has not been installed or more than one device 
  141.      *   has been opened, return an ERROR.
  142.      */
  143.     if ((vDrivNum < 1) || (vDrivOpen > 1))
  144.         {
  145.         return(ERROR);
  146.         }
  147.     /* Create the device descriptor */
  148.     if ((pFd = (VDRIV_DEV*)cacheDmaMalloc (sizeof(VDRIV_DEV))) == NULL)
  149.         {
  150.         return (ERROR);
  151.         }
  152.     /* Initialize descriptor values */
  153.     pFd->state       = VISION_STATE_CLOSED; 
  154.     pFd->pollTaskId  = ERROR;
  155.     pFd->pDeviceName = pName;
  156.     pFd->opMode      = opMode;
  157.     pFd->rdWrMode    = O_RDWR;
  158.     pFd->bufferMode  = bufferMode;
  159.     pFd->blockMode   = blockMode;
  160.     pFd->loopMode    = VISION_NORMAL_MODE;
  161.     pFd->pollDelay   = taskDelay;
  162.     pFd->inter.openFunc        = (VDR_OPEN_PTR) NULL;
  163.     pFd->inter.closeFunc       = (VDR_CLOSE_PTR) NULL;
  164.     pFd->inter.readFunc        = (VDR_READ_PTR) NULL;
  165.     pFd->inter.writeFunc       = (VDR_WRITE_PTR) NULL;
  166.     pFd->inter.readStatusFunc  = (VDR_READ_STATUS_PTR) NULL;
  167.     pFd->inter.writeStatusFunc = (VDR_WRITE_STATUS_PTR) NULL;
  168.     pFd->inter.privateData     = (VDR_PDATA) NULL;
  169.     /* Try and initialize the low-level I/O driver. */
  170.     ioStatus = (*(VDR_INIT_PTR)pIOEntryRoutine)(&pFd->inter);
  171.     if (ioStatus == VDR_FAILURE)
  172.         {
  173.         return (ERROR);
  174.         }
  175.     /* Add device to device table */
  176.     if ((iosDevAdd ((DEV_HDR*)pFd ,pName ,vDrivNum)) == ERROR)
  177.         {
  178.         return (ERROR);
  179.         }
  180.     /* Create a LOOPBACK queueu */
  181.     if (visionInitQueue (&pFd->loopQueue ,LOOP_BUFFER_SIZE) == ERROR)
  182.         {
  183.         return (ERROR);
  184.         }
  185.     /* If buffered operation is selected, set up initial buffer queues */
  186.     if (bufferMode == VISION_BUFFERED_MODE)
  187.         {
  188.         if (visionInitQueue (&pFd->txQueue ,TX_BUFFER_SIZE) == ERROR)
  189.             {
  190.             return (ERROR);
  191.             }
  192.         if (visionInitQueue (&pFd->rxQueue ,RX_BUFFER_SIZE) == ERROR)
  193.             {
  194.             return (ERROR);
  195.             }
  196.         }
  197.     /* Create a Tx and Rx Critical Section mutual exclusion construct */
  198.     CREATE_CRITSECT(pFd->txCrSection);
  199.     CREATE_CRITSECT(pFd->rxCrSection);
  200.     CREATE_CRITSECT(pFd->loopCrSection);
  201.     /* 
  202.      *   If the operation mode specified is pseudo-interrupt, start
  203.      *   a background polling task to simulate Tx and Rx interrupts.
  204.      */
  205.     if (opMode == VISION_PINTR_MODE)
  206.         {
  207.         if (visionStartPollTask(pFd ,taskPriority) == ERROR)
  208.             {
  209.             return(ERROR);
  210.             }
  211.         }
  212.     pFd->state = VISION_STATE_OPEN;
  213.     return (OK);
  214.     }
  215. /***************************************************************************
  216. *
  217. * visionDriverOpen - open a connection 
  218. *
  219. * This routine open a connection between the high level driver and the low
  220. * level driver
  221. *
  222. * RETURNS: The file descriptor number, or ERROR if the name is not a valid 
  223. *          number.
  224. */
  225. int visionDriverOpen 
  226.     (
  227.     VDRIV_DEV *pDev,       /* pointer to device descriptor           */
  228.     char      *pRemainder, /* stuff after /vtd0 not valid            */
  229.     int        mode        /* access mode (O_RDONLY,O_WRONLY,O_RDWR) */
  230.     )           
  231.     {
  232.     volatile VDRIV_DEV *pFd      = pDev; 
  233.     VDR_ULONG           ioStatus = VDR_SUCCESS;
  234.    
  235.     if (pRemainder[0] != 0)
  236.         {
  237.         return (ERROR);
  238.         }
  239.     pFd->rdWrMode = mode;
  240.     /*
  241.      *   Invoke the lower level driver's open function to perform any
  242.      *   intialization or allocation of resources.
  243.      */
  244.     ioStatus = pFd->inter.openFunc (pFd->inter.privateData);
  245.   
  246.     if (ioStatus != VDR_SUCCESS)
  247.         {
  248.         return (ERROR);
  249.         }
  250.     return ((int)pFd);
  251.     }
  252. /***************************************************************************
  253. *
  254. * visionDriverClose - close a connection 
  255. *
  256. * This routine close the connection between the high level driver and the low
  257. * level driver
  258. * RETURNS: OK, or ERROR 
  259. */
  260. int visionDriverClose 
  261.     (
  262.     VDRIV_DEV *pDev /* pointer to device descriptor */
  263.     )           
  264.     {
  265.     volatile VDRIV_DEV *pFd = pDev; 
  266.     VDR_ULONG           ioStatus;
  267.     /*
  268.      *   Invoke the lower level driver's close function to cleanup and 
  269.      *   resources they may have allocated.
  270.      */
  271.     ioStatus = pFd->inter.closeFunc (pFd->inter.privateData);
  272.   
  273.     if (ioStatus == VDR_SUCCESS)
  274.         {
  275.         return (OK);
  276.         }
  277.     else
  278.         {
  279.         return(ERROR);
  280.         }
  281.     }
  282. /***************************************************************************
  283. *
  284. * visionDriverRead - read from a memory file
  285. *
  286. * This routine read data from the low level driver.
  287. *
  288. * RETURNS: The number of bytes read, or ERROR if past the end of memory or 
  289. *          is O_WRONLY only.
  290. */
  291. int visionDriverRead 
  292.     (
  293.     VDRIV_DEV *pDev,    /* file descriptor of file to close */
  294.     char      *pBuffer, /* buffer to receive data           */
  295.     int        maxbytes /* max bytes to read in to buffer   */
  296.     )
  297.     {
  298.     volatile VDRIV_DEV *pFd = pDev;
  299.     int                 bytesRead = 0;
  300.     VDR_ULONG           ioStatus;
  301.     VDR_ULONG           readStatus;
  302.     VDR_ULONG           recvBytes;
  303.     /* Insure proper rwMode */
  304.     if (pFd->rdWrMode == O_WRONLY)
  305.         {
  306.         return (ERROR);
  307.         }
  308.     /* 
  309.      *   Sanity check on maxbytes, zero is a legal value, 
  310.      *   it is used to indicate a status poll is requested.
  311.      */
  312.     if (maxbytes < 0)
  313.         {
  314.         return (ERROR);
  315.         }
  316.     /* 
  317.      *    Polled verses Pseudo-Interrupt, Blocking verses Non-Blocking,
  318.      *    and Buffered verses Non-Buffered are handled slightly different. 
  319.      *    (see Application Note, Mode Matrix for details)
  320.      */
  321.     if (pFd->opMode == VISION_POLL_MODE)
  322.         {
  323.         if (pFd->blockMode == VISION_BLOCKED_MODE)
  324.             {
  325.             /*
  326.              *   (This mode has to be VISION_NONBUFFERED_MODE)
  327.              *
  328.              *   Wait for available data from emulator 
  329.              */
  330.             readStatus = VDR_DATA_NONE;
  331.             while (readStatus == VDR_DATA_NONE)
  332.                 {
  333.                 ioStatus = pFd->inter.readStatusFunc (pFd->inter.privateData,
  334.                                                       &readStatus);
  335.                 if (ioStatus == VDR_FAILURE)
  336.                     {
  337.                     return (ERROR);
  338.                     }
  339.                 }
  340.             ioStatus = pFd->inter.readFunc(pFd->inter.privateData,
  341.                                            (VDR_UCHAR*)pBuffer,
  342.                                            (VDR_ULONG)maxbytes,
  343.                                            &recvBytes);
  344.             if (ioStatus == VDR_FAILURE)
  345.                 {
  346.                 return (ERROR);
  347.                 }
  348.             bytesRead = recvBytes;
  349.             }
  350.         else /* POLL_MODE & NONBLOCKED_MODE */
  351.             {
  352.             if (pFd->bufferMode == VISION_NONBUFFERED_MODE)
  353.                 {
  354.                 ioStatus = pFd->inter.readFunc (pFd->inter.privateData,
  355.                                                 (VDR_UCHAR*) pBuffer,
  356.                                                 (VDR_ULONG) maxbytes,
  357.                                                 &recvBytes);
  358.                 if (ioStatus == VDR_FAILURE)
  359.                     {
  360.                     return (ERROR);
  361.                     }
  362.                 bytesRead = recvBytes;
  363.                 }
  364.             else /* POLL_MODE, NONBLOCKED_MODE, BUFFERED_MODE */
  365.                 {
  366.                 /* 
  367.                  *   This is a possible mode, but not a practical mode. The 
  368.                  *   buffered mode was intended to be used with a pTask running.
  369.                  */
  370.                 return (ERROR);
  371.                 }
  372.             }
  373.         }
  374.     else if (pFd->opMode == VISION_PINTR_MODE)
  375.         {
  376.         if (pFd->blockMode == VISION_BLOCKED_MODE)
  377.             {
  378.             /* (This mode has to be VISION_BUFFERED_MODE) */
  379.             /* 
  380.              * In this mode, the visionDriverRead() function will block until
  381.              * data is available. The background pTask is responsible
  382.              * for monitoring the Rx descriptor buffer and filling the
  383.              * Rx Queue.
  384.              */
  385.             /* Wait for data to be available in the Rx queue */
  386.             do  {
  387.                 ENTER_CRITSECT (pFd->rxCrSection);
  388.                 bytesRead = visionRemoveFromQueue (&pFd->rxQueue ,pBuffer ,maxbytes);
  389.                 EXIT_CRITSECT (pFd->rxCrSection);
  390.                 if (bytesRead == 0)
  391.                     {
  392.                     DELAY_TASK (pFd->pollDelay);
  393.                     }
  394.                 } while(bytesRead == 0);
  395.             return(bytesRead);
  396.             }
  397.         else /* PINTR_MODE, NONBLOCKED_MODE, BUFFERED_MODE */
  398.             {
  399.             /* (This mode has to be VISION_BUFFERED_MODE) */
  400.             ENTER_CRITSECT (pFd->rxCrSection);
  401.             bytesRead = visionRemoveFromQueue (&pFd->rxQueue ,pBuffer ,maxbytes);
  402.             EXIT_CRITSECT (pFd->rxCrSection);
  403.             return (bytesRead);
  404.             }
  405.         }       
  406.     else if (pFd->opMode == VISION_PISR_MODE)
  407.         {
  408.         return (ERROR);
  409.         }
  410.     else
  411.         {
  412.         return(ERROR);
  413.         }
  414.     return (bytesRead);
  415.     }
  416. /***************************************************************************
  417. *
  418. * visionDriverWrite - write to vision driver
  419. *
  420. * This routine write to the low level driver.
  421. *
  422. * RETURNS: The number of bytes written, or ERROR/errno 
  423. *
  424. * NOTE: some redundancy in various mode sections.
  425. */
  426. int visionDriverWrite 
  427.     (
  428.     VDRIV_DEV *pDev,    /* file descriptor of file to close     */
  429.     char      *pBuffer, /* buffer to be written                 */
  430.     int        nbytes   /* number of bytes to write from buffer */
  431.     )
  432.     {
  433.     volatile VDRIV_DEV *pFd = pDev;
  434.     VDR_ULONG           nToWrite;
  435.     int                 bytesAdded;
  436.     VDR_ULONG           ioStatus;
  437.     VDR_ULONG           writeStatus;
  438.     VDR_ULONG           curLoc;
  439.     /* Insure driver has been previously opened */
  440.     if (pFd->state != VISION_STATE_OPEN)
  441.         {
  442.         return (ERROR);
  443.         }
  444.     /* Insure proper read/write mode */
  445.     if (pFd->rdWrMode == O_RDONLY)
  446.         {
  447.         return (ERROR);
  448.         }
  449.     /* Normal/Loopback Mode ? */
  450.     if (pFd->loopMode == VISION_LPBK_MODE)
  451.         {
  452.         ENTER_CRITSECT (pFd->loopCrSection);
  453.         bytesAdded = visionAddToQueue(&pFd->loopQueue ,pBuffer ,nbytes); 
  454.         EXIT_CRITSECT (pFd->loopCrSection);
  455.         if (bytesAdded != nbytes) 
  456.             {
  457.             return (ERROR); 
  458.             }
  459.         }
  460.     /* 
  461.      * Polled verses Pseudo-Interrupt, Blocking verses Non-Blocking,
  462.      * and Buffered verses Non-Buffered are handled slightly different. 
  463.      * (see Application Note, Mode Matrix for details). 
  464.      */
  465.     if (pFd->opMode == VISION_POLL_MODE)
  466.         {
  467.         if (pFd->blockMode == VISION_BLOCKED_MODE)
  468.             {
  469.             /* This mode has to be VISION_NONBUFFERED_MODE */
  470.             nToWrite = nbytes;
  471.             curLoc   = 0;
  472.             while (nToWrite > 0)
  473.                 {
  474.                 /* 
  475.                  *   If emulator is not busy, place buffer in tx descriptor
  476.                  *   otherwise wait for emulator to come ready.
  477.                  */
  478.   
  479.                 ioStatus = pFd->inter.writeStatusFunc (pFd->inter.privateData,
  480.                                                        &writeStatus);
  481.                 if (ioStatus == VDR_SUCCESS)
  482.                     {
  483.                     if (writeStatus == VDR_WRITE_COMPLETE)
  484.                         {
  485.                         if (nToWrite < VISION_PKT_MTU) 
  486.                             {
  487.                             ioStatus = pFd->inter.writeFunc (pFd->inter.privateData,
  488.                                                              pBuffer,
  489.                                                              nToWrite);
  490.     
  491.                             if (ioStatus == VDR_FAILURE)
  492.                                 {
  493.                                 return (ERROR);
  494.                                 }
  495.         
  496.                             nToWrite = 0;
  497.                             }
  498.                         else
  499.                             {
  500.                             ioStatus = pFd->inter.writeFunc (pFd->inter.privateData,
  501.                                                              &pBuffer[curLoc],
  502.                                                              nToWrite);
  503.     
  504.                             if (ioStatus == VDR_FAILURE)
  505.                                 {
  506.                                 return (ERROR);
  507.                                 }
  508.     
  509.                             nToWrite -= VISION_PKT_MTU;
  510.                             curLoc   += VISION_PKT_MTU;
  511.                             }
  512.                         }
  513.                     else /* Emulator busy reading buffer */
  514.                         {
  515.                         DELAY_TASK (pFd->pollDelay);
  516.                         }
  517.                     }
  518.                 else
  519.                     {
  520.                     return (ERROR);
  521.                     }
  522. }
  523.        
  524.             /* Before returning, insure emulator has retrieved the buffer */
  525.             writeStatus = VDR_WRITE_PENDING;
  526.             while (writeStatus == VDR_WRITE_PENDING)
  527.                 {
  528.                 DELAY_TASK (pFd->pollDelay);
  529.                 ioStatus = pFd->inter.writeStatusFunc (pFd->inter.privateData,
  530.                                                        &writeStatus);
  531.                 if (ioStatus == VDR_FAILURE)
  532.                     {
  533.                     return (ERROR);
  534.                     }
  535.                 }
  536.    
  537.             return (nbytes);
  538.             }
  539.         else  /* VISION_POLL_MODE & VISION_NONBLOCKED_MODE */
  540.             {
  541.             if (pFd->bufferMode == VISION_NONBUFFERED_MODE)
  542.                 {
  543.                 /* NonBlocking Poll Mode cannot handle > MTU blocks */
  544.                 if (nbytes > VISION_PKT_MTU)
  545.                     {
  546.                     return (ERROR);
  547.                     }
  548.                 /* 
  549.                  *   Request that the lowlevel I/O subsystem transmit the
  550.                  *   data across the communications media.
  551.                  */
  552.   
  553.                 ioStatus = pFd->inter.writeStatusFunc (pFd->inter.privateData,
  554.                                                        &writeStatus);
  555.                 if (ioStatus == VDR_SUCCESS)
  556.                     {
  557.                     if (writeStatus == VDR_WRITE_COMPLETE)
  558.                         {
  559.                         ioStatus = pFd->inter.writeFunc (pFd->inter.privateData,
  560.                                                          pBuffer,
  561.                                                          nbytes);
  562.     
  563.                         if (ioStatus == VDR_FAILURE)
  564.                             {
  565.                             return (ERROR);
  566.                             }
  567.       
  568.                         return (nbytes);
  569.                         }
  570.                     else /* Emulator busy reading buffer */
  571.                         {
  572.                         return(ERROR);
  573.                         }
  574.                     }
  575.                 else
  576.                     {
  577.                     return (ERROR);
  578.                     }
  579.                 }
  580.             else /* POLL_MODE, NONBLOCKING_MODE, BUFFERED  */
  581.                 {
  582.                 /* 
  583.                  *   This is a possible mode, but not a practical mode. The 
  584.                  *   buffered mode was intended to be used with a pTask running.
  585.                  */
  586.                 return (ERROR);
  587.                 }
  588.             }
  589.         }
  590.     else if (pFd->opMode == VISION_PINTR_MODE) 
  591.         {
  592.         if (pFd->blockMode == VISION_BLOCKED_MODE)
  593.             {
  594.             /*
  595.              *  Since this mode is Blocking, there is no reason to 
  596.              *  buffer the transmit packet -- it can be sent out
  597.              *  directly in MTU size chunks (identical to POLL,
  598.              *  BLOCKING,NONBUFFERED). In this mode, the term BUFFERED
  599.              *  refers to the receiver.
  600.              *
  601.              *  Note: the pTask will still monitor the tx queue, but 
  602.              *        since this write routine never writes anything
  603.              *        to it, it is affectively disabled.
  604.              */
  605.             nToWrite = nbytes;
  606.             curLoc   = 0;
  607.             while (nToWrite > 0)
  608.                 {
  609.                 /* 
  610.                  *   If emulator is not busy, place buffer in tx descriptor
  611.                  *   otherwise wait for emulator to come ready.
  612.                  */
  613.   
  614.                 ioStatus = pFd->inter.writeStatusFunc (pFd->inter.privateData,
  615.                                                        &writeStatus);
  616.                 if (ioStatus == VDR_SUCCESS)
  617.                     {
  618.                     if (writeStatus == VDR_WRITE_COMPLETE)
  619.                         {
  620.                         if (nToWrite < VISION_PKT_MTU) 
  621.                             {
  622.                             ioStatus = pFd->inter.writeFunc (pFd->inter.privateData,
  623.                                                              pBuffer,
  624.                                                              nToWrite);
  625.     
  626.                             if (ioStatus == VDR_FAILURE)
  627.                                 {
  628.                                 return (ERROR);
  629.                                 }
  630.         
  631.                             nToWrite = 0;
  632.                             }
  633.                         else
  634.                             {
  635.                             ioStatus = pFd->inter.writeFunc (pFd->inter.privateData,
  636.                                                              &pBuffer[curLoc],
  637.                                                              nToWrite);
  638.     
  639.                             if (ioStatus == VDR_FAILURE)
  640.                                 {
  641.                                 return (ERROR);
  642.                                 }
  643.     
  644.                             nToWrite -= VISION_PKT_MTU;
  645.                             curLoc   += VISION_PKT_MTU;
  646.                             }
  647.                         }
  648.                     else  /* Emulator busy reading buffer */
  649.                         {
  650.                         DELAY_TASK (pFd->pollDelay);
  651.                         }
  652.                     }
  653.                 else
  654.                     {
  655.                     return (ERROR);
  656.                     }
  657. }
  658.        
  659.             /* Before returning, insure emulator has retrieved the buffer */
  660.             writeStatus = VDR_WRITE_PENDING;
  661.             while (writeStatus == VDR_WRITE_PENDING)
  662.                 {
  663.                 DELAY_TASK (pFd->pollDelay);
  664.                 ioStatus = pFd->inter.writeStatusFunc (pFd->inter.privateData,
  665.                                                        &writeStatus);
  666.                 if (ioStatus == VDR_FAILURE)
  667.                     {
  668.                     return (ERROR);
  669.                     }
  670.                 }
  671.             return (nbytes);
  672.             }
  673.         else  /* VISION_PINTR_MODE & VISION_NONBLOCKED_MODE */
  674.             {
  675.             /* (This mode has to be VISION_BUFFERED_MODE) */
  676.             /*
  677.              *   Queue up transmit buffer for background pTask to 
  678.              *   send it -- don't block.
  679.              */
  680.             ENTER_CRITSECT (pFd->txCrSection);
  681.             bytesAdded = visionAddToQueue (&pFd->txQueue , pBuffer, nbytes);
  682.             EXIT_CRITSECT (pFd->txCrSection);
  683.             return (bytesAdded);
  684.             }
  685.         }
  686.     else if (pFd->opMode == VISION_PISR_MODE)
  687.         {
  688.         return (ERROR);
  689.         }
  690.     else   
  691.         {
  692.         return (ERROR);
  693.         }
  694.     return (nbytes);
  695.     }
  696. /***************************************************************************
  697. *
  698. * visionDriverIoctl - do device specific control function
  699. *
  700. * This routine do device specific control functions as listed below:
  701. *
  702. *   VISION_POLL_MODE        - switch to Polling Mode
  703. *   VISION_PINTR_MODE       - switch to Pseudo Interrupt Mode
  704. *   VISION_BLOCKED_MODE     - switch to blocking mode
  705. *   VISION_NONBLOCKED_MODE  - switch to non-blocking mode
  706. *   VISION_BUFFERED_MODE    - switch to buffered mode
  707. *   VISION_NONBUFFERED_MODE - switch to non-buffered mode
  708. *   VISION_RX_QUEUE_SIZE    - Set the size of the RX queue.
  709. *                             This will remove any characters in the RX queue.
  710. *   VISION_TX_QUEUE_SIZE    - Set the size of the TX queue.
  711. *                             This will remove any characters in the TX queue.
  712. *
  713. * RETURNS: OK, or ERROR if seeking passed the end of memory.
  714. */
  715. int visionDriverIoctl
  716.     (
  717.     VDRIV_DEV *pDev,     /* descriptor to control */
  718.     int        function, /* function code         */
  719.     int        arg       /* some argument         */
  720.     )
  721.     {
  722.     int                  status = OK;
  723.     volatile VDRIV_DEV *pFd    = pDev;
  724.     switch (function)
  725.         {
  726.         case VISION_PINTR_MODE:
  727.         case VISION_PISR_MODE:
  728.         case VISION_BLOCKED_MODE:
  729.         case VISION_NONBLOCKED_MODE:
  730.         case VISION_BUFFERED_MODE:
  731.         case VISION_NONBUFFERED_MODE:
  732.             {
  733.  
  734.             /*
  735.              *   For now, do not allow dynamic mode switching 
  736.              *   of these individual items.
  737.              */
  738.   
  739.             status = ERROR;
  740.             break;                                           
  741.             }
  742.  
  743.         case VISION_POLL_MODE | VISION_NONBLOCKED_MODE | VISION_NONBUFFERED_MODE:
  744.             {
  745.  
  746.             /*
  747.              *   This is a special major mode switch. This is used when the TM 
  748.              *   Driver is configured as a WDB Agent Driver. This mode switch is 
  749.              *   called when specifying 'System-Level' debug mode. Since the 
  750.              *   user will probably reissue a 'Task-Level' debug mode' command, 
  751.              *   don't back completely out of the existing settings -- just 
  752.              *   tidy up and make safe (i.e. don't free malloc'ed memory, etc).
  753.              */
  754.     
  755.             /* Suspend tTmdDrv polling task */
  756.      
  757.             if (taskSuspend (pFd->pollTaskId) == ERROR)
  758.                 {
  759.                 return (ERROR);
  760.                 }
  761.             /* flush the Tx/Rx buffer queues */
  762.  
  763.             ENTER_CRITSECT   ( pFd->txCrSection);
  764.             visionFlushQueue (&pFd->txQueue);
  765.             EXIT_CRITSECT    ( pFd->txCrSection);
  766.  
  767.             ENTER_CRITSECT   ( pFd->rxCrSection);
  768.             visionFlushQueue (&pFd->rxQueue);
  769.             EXIT_CRITSECT    ( pFd->rxCrSection);
  770.  
  771.             ENTER_CRITSECT   ( pFd->loopCrSection);
  772.             visionFlushQueue (&pFd->loopQueue);
  773.             EXIT_CRITSECT    ( pFd->loopCrSection);
  774.  
  775.             /* Specify polling, non-buffered, non-blocking mode */
  776.  
  777.             pFd->opMode     = VISION_POLL_MODE;
  778.             pFd->blockMode  = VISION_NONBLOCKED_MODE;
  779.             pFd->bufferMode = VISION_NONBUFFERED_MODE;
  780.             break;                                           
  781.             }
  782.         case VISION_PINTR_MODE | VISION_BLOCKED_MODE | VISION_BUFFERED_MODE:
  783.             {
  784.             /*
  785.              * This is a special major mode switch, it is used when the 
  786.              * vision Driver is configured  as a WDB Agent Driver. This 
  787.              * mode switch  is called when  specifying 'Task-Level 
  788.              * Debugging Mode'.  Since the user may reissue a 
  789.              * 'System-Level Debug Mode' cmnd,  don't back completely  
  790.              * out of  the existing settings -- just tidy up and make 
  791.              * safe  (i.e. don't free malloc'ed memory, remove tasks, etc).
  792.              */
  793.  
  794.             /* Restart the tVisionDrv polling task */
  795.             if ( taskRestart (pFd->pollTaskId) == ERROR)
  796.                 {
  797.                 return (ERROR);
  798.                 }
  799.             /* Specify polling, non-buffered, non-blocking mode */
  800.             pFd->opMode     = VISION_PINTR_MODE;
  801.             pFd->blockMode  = VISION_BLOCKED_MODE;
  802.             pFd->bufferMode = VISION_BUFFERED_MODE;
  803.  
  804.             break;                                           
  805.             }
  806.         case VISION_PTASK_PRIORITY:
  807.     {
  808.             if ((arg < VISION_MIN_PTASK_PRIOR) || (arg > VISION_MAX_PTASK_PRIOR))
  809.                 {
  810.                 status = ERROR;
  811.                 }
  812.             else
  813.                 {
  814.                 status = taskPrioritySet (pFd->pollTaskId , arg);
  815.                 }
  816.             break;
  817.             }
  818.         case VISION_PTASK_DELAY: 
  819.             {
  820.             if ((arg < 0) || (arg > VISION_MAX_PTASK_DELAY))
  821.                 {
  822.                 status = ERROR;
  823.                 }
  824.             else
  825.                 {
  826.                 pFd->pollDelay = arg;
  827.                 }
  828.             break;
  829.             }
  830.         case VISION_LPBK_MODE:
  831.             {
  832.             pFd->loopMode = VISION_LPBK_MODE;
  833.             break;
  834.             }
  835.         case VISION_NORMAL_MODE:
  836.             {
  837.             pFd->loopMode = VISION_NORMAL_MODE;
  838.             break;
  839.             }
  840.         case VISION_RX_QUEUE_SIZE:
  841.             {
  842.             free (pFd->rxQueue.pData);
  843.             if (visionInitQueue (&pFd->rxQueue, arg) == ERROR)
  844.                 {
  845.                 status = ERROR;
  846.                 }
  847.             break;
  848.             }
  849.         case VISION_TX_QUEUE_SIZE:
  850.             {
  851.             free (pFd->txQueue.pData);
  852.             if (visionInitQueue (&pFd->txQueue, arg) == ERROR)
  853.                 {
  854.                 status = ERROR;
  855.                 }
  856.             break;
  857.             }
  858.         default: /* Unknown Function */
  859.             {
  860.             status = ERROR;
  861.             break;
  862.             }
  863.         }
  864.     return (status);
  865.     }
  866. /***************************************************************************
  867. *
  868. * visionFillRxQueue - read from a memory file into receive queue
  869. *
  870. * This routine read from a memory file intp recive queue.
  871. *
  872. * RETURNS: The number of bytes read, or ERORR
  873. */
  874. LOCAL int visionFillRxQueue
  875.     (
  876.     VDRIV_DEV * pDev /* file descriptor of file to close */
  877.     )
  878.     {
  879.     volatile VDRIV_DEV *pFd   = pDev;
  880.     int                 nRead = 0;
  881.     int                 numBytes;
  882.     char                data;
  883.     VDR_ULONG           ioStatus;
  884.     VDR_ULONG           recvBytes = 0;
  885.     static VDR_UCHAR    buffer[VISION_PKT_MTU];
  886.     /* 
  887.      *   If we are looping back data then extract the data from the 
  888.      *   loopback QUEUE and place it in the Receive QUEUE.
  889.      */
  890.     if (pFd->loopMode == VISION_LPBK_MODE)
  891.         {
  892.         ENTER_CRITSECT (pFd->loopCrSection);
  893.         numBytes = visionBytesInQueue (&pFd->loopQueue); 
  894.         EXIT_CRITSECT (pFd->loopCrSection);
  895.         if (numBytes != 0)
  896.             {
  897.             for ( ;; )
  898.                 {
  899.                 ENTER_CRITSECT (pFd->loopCrSection);
  900.                 numBytes = visionRemoveFromQueue (&pFd->loopQueue, &data, 1);
  901.                 EXIT_CRITSECT (pFd->loopCrSection);
  902.                 if (numBytes == 0)
  903.                     {
  904.                     break;
  905.                     }
  906.                 else
  907.                     { 
  908.                     ENTER_CRITSECT (pFd->rxCrSection);
  909.                     numBytes = visionAddToQueue (&pFd->rxQueue, &data, 1);
  910.                     EXIT_CRITSECT (pFd->rxCrSection);
  911.                     if (numBytes == 1)
  912.                         {
  913.                         nRead ++;
  914.                         }
  915.                     else
  916.                         {
  917.                         break ; /* RNR - need to deal with this better */
  918.                         }
  919.     }
  920. }
  921.     }
  922. }
  923.     /*
  924.      *   Now that we have dealt with the loopback information lets see
  925.      *   see if there is any data waiting for us.
  926.      */
  927.     ioStatus = pFd->inter.readFunc (pFd->inter.privateData,
  928.                                     (VDR_UCHAR*)buffer,
  929.                                     (VDR_ULONG)VISION_PKT_MTU,
  930.                                     &recvBytes);
  931.     if ((ioStatus == VDR_SUCCESS) && (recvBytes != 0))
  932.         {
  933.         ENTER_CRITSECT (pFd->rxCrSection);
  934.         numBytes = visionAddToQueue (&pFd->rxQueue, buffer, recvBytes);
  935.         EXIT_CRITSECT (pFd->rxCrSection);
  936.         if (recvBytes != numBytes)
  937.             {
  938.             return (0); /* RNR - needs thinking about */
  939.             }
  940.         nRead += numBytes;
  941.         }
  942.     return (nRead);
  943.     }
  944. /***************************************************************************
  945. *
  946. * visionStartPollTask - spawns a polling task to simulate Tx and Rx interrupts
  947. *
  948. * This routine spawns a polling task to simulate Tx and Rx interrupts
  949. *
  950. * RETURNS: OK or ERROR
  951. */ 
  952. LOCAL int visionStartPollTask
  953.     (
  954.     VDRIV_DEV *pVisionDrv,
  955.     int        taskPriority
  956.     )
  957.     {
  958.     int taskId;
  959.     if (taskIdCurrent) /* insure we're multitasking */
  960.         {
  961.         /*
  962.          *   See if the task is already known. In which ase we only
  963.          *   need to start it up again.
  964.          */
  965.         taskId = taskNameToId ("tVisionDrv");    
  966.         if (taskId == ERROR)
  967.             { 
  968.             pVisionDrv->pollTaskId = taskSpawn ("tVisionDrv",                /* name                  */
  969.                                                 taskPriority,                /* runtime priority      */
  970.                                                 0,                           /* options               */
  971.                                                 5000,                        /* Stack size            */
  972.                                                 (int(*)())visionDrvPollTask, /* Entry point of task   */
  973.                                                 (int)pVisionDrv,             /* Arg #01 , device info */
  974.                                                 0,                           /* Arg #02 , not used    */
  975.                                                 0,                           /* Arg #03 , not used    */
  976.                                                 0,                           /* Arg #04 , not used    */
  977.                                                 0,                           /* Arg #05 , not used    */
  978.                                                 0,                           /* Arg #06 , not used    */
  979.                                                 0,                           /* Arg #07 , not used    */
  980.                                                 0,                           /* Arg #08 , not used    */
  981.                                                 0,                           /* Arg #09 , not used    */
  982.                                                 0);                          /* Arg #10 , not used    */
  983.             if (pVisionDrv->pollTaskId == ERROR)
  984.                 {
  985.                 return (ERROR);
  986.                 }
  987.             }
  988.         else
  989.             {
  990.             if (taskRestart (taskId) == ERROR)
  991.                 {
  992.                 return (ERROR);
  993.                 }
  994.             }
  995.         }
  996.     else  /* need to be multitasking */
  997.         {
  998.         return (ERROR);
  999.         }
  1000.     return (OK);
  1001.     }
  1002. /***************************************************************************
  1003. *
  1004. * visionDrvPollTask - background polling task to simulate Rx and Tx interrupts.
  1005. *
  1006. * This routine is the background polling task to simulate Rx and Tx 
  1007. * interrups.
  1008. *
  1009. * RETURNS: N/A
  1010. */ 
  1011. LOCAL void visionDrvPollTask
  1012.     (
  1013.     VDRIV_DEV *pDev
  1014.     )
  1015.     {
  1016.     volatile VDRIV_DEV *pFd = (VDRIV_DEV*)pDev;
  1017.     for ( ;; )
  1018.         {
  1019.         visionPoll (pDev);
  1020.         DELAY_TASK (pFd->pollDelay);
  1021.         }
  1022.     }
  1023. /***************************************************************************
  1024. *
  1025. * visionPoll - poll and service Tx/Rx emulator descriptor buffers and Tx/Rx
  1026. *              queues.
  1027. *
  1028. * This routine poll and service Tx/Rx emulator descriptor buffers and Tx/Rx 
  1029. * queues.
  1030. *
  1031. * RETURNS: OK or ERROR (return status not used as this point)
  1032. */ 
  1033. LOCAL int visionPoll
  1034.     (
  1035.     VDRIV_DEV *pDev
  1036.     )
  1037.     {
  1038.     volatile VDRIV_DEV *pFd = (VDRIV_DEV*)pDev;
  1039.     int                 bytesInQueue;
  1040.     int                 bytesToWrite;
  1041.     static VDR_UCHAR    localXmitBuf[VISION_PKT_MTU];
  1042.            VDR_ULONG    ioStatus;
  1043.            VDR_ULONG    writeStatus;
  1044.     
  1045.     /* Handle any Rx data present in the Rx emulator descriptor */
  1046.     ENTER_CRITSECT (pFd->rxCrSection);
  1047.     visionFillRxQueue ((VDRIV_DEV*)pFd);
  1048.     EXIT_CRITSECT (pFd->rxCrSection);
  1049.     /* Send any Tx data present in the Tx queue */
  1050.     ENTER_CRITSECT (pFd->txCrSection);
  1051.     bytesInQueue = visionBytesInQueue (&pFd->txQueue); 
  1052.     if (bytesInQueue != 0)
  1053.         {
  1054.         bytesToWrite = visionRemoveFromQueue (&pFd->txQueue,
  1055.                                               (char*)localXmitBuf,
  1056.                                               VISION_PKT_MTU);
  1057.         EXIT_CRITSECT (pFd->txCrSection);
  1058.         /* 
  1059.          * bytesToWrite should be equal to bytesInQueue or queue
  1060.          * locking mechanism is not working.
  1061.          */
  1062.         if (bytesToWrite != bytesInQueue)
  1063.             {
  1064.             }
  1065.         while (bytesToWrite > 0)
  1066.             {
  1067.             /* 
  1068.              *   If emulator is not busy, generate a transmission and
  1069.              *   let the emulator pick up the data.
  1070.              */
  1071.   
  1072.             ioStatus = pFd->inter.writeStatusFunc (pFd->inter.privateData,
  1073.                                                    &writeStatus);
  1074.             if ((ioStatus == VDR_SUCCESS) && (writeStatus == VDR_WRITE_COMPLETE))
  1075.                 {
  1076.                 ioStatus = pFd->inter.writeFunc (pFd->inter.privateData,
  1077.                                                  localXmitBuf,
  1078.                                                  bytesToWrite);
  1079.                 if (ioStatus == VDR_FAILURE)
  1080.                     {
  1081.                     return (ERROR);
  1082.                     }
  1083.                 bytesToWrite = 0;
  1084.                 }
  1085.             else  /* Emulator busy reading buffer */
  1086.                 {
  1087.                 DELAY_TASK (pFd->pollDelay);
  1088.                 }
  1089.             }
  1090.         }
  1091.     else
  1092.         {
  1093.         EXIT_CRITSECT (pFd->txCrSection);
  1094.         }
  1095.     return (OK);
  1096.     }
  1097. /***************************************************************************
  1098. *
  1099. * visionInitQueue - create a VISION_QUEUE.
  1100. *
  1101. * This routine create a VISION_QUEUE.
  1102. *
  1103. * RETURNS: OK if queue created or ERROR if faild to create queue
  1104. */ 
  1105. LOCAL int visionInitQueue
  1106.     (
  1107.     volatile VISION_QUEUE *pQueue,
  1108.     int                    qSize
  1109.     )
  1110.     {
  1111.     /* Setup the various fields to indicate an empty QUEUE */
  1112.     pQueue->nofChars = 0;
  1113.     pQueue->size     = qSize;
  1114.     pQueue->head     = 0;
  1115.     pQueue->tail     = 0;
  1116.     /* Actually allocate the QUEUE buffer space */
  1117.     if ((pQueue->pData = cacheDmaMalloc (qSize)) == NULL)
  1118.         {
  1119.         return (ERROR);
  1120.         }
  1121.     return (OK);
  1122.     }
  1123. /***************************************************************************
  1124. *
  1125. * visionAddToQueue - adds a string of characetrs to an VISION_QUEUE.
  1126. *
  1127. * This routine adds a string of characetrs to an VISION_QUEUE.
  1128. *
  1129. * RETURNS: number of characters placed into the buffer.
  1130. */ 
  1131. LOCAL int visionAddToQueue
  1132.     (
  1133.     volatile VISION_QUEUE *pQueue, /* Queue to be manipulated */
  1134.     char                  *pStr,   /* Data to be inserted     */
  1135.     int                    size    /* Amount of data supplied */
  1136.     )
  1137.     {
  1138.     int i;
  1139.     /* See of there is any room left in the QUEUE */
  1140.     if (pQueue->nofChars >= pQueue->size)
  1141.         {
  1142.         return (0);
  1143.         }
  1144.     /*
  1145.      *   If the entire string won't fit in buffer then only place the
  1146.      *   data that will fit into buffer.
  1147.      */
  1148.     if (size > (pQueue->size - pQueue->nofChars))
  1149.         {
  1150.         size = pQueue->size - pQueue->nofChars;
  1151.         }
  1152.     for (i = 0 ;i < size ; i ++)
  1153.         {
  1154.         pQueue->pData[pQueue->head++] = *pStr++;
  1155.         
  1156.         /* Wrap-around the queue's data */
  1157.         pQueue->head %= pQueue->size;
  1158.         }
  1159.     pQueue->nofChars += size;
  1160.     
  1161.     return (size);
  1162.     }
  1163. /***************************************************************************
  1164. *
  1165. * visionRemoveFromQueue - gets a string from an VISION_QUEUE
  1166. *
  1167. * This routine gets a string from an VISION_QUEUE.
  1168. *
  1169. * RETURNS: number of characters read from buffer.
  1170. */ 
  1171. LOCAL int visionRemoveFromQueue
  1172.     (
  1173.     volatile VISION_QUEUE *pQueue, /* Queue to be extracted from */
  1174.     char                  *str,    /* Retrieved data area        */
  1175.     int                    size    /* Amount of data requested   */
  1176.     )
  1177.     {
  1178.     int i;
  1179.     /* 
  1180.      *   If there is not enough characters in buffer to fill it then only
  1181.      *   put in what we have. 
  1182.      */
  1183.     if (size > pQueue->nofChars)
  1184.         {
  1185.         size = pQueue->nofChars;
  1186.         }
  1187.     if (size == 0) /* sanity check */
  1188.         {
  1189.         return (0);
  1190.         }
  1191.     /* Extract the requested data from the QUEUE */
  1192.     for (i = 0; i < size; i ++)
  1193.         {
  1194.         *str++ = pQueue->pData[pQueue->tail++];
  1195.         
  1196.         /* Wrap-around the buffer's data */
  1197.         pQueue->tail %= pQueue->size;
  1198.         }
  1199.     /* Decrement the remaining count by what as extracted */
  1200.     pQueue->nofChars -= size;
  1201.     return (size);
  1202.     }
  1203. /***************************************************************************
  1204. *
  1205. * visionSpaceInQueue - returns space available in queue
  1206. *
  1207. * This routine returns space available in queue
  1208. *
  1209. * RETURNS: number of characters available in queue buffer.
  1210. */ 
  1211. LOCAL int visionSpaceInQueue
  1212.     (
  1213.     volatile VISION_QUEUE *pQueue
  1214.     )
  1215.     {
  1216.     return (pQueue->size - pQueue->nofChars); 
  1217.     } 
  1218. /***************************************************************************
  1219. *
  1220. * visionBytesInQueue - returns number of bytes in queue
  1221. *
  1222. * This routine returns number of bytes in queue
  1223. *
  1224. * RETURNS: number of bytes in the queue
  1225. */ 
  1226. LOCAL int visionBytesInQueue
  1227.     (
  1228.     volatile VISION_QUEUE *pQueue
  1229.     )
  1230.     {
  1231.     return (pQueue->nofChars);
  1232.     }
  1233. /***************************************************************************
  1234. *
  1235. * visionFlushQueue - resets queue to empty
  1236. *
  1237. * This routine resets queue to empty
  1238. *
  1239. * RETURN: number of characters flushed from queue.
  1240. */ 
  1241. LOCAL int visionFlushQueue
  1242.     (
  1243.     volatile VISION_QUEUE *pQueue
  1244.     )
  1245.     {
  1246.     int charsFlushed;
  1247.     charsFlushed     = pQueue->nofChars;
  1248.     pQueue->nofChars = 0;
  1249.     pQueue->head     = pQueue->tail = 0;
  1250.     
  1251.     return (charsFlushed);
  1252.     }