VirtualBox

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

Last change on this file since 53517 was 52776, checked in by vboxsync, 11 years ago

fix OSE

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

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