VirtualBox

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

Last change on this file since 93603 was 93115, checked in by vboxsync, 3 years ago

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