VirtualBox

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

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

ValidationKit/UsbTestService: Updates, implement the protocol bits for passing extended configuration from the client to the gadget, detect multiple busses from dummy_hcd which creates a separate bus for high-speed and super-speed gadgets, some smaller fixes

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