home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / usbd0906.zip / usb_20020906.zip / usbcalls / samples / pc-linq / USBLINK.CPP next >
C/C++ Source or Header  |  2001-11-13  |  15KB  |  605 lines

  1. #define INCL_DOS
  2. #include <os2.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <conio.h>
  7. #include <ctype.h>
  8.  
  9. #pragma pack(1)
  10.  
  11. typedef struct
  12. {
  13.   USHORT usVendorID;
  14.   USHORT usDeviceID;
  15.   USHORT usBCDDevice;
  16.   USHORT usDeviceNumber; // Get the usDeviceNumber device in the system fi. if 2 aquire the 2nd device
  17.                          // 0 means first not aquired device.
  18. }AQUIREDEV,  *PAQUIREDEV;
  19.  
  20. typedef struct
  21. {
  22.   ULONG  ulHandle;
  23.   USHORT usLangID;
  24.   UCHAR  ucStringID;
  25.   UCHAR  ucReserved;
  26. }GETSTRINGPARM, *PGETSTRINGPARM;
  27.  
  28. typedef struct
  29. {
  30.   UCHAR  bRequestType;
  31.   UCHAR  bRequest;
  32.   USHORT wValue;
  33.   USHORT wIndex;
  34.   USHORT wLength;
  35.   ULONG  ulTimeout; /* in milliseconds */
  36. }SETUPPACKET, *PSETUPPACKET;
  37.  
  38. typedef struct
  39. {
  40.   ULONG  ulHandle;
  41.   UCHAR  bRequestType;
  42.   UCHAR  bRequest;
  43.   USHORT wValue;
  44.   USHORT wIndex;
  45.   USHORT wLength;
  46.   ULONG  ulTimeout; /* in milliseconds */
  47. }LIBUSB_CTRL_REQ, *PLIBUSB_CTRL_REQ;
  48.  
  49. typedef struct
  50. {
  51.   ULONG  ulHandle;
  52.   ULONG  ulTimeout; /* in milliseconds */
  53.   UCHAR  Endpoint;
  54.   UCHAR  Interface;
  55.   USHORT usDataLen;
  56.   UCHAR  Data[1];
  57. }LIBUSB_BULK_REQ, *PLIBUSB_BULK_REQ;
  58.  
  59. #define PLUSMAGIC 0x554C4E4B
  60. typedef struct
  61. {
  62.   ULONG ulMagic;
  63.   ULONG ulTag;
  64.   ULONG ulLength;
  65. }LNK_HEADER;
  66.  
  67. typedef struct
  68. {
  69.   LNK_HEADER Header;
  70.   ULONG ulStatus;
  71. }LNK_STATUS;
  72.  
  73. typedef struct
  74. {
  75.   LNK_HEADER Header;
  76.   ULONG ulFileSize;
  77.   UCHAR szFileName[256];
  78. }LNK_FILE_NAME;
  79.  
  80. typedef struct
  81. {
  82.   LNK_HEADER Header;
  83.   ULONG ulHandle;
  84. }LNK_FILE_ACCEPT;
  85.  
  86. typedef struct
  87. {
  88.   LNK_HEADER Header;
  89.   ULONG ulHandle;
  90.   UCHAR ucData[4];
  91. }LNK_FILE_DATA;
  92.  
  93. #define LNK_TAG_STATUS      1
  94. #define LNK_TAG_FILE_NAME   2
  95. #define LNK_TAG_FILE_ACCEPT 3
  96. #define LNK_TAG_FILE_DATA   4
  97. #define LNK_TAG_FILE_DONE   5
  98. #pragma pack()
  99.  
  100. HFILE hDriver;
  101.  
  102. int sendCtrlReq( ULONG ulUSBHandle,
  103.                  PSETUPPACKET pReq,
  104.                  UCHAR* pData)
  105. {
  106.   ULONG i,ulParmLen, ulDataLen;
  107.   LIBUSB_CTRL_REQ CtrlRequest;
  108.   int rc;
  109.   UCHAR *pSP;
  110.   ulParmLen = sizeof(LIBUSB_CTRL_REQ);
  111.   CtrlRequest.ulHandle     = ulUSBHandle;
  112.   CtrlRequest.bRequestType = pReq->bRequestType;
  113.   CtrlRequest.bRequest     = pReq->bRequest;
  114.   CtrlRequest.wValue       = pReq->wValue;
  115.   CtrlRequest.wIndex       = pReq->wIndex;
  116.   CtrlRequest.wLength      = pReq->wLength;
  117.   CtrlRequest.ulTimeout    = pReq->ulTimeout;
  118.   ulDataLen = pReq->wLength;
  119. #if 0
  120.   pSP = (UCHAR*)pReq;
  121.   printf("SetupPacket : ");
  122.   for(i=0;i<(sizeof(SETUPPACKET)-4);i++)
  123.     printf("%02X ",*(pSP+i));
  124.   printf("\r\n");
  125.   if((pReq->bRequestType & 0x80)==0 && ulDataLen>0)
  126.   {
  127.     printf("Sending CtrlData: ");
  128.     for(i=0;i<ulDataLen;i++)
  129.       printf("%02X ",*(pData+i));
  130.     printf("\r\n");
  131.   }
  132. #endif
  133.   rc = DosDevIOCtl( hDriver, 0xA0, 0x36, // Send Ctrl Req
  134.                     (PVOID)&CtrlRequest, ulParmLen, &ulParmLen,
  135.                     ulDataLen>0?(PVOID)pData:NULL,
  136.                     ulDataLen,
  137.                     ulDataLen>0?&ulDataLen:NULL);
  138.   if(rc)
  139.     printf("Send Ctrl Req, rc=%d\r\n",rc);
  140.   if(ulDataLen && (pReq->bRequestType &0x80)== 0x80)
  141.   {
  142.     printf("Returned Data: ");
  143.     for(i=0;i<ulDataLen;i++)
  144.     {
  145.       printf("%02X ",*(pData+i));
  146.       if(((i+1)%16)==0)
  147.        printf("\r\n               ");
  148.     }
  149.     printf("\r\n");
  150.   }
  151.   return rc;
  152. }
  153.  
  154. int ulReadHeader(HFILE hDrv, LNK_HEADER *pHeader)
  155. {
  156.   ULONG ulActual;
  157.   int rc;
  158.   rc = DosRead(hDrv, pHeader, sizeof(LNK_HEADER), &ulActual);
  159.   {
  160.    printf("DosRead rc=%d ulActual %d\r\n",rc, ulActual);
  161.     return 1;
  162.   }
  163.   if(ulActual != sizeof(LNK_HEADER))
  164.     return 2;
  165.   if(pHeader->ulMagic != PLUSMAGIC)
  166.     return 3;
  167.   return 0;
  168. }
  169.  
  170. ULONG ulGetStatus(HFILE hDrv)
  171. {
  172.   LNK_STATUS USBStatus;
  173.   ULONG ulActual, lrc;
  174.   int rc;
  175.   rc = ulReadHeader(hDrv, &USBStatus.Header);
  176.   if(rc)
  177.     return rc;
  178.   if(USBStatus.Header.ulTag != LNK_TAG_STATUS ||
  179.      USBStatus.Header.ulLength != sizeof(ULONG) )
  180.     return 4;
  181.   rc = DosRead(hDrv, &USBStatus.ulStatus, sizeof(ULONG), &ulActual);
  182.   if(sizeof(ULONG)!=ulActual)
  183.     return 5;
  184.   return USBStatus.ulStatus;
  185. }
  186.  
  187. int SendStatus(HFILE hDrv, ULONG ulStatus)
  188. {
  189.   LNK_STATUS USBStatus;
  190.   ULONG ulActual;
  191.   int rc;
  192.   USBStatus.Header.ulMagic  = PLUSMAGIC;
  193.   USBStatus.Header.ulTag    = LNK_TAG_STATUS;
  194.   USBStatus.Header.ulLength = sizeof(ULONG);
  195.   USBStatus.ulStatus        = ulStatus;
  196.   rc = DosWrite(hDrv, &USBStatus, sizeof(USBStatus), &ulActual);
  197.   if(rc)
  198.     return rc;
  199.   if(ulActual != sizeof(USBStatus))
  200.     return 0xdeadbeef;
  201.   return 0;
  202. }
  203.  
  204. int SendAccept(HFILE hDrv, HFILE hLocFile)
  205. {
  206.   LNK_FILE_ACCEPT FileAccept;
  207.   ULONG ulActual;
  208.   int rc;
  209.  
  210.   FileAccept.Header.ulMagic  = PLUSMAGIC;
  211.   FileAccept.Header.ulTag    = LNK_TAG_FILE_ACCEPT;
  212.   FileAccept.Header.ulLength = sizeof(ULONG);
  213.   FileAccept.ulHandle        = (ULONG)hLocFile;
  214.   rc = DosWrite(hDrv, &FileAccept, sizeof(FileAccept), &ulActual);
  215.   if(rc)
  216.     return rc;
  217.   if(ulActual != sizeof(FileAccept))
  218.     return 0xdeadbeef;
  219.   return 0;
  220. }
  221.  
  222. int ReadAccept(HFILE hDrv, ULONG *pulHandle)
  223. {
  224.   LNK_FILE_ACCEPT FileAccept;
  225.   ULONG ulActual;
  226.   int rc;
  227.  
  228.   rc = ulReadHeader(hDrv, &FileAccept.Header);
  229.   if(rc)
  230.     return rc;
  231.   if(FileAccept.Header.ulTag!=LNK_TAG_FILE_ACCEPT)
  232.     return 108;
  233.   rc = DosRead(hDrv, &FileAccept.ulHandle, sizeof(ULONG), &ulActual);
  234.   if(ulActual != sizeof(ULONG))
  235.     return 0xdeadbeef;
  236.   *pulHandle = FileAccept.ulHandle;
  237.   return 0;
  238. }
  239.  
  240. int ReadFileBlock(HFILE hDrv, HFILE hLocFile)
  241. {
  242.   LNK_FILE_DATA *pData;
  243.   int rc;
  244.   LNK_HEADER Header;
  245.   ULONG ulActual;
  246.  
  247.   rc = ulReadHeader(hDrv,&Header);
  248.   if(rc)
  249.   {
  250.     printf("Error %d reading Header",rc);
  251.     return rc;
  252.   }
  253.   if(LNK_TAG_FILE_DATA !=Header.ulTag)
  254.   {
  255.     printf("Error Wrong Tag %d ",Header.ulTag);
  256.     return rc;
  257.   }
  258.   if(Header.ulLength <8)
  259.   {
  260.     printf("Wrong Datasize %d",Header.ulLength);
  261.     return 102;
  262.   }
  263.   pData = (LNK_FILE_DATA*) malloc(Header.ulLength+ sizeof(Header) );
  264.   rc = DosRead(hDrv,&pData->ulHandle, Header.ulLength, &ulActual);
  265.   if(!rc)
  266.     rc = DosWrite(hLocFile,&pData->ucData[0],Header.ulLength-4, &ulActual);
  267.   SendStatus(hDrv,rc);
  268.   free (pData);
  269.   return rc;
  270. }
  271.  
  272. int SendFileBlock(HFILE hDrv, HFILE hLocFile, ULONG ulRemoteHandle, ULONG ulLength)
  273. {
  274.   LNK_FILE_DATA *pData;
  275.   int rc;
  276.   ULONG ulActual, ulStat;
  277.  
  278.   pData = (LNK_FILE_DATA*) malloc( ulLength + sizeof(LNK_HEADER) + 4);
  279.   pData->Header.ulMagic  = PLUSMAGIC;
  280.   pData->Header.ulTag    = LNK_TAG_FILE_DATA;
  281.   pData->Header.ulLength = ulLength+4;
  282.   pData->ulHandle = ulRemoteHandle;
  283.   rc = DosRead(hLocFile,&pData->ucData[0], ulLength, &ulActual);
  284.   if(!rc)
  285.     rc = DosWrite(hDrv,pData,ulLength+4+sizeof(LNK_HEADER), &ulActual);
  286.   else
  287.     return rc;
  288.   free(pData);
  289.   ulStat = ulGetStatus(hDrv);
  290.   return ulStat;
  291. }
  292.  
  293.  
  294. void RecvFile(HFILE hDrv)
  295. {
  296.   int rc;
  297.   HFILE hLocFile;
  298.   LNK_FILE_NAME FileName;
  299.   ULONG ulActual,ulAction, ulBytesRecv=0;
  300.   char  ch;
  301.   rc = ulReadHeader(hDrv,&FileName.Header);
  302.   if(rc)
  303.   {
  304.     printf("Error %d reading Header",rc);
  305.     return;
  306.   }
  307.   if(LNK_TAG_FILE_NAME !=FileName.Header.ulTag)
  308.   {
  309.     printf("Error Wrong Tag %d ",FileName.Header.ulTag);
  310.     return;
  311.   }
  312.   if(FileName.Header.ulLength !=sizeof(FileName)-sizeof(FileName.Header))
  313.   {
  314.     printf("Error Wrong DataSize %d ",FileName.Header.ulLength);
  315.     return;
  316.   }
  317.  
  318.   rc = DosRead( hDrv,
  319.                 &FileName.ulFileSize,
  320.                 sizeof(FileName)-sizeof(FileName.Header),
  321.                 &ulActual);
  322.   if(rc)
  323.   {
  324.     printf("Error %d reading Filename",rc);
  325.     return;
  326.   }
  327.  
  328.   if(ulActual !=(sizeof(FileName)-sizeof(FileName.Header)))
  329.   {
  330.     printf("Not all Data read %d ",ulActual);
  331.     return;
  332.   }
  333.  
  334.   printf("Receive File %s Size %d Bytes (Y/N)\r\n ?",
  335.          FileName.szFileName,FileName.ulFileSize);
  336.   do
  337.   {
  338.     ch = toupper(_getch());
  339.   }while(ch!='Y' && ch!='N');
  340.  
  341.   if(ch=='N')
  342.   {
  343.     SendStatus(hDrv,1111);
  344.     return;
  345.   }
  346.   rc = DosOpen( (PCSZ)&FileName.szFileName[0],
  347.                 &hLocFile,
  348.                 &ulAction,
  349.                 FileName.ulFileSize,
  350.                 FILE_NORMAL,
  351.                 OPEN_ACTION_OPEN_IF_EXISTS,
  352.                 OPEN_ACCESS_READWRITE |
  353.                 OPEN_FLAGS_NOINHERIT |
  354.                 OPEN_SHARE_DENYNONE,
  355.                 0 );
  356.   if(rc)
  357.   {
  358.     printf("Error %d opening local File\r\n",rc);
  359.     SendStatus(hDrv,100);
  360.   }
  361.   rc = SendStatus(hDrv,0);
  362.   if(rc)
  363.   {
  364.     DosClose(hLocFile);
  365.     printf("Error %d sending Status\r\n",rc);
  366.     return;
  367.   }
  368.   rc = SendAccept(hDrv, hLocFile);
  369.   if(rc)
  370.   {
  371.     DosClose(hLocFile);
  372.     printf("Error %d sending Accept\r\n",rc);
  373.     return;
  374.   }
  375.  
  376.   while (!rc && ulBytesRecv<FileName.ulFileSize)
  377.   {
  378.     rc = ReadFileBlock(hDrv,hLocFile);
  379.   }
  380.   DosClose(hLocFile);
  381.   if(rc)
  382.   {
  383.     printf("Error %d during File transfer.\r\n");
  384.   }
  385. }
  386.  
  387. void SendFile(HFILE hDrv, char* szFileName)
  388. {
  389.   char * pszLastPathDel;
  390.   char * pColon;
  391.   char * pszRemoteName;
  392.   HFILE  hLocFile;
  393.   int rc;
  394.   ULONG ulAction, ulRemoteHandle, ulBytesToSend,ulActual;
  395.   LNK_FILE_NAME FileName;
  396.   FILESTATUS3  fsts3ConfigInfo = {{0}};       /* Buffer for file information */
  397.   ULONG        ulBufSize     = sizeof(FILESTATUS3);  /* Size of above buffer */
  398.  
  399.   pColon = strrchr(szFileName,':');
  400.   pszLastPathDel = strrchr(szFileName,'\\');
  401.   if(pszLastPathDel>=pColon)
  402.     if(pszLastPathDel==NULL)
  403.       pszRemoteName = szFileName;
  404.     else
  405.       pszRemoteName = pszLastPathDel+1;
  406.   else
  407.     pszRemoteName = pColon;
  408.  
  409.   FileName.Header.ulMagic  = PLUSMAGIC;
  410.   FileName.Header.ulTag    = LNK_TAG_FILE_NAME;
  411.   FileName.Header.ulLength = sizeof(FileName)-sizeof(FileName.Header);
  412.   memset(&FileName.szFileName[0],0,sizeof(FileName.szFileName) );
  413.   strcpy((PSZ)&FileName.szFileName[0],pszRemoteName);
  414.  
  415.   rc = DosOpen( szFileName,
  416.                 &hLocFile,
  417.                 &ulAction,
  418.                 0,
  419.                 FILE_READONLY,
  420.                 OPEN_ACTION_FAIL_IF_NEW|
  421.                 OPEN_ACTION_OPEN_IF_EXISTS,
  422.                 OPEN_ACCESS_READONLY |
  423.                 OPEN_FLAGS_NOINHERIT |
  424.                 OPEN_SHARE_DENYNONE,
  425.                 0 );
  426.   if(rc)
  427.   {
  428.     printf("Error %d opening source file %s",rc,szFileName);
  429.     return;
  430.   }
  431.  
  432.   rc = DosQueryFileInfo(hLocFile,
  433.                         FIL_STANDARD,
  434.                         &fsts3ConfigInfo,
  435.                         ulBufSize);
  436.   if (rc)
  437.   {
  438.     DosClose(hLocFile);
  439.     printf("DosQueryFileInfo error: return code = %u\n", rc);
  440.     return;
  441.   }
  442.   FileName.ulFileSize      = fsts3ConfigInfo.cbFile;
  443.   printf("Sending Header for file %s of Size %d",FileName.szFileName,FileName.ulFileSize);
  444.   rc = DosWrite(hDrv,&FileName, sizeof(FileName), &ulActual);
  445.   if(rc)
  446.   {
  447.     printf("Error %d sending fileheader\r\n",rc);
  448.     DosClose(hLocFile);
  449.     return;
  450.   }
  451.   rc = ulGetStatus(hDrv);
  452.   if(rc)
  453.   {
  454.     printf("Error %d getting status\r\n",rc);
  455.     DosClose(hLocFile);
  456.     return;
  457.   }
  458.   rc = ReadAccept(hDrv,&ulRemoteHandle);
  459.   if(rc)
  460.   {
  461.     printf("Error %d getting RemoteHandle\r\n",rc);
  462.     DosClose(hLocFile);
  463.     return;
  464.   }
  465.   ulBytesToSend = FileName.ulFileSize;
  466.   while(!rc && ulBytesToSend)
  467.   {
  468.     ULONG ulNumBytes = ulBytesToSend>64*1024?64*1024:ulBytesToSend;
  469.     rc = SendFileBlock(hDrv, hLocFile, ulRemoteHandle, ulNumBytes);
  470.     if(!rc)
  471.       ulBytesToSend -= ulNumBytes;
  472.   }
  473.   if(rc)
  474.   {
  475.     printf("Error %d during send file\r\n",rc);
  476.   }
  477. }
  478.  
  479. void main(int argc, char *argv[])
  480. {
  481.   int rc,i;
  482.   ULONG ulAction, ulParmLen, ulDataLen, ulUSBHandle, *pData;
  483.   AQUIREDEV  USBDevice;
  484.   SETUPPACKET SPConfigure;
  485.   UCHAR ucBuffer[640];
  486.  
  487.   if(argc >2)
  488.   {
  489.     printf("Usage:\r\n-To Receive %s\r\n-To Send %s filename",argv[0],argv[0]);
  490.     return;
  491.   }
  492.   if(argc==2)
  493.   {
  494.     char ch;
  495.     printf("Press S to send File %s to the other PC\r\nPress X to Exit\r\n", argv[1]);
  496.     do
  497.     {
  498.       ch = toupper(_getch());
  499.     }
  500.     while(ch !='S' && ch!= 'X');
  501.     if(ch=='X')
  502.       return;
  503.   }
  504.  
  505.   rc = DosOpen( "USBRESM$",
  506.                 &hDriver,
  507.                 &ulAction,
  508.                 0,
  509.                 FILE_NORMAL,
  510.                 OPEN_ACTION_OPEN_IF_EXISTS,
  511.                 OPEN_ACCESS_READWRITE |
  512.                 OPEN_FLAGS_NOINHERIT |
  513.                 OPEN_SHARE_DENYNONE,
  514.                 0 );
  515.   if(rc)
  516.     printf("Open returned %d\r\n",rc);
  517.   else
  518.     printf("Driver opened\r\n");
  519.   ulDataLen = sizeof(ulUSBHandle);
  520.   ulUSBHandle = 0;
  521.   rc = DosDevIOCtl( hDriver, 0xA0, 0x31, // Aquire Device
  522.                     NULL,0,0,
  523.                     (PVOID)&ulUSBHandle, ulDataLen, &ulDataLen);
  524.   if(rc)
  525.     printf("Error getting number of USB devices\r\n");
  526.   else
  527.     printf("%d USB Devices\r\n",ulUSBHandle);
  528.  
  529.   if(!rc)
  530.   {
  531.     USBDevice.usVendorID  = 0x067B;
  532.     USBDevice.usDeviceID  = 0x0000;
  533.     USBDevice.usBCDDevice = 0xFFFF; //0x0007;
  534.     USBDevice.usDeviceNumber = 0; // Get the usDeviceNumber device in the system fi. if 2 aquire the 2nd device
  535.     ulParmLen = sizeof(USBDevice);
  536.     ulDataLen = sizeof(ulUSBHandle);
  537.     ulUSBHandle = 0xdeadbeef;
  538.     rc = DosDevIOCtl( hDriver, 0xA0, 0x33, // Aquire Device
  539.                       (PVOID)&USBDevice, ulParmLen, &ulParmLen,
  540.                       (PVOID)&ulUSBHandle, ulDataLen, &ulDataLen);
  541.     if(rc)
  542.       printf("Aquire returned %d Handle is 0x%08x\r\n",rc,ulUSBHandle);
  543.   }
  544.  
  545.   if(!rc && ulUSBHandle!=0)
  546.   {
  547.     UCHAR ucData[20];
  548.     SPConfigure.bRequestType = 0; // standard
  549.     SPConfigure.bRequest     = 9; // Set config
  550.     SPConfigure.wValue       = 1;
  551.     SPConfigure.wIndex       = 0;
  552.     SPConfigure.wLength      = 0;
  553.     SPConfigure.ulTimeout    = 0;
  554.  
  555.     printf("Set Configuration ... ");
  556.     rc = sendCtrlReq( ulUSBHandle, &SPConfigure, NULL);
  557.     if(rc)
  558.       printf("failed rc=%d\r\n",rc);
  559.     else
  560.       printf("Ok!\r\n");
  561.     memset(ucData,0,sizeof(ucData));
  562.     SPConfigure.bRequestType = 0x80; // standard
  563.     SPConfigure.bRequest     = 0x08; // Get config
  564.     SPConfigure.wValue       = 0;
  565.     SPConfigure.wIndex       = 0;
  566.     SPConfigure.wLength      = 1;
  567.     SPConfigure.ulTimeout    = 0;
  568.     printf("Get Configuration ... ");
  569.     rc = sendCtrlReq( ulUSBHandle, &SPConfigure, ucData);
  570.     if(rc)
  571.       printf("failed rc=%d\r\n",rc);
  572.     else
  573.       printf("Ok!\r\n");
  574.     SPConfigure.bRequestType = 0x41; // Vendor
  575.     SPConfigure.bRequest     = 0x01; // SetQuickLink Feature;
  576.     SPConfigure.wValue       = 1; // Peer exits
  577.     SPConfigure.wIndex       = 0;
  578.     SPConfigure.wLength      = 0;
  579.     SPConfigure.ulTimeout    = 0;
  580.     printf("SetQuickLinkFeature ... ");
  581.     rc = sendCtrlReq( ulUSBHandle, &SPConfigure, NULL);
  582.     if(rc)
  583.       printf("failed rc=%d\r\n",rc);
  584.     else
  585.       printf("Ok!\r\n");
  586.  
  587.     if(argc==2)
  588.     {
  589.       SendFile(hDriver,argv[1]);
  590.     }
  591.     else
  592.     {
  593.       RecvFile(hDriver);
  594.     }
  595.  
  596.     ulParmLen = sizeof(ulUSBHandle);
  597.     ulDataLen = 0;
  598.     rc = DosDevIOCtl( hDriver, 0xA0, 0x34, // Release Device
  599.                       (PVOID)&ulUSBHandle, ulParmLen, &ulParmLen,
  600.                       NULL, ulDataLen, &ulDataLen);
  601.   }
  602.  
  603.   DosClose(hDriver);
  604. }
  605.