VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/usb/UsbTestServicePlatform-linux.cpp@ 64365

Last change on this file since 64365 was 64365, checked in by vboxsync, 8 years ago

ValidationKit/UsbTestService: Doxygen

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.6 KB
Line 
1/* $Id: UsbTestServicePlatform-linux.cpp 64365 2016-10-22 16:33:45Z vboxsync $ */
2/** @file
3 * UsbTestServ - Remote USB test configuration and execution server, Platform
4 * specific helpers - Linux version.
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/types.h>
43
44#include <iprt/linux/sysfs.h>
45
46#include "UsbTestServicePlatform.h"
47
48
49/*********************************************************************************************************************************
50* Constants And Macros, Structures and Typedefs *
51*********************************************************************************************************************************/
52
53/** Where the dummy_hcd.* and dummy_udc.* entries are stored. */
54#define UTS_PLATFORM_LNX_DUMMY_HCD_PATH "/sys/devices/platform"
55
56/**
57 * A USB bus provided by the dummy HCD.
58 */
59typedef struct UTSPLATFORMLNXDUMMYHCDBUS
60{
61 /** The bus ID on the host the dummy HCD is serving. */
62 uint32_t uBusId;
63 /** Flag whether this is a super speed bus. */
64 bool fSuperSpeed;
65} UTSPLATFORMLNXDUMMYHCDBUS;
66/** Pointer to a Dummy HCD bus. */
67typedef UTSPLATFORMLNXDUMMYHCDBUS *PUTSPLATFORMLNXDUMMYHCDBUS;
68
69/**
70 * A dummy UDC descriptor.
71 */
72typedef struct UTSPLATFORMLNXDUMMYHCD
73{
74 /** Index of the dummy hcd entry. */
75 uint32_t idxDummyHcd;
76 /** Name for the dummy HCD. */
77 const char *pszHcdName;
78 /** Name for the accompanying dummy HCD. */
79 const char *pszUdcName;
80 /** Flag whether this HCD is free for use. */
81 bool fAvailable;
82 /** Flag whether this HCD contains a super speed capable bus. */
83 bool fSuperSpeed;
84 /** Number of busses this HCD instance serves. */
85 unsigned cBusses;
86 /** Bus structures the HCD serves.*/
87 PUTSPLATFORMLNXDUMMYHCDBUS paBusses;
88} UTSPLATFORMLNXDUMMYHCD;
89/** Pointer to a dummy HCD entry. */
90typedef UTSPLATFORMLNXDUMMYHCD *PUTSPLATFORMLNXDUMMYHCD;
91
92
93/*********************************************************************************************************************************
94* Global Variables *
95*********************************************************************************************************************************/
96
97/** Array of dummy HCD entries. */
98static PUTSPLATFORMLNXDUMMYHCD g_paDummyHcd = NULL;
99/** Number of Dummy hCD entries in the array. */
100static unsigned g_cDummyHcd = 0;
101
102
103/*********************************************************************************************************************************
104* Internal Functions *
105*********************************************************************************************************************************/
106
107
108/**
109 * Queries the assigned busses for the given dummy HCD instance.
110 *
111 * @returns IPRT status code.
112 * @param pHcd The dummy HCD bus instance.
113 * @param pszHcdName The base HCD name.
114 */
115static int utsPlatformLnxDummyHcdQueryBusses(PUTSPLATFORMLNXDUMMYHCD pHcd, const char *pszHcdName)
116{
117 int rc = VINF_SUCCESS;
118 char aszPath[RTPATH_MAX + 1];
119 unsigned idxBusCur = 0;
120 unsigned idxBusMax = 0;
121
122 size_t cchPath = RTStrPrintf(&aszPath[0], RT_ELEMENTS(aszPath), UTS_PLATFORM_LNX_DUMMY_HCD_PATH "/%s.%u/usb*",
123 pszHcdName, pHcd->idxDummyHcd);
124 if (cchPath == RT_ELEMENTS(aszPath))
125 return VERR_BUFFER_OVERFLOW;
126
127 PRTDIR pDir = NULL;
128 rc = RTDirOpenFiltered(&pDir, aszPath, RTDIRFILTER_WINNT, 0);
129 if (RT_SUCCESS(rc))
130 {
131 do
132 {
133 RTDIRENTRY DirFolderContent;
134 rc = RTDirRead(pDir, &DirFolderContent, NULL);
135 if (RT_SUCCESS(rc))
136 {
137 uint32_t uBusId = 0;
138
139 /* Extract the bus number - it is after "usb", i.e. "usb9" indicates a bus ID of 9. */
140 rc = RTStrToUInt32Ex(&DirFolderContent.szName[3], NULL, 10, &uBusId);
141 if (RT_SUCCESS(rc))
142 {
143 /* Check whether this is a super speed bus. */
144 int64_t iSpeed = 0;
145 bool fSuperSpeed = false;
146 rc = RTLinuxSysFsReadIntFile(10, &iSpeed, UTS_PLATFORM_LNX_DUMMY_HCD_PATH "/%s.%u/%s/speed",
147 pszHcdName, pHcd->idxDummyHcd, DirFolderContent.szName);
148 if ( RT_SUCCESS(rc)
149 && (iSpeed == 5000 || iSpeed == 10000))
150 {
151 fSuperSpeed = true;
152 pHcd->fSuperSpeed = true;
153 }
154
155 /* Add to array of available busses for this HCD. */
156 if (idxBusCur == idxBusMax)
157 {
158 size_t cbNew = (idxBusMax + 10) * sizeof(UTSPLATFORMLNXDUMMYHCDBUS);
159 PUTSPLATFORMLNXDUMMYHCDBUS pNew = (PUTSPLATFORMLNXDUMMYHCDBUS)RTMemRealloc(pHcd->paBusses, cbNew);
160 if (pNew)
161 {
162 idxBusMax += 10;
163 pHcd->paBusses = pNew;
164 }
165 }
166
167 if (idxBusCur < idxBusMax)
168 {
169 pHcd->paBusses[idxBusCur].uBusId = uBusId;
170 pHcd->paBusses[idxBusCur].fSuperSpeed = fSuperSpeed;
171 idxBusCur++;
172 }
173 else
174 rc = VERR_NO_MEMORY;
175 }
176 }
177 } while (RT_SUCCESS(rc));
178
179 pHcd->cBusses = idxBusCur;
180
181 if (rc == VERR_NO_MORE_FILES)
182 rc = VINF_SUCCESS;
183
184 RTDirClose(pDir);
185 }
186
187 return rc;
188}
189
190
191/**
192 * Scans all available HCDs with the given name.
193 *
194 * @returns IPRT status code.
195 * @param pszHcdName The base HCD name.
196 * @param pszUdcName The base UDC name.
197 */
198static int utsPlatformLnxHcdScanByName(const char *pszHcdName, const char *pszUdcName)
199{
200 char aszPath[RTPATH_MAX + 1];
201 size_t cchPath = RTStrPrintf(&aszPath[0], RT_ELEMENTS(aszPath),
202 UTS_PLATFORM_LNX_DUMMY_HCD_PATH "/%s.*", pszHcdName);
203 if (cchPath == RT_ELEMENTS(aszPath))
204 return VERR_BUFFER_OVERFLOW;
205
206 /* Enumerate the available HCD and their bus numbers. */
207 PRTDIR pDir = NULL;
208 int rc = RTDirOpenFiltered(&pDir, aszPath, RTDIRFILTER_WINNT, 0);
209 if (RT_SUCCESS(rc))
210 {
211 unsigned idxHcdCur = g_cDummyHcd;
212 unsigned idxHcdMax = g_cDummyHcd;
213
214 do
215 {
216 RTDIRENTRY DirFolderContent;
217 rc = RTDirRead(pDir, &DirFolderContent, NULL);
218 if (RT_SUCCESS(rc))
219 {
220 /*
221 * Get the HCD index and assigned bus number form the sysfs entries,
222 * Any error here is silently ignored and results in the HCD not being
223 * added to the list of available controllers.
224 */
225 const char *pszIdx = RTStrStr(DirFolderContent.szName, ".");
226 if (pszIdx)
227 {
228 /* Skip the separator and convert number to index. */
229 pszIdx++;
230
231 uint32_t idxHcd = 0;
232 rc = RTStrToUInt32Ex(pszIdx, NULL, 10, &idxHcd);
233 if (RT_SUCCESS(rc))
234 {
235 /* Add to array of available HCDs. */
236 if (idxHcdCur == idxHcdMax)
237 {
238 size_t cbNew = (idxHcdMax + 10) * sizeof(UTSPLATFORMLNXDUMMYHCD);
239 PUTSPLATFORMLNXDUMMYHCD pNew = (PUTSPLATFORMLNXDUMMYHCD)RTMemRealloc(g_paDummyHcd, cbNew);
240 if (pNew)
241 {
242 idxHcdMax += 10;
243 g_paDummyHcd = pNew;
244 }
245 }
246
247 if (idxHcdCur < idxHcdMax)
248 {
249 g_paDummyHcd[idxHcdCur].idxDummyHcd = idxHcd;
250 g_paDummyHcd[idxHcdCur].pszHcdName = pszHcdName;
251 g_paDummyHcd[idxHcdCur].pszUdcName = pszUdcName;
252 g_paDummyHcd[idxHcdCur].fAvailable = true;
253 g_paDummyHcd[idxHcdCur].fSuperSpeed = false;
254 g_paDummyHcd[idxHcdCur].cBusses = 0;
255 g_paDummyHcd[idxHcdCur].paBusses = NULL;
256 rc = utsPlatformLnxDummyHcdQueryBusses(&g_paDummyHcd[idxHcdCur], pszHcdName);
257 if (RT_SUCCESS(rc))
258 idxHcdCur++;
259 }
260 else
261 rc = VERR_NO_MEMORY;
262 }
263 }
264 }
265 } while (RT_SUCCESS(rc));
266
267 g_cDummyHcd = idxHcdCur;
268
269 if (rc == VERR_NO_MORE_FILES)
270 rc = VINF_SUCCESS;
271
272 RTDirClose(pDir);
273 }
274
275 return rc;
276}
277
278DECLHIDDEN(int) utsPlatformInit(void)
279{
280 /* Load the modules required for setting up USB/IP testing. */
281 int rc = utsPlatformModuleLoad("libcomposite", NULL, 0);
282 if (RT_SUCCESS(rc))
283 {
284 const char *apszArg[] = { "num=20" }; /** @todo: Make configurable from config. */
285 rc = utsPlatformModuleLoad("dummy_hcd", &apszArg[0], RT_ELEMENTS(apszArg));
286 if (RT_SUCCESS(rc))
287 rc = utsPlatformModuleLoad("dummy_hcd_ss", &apszArg[0], RT_ELEMENTS(apszArg));
288 if (RT_SUCCESS(rc))
289 rc = utsPlatformLnxHcdScanByName("dummy_hcd", "dummy_udc");
290 if (RT_SUCCESS(rc))
291 rc = utsPlatformLnxHcdScanByName("dummy_hcd_ss", "dummy_udc_ss");
292 }
293
294 return rc;
295}
296
297
298DECLHIDDEN(void) utsPlatformTerm(void)
299{
300 /* Unload dummy HCD. */
301 utsPlatformModuleUnload("dummy_hcd");
302 utsPlatformModuleUnload("dummy_hcd_ss");
303
304 RTMemFree(g_paDummyHcd);
305}
306
307
308DECLHIDDEN(int) utsPlatformModuleLoad(const char *pszModule, const char **papszArgv,
309 unsigned cArgv)
310{
311 RTPROCESS hProcModprobe = NIL_RTPROCESS;
312 const char **papszArgs = (const char **)RTMemAllocZ((3 + cArgv) * sizeof(const char *));
313 if (RT_UNLIKELY(!papszArgs))
314 return VERR_NO_MEMORY;
315
316 papszArgs[0] = "modprobe";
317 papszArgs[1] = pszModule;
318
319 unsigned idx;
320 for (idx = 0; idx < cArgv; idx++)
321 papszArgs[2+idx] = papszArgv[idx];
322 papszArgs[2+idx] = NULL;
323
324 int rc = RTProcCreate("modprobe", papszArgs, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProcModprobe);
325 if (RT_SUCCESS(rc))
326 {
327 RTPROCSTATUS ProcSts;
328 rc = RTProcWait(hProcModprobe, RTPROCWAIT_FLAGS_BLOCK, &ProcSts);
329 if (RT_SUCCESS(rc))
330 {
331 /* Evaluate the process status. */
332 if ( ProcSts.enmReason != RTPROCEXITREASON_NORMAL
333 || ProcSts.iStatus != 0)
334 rc = VERR_UNRESOLVED_ERROR; /** @todo Log and give finer grained status code. */
335 }
336 }
337
338 RTMemFree(papszArgs);
339 return rc;
340}
341
342
343DECLHIDDEN(int) utsPlatformModuleUnload(const char *pszModule)
344{
345 RTPROCESS hProcModprobe = NIL_RTPROCESS;
346 const char *apszArgv[3];
347
348 apszArgv[0] = "rmmod";
349 apszArgv[1] = pszModule;
350 apszArgv[2] = NULL;
351
352 int rc = RTProcCreate("rmmod", apszArgv, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProcModprobe);
353 if (RT_SUCCESS(rc))
354 {
355 RTPROCSTATUS ProcSts;
356 rc = RTProcWait(hProcModprobe, RTPROCWAIT_FLAGS_BLOCK, &ProcSts);
357 if (RT_SUCCESS(rc))
358 {
359 /* Evaluate the process status. */
360 if ( ProcSts.enmReason != RTPROCEXITREASON_NORMAL
361 || ProcSts.iStatus != 0)
362 rc = VERR_UNRESOLVED_ERROR; /** @todo Log and give finer grained status code. */
363 }
364 }
365
366 return rc;
367}
368
369
370DECLHIDDEN(int) utsPlatformLnxAcquireUDC(bool fSuperSpeed, char **ppszUdc, uint32_t *puBusId)
371{
372 int rc = VERR_NOT_FOUND;
373
374 for (unsigned i = 0; i < g_cDummyHcd; i++)
375 {
376 PUTSPLATFORMLNXDUMMYHCD pHcd = &g_paDummyHcd[i];
377
378 /*
379 * We can't use a super speed capable UDC for gadgets with lower speeds
380 * because they hardcode the maximum speed to SuperSpeed most of the time
381 * which will make it unusable for lower speeds.
382 */
383 if ( pHcd->fAvailable
384 && pHcd->fSuperSpeed == fSuperSpeed)
385 {
386 /* Check all assigned busses for a speed match. */
387 for (unsigned idxBus = 0; idxBus < pHcd->cBusses; idxBus++)
388 {
389 if (pHcd->paBusses[idxBus].fSuperSpeed == fSuperSpeed)
390 {
391 rc = VINF_SUCCESS;
392 int cbRet = RTStrAPrintf(ppszUdc, "%s.%u", pHcd->pszUdcName, pHcd->idxDummyHcd);
393 if (cbRet == -1)
394 rc = VERR_NO_STR_MEMORY;
395 *puBusId = pHcd->paBusses[idxBus].uBusId;
396 pHcd->fAvailable = false;
397 break;
398 }
399 }
400
401 if (rc != VERR_NOT_FOUND)
402 break;
403 }
404 }
405
406 return rc;
407}
408
409
410DECLHIDDEN(int) utsPlatformLnxReleaseUDC(const char *pszUdc)
411{
412 int rc = VERR_INVALID_PARAMETER;
413 const char *pszIdx = RTStrStr(pszUdc, ".");
414 if (pszIdx)
415 {
416 size_t cchUdcName = pszIdx - pszUdc;
417 pszIdx++;
418 uint32_t idxHcd = 0;
419 rc = RTStrToUInt32Ex(pszIdx, NULL, 10, &idxHcd);
420 if (RT_SUCCESS(rc))
421 {
422 rc = VERR_NOT_FOUND;
423
424 for (unsigned i = 0; i < g_cDummyHcd; i++)
425 {
426 if ( g_paDummyHcd[i].idxDummyHcd == idxHcd
427 && !RTStrNCmp(g_paDummyHcd[i].pszUdcName, pszUdc, cchUdcName))
428 {
429 AssertReturn(!g_paDummyHcd[i].fAvailable, VERR_INVALID_PARAMETER);
430 g_paDummyHcd[i].fAvailable = true;
431 rc = VINF_SUCCESS;
432 break;
433 }
434 }
435 }
436 }
437
438 return rc;
439}
440
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