VirtualBox

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

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

ValidationKit/usb/UsbTestServices: Updates, use configfs to create a USB test device (works only on Linux), untested

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