VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetClassTest.cpp@ 71214

Last change on this file since 71214 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id: UsbTestServiceGadgetClassTest.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * UsbTestServ - Remote USB test configuration and execution server, USB gadget class
4 * for the test device.
5 */
6
7/*
8 * Copyright (C) 2016-2017 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
33#include <iprt/asm.h>
34#include <iprt/cdefs.h>
35#include <iprt/ctype.h>
36#include <iprt/dir.h>
37#include <iprt/env.h>
38#include <iprt/mem.h>
39#include <iprt/path.h>
40#include <iprt/process.h>
41#include <iprt/string.h>
42#include <iprt/symlink.h>
43#include <iprt/thread.h>
44#include <iprt/types.h>
45
46#include <iprt/linux/sysfs.h>
47
48#include "UsbTestServiceGadgetInternal.h"
49#include "UsbTestServicePlatform.h"
50
51
52/*********************************************************************************************************************************
53* Constants And Macros, Structures and Typedefs *
54*********************************************************************************************************************************/
55
56/** Default configfs mount point. */
57#define UTS_GADGET_CLASS_CONFIGFS_MNT_DEF "/sys/kernel/config/usb_gadget"
58/** Gadget template name */
59#define UTS_GADGET_TEMPLATE_NAME "gadget_test"
60
61/** Default vendor ID which is recognized by the usbtest driver. */
62#define UTS_GADGET_TEST_VENDOR_ID_DEF UINT16_C(0x0525)
63/** Default product ID which is recognized by the usbtest driver. */
64#define UTS_GADGET_TEST_PRODUCT_ID_DEF UINT16_C(0xa4a0)
65/** Default device class. */
66#define UTS_GADGET_TEST_DEVICE_CLASS_DEF UINT8_C(0xff)
67/** Default serial number string. */
68#define UTS_GADGET_TEST_SERIALNUMBER_DEF "0123456789"
69/** Default manufacturer string. */
70#define UTS_GADGET_TEST_MANUFACTURER_DEF "Oracle Inc."
71/** Default product string. */
72#define UTS_GADGET_TEST_PRODUCT_DEF "USB test device"
73
74/**
75 * Internal UTS gadget host instance data.
76 */
77typedef struct UTSGADGETCLASSINT
78{
79 /** Gadget template path. */
80 char *pszGadgetPath;
81 /** The UDC this gadget is connected to. */
82 char *pszUdc;
83 /** Bus identifier for the used UDC. */
84 uint32_t uBusId;
85 /** Device identifier. */
86 uint32_t uDevId;
87} UTSGADGETCLASSINT;
88
89
90/*********************************************************************************************************************************
91* Global Variables *
92*********************************************************************************************************************************/
93
94/** Number of already created gadgets, used for the template name. */
95static volatile uint32_t g_cGadgets = 0;
96
97
98/*********************************************************************************************************************************
99* Internal Functions *
100*********************************************************************************************************************************/
101
102/**
103 * Creates a new directory pointed to by the given format string.
104 *
105 * @returns IPRT status code.
106 * @param pszFormat The format string.
107 * @param va The arguments.
108 */
109static int utsGadgetClassTestDirCreateV(const char *pszFormat, va_list va)
110{
111 int rc = VINF_SUCCESS;
112 char aszPath[RTPATH_MAX + 1];
113
114 size_t cbStr = RTStrPrintfV(&aszPath[0], sizeof(aszPath), pszFormat, va);
115 if (cbStr <= sizeof(aszPath) - 1)
116 rc = RTDirCreateFullPath(aszPath, 0700);
117 else
118 rc = VERR_BUFFER_OVERFLOW;
119
120 return rc;
121}
122
123
124/**
125 * Creates a new directory pointed to by the given format string.
126 *
127 * @returns IPRT status code.
128 * @param pszFormat The format string.
129 * @param ... The arguments.
130 */
131static int utsGadgetClassTestDirCreate(const char *pszFormat, ...)
132{
133 va_list va;
134 va_start(va, pszFormat);
135 int rc = utsGadgetClassTestDirCreateV(pszFormat, va);
136 va_end(va);
137 return rc;
138}
139
140
141/**
142 * Removes a directory pointed to by the given format string.
143 *
144 * @returns IPRT status code.
145 * @param pszFormat The format string.
146 * @param va The arguments.
147 */
148static int utsGadgetClassTestDirRemoveV(const char *pszFormat, va_list va)
149{
150 int rc = VINF_SUCCESS;
151 char aszPath[RTPATH_MAX + 1];
152
153 size_t cbStr = RTStrPrintfV(&aszPath[0], sizeof(aszPath), pszFormat, va);
154 if (cbStr <= sizeof(aszPath) - 1)
155 rc = RTDirRemove(aszPath);
156 else
157 rc = VERR_BUFFER_OVERFLOW;
158
159 return rc;
160}
161
162
163/**
164 * Removes a directory pointed to by the given format string.
165 *
166 * @returns IPRT status code.
167 * @param pszFormat The format string.
168 * @param ... The arguments.
169 */
170static int utsGadgetClassTestDirRemove(const char *pszFormat, ...)
171{
172 va_list va;
173 va_start(va, pszFormat);
174 int rc = utsGadgetClassTestDirRemoveV(pszFormat, va);
175 va_end(va);
176 return rc;
177}
178
179
180/**
181 * Links the given function to the given config.
182 *
183 * @returns IPRT status code.
184 * @param pClass The gadget class instance data.
185 * @param pszFunc The function to link.
186 * @param pszCfg The configuration which the function will be part of.
187 */
188static int utsGadgetClassTestLinkFuncToCfg(PUTSGADGETCLASSINT pClass, const char *pszFunc, const char *pszCfg)
189{
190 int rc = VINF_SUCCESS;
191 char aszPathFunc[RTPATH_MAX + 1];
192 char aszPathCfg[RTPATH_MAX + 1];
193
194 size_t cbStr = RTStrPrintf(&aszPathFunc[0], sizeof(aszPathFunc), "%s/functions/%s",
195 pClass->pszGadgetPath, pszFunc);
196 if (cbStr <= sizeof(aszPathFunc) - 1)
197 {
198 cbStr = RTStrPrintf(&aszPathCfg[0], sizeof(aszPathCfg), "%s/configs/%s/%s",
199 pClass->pszGadgetPath, pszCfg, pszFunc);
200 if (cbStr <= sizeof(aszPathCfg) - 1)
201 rc = RTSymlinkCreate(&aszPathCfg[0], &aszPathFunc[0], RTSYMLINKTYPE_DIR, 0);
202 else
203 rc = VERR_BUFFER_OVERFLOW;
204 }
205 else
206 rc = VERR_BUFFER_OVERFLOW;
207
208 return rc;
209}
210
211
212/**
213 * Unlinks the given function from the given configuration.
214 *
215 * @returns IPRT status code.
216 * @param pClass The gadget class instance data.
217 * @param pszFunc The function to unlink.
218 * @param pszCfg The configuration which the function is currently part of.
219 */
220static int utsGadgetClassTestUnlinkFuncFromCfg(PUTSGADGETCLASSINT pClass, const char *pszFunc, const char *pszCfg)
221{
222 int rc = VINF_SUCCESS;
223 char aszPath[RTPATH_MAX + 1];
224 size_t cbStr = RTStrPrintf(&aszPath[0], sizeof(aszPath), "%s/configs/%s/%s",
225 pClass->pszGadgetPath, pszCfg, pszFunc);
226 if (cbStr <= sizeof(aszPath) - 1)
227 rc = RTSymlinkDelete(&aszPath[0], 0);
228 else
229 rc = VERR_BUFFER_OVERFLOW;
230
231 return rc;
232}
233
234
235/**
236 * Cleans up any leftover configurations from the gadget class.
237 *
238 * @returns nothing.
239 * @param pClass The gadget class instance data.
240 */
241static void utsGadgetClassTestCleanup(PUTSGADGETCLASSINT pClass)
242{
243 /* Unbind the gadget from the currently assigned UDC first. */
244 int rc = RTLinuxSysFsWriteStrFile("", 0, NULL, "%s/UDC", pClass->pszGadgetPath);
245 AssertRC(rc);
246
247 /* Delete the symlinks, ignore any errors. */
248 utsGadgetClassTestUnlinkFuncFromCfg(pClass, "Loopback.0", "c.2");
249 utsGadgetClassTestUnlinkFuncFromCfg(pClass, "SourceSink.0", "c.1");
250
251 /* Delete configuration strings and then the configuration directories. */
252 utsGadgetClassTestDirRemove("%s/configs/c.2/strings/0x409", pClass->pszGadgetPath);
253 utsGadgetClassTestDirRemove("%s/configs/c.1/strings/0x409", pClass->pszGadgetPath);
254
255 utsGadgetClassTestDirRemove("%s/configs/c.2", pClass->pszGadgetPath);
256 utsGadgetClassTestDirRemove("%s/configs/c.1", pClass->pszGadgetPath);
257
258 /* Delete the functions. */
259 utsGadgetClassTestDirRemove("%s/functions/Loopback.0", pClass->pszGadgetPath);
260 utsGadgetClassTestDirRemove("%s/functions/SourceSink.0", pClass->pszGadgetPath);
261
262 /* Delete the english strings. */
263 utsGadgetClassTestDirRemove("%s/strings/0x409", pClass->pszGadgetPath);
264
265 /* Finally delete the gadget template. */
266 utsGadgetClassTestDirRemove(pClass->pszGadgetPath);
267
268 /* Release the UDC. */
269 if (pClass->pszUdc)
270 {
271 rc = utsPlatformLnxReleaseUDC(pClass->pszUdc);
272 AssertRC(rc);
273 RTStrFree(pClass->pszUdc);
274 }
275}
276
277/**
278 * @interface_method_impl{UTSGADGETCLASSIF,pfnInit}
279 */
280static DECLCALLBACK(int) utsGadgetClassTestInit(PUTSGADGETCLASSINT pClass, PCUTSGADGETCFGITEM paCfg)
281{
282 int rc = VINF_SUCCESS;
283
284 if (RTLinuxSysFsExists(UTS_GADGET_CLASS_CONFIGFS_MNT_DEF))
285 {
286 /* Create the gadget template */
287 unsigned idx = ASMAtomicIncU32(&g_cGadgets);
288
289 int rcStr = RTStrAPrintf(&pClass->pszGadgetPath, "%s/%s%u", UTS_GADGET_CLASS_CONFIGFS_MNT_DEF,
290 UTS_GADGET_TEMPLATE_NAME, idx);
291 if (rcStr == -1)
292 return VERR_NO_STR_MEMORY;
293
294 rc = utsGadgetClassTestDirCreate(pClass->pszGadgetPath);
295 if (RT_SUCCESS(rc))
296 {
297 uint16_t idVendor = 0;
298 uint16_t idProduct = 0;
299 uint8_t bDeviceClass = 0;
300 char *pszSerial = NULL;
301 char *pszManufacturer = NULL;
302 char *pszProduct = NULL;
303 bool fSuperSpeed = false;
304
305 /* Get basic device config. */
306 rc = utsGadgetCfgQueryU16Def(paCfg, "Gadget/idVendor", &idVendor, UTS_GADGET_TEST_VENDOR_ID_DEF);
307 if (RT_SUCCESS(rc))
308 rc = utsGadgetCfgQueryU16Def(paCfg, "Gadget/idProduct", &idProduct, UTS_GADGET_TEST_PRODUCT_ID_DEF);
309 if (RT_SUCCESS(rc))
310 rc = utsGadgetCfgQueryU8Def(paCfg, "Gadget/bDeviceClass", &bDeviceClass, UTS_GADGET_TEST_DEVICE_CLASS_DEF);
311 if (RT_SUCCESS(rc))
312 rc = utsGadgetCfgQueryStringDef(paCfg, "Gadget/SerialNumber", &pszSerial, UTS_GADGET_TEST_SERIALNUMBER_DEF);
313 if (RT_SUCCESS(rc))
314 rc = utsGadgetCfgQueryStringDef(paCfg, "Gadget/Manufacturer", &pszManufacturer, UTS_GADGET_TEST_MANUFACTURER_DEF);
315 if (RT_SUCCESS(rc))
316 rc = utsGadgetCfgQueryStringDef(paCfg, "Gadget/Product", &pszProduct, UTS_GADGET_TEST_PRODUCT_DEF);
317 if (RT_SUCCESS(rc))
318 rc = utsGadgetCfgQueryBoolDef(paCfg, "Gadget/SuperSpeed", &fSuperSpeed, false);
319
320 if (RT_SUCCESS(rc))
321 {
322 /* Write basic attributes. */
323 rc = RTLinuxSysFsWriteU16File(16, idVendor, "%s/idVendor", pClass->pszGadgetPath);
324 if (RT_SUCCESS(rc))
325 rc = RTLinuxSysFsWriteU16File(16, idProduct, "%s/idProduct", pClass->pszGadgetPath);
326 if (RT_SUCCESS(rc))
327 rc = RTLinuxSysFsWriteU16File(16, bDeviceClass, "%s/bDeviceClass", pClass->pszGadgetPath);
328
329 /* Create english language strings. */
330 if (RT_SUCCESS(rc))
331 rc = utsGadgetClassTestDirCreate("%s/strings/0x409", pClass->pszGadgetPath);
332 if (RT_SUCCESS(rc))
333 rc = RTLinuxSysFsWriteStrFile(pszSerial, 0, NULL, "%s/strings/0x409/serialnumber", pClass->pszGadgetPath);
334 if (RT_SUCCESS(rc))
335 rc = RTLinuxSysFsWriteStrFile(pszManufacturer, 0, NULL, "%s/strings/0x409/manufacturer", pClass->pszGadgetPath);
336 if (RT_SUCCESS(rc))
337 rc = RTLinuxSysFsWriteStrFile(pszProduct, 0, NULL, "%s/strings/0x409/product", pClass->pszGadgetPath);
338
339 /* Create the gadget functions. */
340 if (RT_SUCCESS(rc))
341 rc = utsGadgetClassTestDirCreate("%s/functions/SourceSink.0", pClass->pszGadgetPath);
342 if (RT_SUCCESS(rc))
343 rc = utsGadgetClassTestDirCreate("%s/functions/Loopback.0", pClass->pszGadgetPath);
344
345 /* Create the device configs. */
346 if (RT_SUCCESS(rc))
347 rc = utsGadgetClassTestDirCreate("%s/configs/c.1", pClass->pszGadgetPath);
348 if (RT_SUCCESS(rc))
349 rc = utsGadgetClassTestDirCreate("%s/configs/c.2", pClass->pszGadgetPath);
350
351 /* Write configuration strings. */
352 if (RT_SUCCESS(rc))
353 rc = utsGadgetClassTestDirCreate("%s/configs/c.1/strings/0x409", pClass->pszGadgetPath);
354 if (RT_SUCCESS(rc))
355 rc = utsGadgetClassTestDirCreate("%s/configs/c.2/strings/0x409", pClass->pszGadgetPath);
356 if (RT_SUCCESS(rc))
357 rc = RTLinuxSysFsWriteStrFile("source and sink data", 0, NULL, "%s/configs/c.1/strings/0x409/configuration", pClass->pszGadgetPath);
358 if (RT_SUCCESS(rc))
359 rc = RTLinuxSysFsWriteStrFile("loop input to output", 0, NULL, "%s/configs/c.2/strings/0x409/configuration", pClass->pszGadgetPath);
360
361 /* Link the functions into the configurations. */
362 if (RT_SUCCESS(rc))
363 rc = utsGadgetClassTestLinkFuncToCfg(pClass, "SourceSink.0", "c.1");
364 if (RT_SUCCESS(rc))
365 rc = utsGadgetClassTestLinkFuncToCfg(pClass, "Loopback.0", "c.2");
366
367 /* Finally enable the gadget by attaching it to a UDC. */
368 if (RT_SUCCESS(rc))
369 {
370 pClass->pszUdc = NULL;
371
372 rc = utsPlatformLnxAcquireUDC(fSuperSpeed, &pClass->pszUdc, &pClass->uBusId);
373 if (RT_SUCCESS(rc))
374 rc = RTLinuxSysFsWriteStrFile(pClass->pszUdc, 0, NULL, "%s/UDC", pClass->pszGadgetPath);
375 if (RT_SUCCESS(rc))
376 RTThreadSleep(500); /* Fudge: Sleep a bit to give the device a chance to appear on the host so binding succeeds. */
377 }
378 }
379
380 if (pszSerial)
381 RTStrFree(pszSerial);
382 if (pszManufacturer)
383 RTStrFree(pszManufacturer);
384 if (pszProduct)
385 RTStrFree(pszProduct);
386 }
387 }
388 else
389 rc = VERR_NOT_FOUND;
390
391 if (RT_FAILURE(rc))
392 utsGadgetClassTestCleanup(pClass);
393
394 return rc;
395}
396
397
398/**
399 * @interface_method_impl{UTSGADGETCLASSIF,pfnTerm}
400 */
401static DECLCALLBACK(void) utsGadgetClassTestTerm(PUTSGADGETCLASSINT pClass)
402{
403 utsGadgetClassTestCleanup(pClass);
404
405 if (pClass->pszGadgetPath)
406 RTStrFree(pClass->pszGadgetPath);
407}
408
409
410/**
411 * @interface_method_impl{UTSGADGETCLASSIF,pfnGetBusId}
412 */
413static DECLCALLBACK(uint32_t) utsGadgetClassTestGetBusId(PUTSGADGETCLASSINT pClass)
414{
415 return pClass->uBusId;
416}
417
418
419/**
420 * @interface_method_impl{UTSGADGETCLASSIF,pfnConnect}
421 */
422static DECLCALLBACK(int) utsGadgetClassTestConnect(PUTSGADGETCLASSINT pClass)
423{
424 int rc = RTLinuxSysFsWriteStrFile("connect", 0, NULL, "/sys/class/udc/%s/soft_connect", pClass->pszUdc);
425 if (RT_SUCCESS(rc))
426 RTThreadSleep(500); /* Fudge: Sleep a bit to give the device a chance to appear on the host so binding succeeds. */
427
428 return rc;
429}
430
431
432/**
433 * @interface_method_impl{UTSGADGETCLASSIF,pfnDisconnect}
434 */
435static DECLCALLBACK(int) utsGadgetClassTestDisconnect(PUTSGADGETCLASSINT pClass)
436{
437 return RTLinuxSysFsWriteStrFile("disconnect", 0, NULL, "/sys/class/udc/%s/soft_connect", pClass->pszUdc);}
438
439
440
441/**
442 * The gadget host interface callback table.
443 */
444const UTSGADGETCLASSIF g_UtsGadgetClassTest =
445{
446 /** enmType */
447 UTSGADGETCLASS_TEST,
448 /** pszDesc */
449 "UTS test device gadget class",
450 /** cbIf */
451 sizeof(UTSGADGETCLASSINT),
452 /** pfnInit */
453 utsGadgetClassTestInit,
454 /** pfnTerm */
455 utsGadgetClassTestTerm,
456 /** pfnGetBusId */
457 utsGadgetClassTestGetBusId,
458 /** pfnConnect */
459 utsGadgetClassTestConnect,
460 /** pfnDisconnect. */
461 utsGadgetClassTestDisconnect
462};
463
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