VirtualBox

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

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

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: UsbTest.cpp 57358 2015-08-14 15:16:38Z 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/** Number of tests implemented at the moment. */
59#define USBTEST_TEST_CASES 25
60
61
62/*********************************************************************************************************************************
63* Structures and Typedefs *
64*********************************************************************************************************************************/
65
66/**
67 * USB test request data.
68 * There is no public header with this information so we define it ourself here.
69 */
70typedef struct USBTESTPARMS
71{
72 /** Specifies the test to run. */
73 uint32_t idxTest;
74 /** How many iterations the test should be executed. */
75 uint32_t cIterations;
76 /** Size of the data packets. */
77 uint32_t cbData;
78 /** Size of */
79 uint32_t cbVariation;
80 /** Length of the S/G list for the test. */
81 uint32_t cSgLength;
82 /** Returned time data after completing the test. */
83 struct timeval TimeTest;
84} USBTESTPARAMS;
85/** Pointer to a test parameter structure. */
86typedef USBTESTPARAMS *PUSBTESTPARAMS;
87
88/**
89 * USB device descriptor. Used to search for the test device based
90 * on the vendor and product id.
91 */
92#pragma pack(1)
93typedef struct USBDEVDESC
94{
95 uint8_t bLength;
96 uint8_t bDescriptorType;
97 uint16_t bcdUSB;
98 uint8_t bDeviceClass;
99 uint8_t bDeviceSubClass;
100 uint8_t bDeviceProtocol;
101 uint8_t bMaxPacketSize0;
102 uint16_t idVendor;
103 uint16_t idProduct;
104 uint16_t bcdDevice;
105 uint8_t iManufacturer;
106 uint8_t iProduct;
107 uint8_t iSerialNumber;
108 uint8_t bNumConfigurations;
109} USBDEVDESC;
110#pragma pack()
111
112#define USBTEST_REQUEST _IOWR('U', 100, USBTESTPARMS)
113
114
115/*********************************************************************************************************************************
116* Global Variables *
117*********************************************************************************************************************************/
118
119/** Command line parameters */
120static const RTGETOPTDEF g_aCmdOptions[] =
121{
122 {"--device", 'd', RTGETOPT_REQ_STRING },
123 {"--help", 'h', RTGETOPT_REQ_NOTHING}
124};
125
126/** (Sort of) Descriptive test descriptions. */
127static const char *g_apszTests[] =
128{
129 "NOP",
130 "Non-queued Bulk write",
131 "Non-queued Bulk read",
132 "Non-queued Bulk write variabe size",
133 "Non-queued Bulk read variabe size",
134 "Queued Bulk write",
135 "Queued Bulk read",
136 "Queued Bulk write variabe size",
137 "Queued Bulk read variabe size",
138 "Chapter 9 Control Test",
139 "Queued control messaging",
140 "Unlink reads",
141 "Unlink writes",
142 "Set/Clear halts",
143 "Control writes",
144 "Isochronous write",
145 "Isochronous read",
146 "Bulk write unaligned (DMA)",
147 "Bulk read unaligned (DMA)",
148 "Bulk write unaligned (no DMA)",
149 "Bulk read unaligned (no DMA)",
150 "Control writes unaligned",
151 "Isochronous write unaligned",
152 "Isochronous read unaligned",
153 "Unlink queued Bulk"
154};
155AssertCompile(RT_ELEMENTS(g_apszTests) == USBTEST_TEST_CASES);
156
157/** The test handle. */
158static RTTEST g_hTest;
159
160
161static void usbTestUsage(PRTSTREAM pStrm)
162{
163 char szExec[RTPATH_MAX];
164 RTStrmPrintf(pStrm, "usage: %s [options]\n",
165 RTPathFilename(RTProcGetExecutablePath(szExec, sizeof(szExec))));
166 RTStrmPrintf(pStrm, "\n");
167 RTStrmPrintf(pStrm, "options: \n");
168
169
170 for (unsigned i = 0; i < RT_ELEMENTS(g_aCmdOptions); i++)
171 {
172 const char *pszHelp;
173 switch (g_aCmdOptions[i].iShort)
174 {
175 case 'h':
176 pszHelp = "Displays this help and exit";
177 break;
178 case 'd':
179 pszHelp = "Use the specified test device";
180 break;
181 default:
182 pszHelp = "Option undocumented";
183 break;
184 }
185 char szOpt[256];
186 RTStrPrintf(szOpt, sizeof(szOpt), "%s, -%c", g_aCmdOptions[i].pszLong, g_aCmdOptions[i].iShort);
187 RTStrmPrintf(pStrm, " %-20s%s\n", szOpt, pszHelp);
188 }
189}
190
191/**
192 * Search for a USB test device and return the device path.
193 *
194 * @returns Path to the USB test device or NULL if none was found.
195 */
196static char *usbTestFindDevice(void)
197{
198 /*
199 * Very crude and quick way to search for the correct test device.
200 * Assumption is that the path looks like /dev/bus/usb/%3d/%3d.
201 */
202 uint8_t uBus = 1;
203 bool fBusExists = false;
204 char aszDevPath[64];
205
206 RT_ZERO(aszDevPath);
207
208 do
209 {
210 RTStrPrintf(aszDevPath, sizeof(aszDevPath), "/dev/bus/usb/%03d", uBus);
211
212 fBusExists = RTPathExists(aszDevPath);
213
214 if (fBusExists)
215 {
216 /* Check every device. */
217 bool fDevExists = false;
218 uint8_t uDev = 1;
219
220 do
221 {
222 RTStrPrintf(aszDevPath, sizeof(aszDevPath), "/dev/bus/usb/%03d/%03d", uBus, uDev);
223
224 fDevExists = RTPathExists(aszDevPath);
225
226 if (fDevExists)
227 {
228 RTFILE hFileDev;
229 int rc = RTFileOpen(&hFileDev, aszDevPath, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
230 if (RT_SUCCESS(rc))
231 {
232 USBDEVDESC DevDesc;
233
234 rc = RTFileRead(hFileDev, &DevDesc, sizeof(DevDesc), NULL);
235 RTFileClose(hFileDev);
236
237 if ( RT_SUCCESS(rc)
238 && DevDesc.idVendor == 0x0525
239 && DevDesc.idProduct == 0xa4a0)
240 return RTStrDup(aszDevPath);
241 }
242 }
243
244 uDev++;
245 } while (fDevExists);
246 }
247
248 uBus++;
249 } while (fBusExists);
250
251 return NULL;
252}
253
254static int usbTestIoctl(int iDevFd, int iInterface, PUSBTESTPARAMS pParams)
255{
256 struct usbdevfs_ioctl IoCtlData;
257
258 IoCtlData.ifno = iInterface;
259 IoCtlData.ioctl_code = (int)USBTEST_REQUEST;
260 IoCtlData.data = pParams;
261 return ioctl(iDevFd, USBDEVFS_IOCTL, &IoCtlData);
262}
263
264/**
265 * Test execution worker.
266 *
267 * @returns nothing.
268 * @param pszDevice The device to use for testing.
269 */
270static void usbTestExec(const char *pszDevice)
271{
272 int iDevFd;
273
274 RTTestSub(g_hTest, "Opening device");
275 iDevFd = open(pszDevice, O_RDWR);
276 if (iDevFd != -1)
277 {
278 USBTESTPARAMS Params;
279
280 RTTestPassed(g_hTest, "Opening device successful\n");
281
282 /*
283 * Fill params with some defaults.
284 * @todo: Make them configurable.
285 */
286 Params.cIterations = 1000;
287 Params.cbData = 512;
288 Params.cbVariation = 512;
289 Params.cSgLength = 32;
290
291 for (unsigned i = 0; i < USBTEST_TEST_CASES; i++)
292 {
293 RTTestSub(g_hTest, g_apszTests[i]);
294
295 Params.idxTest = i;
296
297 /* Assume the test interface has the number 0 for now. */
298 int rcPosix = usbTestIoctl(iDevFd, 0, &Params);
299 if (rcPosix < 0 && errno == EOPNOTSUPP)
300 {
301 RTTestSkipped(g_hTest, "Not supported");
302 continue;
303 }
304
305 if (rcPosix < 0)
306 RTTestFailed(g_hTest, "Test failed with %Rrc\n", RTErrConvertFromErrno(errno));
307 else
308 {
309 uint64_t u64Ns = Params.TimeTest.tv_sec * RT_NS_1SEC + Params.TimeTest.tv_usec * RT_NS_1US;
310 RTTestValue(g_hTest, "Runtime", u64Ns, RTTESTUNIT_NS);
311 }
312 RTTestSubDone(g_hTest);
313 }
314
315 close(iDevFd);
316 }
317 else
318 RTTestFailed(g_hTest, "Opening device failed with %Rrc\n", RTErrConvertFromErrno(errno));
319
320}
321
322int main(int argc, char *argv[])
323{
324 /*
325 * Init IPRT and globals.
326 */
327 int rc = RTTestInitAndCreate("UsbTest", &g_hTest);
328 if (rc)
329 return rc;
330
331 /*
332 * Default values.
333 */
334 const char *pszDevice = NULL;
335
336 RTGETOPTUNION ValueUnion;
337 RTGETOPTSTATE GetState;
338 RTGetOptInit(&GetState, argc, argv, g_aCmdOptions, RT_ELEMENTS(g_aCmdOptions), 1, 0 /* fFlags */);
339 while ((rc = RTGetOpt(&GetState, &ValueUnion)))
340 {
341 switch (rc)
342 {
343 case 'h':
344 usbTestUsage(g_pStdOut);
345 return RTEXITCODE_SUCCESS;
346 case 'd':
347 pszDevice = ValueUnion.psz;
348 break;
349 default:
350 return RTGetOptPrintError(rc, &ValueUnion);
351 }
352 }
353
354 /*
355 * Start testing.
356 */
357 RTTestBanner(g_hTest);
358
359 /* Find the first test device if none was given. */
360 if (!pszDevice)
361 pszDevice = usbTestFindDevice();
362
363 if (pszDevice)
364 usbTestExec(pszDevice);
365 else
366 {
367 RTTestPrintf(g_hTest, RTTESTLVL_FAILURE, "Failed to find a test device\n");
368 RTTestErrorInc(g_hTest);
369 }
370
371 RTEXITCODE rcExit = RTTestSummaryAndDestroy(g_hTest);
372 return rcExit;
373}
374
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