VirtualBox

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

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

ValidationKit/usb: Updates for UsbTestService

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