PageRenderTime 67ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/libusbK/src/kBench/kBench.c

http://usb-travis.googlecode.com/
C | 2049 lines | 1593 code | 301 blank | 155 comment | 356 complexity | 57a59ecd824523bd8083cb8196dbf8f2 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*!********************************************************************
  2. libusbK - kBench USB benchmark/diagnostic tool.
  3. Copyright (C) 2012 Travis Lee Robinson. All Rights Reserved.
  4. libusb-win32.sourceforge.net
  5. Development : Travis Lee Robinson (libusbdotnet@gmail.com)
  6. Testing : Xiaofan Chen (xiaofanc@gmail.com)
  7. At the discretion of the user of this library, this software may be
  8. licensed under the terms of the GNU Public License v3 or a BSD-Style
  9. license as outlined in the following files:
  10. * LICENSE-gpl3.txt
  11. * LICENSE-bsd.txt
  12. License files are located in a license folder at the root of source and
  13. binary distributions.
  14. ********************************************************************!*/
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <conio.h>
  19. #include <wtypes.h>
  20. #include "libusbk.h"
  21. #include "lusbk_version.h"
  22. #include "lusbk_linked_list.h"
  23. // warning C4127: conditional expression is constant.
  24. #pragma warning(disable: 4127)
  25. #define COMPOSITE_MERGE_MODE 1
  26. #define MAX_OUTSTANDING_TRANSFERS 10
  27. #define USB_ENDPOINT_ADDRESS_MASK 0x0F
  28. // This is used only in VerifyData() for display information
  29. // about data validation mismatches.
  30. #define CONVDAT(format,...) printf("[data-mismatch] " format,__VA_ARGS__)
  31. // All output is directed through these macros.
  32. //
  33. #define LOG(LogTypeString,format,...) printf("%s[" __FUNCTION__ "] "format, LogTypeString, __VA_ARGS__)
  34. #define LOG_NO_FN(LogTypeString,format,...) printf("%s" format "%s",LogTypeString,__VA_ARGS__,"")
  35. #define CONERR(format,...) LOG("Error:",format,__VA_ARGS__)
  36. #define CONMSG(format,...) LOG_NO_FN("",format,__VA_ARGS__)
  37. #define CONWRN(format,...) LOG("Warn:",format,__VA_ARGS__)
  38. #define CONDBG(format,...) LOG_NO_FN("",format,__VA_ARGS__)
  39. #define CONERR0(message) CONERR("%s", message)
  40. #define CONMSG0(message) CONMSG("%s", message)
  41. #define CONWRN0(message) CONWRN("%s", message)
  42. #define CONDBG0(message) CONDBG("%s", message)
  43. static LPCSTR DrvIdNames[8] = {"libusbK", "libusb0", "WinUSB", "libusb0 filter", "Unknown", "Unknown", "Unknown"};
  44. #define GetDrvIdString(DriverID) (DrvIdNames[((((LONG)(DriverID))<0) || ((LONG)(DriverID)) >= KUSB_DRVID_COUNT)?KUSB_DRVID_COUNT:(DriverID)])
  45. static LPCSTR DevSpeedStrings[4] = {"Unknown", "Low/Full", "Unknown", "High"};
  46. #define GetDevSpeedString(DevSpeed) (DevSpeedStrings[(DevSpeed) & 0x3])
  47. #define VerifyListLock(mTest) while(InterlockedExchange(&((mTest)->VerifyLock),1) != 0) Sleep(0)
  48. #define VerifyListUnlock(mTest) InterlockedExchange(&((mTest)->VerifyLock),0)
  49. KUSB_DRIVER_API K;
  50. typedef struct _BENCHMARK_BUFFER
  51. {
  52. PUCHAR Data;
  53. LONG DataLength;
  54. LONG SyncFailed;
  55. struct _BENCHMARK_BUFFER* prev;
  56. struct _BENCHMARK_BUFFER* next;
  57. } BENCHMARK_BUFFER, *PBENCHMARK_BUFFER;
  58. // Custom vendor requests that must be implemented in the benchmark firmware.
  59. // Test selection can be bypassed with the "notestselect" argument.
  60. //
  61. typedef enum _BENCHMARK_DEVICE_COMMAND
  62. {
  63. SET_TEST = 0x0E,
  64. GET_TEST = 0x0F,
  65. } BENCHMARK_DEVICE_COMMAND, *PBENCHMARK_DEVICE_COMMAND;
  66. // Tests supported by the official benchmark firmware.
  67. //
  68. typedef enum _BENCHMARK_DEVICE_TEST_TYPE
  69. {
  70. TestTypeNone = 0x00,
  71. TestTypeRead = 0x01,
  72. TestTypeWrite = 0x02,
  73. TestTypeLoop = TestTypeRead | TestTypeWrite,
  74. } BENCHMARK_DEVICE_TEST_TYPE, *PBENCHMARK_DEVICE_TEST_TYPE;
  75. // This software was mainly created for testing the libusb-win32 kernel & user driver.
  76. typedef enum _BENCHMARK_TRANSFER_MODE
  77. {
  78. // Tests for the libusb-win32 sync transfer function.
  79. TRANSFER_MODE_SYNC,
  80. // Test for async function, iso transfers, and queued transfers
  81. TRANSFER_MODE_ASYNC,
  82. } BENCHMARK_TRANSFER_MODE;
  83. // Holds all of the information about a test.
  84. typedef struct _BENCHMARK_TEST_PARAM
  85. {
  86. // User configurable value set from the command line.
  87. //
  88. INT Vid; // Vendor ID
  89. INT Pid; // Porduct ID
  90. INT Intf; // Interface number
  91. INT Altf; // Alt Interface number
  92. INT Ep; // Endpoint number (1-15)
  93. INT Refresh; // Refresh interval (ms)
  94. INT Timeout; // Transfer timeout (ms)
  95. INT Retry; // Number for times to retry a timed out transfer before aborting
  96. INT AllocBufferSize; // Number of bytes to transfer
  97. INT ReadLength;
  98. INT WriteLength;
  99. INT BufferCount; // Number of outstanding asynchronous transfers
  100. BOOL NoTestSelect; // If true, don't send control message to select the test type.
  101. BOOL UseList; // Show the user a device list and let them choose a benchmark device.
  102. INT FixedIsoPackets; // Number of fixed packets to use for ISO writes. Ignored for read eps.
  103. INT Priority; // Priority to run this thread at.
  104. BOOL Verify; // Only for loop and read test. If true, verifies data integrity.
  105. BOOL VerifyDetails; // If true, prints detailed information for each invalid byte.
  106. enum BENCHMARK_DEVICE_TEST_TYPE TestType; // The benchmark test type.
  107. enum BENCHMARK_TRANSFER_MODE TransferMode; // Sync or Async
  108. // Internal value use during the test.
  109. //
  110. KLST_HANDLE DeviceList;
  111. KLST_DEVINFO_HANDLE SelectedDeviceProfile;
  112. HANDLE DeviceHandle;
  113. KUSB_HANDLE InterfaceHandle;
  114. USB_DEVICE_DESCRIPTOR DeviceDescriptor;
  115. USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
  116. WINUSB_PIPE_INFORMATION PipeInformation[32];
  117. BOOL IsCancelled;
  118. BOOL IsUserAborted;
  119. BYTE* VerifyBuffer; // Stores the verify test pattern for 1 packet.
  120. WORD VerifyBufferSize; // Size of VerifyBuffer
  121. BOOL Use_UsbK_Init;
  122. BOOL ListDevicesOnly;
  123. ULONG DeviceSpeed;
  124. BOOL ReadLogEnabled;
  125. FILE* ReadLogFile;
  126. BOOL WriteLogEnabled;
  127. FILE* WriteLogFile;
  128. volatile long VerifyLock;
  129. BENCHMARK_BUFFER* VerifyList;
  130. BOOL IsLoopSynced;
  131. UCHAR UseRawIO;
  132. } BENCHMARK_TEST_PARAM, *PBENCHMARK_TEST_PARAM;
  133. // The benchmark transfer context used for asynchronous transfers. see TransferAsync().
  134. typedef struct _BENCHMARK_TRANSFER_HANDLE
  135. {
  136. OVERLAPPED Overlapped;
  137. BOOL InUse;
  138. PUCHAR Data;
  139. INT DataMaxLength;
  140. INT ReturnCode;
  141. } BENCHMARK_TRANSFER_HANDLE, *PBENCHMARK_TRANSFER_HANDLE;
  142. #pragma warning(disable:4200)
  143. // Holds all of the information about a transfer.
  144. typedef struct _BENCHMARK_TRANSFER_PARAM
  145. {
  146. PBENCHMARK_TEST_PARAM Test;
  147. HANDLE ThreadHandle;
  148. DWORD ThreadID;
  149. WINUSB_PIPE_INFORMATION Ep;
  150. BOOL IsRunning;
  151. LONGLONG TotalTransferred;
  152. LONG LastTransferred;
  153. LONG Packets;
  154. DWORD StartTick;
  155. DWORD LastTick;
  156. DWORD LastStartTick;
  157. INT TotalTimeoutCount;
  158. INT RunningTimeoutCount;
  159. INT TotalErrorCount;
  160. INT RunningErrorCount;
  161. INT ShortTransferCount;
  162. INT TransferHandleNextIndex;
  163. INT TransferHandleWaitIndex;
  164. INT OutstandingTransferCount;
  165. BENCHMARK_TRANSFER_HANDLE TransferHandles[MAX_OUTSTANDING_TRANSFERS];
  166. // Placeholder for end of structure; this is where the raw data for the
  167. // transfer buffer is allocated.
  168. //
  169. UCHAR Buffer[0];
  170. } BENCHMARK_TRANSFER_PARAM, *PBENCHMARK_TRANSFER_PARAM;
  171. #include <pshpack1.h>
  172. typedef struct _KBENCH_CONTEXT_LSTK
  173. {
  174. BYTE Selected;
  175. } KBENCH_CONTEXT_LSTK, *PKBENCH_CONTEXT_LSTK;
  176. #include <poppack.h>
  177. #pragma warning(default:4200)
  178. // Benchmark device api.
  179. BOOL Bench_Open(__in PBENCHMARK_TEST_PARAM test);
  180. BOOL Bench_Configure(__in KUSB_HANDLE handle,
  181. __in BENCHMARK_DEVICE_COMMAND command,
  182. __in UCHAR intf,
  183. __deref_inout PBENCHMARK_DEVICE_TEST_TYPE testType);
  184. // Critical section for running status.
  185. CRITICAL_SECTION DisplayCriticalSection;
  186. // Finds the interface for [interface_number] in a libusb-win32 config descriptor.
  187. // If first_interface is not NULL, it is set to the first interface in the config.
  188. //
  189. // Internal function used by the benchmark application.
  190. void ShowHelp(void);
  191. void ShowCopyright(void);
  192. void SetTestDefaults(PBENCHMARK_TEST_PARAM test);
  193. int GetTestDeviceFromArgs(PBENCHMARK_TEST_PARAM test);
  194. int GetTestDeviceFromList(PBENCHMARK_TEST_PARAM test);
  195. char* GetParamStrValue(const char* src, const char* paramName);
  196. BOOL GetParamIntValue(const char* src, const char* paramName, INT* returnValue);
  197. int ValidateBenchmarkArgs(PBENCHMARK_TEST_PARAM test);
  198. int ParseBenchmarkArgs(PBENCHMARK_TEST_PARAM testParams, int argc, char** argv);
  199. void FreeTransferParam(PBENCHMARK_TRANSFER_PARAM* testTransferRef);
  200. PBENCHMARK_TRANSFER_PARAM CreateTransferParam(PBENCHMARK_TEST_PARAM test, int endpointID);
  201. void GetAverageBytesSec(PBENCHMARK_TRANSFER_PARAM transferParam, DOUBLE* bps);
  202. void GetCurrentBytesSec(PBENCHMARK_TRANSFER_PARAM transferParam, DOUBLE* bps);
  203. void ShowRunningStatus(PBENCHMARK_TRANSFER_PARAM transferParam);
  204. void ShowTestInfo(PBENCHMARK_TEST_PARAM test);
  205. void ShowTransferInfo(PBENCHMARK_TRANSFER_PARAM transferParam);
  206. void WaitForTestTransfer(PBENCHMARK_TRANSFER_PARAM transferParam);
  207. void ResetRunningStatus(PBENCHMARK_TRANSFER_PARAM transferParam);
  208. // The thread transfer routine.
  209. DWORD TransferThreadProc(PBENCHMARK_TRANSFER_PARAM transferParams);
  210. #define TRANSFER_DISPLAY(TransferParam, ReadingString, WritingString) \
  211. ((TransferParam->Ep.PipeId & USB_ENDPOINT_DIRECTION_MASK) ? ReadingString : WritingString)
  212. #define INC_ROLL(IncField, RollOverValue) if ((++IncField) >= RollOverValue) IncField = 0
  213. #define ENDPOINT_TYPE(TransferParam) (TransferParam->Ep.PipeType & 3)
  214. const char* TestDisplayString[] = {"None", "Read", "Write", "Loop", NULL};
  215. const char* EndpointTypeDisplayString[] = {"Control", "Isochronous", "Bulk", "Interrupt", NULL};
  216. LONG WinError(__in_opt DWORD errorCode)
  217. {
  218. LPSTR buffer = NULL;
  219. errorCode = errorCode ? labs(errorCode) : GetLastError();
  220. if (!errorCode) return errorCode;
  221. if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  222. NULL, errorCode, 0, (LPSTR)&buffer, 0, NULL) > 0)
  223. {
  224. CONERR("%s\n", buffer);
  225. SetLastError(0);
  226. }
  227. else
  228. {
  229. CONERR("FormatMessage error!\n");
  230. }
  231. if (buffer)
  232. LocalFree(buffer);
  233. return -labs(errorCode);
  234. }
  235. void SetTestDefaults(PBENCHMARK_TEST_PARAM test)
  236. {
  237. memset(test, 0, sizeof(*test));
  238. test->Ep = 0x00;
  239. test->Vid = 0x04D8;
  240. test->Pid = 0xFA2E;
  241. test->Refresh = 1000;
  242. test->Timeout = 5000;
  243. test->TestType = TestTypeLoop;
  244. test->AllocBufferSize = 4096;
  245. test->ReadLength = test->AllocBufferSize;
  246. test->WriteLength = test->AllocBufferSize;
  247. test->BufferCount = 1;
  248. test->Priority = THREAD_PRIORITY_NORMAL;
  249. test->Intf = -1;
  250. test->Altf = -1;
  251. test->UseRawIO = 0xFF;
  252. }
  253. VOID AppendLoopBuffer(PBENCHMARK_TEST_PARAM Test, PUCHAR data, LONG dataLength)
  254. {
  255. if (Test->Verify && Test->TestType == TestTypeLoop)
  256. {
  257. BENCHMARK_BUFFER* newVerifyBuf = malloc(sizeof(BENCHMARK_BUFFER) + dataLength);
  258. memset(newVerifyBuf, 0, sizeof(BENCHMARK_BUFFER));
  259. newVerifyBuf->Data = &(((PUCHAR)newVerifyBuf)[sizeof(BENCHMARK_BUFFER)]);
  260. newVerifyBuf->DataLength = dataLength;
  261. memcpy(newVerifyBuf->Data, data, dataLength);
  262. VerifyListLock(Test);
  263. DL_APPEND(Test->VerifyList, newVerifyBuf);
  264. VerifyListUnlock(Test);
  265. }
  266. }
  267. BOOL Bench_Open(__in PBENCHMARK_TEST_PARAM test)
  268. {
  269. UCHAR altSetting;
  270. KUSB_HANDLE associatedHandle;
  271. UINT transferred;
  272. KLST_DEVINFO_HANDLE deviceInfo;
  273. test->SelectedDeviceProfile = NULL;
  274. LstK_MoveReset(test->DeviceList);
  275. while (LstK_MoveNext(test->DeviceList, &deviceInfo))
  276. {
  277. // enabled
  278. UINT userContext = (UINT)LibK_GetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK);
  279. if (userContext != TRUE) continue;
  280. if (!LibK_LoadDriverAPI(&K, deviceInfo->DriverID))
  281. {
  282. WinError(0);
  283. CONWRN("could not load driver api %s.\n", GetDrvIdString(deviceInfo->DriverID));
  284. continue;
  285. }
  286. if (!test->Use_UsbK_Init)
  287. {
  288. test->DeviceHandle = CreateFileA(deviceInfo->DevicePath,
  289. GENERIC_READ | GENERIC_WRITE,
  290. FILE_SHARE_READ | FILE_SHARE_WRITE,
  291. NULL,
  292. OPEN_EXISTING,
  293. FILE_FLAG_OVERLAPPED,
  294. NULL);
  295. if (!test->DeviceHandle || test->DeviceHandle == INVALID_HANDLE_VALUE)
  296. {
  297. WinError(0);
  298. test->DeviceHandle = NULL;
  299. CONWRN("could not create device handle.\n%s\n", deviceInfo->DevicePath);
  300. continue;
  301. }
  302. if (!K.Initialize(test->DeviceHandle, &test->InterfaceHandle))
  303. {
  304. WinError(0);
  305. CloseHandle(test->DeviceHandle);
  306. test->DeviceHandle = NULL;
  307. test->InterfaceHandle = NULL;
  308. CONWRN("could not initialize device.\n%s\n", deviceInfo->DevicePath);
  309. continue;
  310. }
  311. }
  312. else
  313. {
  314. if (!K.Init(&test->InterfaceHandle, deviceInfo))
  315. {
  316. WinError(0);
  317. test->DeviceHandle = NULL;
  318. test->InterfaceHandle = NULL;
  319. CONWRN("could not open device.\n%s\n", deviceInfo->DevicePath);
  320. continue;
  321. }
  322. }
  323. if (!K.GetDescriptor(test->InterfaceHandle,
  324. USB_DESCRIPTOR_TYPE_DEVICE,
  325. 0, 0,
  326. (PUCHAR)&test->DeviceDescriptor,
  327. sizeof(test->DeviceDescriptor),
  328. &transferred))
  329. {
  330. WinError(0);
  331. K.Free(test->InterfaceHandle);
  332. test->InterfaceHandle = NULL;
  333. if (!test->Use_UsbK_Init)
  334. {
  335. CloseHandle(test->DeviceHandle);
  336. test->DeviceHandle = NULL;
  337. }
  338. CONWRN("could not get device descriptor.\n%s\n", deviceInfo->DevicePath);
  339. continue;
  340. }
  341. test->Vid = (INT)test->DeviceDescriptor.idVendor;
  342. test->Pid = (INT)test->DeviceDescriptor.idProduct;
  343. NextInterface:
  344. // While searching for hardware specifics we are also gathering information and storing it
  345. // in our test.
  346. memset(&test->InterfaceDescriptor, 0, sizeof(test->InterfaceDescriptor));
  347. altSetting = 0;
  348. while(K.QueryInterfaceSettings(test->InterfaceHandle, altSetting, &test->InterfaceDescriptor))
  349. {
  350. // found an interface
  351. UCHAR pipeIndex = 0;
  352. int hasIsoEndpoints = 0;
  353. int hasZeroMaxPacketEndpoints = 0;
  354. memset(&test->PipeInformation, 0, sizeof(test->PipeInformation));
  355. while(K.QueryPipe(test->InterfaceHandle, altSetting, pipeIndex, &test->PipeInformation[pipeIndex]))
  356. {
  357. // found a pipe
  358. if (test->PipeInformation[pipeIndex].PipeType == UsbdPipeTypeIsochronous)
  359. hasIsoEndpoints++;
  360. if (!test->PipeInformation[pipeIndex].MaximumPacketSize)
  361. hasZeroMaxPacketEndpoints++;
  362. pipeIndex++;
  363. }
  364. // -1 means the user din't specifiy so we find the most suitable device.
  365. //
  366. if ( (( test->Intf == -1) || (test->Intf == test->InterfaceDescriptor.bInterfaceNumber)) &&
  367. (( test->Altf == -1) || (test->Altf == test->InterfaceDescriptor.bAlternateSetting)) )
  368. {
  369. // if the user actually specifies an alt iso setting with zero MaxPacketEndpoints
  370. // we let let them.
  371. if (test->Altf == -1 && hasIsoEndpoints && hasZeroMaxPacketEndpoints)
  372. {
  373. // user didn't specfiy and we know we can't tranfer with this alt setting so skip it.
  374. CONMSG("skipping interface %02X:%02X. zero-length iso endpoints exist.\n",
  375. test->InterfaceDescriptor.bInterfaceNumber,
  376. test->InterfaceDescriptor.bAlternateSetting);
  377. }
  378. else
  379. {
  380. // this is the one we are looking for.
  381. test->Intf = test->InterfaceDescriptor.bInterfaceNumber;
  382. test->Altf = test->InterfaceDescriptor.bAlternateSetting;
  383. test->SelectedDeviceProfile = deviceInfo;
  384. // some buffering is required for iso.
  385. if (hasIsoEndpoints && test->BufferCount == 1)
  386. test->BufferCount++;
  387. if (!K.SetCurrentAlternateSetting(test->InterfaceHandle, test->InterfaceDescriptor.bAlternateSetting))
  388. {
  389. CONERR("failed selecting alternate setting %02Xh\n", test->Altf);
  390. return FALSE;
  391. }
  392. return TRUE;
  393. }
  394. }
  395. altSetting++;
  396. memset(&test->InterfaceDescriptor, 0, sizeof(test->InterfaceDescriptor));
  397. }
  398. if (K.GetAssociatedInterface(test->InterfaceHandle, 0, &associatedHandle))
  399. {
  400. // this device has more interfaces to look at.
  401. //
  402. K.Free(test->InterfaceHandle);
  403. test->InterfaceHandle = associatedHandle;
  404. goto NextInterface;
  405. }
  406. // This one didn't match the test specifics; continue on to the next potential match.
  407. K.Free(test->InterfaceHandle);
  408. test->InterfaceHandle = NULL;
  409. }
  410. CONERR("device interface/alt interface not found (%02Xh/%02Xh).\n", test->Intf, test->Altf);
  411. return FALSE;
  412. }
  413. BOOL Bench_Configure(__in KUSB_HANDLE handle,
  414. __in BENCHMARK_DEVICE_COMMAND command,
  415. __in UCHAR intf,
  416. __deref_inout PBENCHMARK_DEVICE_TEST_TYPE testType)
  417. {
  418. UCHAR buffer[1];
  419. UINT transferred = 0;
  420. WINUSB_SETUP_PACKET Pkt;
  421. KUSB_SETUP_PACKET* defPkt = (KUSB_SETUP_PACKET*)&Pkt;
  422. memset(&Pkt, 0, sizeof(Pkt));
  423. defPkt->BmRequest.Dir = BMREQUEST_DIR_DEVICE_TO_HOST;
  424. defPkt->BmRequest.Type = BMREQUEST_TYPE_VENDOR;
  425. defPkt->Request = (UCHAR)command;
  426. defPkt->Value = (UCHAR) * testType;
  427. defPkt->Index = intf;
  428. defPkt->Length = 1;
  429. if (!handle || handle == INVALID_HANDLE_VALUE)
  430. return WinError(ERROR_INVALID_HANDLE);
  431. if (K.ControlTransfer(handle, Pkt, buffer, 1, &transferred, NULL))
  432. {
  433. if (transferred)
  434. return TRUE;
  435. }
  436. return WinError(0);
  437. }
  438. INT VerifyData(PBENCHMARK_TRANSFER_PARAM transferParam, BYTE* data, INT dataLength)
  439. {
  440. WORD verifyDataSize = transferParam->Test->VerifyBufferSize;
  441. BYTE* verifyData = transferParam->Test->VerifyBuffer;
  442. BYTE keyC = 0;
  443. BOOL seedKey = TRUE;
  444. INT dataLeft = dataLength;
  445. INT dataIndex = 0;
  446. INT packetIndex = 0;
  447. INT verifyIndex = 0;
  448. while(dataLeft > 1)
  449. {
  450. verifyDataSize = dataLeft > transferParam->Test->VerifyBufferSize ? transferParam->Test->VerifyBufferSize : (WORD)dataLeft;
  451. if (seedKey)
  452. keyC = data[dataIndex + 1];
  453. else
  454. {
  455. if (data[dataIndex + 1] == 0)
  456. {
  457. keyC = 0;
  458. }
  459. else
  460. {
  461. keyC++;
  462. }
  463. }
  464. seedKey = FALSE;
  465. // Index 0 is always 0.
  466. // The key is always at index 1
  467. verifyData[1] = keyC;
  468. if (memcmp(&data[dataIndex], verifyData, verifyDataSize) != 0)
  469. {
  470. // Packet verification failed.
  471. // Reset the key byte on the next packet.
  472. seedKey = TRUE;
  473. CONVDAT("Packet=#%d Data=#%d\n", packetIndex, dataIndex);
  474. if (transferParam->Test->VerifyDetails)
  475. {
  476. for (verifyIndex = 0; verifyIndex < verifyDataSize; verifyIndex++)
  477. {
  478. if (verifyData[verifyIndex] == data[dataIndex + verifyIndex])
  479. continue;
  480. CONVDAT("packet-offset=%d expected %02Xh got %02Xh\n",
  481. verifyIndex,
  482. verifyData[verifyIndex],
  483. data[dataIndex + verifyIndex]);
  484. }
  485. }
  486. }
  487. // Move to the next packet.
  488. packetIndex++;
  489. dataLeft -= verifyDataSize;
  490. dataIndex += verifyDataSize;
  491. }
  492. return 0;
  493. }
  494. int TransferSync(PBENCHMARK_TRANSFER_PARAM transferParam)
  495. {
  496. UINT transferred;
  497. BOOL success;
  498. if (transferParam->Ep.PipeId & USB_ENDPOINT_DIRECTION_MASK)
  499. {
  500. success = K.ReadPipe(transferParam->Test->InterfaceHandle,
  501. transferParam->Ep.PipeId,
  502. transferParam->Buffer,
  503. transferParam->Test->ReadLength,
  504. &transferred,
  505. NULL);
  506. }
  507. else
  508. {
  509. AppendLoopBuffer(transferParam->Test, transferParam->Buffer, transferParam->Test->WriteLength);
  510. success = K.WritePipe(transferParam->Test->InterfaceHandle,
  511. transferParam->Ep.PipeId,
  512. transferParam->Buffer,
  513. transferParam->Test->WriteLength,
  514. &transferred,
  515. NULL);
  516. }
  517. return success ? (int)transferred : -labs(GetLastError());
  518. }
  519. int TransferAsync(PBENCHMARK_TRANSFER_PARAM transferParam, PBENCHMARK_TRANSFER_HANDLE* handleRef)
  520. {
  521. int ret = 0;
  522. BOOL success;
  523. PBENCHMARK_TRANSFER_HANDLE handle;
  524. DWORD transferErrorCode;
  525. *handleRef = NULL;
  526. // Submit transfers until the maximum number of outstanding transfer(s) is reached.
  527. while (transferParam->OutstandingTransferCount < transferParam->Test->BufferCount)
  528. {
  529. // Get the next available benchmark transfer handle.
  530. *handleRef = handle = &transferParam->TransferHandles[transferParam->TransferHandleNextIndex];
  531. // If a libusb-win32 transfer context hasn't been setup for this benchmark transfer
  532. // handle, do it now.
  533. //
  534. if (!handle->Overlapped.hEvent)
  535. {
  536. handle->Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  537. // Data buffer(s) are located at the end of the transfer param.
  538. handle->Data = transferParam->Buffer + (transferParam->TransferHandleNextIndex * transferParam->Test->AllocBufferSize);
  539. }
  540. else
  541. {
  542. // re-initialize and re-use the overlapped
  543. HANDLE h = handle->Overlapped.hEvent;
  544. ResetEvent(h);
  545. memset(&handle->Overlapped, 0, sizeof(handle->Overlapped));
  546. handle->Overlapped.hEvent = h;
  547. }
  548. if (transferParam->Ep.PipeId & USB_ENDPOINT_DIRECTION_MASK)
  549. {
  550. handle->DataMaxLength = transferParam->Test->ReadLength;
  551. success = K.ReadPipe(transferParam->Test->InterfaceHandle,
  552. transferParam->Ep.PipeId,
  553. handle->Data,
  554. handle->DataMaxLength,
  555. NULL,
  556. &handle->Overlapped);
  557. }
  558. else
  559. {
  560. AppendLoopBuffer(transferParam->Test, handle->Data, transferParam->Test->WriteLength);
  561. handle->DataMaxLength = transferParam->Test->WriteLength;
  562. success = K.WritePipe(transferParam->Test->InterfaceHandle,
  563. transferParam->Ep.PipeId,
  564. handle->Data,
  565. handle->DataMaxLength,
  566. NULL,
  567. &handle->Overlapped);
  568. }
  569. transferErrorCode = GetLastError();
  570. if (!success && transferErrorCode == ERROR_IO_PENDING)
  571. {
  572. transferErrorCode = ERROR_SUCCESS;
  573. success = TRUE;
  574. }
  575. // Submit this transfer now.
  576. handle->ReturnCode = ret = -labs(transferErrorCode);
  577. if (ret < 0)
  578. {
  579. handle->InUse = FALSE;
  580. goto Done;
  581. }
  582. // Mark this handle has InUse.
  583. handle->InUse = TRUE;
  584. // When transfers ir successfully submitted, OutstandingTransferCount goes up; when
  585. // they are completed it goes down.
  586. //
  587. transferParam->OutstandingTransferCount++;
  588. // Move TransferHandleNextIndex to the next available transfer.
  589. INC_ROLL(transferParam->TransferHandleNextIndex, transferParam->Test->BufferCount);
  590. }
  591. // If the number of outstanding transfers has reached the limit, wait for the
  592. // oldest outstanding transfer to complete.
  593. //
  594. if (transferParam->OutstandingTransferCount == transferParam->Test->BufferCount)
  595. {
  596. UINT transferred;
  597. // TransferHandleWaitIndex is the index of the oldest outstanding transfer.
  598. *handleRef = handle = &transferParam->TransferHandles[transferParam->TransferHandleWaitIndex];
  599. // Only wait, cancelling & freeing is handled by the caller.
  600. if (WaitForSingleObject(handle->Overlapped.hEvent, transferParam->Test->Timeout) != WAIT_OBJECT_0)
  601. {
  602. if (!transferParam->Test->IsUserAborted)
  603. ret = WinError(0);
  604. else
  605. ret = -labs(GetLastError());
  606. handle->ReturnCode = ret;
  607. goto Done;
  608. }
  609. if (!K.GetOverlappedResult(transferParam->Test->InterfaceHandle, &handle->Overlapped, &transferred, FALSE))
  610. {
  611. if (!transferParam->Test->IsUserAborted)
  612. ret = WinError(0);
  613. else
  614. ret = -labs(GetLastError());
  615. handle->ReturnCode = ret;
  616. goto Done;
  617. }
  618. handle->ReturnCode = ret = (DWORD)transferred;
  619. if (ret < 0) goto Done;
  620. // Mark this handle has no longer InUse.
  621. handle->InUse = FALSE;
  622. // When transfers ir successfully submitted, OutstandingTransferCount goes up; when
  623. // they are completed it goes down.
  624. //
  625. transferParam->OutstandingTransferCount--;
  626. // Move TransferHandleWaitIndex to the oldest outstanding transfer.
  627. INC_ROLL(transferParam->TransferHandleWaitIndex, transferParam->Test->BufferCount);
  628. }
  629. Done:
  630. return ret;
  631. }
  632. VOID VerifyLoopData(PBENCHMARK_TEST_PARAM Test, PUCHAR chData, int dataRemaining)
  633. {
  634. LONG syncOffset = 0;
  635. PUCHAR dataBuffer = chData;
  636. int dataLength = dataRemaining;
  637. VerifyListLock(Test);
  638. if (dataRemaining)
  639. {
  640. int verifyStageSize;
  641. PBENCHMARK_BUFFER writeVerifyBuffer, tmpWriteVerifyBuffer;
  642. DL_FOREACH_SAFE(Test->VerifyList, writeVerifyBuffer, tmpWriteVerifyBuffer)
  643. {
  644. if (!Test->IsLoopSynced)
  645. {
  646. verifyStageSize = min(writeVerifyBuffer->DataLength, dataRemaining);
  647. while(verifyStageSize > 0)
  648. {
  649. Test->IsLoopSynced = memcmp(writeVerifyBuffer->Data, chData, verifyStageSize) == 0 ? TRUE : FALSE;
  650. if (Test->IsLoopSynced) break;
  651. syncOffset++;
  652. dataRemaining--;
  653. chData++;
  654. verifyStageSize = min(writeVerifyBuffer->DataLength, dataRemaining);
  655. }
  656. if (!Test->IsLoopSynced)
  657. {
  658. chData = dataBuffer;
  659. dataRemaining = dataLength;
  660. if (writeVerifyBuffer->SyncFailed++ == 0)
  661. {
  662. writeVerifyBuffer = NULL;
  663. }
  664. }
  665. else
  666. {
  667. float reliability = ((float)verifyStageSize / (float)dataLength) * 100.0F;
  668. CONMSG("Loop data synchronized. Offset=%u Byte=%02Xh Reliability=%.1f%%.\n",
  669. syncOffset, chData[0], reliability);
  670. }
  671. }
  672. if (Test->IsLoopSynced)
  673. {
  674. verifyStageSize = min(writeVerifyBuffer->DataLength, dataRemaining);
  675. if (memcmp(writeVerifyBuffer->Data, chData, verifyStageSize) == 0)
  676. {
  677. writeVerifyBuffer->DataLength -= verifyStageSize;
  678. dataRemaining -= verifyStageSize;
  679. writeVerifyBuffer->Data += verifyStageSize;
  680. chData = &chData[verifyStageSize];
  681. }
  682. else
  683. {
  684. CONVDAT("DataLength=%u\n", writeVerifyBuffer->DataLength);
  685. Test->IsLoopSynced = FALSE;
  686. if (writeVerifyBuffer->SyncFailed++ == 0)
  687. {
  688. // Do not delete the verify buffer until it fails to verify once before.
  689. writeVerifyBuffer = NULL;
  690. dataRemaining = 0;
  691. }
  692. }
  693. }
  694. if (dataRemaining == 0)
  695. break;
  696. }
  697. if (!Test->IsLoopSynced)
  698. {
  699. CONVDAT("Loop data not in sync.\n");
  700. }
  701. // If writeVerifyBuffer is not null at this point, all buffers before it are deleted.
  702. // if writeVerifyBuffer.DataLength == 0, it is also deleted.
  703. if (writeVerifyBuffer && Test->VerifyList)
  704. {
  705. PBENCHMARK_BUFFER writeVerifyBufferDel, tmpWriteVerifyBuffer;
  706. DL_FOREACH_SAFE(Test->VerifyList, writeVerifyBufferDel, tmpWriteVerifyBuffer)
  707. {
  708. if (writeVerifyBuffer != writeVerifyBufferDel)
  709. {
  710. DL_DELETE(Test->VerifyList, writeVerifyBufferDel);
  711. free(writeVerifyBufferDel);
  712. }
  713. else
  714. {
  715. if (writeVerifyBufferDel->DataLength <= 0)
  716. {
  717. DL_DELETE(Test->VerifyList, writeVerifyBufferDel);
  718. free(writeVerifyBufferDel);
  719. }
  720. break;
  721. }
  722. }
  723. }
  724. }
  725. VerifyListUnlock(Test);
  726. }
  727. DWORD TransferThreadProc(PBENCHMARK_TRANSFER_PARAM transferParam)
  728. {
  729. int ret, i;
  730. PBENCHMARK_TRANSFER_HANDLE handle;
  731. PUCHAR data;
  732. transferParam->IsRunning = TRUE;
  733. K.ResetPipe(transferParam->Test->InterfaceHandle, transferParam->Ep.PipeId);
  734. while (!transferParam->Test->IsCancelled)
  735. {
  736. data = NULL;
  737. handle = NULL;
  738. if (transferParam->Test->TransferMode == TRANSFER_MODE_SYNC)
  739. {
  740. ret = TransferSync(transferParam);
  741. if (ret >= 0) data = transferParam->Buffer;
  742. }
  743. else if (transferParam->Test->TransferMode == TRANSFER_MODE_ASYNC)
  744. {
  745. ret = TransferAsync(transferParam, &handle);
  746. if ((handle) && ret >= 0) data = handle->Data;
  747. }
  748. else
  749. {
  750. CONERR("invalid transfer mode %d\n", transferParam->Test->TransferMode);
  751. goto Done;
  752. }
  753. if (transferParam->Test->Verify &&
  754. transferParam->Test->VerifyList &&
  755. transferParam->Test->TestType == TestTypeLoop &&
  756. USB_ENDPOINT_DIRECTION_IN(transferParam->Ep.PipeId) && ret > 0)
  757. {
  758. VerifyLoopData(transferParam->Test, data, ret);
  759. }
  760. if (ret < 0)
  761. {
  762. // The user pressed 'Q'.
  763. if (transferParam->Test->IsUserAborted) break;
  764. // Transfer timed out
  765. if (ret == ERROR_SEM_TIMEOUT || ret == ERROR_OPERATION_ABORTED || ret == ERROR_CANCELLED)
  766. {
  767. transferParam->TotalTimeoutCount++;
  768. transferParam->RunningTimeoutCount++;
  769. CONWRN("Timeout #%d %s on Ep%02Xh..\n",
  770. transferParam->RunningTimeoutCount,
  771. TRANSFER_DISPLAY(transferParam, "reading", "writing"),
  772. transferParam->Ep.PipeId);
  773. if (transferParam->RunningTimeoutCount > transferParam->Test->Retry)
  774. break;
  775. }
  776. else
  777. {
  778. // An error (other than a timeout) occured.
  779. transferParam->TotalErrorCount++;
  780. transferParam->RunningErrorCount++;
  781. CONERR("failed %s! %d of %d ret=%d\n",
  782. TRANSFER_DISPLAY(transferParam, "reading", "writing"),
  783. transferParam->RunningErrorCount,
  784. transferParam->Test->Retry + 1,
  785. ret);
  786. K.ResetPipe(transferParam->Test->InterfaceHandle, transferParam->Ep.PipeId);
  787. if (transferParam->RunningErrorCount > transferParam->Test->Retry)
  788. break;
  789. }
  790. ret = 0;
  791. }
  792. else
  793. {
  794. transferParam->RunningErrorCount = 0;
  795. transferParam->RunningTimeoutCount = 0;
  796. if (USB_ENDPOINT_DIRECTION_IN(transferParam->Ep.PipeId))
  797. {
  798. if (transferParam->Test->ReadLogFile)
  799. {
  800. fwrite(data, ret, 1, transferParam->Test->ReadLogFile);
  801. }
  802. if (transferParam->Test->Verify && transferParam->Test->TestType != TestTypeLoop)
  803. {
  804. VerifyData(transferParam, data, ret);
  805. }
  806. }
  807. else
  808. {
  809. if (transferParam->Test->WriteLogFile)
  810. {
  811. fwrite(data, ret, 1, transferParam->Test->WriteLogFile);
  812. }
  813. }
  814. }
  815. EnterCriticalSection(&DisplayCriticalSection);
  816. if (!transferParam->StartTick && transferParam->Packets >= 0)
  817. {
  818. transferParam->StartTick = GetTickCount();
  819. transferParam->LastStartTick = transferParam->StartTick;
  820. transferParam->LastTick = transferParam->StartTick;
  821. transferParam->LastTransferred = 0;
  822. transferParam->TotalTransferred = 0;
  823. transferParam->Packets = 0;
  824. }
  825. else
  826. {
  827. if (!transferParam->LastStartTick)
  828. {
  829. transferParam->LastStartTick = transferParam->LastTick;
  830. transferParam->LastTransferred = 0;
  831. }
  832. transferParam->LastTick = GetTickCount();
  833. transferParam->LastTransferred += ret;
  834. transferParam->TotalTransferred += ret;
  835. transferParam->Packets++;
  836. }
  837. LeaveCriticalSection(&DisplayCriticalSection);
  838. }
  839. Done:
  840. for (i = 0; i < transferParam->Test->BufferCount; i++)
  841. {
  842. if (transferParam->TransferHandles[i].Overlapped.hEvent)
  843. {
  844. if (transferParam->TransferHandles[i].InUse)
  845. {
  846. if (!K.AbortPipe(
  847. transferParam->Test->InterfaceHandle, transferParam->Ep.PipeId) &&
  848. !transferParam->Test->IsUserAborted)
  849. {
  850. ret = WinError(0);
  851. CONERR("failed cancelling transfer! ret=%d\n", ret);
  852. }
  853. else
  854. {
  855. CloseHandle(transferParam->TransferHandles[i].Overlapped.hEvent);
  856. transferParam->TransferHandles[i].Overlapped.hEvent = NULL;
  857. transferParam->TransferHandles[i].InUse = FALSE;
  858. }
  859. }
  860. Sleep(0);
  861. }
  862. }
  863. for (i = 0; i < transferParam->Test->BufferCount; i++)
  864. {
  865. if (transferParam->TransferHandles[i].Overlapped.hEvent)
  866. {
  867. if (transferParam->TransferHandles[i].InUse)
  868. {
  869. WaitForSingleObject(transferParam->TransferHandles[i].Overlapped.hEvent, transferParam->Test->Timeout);
  870. }
  871. else
  872. {
  873. WaitForSingleObject(transferParam->TransferHandles[i].Overlapped.hEvent, 0);
  874. }
  875. CloseHandle(transferParam->TransferHandles[i].Overlapped.hEvent);
  876. transferParam->TransferHandles[i].Overlapped.hEvent = NULL;
  877. }
  878. transferParam->TransferHandles[i].InUse = FALSE;
  879. }
  880. transferParam->IsRunning = FALSE;
  881. return 0;
  882. }
  883. char* GetParamStrValue(const char* src, const char* paramName)
  884. {
  885. return (strstr(src, paramName) == src) ? (char*)(src + strlen(paramName)) : NULL;
  886. }
  887. BOOL GetParamIntValue(const char* src, const char* paramName, INT* returnValue)
  888. {
  889. char* value = GetParamStrValue(src, paramName);
  890. if (value)
  891. {
  892. *returnValue = strtol(value, NULL, 0);
  893. return TRUE;
  894. }
  895. return FALSE;
  896. }
  897. int ValidateBenchmarkArgs(PBENCHMARK_TEST_PARAM test)
  898. {
  899. if (test->BufferCount < 1 || test->BufferCount > MAX_OUTSTANDING_TRANSFERS)
  900. {
  901. CONERR("Invalid BufferCount argument %d. BufferCount must be greater than 0 and less than or equal to %d.\n",
  902. test->BufferCount, MAX_OUTSTANDING_TRANSFERS);
  903. return -1;
  904. }
  905. return 0;
  906. }
  907. int ParseBenchmarkArgs(PBENCHMARK_TEST_PARAM testParams, int argc, char** argv)
  908. {
  909. #define GET_INT_VAL
  910. char arg[MAX_PATH];
  911. char* value;
  912. int iarg;
  913. for (iarg = 1; iarg < argc; iarg++)
  914. {
  915. if (strcpy_s(arg, _countof(arg), argv[iarg]) != ERROR_SUCCESS)
  916. return -1;
  917. _strlwr_s(arg, MAX_PATH);
  918. if (GetParamIntValue(arg, "vid=", &testParams->Vid)) {}
  919. else if (GetParamIntValue(arg, "pid=", &testParams->Pid)) {}
  920. else if (GetParamIntValue(arg, "retry=", &testParams->Retry)) {}
  921. else if (GetParamIntValue(arg, "buffercount=", &testParams->BufferCount))
  922. {
  923. if (testParams->BufferCount > 1)
  924. testParams->TransferMode = TRANSFER_MODE_ASYNC;
  925. }
  926. else if (GetParamIntValue(arg, "buffersize=", &testParams->AllocBufferSize) ||
  927. GetParamIntValue(arg, "size=", &testParams->AllocBufferSize))
  928. {
  929. if (testParams->ReadLength == 4096)
  930. testParams->ReadLength = testParams->AllocBufferSize;
  931. if (testParams->WriteLength == 4096)
  932. testParams->WriteLength = testParams->AllocBufferSize;
  933. }
  934. else if (GetParamIntValue(arg, "readsize=", &testParams->ReadLength)) {}
  935. else if (GetParamIntValue(arg, "writesize=", &testParams->WriteLength)) {}
  936. else if (GetParamIntValue(arg, "timeout=", &testParams->Timeout)) {}
  937. else if (GetParamIntValue(arg, "intf=", &testParams->Intf)) {}
  938. else if (GetParamIntValue(arg, "altf=", &testParams->Altf)) {}
  939. else if (GetParamIntValue(arg, "ep=", &testParams->Ep))
  940. {
  941. testParams->Ep &= 0xf;
  942. }
  943. else if (GetParamIntValue(arg, "refresh=", &testParams->Refresh)) {}
  944. else if (GetParamIntValue(arg, "fixedisopackets=", &testParams->FixedIsoPackets)) {}
  945. else if ((value = GetParamStrValue(arg, "mode=")) != NULL)
  946. {
  947. if (GetParamStrValue(value, "sync"))
  948. {
  949. testParams->TransferMode = TRANSFER_MODE_SYNC;
  950. }
  951. else if (GetParamStrValue(value, "async"))
  952. {
  953. testParams->TransferMode = TRANSFER_MODE_ASYNC;
  954. }
  955. else
  956. {
  957. // Invalid EndpointType argument.
  958. CONERR("invalid transfer mode argument! %s\n", argv[iarg]);
  959. return -1;
  960. }
  961. }
  962. else if ((value = GetParamStrValue(arg, "priority=")) != NULL)
  963. {
  964. if (GetParamStrValue(value, "lowest"))
  965. {
  966. testParams->Priority = THREAD_PRIORITY_LOWEST;
  967. }
  968. else if (GetParamStrValue(value, "belownormal"))
  969. {
  970. testParams->Priority = THREAD_PRIORITY_BELOW_NORMAL;
  971. }
  972. else if (GetParamStrValue(value, "normal"))
  973. {
  974. testParams->Priority = THREAD_PRIORITY_NORMAL;
  975. }
  976. else if (GetParamStrValue(value, "abovenormal"))
  977. {
  978. testParams->Priority = THREAD_PRIORITY_ABOVE_NORMAL;
  979. }
  980. else if (GetParamStrValue(value, "highest"))
  981. {
  982. testParams->Priority = THREAD_PRIORITY_HIGHEST;
  983. }
  984. else
  985. {
  986. CONERR("invalid priority argument! %s\n", argv[iarg]);
  987. return -1;
  988. }
  989. }
  990. else if ((value = GetParamStrValue(arg, "rawio=")) != NULL)
  991. {
  992. if (GetParamStrValue(value, "t") ||
  993. GetParamStrValue(value, "y") ||
  994. GetParamStrValue(value, "1"))
  995. {
  996. testParams->UseRawIO = 1;
  997. }
  998. else
  999. {
  1000. testParams->UseRawIO = 0;
  1001. }
  1002. }
  1003. else if (!_stricmp(arg, "notestselect"))
  1004. {
  1005. testParams->NoTestSelect = TRUE;
  1006. }
  1007. else if (!_stricmp(arg, "logread"))
  1008. {
  1009. testParams->ReadLogEnabled = TRUE;
  1010. }
  1011. else if (!_stricmp(arg, "logwrite"))
  1012. {
  1013. testParams->WriteLogEnabled = TRUE;
  1014. }
  1015. else if (!_stricmp(arg, "log"))
  1016. {
  1017. testParams->ReadLogEnabled = TRUE;
  1018. testParams->WriteLogEnabled = TRUE;
  1019. }
  1020. else if (!_stricmp(arg, "read"))
  1021. {
  1022. testParams->TestType = TestTypeRead;
  1023. }
  1024. else if (!_stricmp(arg, "write"))
  1025. {
  1026. testParams->TestType = TestTypeWrite;
  1027. }
  1028. else if (!_stricmp(arg, "loop"))
  1029. {
  1030. testParams->TestType = TestTypeLoop;
  1031. }
  1032. else if (!_stricmp(arg, "listonly"))
  1033. {
  1034. testParams->UseList = TRUE;
  1035. testParams->ListDevicesOnly = TRUE;
  1036. }
  1037. else if (!_stricmp(arg, "list"))
  1038. {
  1039. testParams->UseList = TRUE;
  1040. }
  1041. else if (!_stricmp(arg, "verifydetails"))
  1042. {
  1043. testParams->VerifyDetails = TRUE;
  1044. testParams->Verify = TRUE;
  1045. }
  1046. else if (!_stricmp(arg, "verify"))
  1047. {
  1048. testParams->Verify = TRUE;
  1049. }
  1050. else if (!_stricmp(arg, "composite"))
  1051. {
  1052. testParams->Use_UsbK_Init = TRUE;
  1053. }
  1054. else
  1055. {
  1056. CONERR("invalid argument! %s\n", argv[iarg]);
  1057. return -1;
  1058. }
  1059. }
  1060. return ValidateBenchmarkArgs(testParams);
  1061. }
  1062. INT CreateVerifyBuffer(PBENCHMARK_TEST_PARAM test, WORD endpointMaxPacketSize)
  1063. {
  1064. int i;
  1065. BYTE indexC = 0;
  1066. test->VerifyBuffer = malloc(endpointMaxPacketSize);
  1067. if (!test->VerifyBuffer)
  1068. {
  1069. CONERR("memory allocation failure at line %d!\n", __LINE__);
  1070. return -1;
  1071. }
  1072. test->VerifyBufferSize = endpointMaxPacketSize;
  1073. for(i = 0; i < endpointMaxPacketSize; i++)
  1074. {
  1075. test->VerifyBuffer[i] = indexC++;
  1076. if (indexC == 0) indexC = 1;
  1077. }
  1078. return 0;
  1079. }
  1080. void FreeTransferParam(PBENCHMARK_TRANSFER_PARAM* testTransferRef)
  1081. {
  1082. PBENCHMARK_TRANSFER_PARAM pTransferParam;
  1083. if ((!testTransferRef) || !*testTransferRef) return;
  1084. pTransferParam = *testTransferRef;
  1085. if (pTransferParam->ThreadHandle)
  1086. {
  1087. CloseHandle(pTransferParam->ThreadHandle);
  1088. pTransferParam->ThreadHandle = NULL;
  1089. }
  1090. free(pTransferParam);
  1091. *testTransferRef = NULL;
  1092. }
  1093. PBENCHMARK_TRANSFER_PARAM CreateTransferParam(PBENCHMARK_TEST_PARAM test, int endpointID)
  1094. {
  1095. PBENCHMARK_TRANSFER_PARAM transferParam = NULL;
  1096. int i;
  1097. int allocSize;
  1098. PWINUSB_PIPE_INFORMATION pipeInfo = NULL;
  1099. /// Get Pipe Information
  1100. for(i = 0; i < test->InterfaceDescriptor.bNumEndpoints; i++)
  1101. {
  1102. if (!(endpointID & USB_ENDPOINT_ADDRESS_MASK))
  1103. {
  1104. // Use first endpoint that matches the direction
  1105. if ((test->PipeInformation[i].PipeId & USB_ENDPOINT_DIRECTION_MASK) == endpointID)
  1106. {
  1107. pipeInfo = &test->PipeInformation[i];
  1108. break;
  1109. }
  1110. }
  1111. else
  1112. {
  1113. if ((int)test->PipeInformation[i].PipeId == endpointID)
  1114. {
  1115. pipeInfo = &test->PipeInformation[i];
  1116. break;
  1117. }
  1118. }
  1119. }
  1120. if (!pipeInfo)
  1121. {
  1122. CONERR("failed locating EP%02Xh!\n", endpointID);
  1123. goto Done;
  1124. }
  1125. if (!pipeInfo->MaximumPacketSize)
  1126. {
  1127. CONWRN("MaximumPacketSize=0 for EP%02Xh. check alternate settings.\n", pipeInfo->PipeId);
  1128. }
  1129. test->AllocBufferSize = max(test->AllocBufferSize, test->ReadLength);
  1130. test->AllocBufferSize = max(test->AllocBufferSize, test->WriteLength);
  1131. allocSize = sizeof(BENCHMARK_TRANSFER_PARAM) + (test->AllocBufferSize * test->BufferCount);
  1132. transferParam = (PBENCHMARK_TRANSFER_PARAM) malloc(allocSize);
  1133. if (transferParam)
  1134. {
  1135. memset(transferParam, 0, allocSize);
  1136. transferParam->Test = test;
  1137. memcpy(&transferParam->Ep, pipeInfo, sizeof(transferParam->Ep));
  1138. if (ENDPOINT_TYPE(transferParam) == USB_ENDPOINT_TYPE_ISOCHRONOUS)
  1139. transferParam->Test->TransferMode = TRANSFER_MODE_ASYNC;
  1140. ResetRunningStatus(transferParam);
  1141. transferParam->ThreadHandle = CreateThread(
  1142. NULL,
  1143. 0,
  1144. (LPTHREAD_START_ROUTINE)TransferThreadProc,
  1145. transferParam,
  1146. CREATE_SUSPENDED,
  1147. &transferParam->ThreadID);
  1148. if (!transferParam->ThreadHandle)
  1149. {
  1150. CONERR0("failed creating thread!\n");
  1151. FreeTransferParam(&transferParam);
  1152. goto Done;
  1153. }
  1154. // If verify mode is on, this is a loop test, and this is a write endpoint, fill
  1155. // the buffers with the same test data sent by a benchmark device when running
  1156. // a read only test.
  1157. if (transferParam->Test->TestType == TestTypeLoop && USB_ENDPOINT_DIRECTION_OUT(pipeInfo->PipeId))
  1158. {
  1159. // Data Format:
  1160. // [0][KeyByte] 2 3 4 5 ..to.. wMaxPacketSize (if data byte rolls it is incremented to 1)
  1161. // Increment KeyByte and repeat
  1162. //
  1163. BYTE indexC = 0;
  1164. INT bufferIndex = 0;
  1165. WORD dataIndex;
  1166. INT packetIndex;
  1167. INT packetCount = ((transferParam->Test->BufferCount * test->ReadLength) / pipeInfo->MaximumPacketSize);
  1168. for(packetIndex = 0; packetIndex < packetCount; packetIndex++)
  1169. {
  1170. indexC = 2;
  1171. for (dataIndex = 0; dataIndex < pipeInfo->MaximumPacketSize; dataIndex++)
  1172. {
  1173. if (dataIndex == 0) // Start
  1174. transferParam->Buffer[bufferIndex] = 0;
  1175. else if (dataIndex == 1) // Key
  1176. transferParam->Buffer[bufferIndex] = packetIndex & 0xFF;
  1177. else // Data
  1178. transferParam->Buffer[bufferIndex] = indexC++;
  1179. // if wMaxPacketSize is > 255, indexC resets to 1.
  1180. if (indexC == 0) indexC = 1;
  1181. bufferIndex++;
  1182. }
  1183. }
  1184. }
  1185. }
  1186. Done:
  1187. if (!transferParam)
  1188. CONERR0("failed creating transfer param!\n");
  1189. return transferParam;
  1190. }
  1191. void GetAverageBytesSec(PBENCHMARK_TRANSFER_PARAM transferParam, DOUBLE* bps)
  1192. {
  1193. DOUBLE ticksSec;
  1194. if ((!transferParam->StartTick) ||
  1195. (transferParam->StartTick >= transferParam->LastTick) ||
  1196. transferParam->TotalTransferred == 0)
  1197. {
  1198. *bps = 0;
  1199. }
  1200. else
  1201. {
  1202. ticksSec = (transferParam->LastTick - transferParam->StartTick) / 1000.0;
  1203. *bps = (transferParam->TotalTransferred / ticksSec);
  1204. }
  1205. }
  1206. void GetCurrentBytesSec(PBENCHMARK_TRANSFER_PARAM transferParam, DOUBLE* bps)
  1207. {
  1208. DOUBLE ticksSec;
  1209. if ((!transferParam->StartTick) ||
  1210. (!transferParam->LastStartTick) ||
  1211. (transferParam->LastTick <= transferParam->LastStartTick) ||
  1212. transferParam->LastTransferred == 0)
  1213. {
  1214. *bps = 0;
  1215. }
  1216. else
  1217. {
  1218. ticksSec = (transferParam->LastTick - transferParam->LastStartTick) / 1000.0;
  1219. *bps = transferParam->LastTransferred / ticksSec;
  1220. }
  1221. }
  1222. void ShowRunningStatus(PBENCHMARK_TRANSFER_PARAM transferParam)
  1223. {
  1224. static BENCHMARK_TRANSFER_PARAM gRunningStatusTransferParam;
  1225. DOUBLE bpsOverall;
  1226. DOUBLE bpsLastTransfer;
  1227. // LOCK the display critical section
  1228. EnterCriticalSection(&DisplayCriticalSection);
  1229. memcpy(&gRunningStatusTransferParam, transferParam, sizeof(BENCHMARK_TRANSFER_PARAM));
  1230. // UNLOCK the display critical section
  1231. LeaveCriticalSection(&DisplayCriticalSection);
  1232. if ((!gRunningStatusTransferParam.StartTick) || (gRunningStatusTransferParam.StartTick >= gRunningStatusTransferParam.LastTick))
  1233. {
  1234. CONMSG("Synchronizing %d..\n", abs(transferParam->Packets));
  1235. }
  1236. else
  1237. {
  1238. GetAverageBytesSec(&gRunningStatusTransferParam, &bpsOverall);
  1239. GetCurrentBytesSec(&gRunningStatusTransferParam, &bpsLastTransfer);
  1240. transferParam->LastStartTick = 0;
  1241. if (transferParam->LastTransferred == 0)
  1242. {
  1243. CONMSG("Avg. Bytes/s: %.2f Transfers: %d 0 Zero-length-transfer(s)\n",
  1244. bpsOverall, gRunningStatusTransferParam.Packets);
  1245. }
  1246. else
  1247. {
  1248. CONMSG("Avg. Bytes/s: %.2f Transfers: %d Bytes/s: %.2f\n",
  1249. bpsOverall, gRunningStatusTransferParam.Packets, bpsLastTransfer);
  1250. }
  1251. }
  1252. }
  1253. void ShowTransferInfo(PBENCHMARK_TRANSFER_PARAM transferParam)
  1254. {
  1255. DOUBLE bpsAverage;
  1256. DOUBLE bpsCurrent;
  1257. DOUBLE elapsedSeconds;
  1258. if (!transferParam) return;
  1259. CONMSG("%s %s (Ep%02Xh) max packet size: %d\n",
  1260. EndpointTypeDisplayString[ENDPOINT_TYPE(transferParam)],
  1261. TRANSFER_DISPLAY(transferParam, "Read", "Write"),
  1262. transferParam->Ep.PipeId,
  1263. transferParam->Ep.MaximumPacketSize);
  1264. if (transferParam->StartTick)
  1265. {
  1266. GetAverageBytesSec(transferParam, &bpsAverage);
  1267. GetCurrentBytesSec(transferParam, &bpsCurrent);
  1268. CONMSG("\tTotal Bytes : %I64d\n", transferParam->TotalTransferred);
  1269. CONMSG("\tTotal Transfers : %d\n", transferParam->Packets);
  1270. if (transferParam->ShortTransferCount)
  1271. {
  1272. CONMSG("\tShort Transfers : %d\n", transferParam->ShortTransferCount);
  1273. }
  1274. if (transferParam->TotalTimeoutCount)
  1275. {
  1276. CONMSG("\tTimeout Errors : %d\n", transferParam->TotalTimeoutCount);
  1277. }
  1278. if (transferParam->TotalErrorCount)
  1279. {
  1280. CONMSG("\tOther Errors : %d\n", transferParam->TotalErrorCount);
  1281. }
  1282. CONMSG("\tAvg. Bytes/sec : %.2f\n", bpsAverage);
  1283. if (transferParam->StartTick && transferParam->StartTick < transferParam->LastTick)
  1284. {
  1285. elapsedSeconds = (transferParam->LastTick - transferParam->StartTick) / 1000.0;
  1286. CONMSG("\tElapsed Time : %.2f seconds\n", elapsedSeconds);
  1287. }
  1288. CONMSG0("\n");
  1289. }
  1290. }
  1291. void ShowTestInfo(PBENCHMARK_TEST_PARAM test)
  1292. {
  1293. if (!test) return;
  1294. CONMSG("%s Test Information\n", TestDisplayString[test->TestType & 3]);
  1295. CONMSG("\tDriver : %s\n", GetDrvIdString(test->SelectedDeviceProfile->DriverID));
  1296. CONMSG("\tVid / Pid : %04Xh / %04Xh\n", test->DeviceDescriptor.idVendor, test->DeviceDescriptor.idProduct);
  1297. CONMSG("\tDevicePath : %s\n", test->SelectedDeviceProfile->DevicePath);
  1298. CONMSG("\tDevice Speed : %s\n", GetDevSpeedString(test->DeviceSpeed));
  1299. CONMSG("\tInterface # : %02Xh\n", test->InterfaceDescriptor.bInterfaceNumber);
  1300. CONMSG("\tAlt Interface # : %02Xh\n", test->InterfaceDescriptor.bAlternateSetting);
  1301. CONMSG("\tNum Endpoints : %u\n", test->InterfaceDescriptor.bNumEndpoints);
  1302. CONMSG("\tPriority : %d\n", test->Priority);
  1303. CONMSG("\tRead Size : %d\n", test->ReadLength);
  1304. CONMSG("\tWrite Size : %d\n", test->WriteLength);
  1305. CONMSG("\tBuffer Count : %d\n", test->BufferCount);
  1306. CONMSG("\tDisplay Refresh : %d (ms)\n", test->Refresh);
  1307. CONMSG("\tTransfer Timeout: %d (ms)\n", test->Timeout);
  1308. CONMSG("\tRetry Count : %d\n", test->Retry);
  1309. CONMSG("\tVerify Data : %s%s\n",
  1310. test->Verify ? "On" : "Off",
  1311. (test->Verify && test->VerifyDetails) ? " (Detailed)" : "");
  1312. CONMSG0("\n");
  1313. }
  1314. void WaitForTestTransfer(PBENCHMARK_TRANSFER_PARAM transferParam)
  1315. {
  1316. DWORD exitCode;
  1317. while (transferParam)
  1318. {
  1319. if (!transferParam->IsRunning)
  1320. {
  1321. if (GetExitCodeThread(transferParam->ThreadHandle, &exitCode))
  1322. {
  1323. if (exitCode == 0)
  1324. {
  1325. CONMSG("stopped Ep%02Xh thread.\tExitCode=%d\n",
  1326. transferParam->Ep.PipeId, exitCode);
  1327. break;
  1328. }
  1329. }
  1330. else
  1331. {
  1332. CONERR("failed getting Ep%02Xh thread exit code!\n", transferParam->Ep.PipeId);
  1333. break;
  1334. }
  1335. }
  1336. Sleep(100);
  1337. CONMSG("waiting for Ep%02Xh thread..\n", transferParam->Ep.PipeId);
  1338. }
  1339. }
  1340. void ResetRunningStatus(PBENCHMARK_TRANSFER_PARAM transferParam)
  1341. {
  1342. if (!transferParam) return;
  1343. transferParam->StartTick = 0;
  1344. transferParam->TotalTransferred = 0;
  1345. transferParam->Packets = -2;
  1346. transferParam->LastTick = 0;
  1347. transferParam->RunningTimeoutCount = 0;
  1348. }
  1349. int GetTestDeviceFromArgs(PBENCHMARK_TEST_PARAM test)
  1350. {
  1351. CHAR id[MAX_PATH];
  1352. KLST_DEVINFO_HANDLE deviceInfo = NULL;
  1353. LstK_MoveReset(test->DeviceList);
  1354. while (LstK_MoveNext(test->DeviceList, &deviceInfo))
  1355. {
  1356. int vid = -1;
  1357. int pid = -1;
  1358. int mi = -1;
  1359. PCHAR chID;
  1360. // disabled
  1361. LibK_SetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK, (KLIB_USER_CONTEXT)FALSE);
  1362. memset(id, 0, sizeof(id));
  1363. strcpy_s(id, MAX_PATH - 1, deviceInfo->DeviceID);
  1364. _strlwr_s(id, MAX_PATH);
  1365. if ( (chID = strstr(id, "vid_")) != NULL)
  1366. sscanf_s(chID, "vid_%04x", &vid);
  1367. if ( (chID = strstr(id, "pid_")) != NULL)
  1368. sscanf_s(chID, "pid_%04x", &pid);
  1369. if ( (chID = strstr(id, "mi_")) != NULL)
  1370. sscanf_s(chID, "mi_%02x", &mi);
  1371. if (test->Vid == vid && test->Pid == pid)
  1372. {
  1373. // enabled
  1374. LibK_SetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK, (KLIB_USER_CONTEXT)TRUE);
  1375. }
  1376. }
  1377. return ERROR_SUCCESS;
  1378. }
  1379. int GetTestDeviceFromList(PBENCHMARK_TEST_PARAM test)
  1380. {
  1381. UCHAR selection;
  1382. UCHAR count = 0;
  1383. KLST_DEVINFO_HANDLE deviceInfo = NULL;
  1384. LstK_MoveReset(test->DeviceList);
  1385. if (test->ListDevicesOnly)
  1386. {
  1387. while (LstK_MoveNext(test->DeviceList, &deviceInfo))
  1388. {
  1389. count++;
  1390. CONMSG("%02u. %s (%s) [%s]\n", count, deviceInfo->DeviceDesc, deviceInfo->DeviceID, GetDrvIdString(deviceInfo->DriverID));
  1391. }
  1392. return ERROR_SUCCESS;
  1393. }
  1394. else
  1395. {
  1396. while (LstK_MoveNext(test->DeviceList, &deviceInfo) && count < 9)
  1397. {
  1398. CONMSG("%u. %s (%s) [%s]\n", count + 1, deviceInfo->DeviceDesc, deviceInfo->DeviceID, GetDrvIdString(deviceInfo->DriverID));
  1399. count++;
  1400. // enabled
  1401. LibK_SetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK, (KLIB_USER_CONTEXT)TRUE);
  1402. }
  1403. if (!count)
  1404. {
  1405. CONERR("%04Xh:%04Xh device not found\n", test->Vid, test->Pid);
  1406. return -1;
  1407. }
  1408. CONMSG("Select device (1-%u) :", count);
  1409. while(_kbhit()) _getch();
  1410. selection = (CHAR)_getche();
  1411. selection -= (UCHAR)'0';
  1412. CONMSG0("\n\n");
  1413. if (selection > 0 && selection <= count)
  1414. {
  1415. count = 0;
  1416. while (LstK_MoveNext(test->DeviceList, &deviceInfo) && ++count != selection)
  1417. {
  1418. // disabled
  1419. LibK_SetContext(deviceInfo, KLIB_HANDLE_TYPE_LSTINFOK, (KLIB_USER_CONTEXT)FALSE);
  1420. }
  1421. if (!deviceInfo)
  1422. {
  1423. CONERR("unknown selection\n");
  1424. return -1;
  1425. }
  1426. return ERROR_SUCCESS;
  1427. }
  1428. }
  1429. return -1;
  1430. }
  1431. int __cdecl main(int argc, char** argv)
  1432. {
  1433. BENCHMARK_TEST_PARAM Test;
  1434. PBENCHMARK_TRANSFER_PARAM ReadTest = NULL;
  1435. PBENCHMARK_TRANSFER_PARAM WriteTest = NULL;
  1436. int key;
  1437. LONG ec;
  1438. UINT count, length;
  1439. if (argc == 1)
  1440. {
  1441. ShowHelp();

Large files files are truncated, but you can click here to view the full file