VirtualBox

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

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

ValidationKit/usb: Fixes, basic compliance testing works finally

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 KB
Line 
1/* $Id: UsbTestServicePlatform-linux.cpp 60522 2016-04-15 14:34:35Z 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 dummy UDC descriptor.
48 */
49typedef struct UTSPLATFORMLNXDUMMYHCD
50{
51 /* Index of the dummy hcd entry. */
52 uint32_t idxDummyHcd;
53 /** The bus ID on the host the dummy HCD is serving. */
54 uint32_t uBusId;
55 /** Flag whether this HCD is free for use. */
56 bool fAvailable;
57} UTSPLATFORMLNXDUMMYHCD;
58/** Pointer to a dummy HCD entry. */
59typedef UTSPLATFORMLNXDUMMYHCD *PUTSPLATFORMLNXDUMMYHCD;
60
61/*********************************************************************************************************************************
62* Global Variables *
63*********************************************************************************************************************************/
64
65/** Array of dummy HCD entries. */
66static PUTSPLATFORMLNXDUMMYHCD g_paDummyHcd = NULL;
67/** Number of Dummy hCD entries in the array. */
68static unsigned g_cDummyHcd = 0;
69
70
71/*********************************************************************************************************************************
72* Internal Functions *
73*********************************************************************************************************************************/
74
75
76/**
77 * Queries the assigned bus ID for the given dummy HCD index.
78 *
79 * @returns IPRT status code.
80 * @param idxHcd The HCD index to query the bus number for.
81 * @param puBusId Where to store the bus number on success.
82 */
83static int utsPlatformLnxDummyHcdQueryBusId(uint32_t idxHcd, uint32_t *puBusId)
84{
85 int rc = VINF_SUCCESS;
86 char aszPath[RTPATH_MAX + 1];
87
88 size_t cchPath = RTStrPrintf(&aszPath[0], RT_ELEMENTS(aszPath), UTS_PLATFORM_LNX_DUMMY_HCD_PATH "/dummy_hcd.%u/usb*", idxHcd);
89 if (cchPath == RT_ELEMENTS(aszPath))
90 return VERR_BUFFER_OVERFLOW;
91
92 PRTDIR pDir = NULL;
93 rc = RTDirOpenFiltered(&pDir, aszPath, RTDIRFILTER_WINNT, 0);
94 if (RT_SUCCESS(rc))
95 {
96 RTDIRENTRY DirFolderContent;
97 rc = RTDirRead(pDir, &DirFolderContent, NULL);
98 if (RT_SUCCESS(rc))
99 {
100 /* Extract the bus number - it is after "usb", i.e. "usb9" indicates a bus ID of 9. */
101 rc = RTStrToUInt32Ex(&DirFolderContent.szName[3], NULL, 10, puBusId);
102 if (RT_SUCCESS(rc))
103 {
104 /* Make sure there is no other entry or something screwed us up. */
105 rc = RTDirRead(pDir, &DirFolderContent, NULL);
106 if (RT_SUCCESS(rc))
107 rc = VERR_INVALID_STATE;
108 else if (rc == VERR_NO_MORE_FILES)
109 rc = VINF_SUCCESS;
110 }
111 }
112
113 RTDirClose(pDir);
114 }
115
116 return rc;
117}
118
119
120DECLHIDDEN(int) utsPlatformInit(void)
121{
122 /* Load the modules required for setting up USB/IP testing. */
123 int rc = utsPlatformModuleLoad("libcomposite", NULL, 0);
124 if (RT_SUCCESS(rc))
125 {
126 const char *pszArg = "num=2"; /** @todo: Make configurable from config. */
127 rc = utsPlatformModuleLoad("dummy_hcd", &pszArg, 1);
128 if (RT_SUCCESS(rc))
129 {
130 /* Enumerate the available HCD and their bus numbers. */
131 PRTDIR pDir = NULL;
132 rc = RTDirOpenFiltered(&pDir, UTS_PLATFORM_LNX_DUMMY_HCD_PATH "/dummy_hcd.*", RTDIRFILTER_WINNT, 0);
133 if (RT_SUCCESS(rc))
134 {
135 unsigned idxHcdCur = 0;
136 unsigned idxHcdMax = 0;
137
138 do
139 {
140 RTDIRENTRY DirFolderContent;
141 rc = RTDirRead(pDir, &DirFolderContent, NULL);
142 if (RT_SUCCESS(rc))
143 {
144 /*
145 * Get the HCD index and assigned bus number form the sysfs entries,
146 * Any error here is silently ignored and results in the HCD not being
147 * added to the list of available controllers.
148 */
149 const char *pszIdx = RTStrStr(DirFolderContent.szName, ".");
150 if (pszIdx)
151 {
152 /* Skip the separator and convert number to index. */
153 pszIdx++;
154
155 uint32_t idxHcd = 0;
156 rc = RTStrToUInt32Ex(pszIdx, NULL, 10, &idxHcd);
157 if (RT_SUCCESS(rc))
158 {
159 uint32_t uBusId = 0;
160 rc = utsPlatformLnxDummyHcdQueryBusId(idxHcd, &uBusId);
161 if (RT_SUCCESS(rc))
162 {
163 /* Add to array of available HCDs. */
164 if (idxHcdCur == idxHcdMax)
165 {
166 size_t cbNew = (idxHcdMax + 10) * sizeof(UTSPLATFORMLNXDUMMYHCD);
167 PUTSPLATFORMLNXDUMMYHCD pNew = (PUTSPLATFORMLNXDUMMYHCD)RTMemRealloc(g_paDummyHcd, cbNew);
168 if (pNew)
169 {
170 idxHcdMax += 10;
171 g_paDummyHcd = pNew;
172 }
173 }
174
175 if (idxHcdCur < idxHcdMax)
176 {
177 g_paDummyHcd[idxHcdCur].idxDummyHcd = idxHcd;
178 g_paDummyHcd[idxHcdCur].uBusId = uBusId;
179 g_paDummyHcd[idxHcdCur].fAvailable = true;
180 idxHcdCur++;
181 }
182 }
183 }
184 }
185 }
186 } while (RT_SUCCESS(rc));
187
188 g_cDummyHcd = idxHcdCur;
189
190 if (rc == VERR_NO_MORE_FILES)
191 rc = VINF_SUCCESS;
192
193 RTDirClose(pDir);
194 }
195 }
196 }
197
198 return rc;
199}
200
201
202DECLHIDDEN(void) utsPlatformTerm(void)
203{
204 /* Unload dummy HCD. */
205 utsPlatformModuleUnload("dummy_hcd");
206
207 RTMemFree(g_paDummyHcd);
208}
209
210
211DECLHIDDEN(int) utsPlatformModuleLoad(const char *pszModule, const char **papszArgv,
212 unsigned cArgv)
213{
214 RTPROCESS hProcModprobe = NIL_RTPROCESS;
215 const char **papszArgs = (const char **)RTMemAllocZ((3 + cArgv) * sizeof(const char *));
216 if (RT_UNLIKELY(!papszArgs))
217 return VERR_NO_MEMORY;
218
219 papszArgs[0] = "modprobe";
220 papszArgs[1] = pszModule;
221
222 unsigned idx;
223 for (idx = 0; idx < cArgv; idx++)
224 papszArgs[2+idx] = papszArgs[idx];
225 papszArgs[2+idx] = NULL;
226
227 int rc = RTProcCreate("modprobe", papszArgs, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProcModprobe);
228 if (RT_SUCCESS(rc))
229 {
230 RTPROCSTATUS ProcSts;
231 rc = RTProcWait(hProcModprobe, RTPROCWAIT_FLAGS_BLOCK, &ProcSts);
232 if (RT_SUCCESS(rc))
233 {
234 /* Evaluate the process status. */
235 if ( ProcSts.enmReason != RTPROCEXITREASON_NORMAL
236 || ProcSts.iStatus != 0)
237 rc = VERR_UNRESOLVED_ERROR; /** @todo: Log and give finer grained status code. */
238 }
239 }
240
241 RTMemFree(papszArgs);
242 return rc;
243}
244
245
246DECLHIDDEN(int) utsPlatformModuleUnload(const char *pszModule)
247{
248 RTPROCESS hProcModprobe = NIL_RTPROCESS;
249 const char *apszArgv[3];
250
251 apszArgv[0] = "rmmod";
252 apszArgv[1] = pszModule;
253 apszArgv[2] = NULL;
254
255 int rc = RTProcCreate("rmmod", apszArgv, RTENV_DEFAULT, RTPROC_FLAGS_SEARCH_PATH, &hProcModprobe);
256 if (RT_SUCCESS(rc))
257 {
258 RTPROCSTATUS ProcSts;
259 rc = RTProcWait(hProcModprobe, RTPROCWAIT_FLAGS_BLOCK, &ProcSts);
260 if (RT_SUCCESS(rc))
261 {
262 /* Evaluate the process status. */
263 if ( ProcSts.enmReason != RTPROCEXITREASON_NORMAL
264 || ProcSts.iStatus != 0)
265 rc = VERR_UNRESOLVED_ERROR; /** @todo: Log and give finer grained status code. */
266 }
267 }
268
269 return rc;
270}
271
272
273DECLHIDDEN(int) utsPlatformLnxAcquireUDC(char **ppszUdc, uint32_t *puBusId)
274{
275 int rc = VERR_NOT_FOUND;
276
277 for (unsigned i = 0; i < g_cDummyHcd; i++)
278 {
279 if (g_paDummyHcd[i].fAvailable)
280 {
281 rc = VINF_SUCCESS;
282 int cbRet = RTStrAPrintf(ppszUdc, "dummy_udc.%u", g_paDummyHcd[i].idxDummyHcd);
283 if (cbRet == -1)
284 rc = VERR_NO_STR_MEMORY;
285 *puBusId = g_paDummyHcd[i].uBusId;
286 g_paDummyHcd[i].fAvailable = false;
287 break;
288 }
289 }
290
291 return rc;
292}
293
294
295DECLHIDDEN(int) utsPlatformLnxReleaseUDC(const char *pszUdc)
296{
297 int rc = VERR_INVALID_PARAMETER;
298 const char *pszIdx = RTStrStr(pszUdc, ".");
299 if (pszIdx)
300 {
301 pszIdx++;
302 uint32_t idxHcd = 0;
303 rc = RTStrToUInt32Ex(pszIdx, NULL, 10, &idxHcd);
304 if (RT_SUCCESS(rc))
305 {
306 rc = VERR_NOT_FOUND;
307
308 for (unsigned i = 0; i < g_cDummyHcd; i++)
309 {
310 if (g_paDummyHcd[i].idxDummyHcd == idxHcd)
311 {
312 AssertReturn(!g_paDummyHcd[i].fAvailable, VERR_INVALID_PARAMETER);
313 g_paDummyHcd[i].fAvailable = true;
314 rc = VINF_SUCCESS;
315 break;
316 }
317 }
318 }
319 }
320
321 return rc;
322}
323
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