VirtualBox

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

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

copyright header fix

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