VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/usb/UsbTest.cpp@ 58907

Last change on this file since 58907 was 58907, checked in by vboxsync, 9 years ago

ValidationKit/usb: More fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: UsbTest.cpp 58907 2015-11-29 17:06:00Z vboxsync $ */
2/** @file
3 * UsbTest - User frontend for the Linux usbtest USB test and benchmarking module.
4 * Integrates with our test framework for nice outputs.
5 */
6
7/*
8 * Copyright (C) 2014-2015 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * The contents of this file may alternatively be used under the terms
19 * of the Common Development and Distribution License Version 1.0
20 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
21 * VirtualBox OSE distribution, in which case the provisions of the
22 * CDDL are applicable instead of those of the GPL.
23 *
24 * You may elect to license modified versions of this file under the
25 * terms and conditions of either the GPL or the CDDL or both.
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/err.h>
33#include <iprt/getopt.h>
34#include <iprt/path.h>
35#include <iprt/param.h>
36#include <iprt/process.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/test.h>
40#include <iprt/file.h>
41
42#include <unistd.h>
43#include <errno.h>
44#include <limits.h>
45
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49
50#include <sys/ioctl.h>
51#include <linux/usbdevice_fs.h>
52
53
54/*********************************************************************************************************************************
55* Defined Constants And Macros *
56*********************************************************************************************************************************/
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61
62/**
63 * USB test request data.
64 * There is no public header with this information so we define it ourself here.
65 */
66typedef struct USBTESTPARMS
67{
68 /** Specifies the test to run. */
69 uint32_t idxTest;
70 /** How many iterations the test should be executed. */
71 uint32_t cIterations;
72 /** Size of the data packets. */
73 uint32_t cbData;
74 /** Size of */
75 uint32_t cbVariation;
76 /** Length of the S/G list for the test. */
77 uint32_t cSgLength;
78 /** Returned time data after completing the test. */
79 struct timeval TimeTest;
80} USBTESTPARAMS;
81/** Pointer to a test parameter structure. */
82typedef USBTESTPARAMS *PUSBTESTPARAMS;
83
84/**
85 * USB device descriptor. Used to search for the test device based
86 * on the vendor and product id.
87 */
88#pragma pack(1)
89typedef struct USBDEVDESC
90{
91 uint8_t bLength;
92 uint8_t bDescriptorType;
93 uint16_t bcdUSB;
94 uint8_t bDeviceClass;
95 uint8_t bDeviceSubClass;
96 uint8_t bDeviceProtocol;
97 uint8_t bMaxPacketSize0;
98 uint16_t idVendor;
99 uint16_t idProduct;
100 uint16_t bcdDevice;
101 uint8_t iManufacturer;
102 uint8_t iProduct;
103 uint8_t iSerialNumber;
104 uint8_t bNumConfigurations;
105} USBDEVDESC;
106#pragma pack()
107
108#define USBTEST_REQUEST _IOWR('U', 100, USBTESTPARMS)
109
110
111/*********************************************************************************************************************************
112* Global Variables *
113*********************************************************************************************************************************/
114
115/** Command line parameters */
116static const RTGETOPTDEF g_aCmdOptions[] =
117{
118 {"--device", 'd', RTGETOPT_REQ_STRING },
119 {"--help", 'h', RTGETOPT_REQ_NOTHING},
120 {"--exclude", 'e', RTGETOPT_REQ_UINT32}
121};
122
123/**
124 * USB test descriptor.
125 */
126typedef struct USBTESTDESC
127{
128 /** (Sort of) Descriptive test name. */
129 const char *pszName;
130 /** Flag whether the test is excluded. */
131 bool fExcluded;
132} USBTESTDESC;
133/** Pointer a USB test descriptor. */
134typedef USBTESTDESC *PUSBTESTDESC;
135
136static USBTESTDESC g_aTests[] =
137{
138 /* pszTest fExcluded */
139 {"NOP", false},
140 {"Non-queued Bulk write", false},
141 {"Non-queued Bulk read", false},
142 {"Non-queued Bulk write variabe size", false},
143 {"Non-queued Bulk read variabe size", false},
144 {"Queued Bulk write", false},
145 {"Queued Bulk read", false},
146 {"Queued Bulk write variabe size", false},
147 {"Queued Bulk read variabe size", false},
148 {"Chapter 9 Control Test", false},
149 {"Queued control messaging", false},
150 {"Unlink reads", false},
151 {"Unlink writes", false},
152 {"Set/Clear halts", false},
153 {"Control writes", false},
154 {"Isochronous write", false},
155 {"Isochronous read", false},
156 {"Bulk write unaligned (DMA)", false},
157 {"Bulk read unaligned (DMA)", false},
158 {"Bulk write unaligned (no DMA)", false},
159 {"Bulk read unaligned (no DMA)", false},
160 {"Control writes unaligned", false},
161 {"Isochronous write unaligned", false},
162 {"Isochronous read unaligned", false},
163 {"Unlink queued Bulk", false}
164};
165
166/** The test handle. */
167static RTTEST g_hTest;
168
169
170static void usbTestUsage(PRTSTREAM pStrm)
171{
172 char szExec[RTPATH_MAX];
173 RTStrmPrintf(pStrm, "usage: %s [options]\n",
174 RTPathFilename(RTProcGetExecutablePath(szExec, sizeof(szExec))));
175 RTStrmPrintf(pStrm, "\n");
176 RTStrmPrintf(pStrm, "options: \n");
177
178
179 for (unsigned i = 0; i < RT_ELEMENTS(g_aCmdOptions); i++)
180 {
181 const char *pszHelp;
182 switch (g_aCmdOptions[i].iShort)
183 {
184 case 'h':
185 pszHelp = "Displays this help and exit";
186 break;
187 case 'd':
188 pszHelp = "Use the specified test device";
189 break;
190 case 'e':
191 pszHelp = "Exclude the given test id from the list";
192 break;
193 default:
194 pszHelp = "Option undocumented";
195 break;
196 }
197 char szOpt[256];
198 RTStrPrintf(szOpt, sizeof(szOpt), "%s, -%c", g_aCmdOptions[i].pszLong, g_aCmdOptions[i].iShort);
199 RTStrmPrintf(pStrm, " %-20s%s\n", szOpt, pszHelp);
200 }
201}
202
203/**
204 * Search for a USB test device and return the device path.
205 *
206 * @returns Path to the USB test device or NULL if none was found.
207 */
208static char *usbTestFindDevice(void)
209{
210 /*
211 * Very crude and quick way to search for the correct test device.
212 * Assumption is that the path looks like /dev/bus/usb/%3d/%3d.
213 */
214 uint8_t uBus = 1;
215 bool fBusExists = false;
216 char aszDevPath[64];
217
218 RT_ZERO(aszDevPath);
219
220 do
221 {
222 RTStrPrintf(aszDevPath, sizeof(aszDevPath), "/dev/bus/usb/%03d", uBus);
223
224 fBusExists = RTPathExists(aszDevPath);
225
226 if (fBusExists)
227 {
228 /* Check every device. */
229 bool fDevExists = false;
230 uint8_t uDev = 1;
231
232 do
233 {
234 RTStrPrintf(aszDevPath, sizeof(aszDevPath), "/dev/bus/usb/%03d/%03d", uBus, uDev);
235
236 fDevExists = RTPathExists(aszDevPath);
237
238 if (fDevExists)
239 {
240 RTFILE hFileDev;
241 int rc = RTFileOpen(&hFileDev, aszDevPath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
242 if (RT_SUCCESS(rc))
243 {
244 USBDEVDESC DevDesc;
245
246 rc = RTFileRead(hFileDev, &DevDesc, sizeof(DevDesc), NULL);
247 RTFileClose(hFileDev);
248
249 if ( RT_SUCCESS(rc)
250 && DevDesc.idVendor == 0x0525
251 && DevDesc.idProduct == 0xa4a0)
252 return RTStrDup(aszDevPath);
253 }
254 }
255
256 uDev++;
257 } while (fDevExists);
258 }
259
260 uBus++;
261 } while (fBusExists);
262
263 return NULL;
264}
265
266static int usbTestIoctl(int iDevFd, int iInterface, PUSBTESTPARAMS pParams)
267{
268 struct usbdevfs_ioctl IoCtlData;
269
270 IoCtlData.ifno = iInterface;
271 IoCtlData.ioctl_code = (int)USBTEST_REQUEST;
272 IoCtlData.data = pParams;
273 return ioctl(iDevFd, USBDEVFS_IOCTL, &IoCtlData);
274}
275
276/**
277 * Test execution worker.
278 *
279 * @returns nothing.
280 * @param pszDevice The device to use for testing.
281 */
282static void usbTestExec(const char *pszDevice)
283{
284 int iDevFd;
285
286 RTTestSub(g_hTest, "Opening device");
287 iDevFd = open(pszDevice, O_RDWR);
288 if (iDevFd != -1)
289 {
290 USBTESTPARAMS Params;
291
292 RTTestPassed(g_hTest, "Opening device successful\n");
293
294 /*
295 * Fill params with some defaults.
296 * @todo: Make them configurable.
297 */
298 Params.cIterations = 1000;
299 Params.cbData = 512;
300 Params.cbVariation = 512;
301 Params.cSgLength = 32;
302
303 for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
304 {
305 RTTestSub(g_hTest, g_aTests[i].pszName);
306
307 if (g_aTests[i].fExcluded)
308 {
309 RTTestSkipped(g_hTest, "Excluded from list");
310 continue;
311 }
312
313 Params.idxTest = i;
314
315 /* Assume the test interface has the number 0 for now. */
316 int rcPosix = usbTestIoctl(iDevFd, 0, &Params);
317 if (rcPosix < 0 && errno == EOPNOTSUPP)
318 {
319 RTTestSkipped(g_hTest, "Not supported");
320 continue;
321 }
322
323 if (rcPosix < 0)
324 RTTestFailed(g_hTest, "Test failed with %Rrc\n", RTErrConvertFromErrno(errno));
325 else
326 {
327 uint64_t u64Ns = Params.TimeTest.tv_sec * RT_NS_1SEC + Params.TimeTest.tv_usec * RT_NS_1US;
328 RTTestValue(g_hTest, "Runtime", u64Ns, RTTESTUNIT_NS);
329 }
330 RTTestSubDone(g_hTest);
331 }
332
333 close(iDevFd);
334 }
335 else
336 RTTestFailed(g_hTest, "Opening device failed with %Rrc\n", RTErrConvertFromErrno(errno));
337
338}
339
340int main(int argc, char *argv[])
341{
342 /*
343 * Init IPRT and globals.
344 */
345 int rc = RTTestInitAndCreate("UsbTest", &g_hTest);
346 if (rc)
347 return rc;
348
349 /*
350 * Default values.
351 */
352 const char *pszDevice = NULL;
353
354 RTGETOPTUNION ValueUnion;
355 RTGETOPTSTATE GetState;
356 RTGetOptInit(&GetState, argc, argv, g_aCmdOptions, RT_ELEMENTS(g_aCmdOptions), 1, 0 /* fFlags */);
357 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
358 {
359 switch (rc)
360 {
361 case 'h':
362 usbTestUsage(g_pStdOut);
363 return RTEXITCODE_SUCCESS;
364 case 'd':
365 pszDevice = ValueUnion.psz;
366 break;
367 case 'e':
368 if (ValueUnion.u32 < RT_ELEMENTS(g_aTests))
369 g_aTests[ValueUnion.u32].fExcluded = true;
370 else
371 {
372 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Failed to find a test device\n");
373 RTTestErrorInc(g_hTest);
374 return RTGetOptPrintError(VERR_INVALID_PARAMETER, &ValueUnion);
375 }
376 break;
377 default:
378 return RTGetOptPrintError(rc, &ValueUnion);
379 }
380 }
381
382 /*
383 * Start testing.
384 */
385 RTTestBanner(g_hTest);
386
387 /* Find the first test device if none was given. */
388 if (!pszDevice)
389 pszDevice = usbTestFindDevice();
390
391 if (pszDevice)
392 usbTestExec(pszDevice);
393 else
394 {
395 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Failed to find a test device\n");
396 RTTestErrorInc(g_hTest);
397 }
398
399 RTEXITCODE rcExit = RTTestSummaryAndDestroy(g_hTest);
400 return rcExit;
401}
402
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette