VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/PDMUsb.cpp@ 107276

Last change on this file since 107276 was 107276, checked in by vboxsync, 5 weeks ago

PDMUsb: bugref:10810 Introduced PDMR3UsbQueryDeviceLun needed by Console::i_onNetworkAdapterChange

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.1 KB
Line 
1/* $Id: PDMUsb.cpp 107276 2024-12-10 12:40:08Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, USB part.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_PDM_DRIVER
33#include "PDMInternal.h"
34#include <VBox/vmm/pdm.h>
35#include <VBox/vusb.h>
36#include <VBox/vmm/mm.h>
37#include <VBox/vmm/cfgm.h>
38#include <VBox/vmm/vmm.h>
39#include <VBox/sup.h>
40#include <VBox/vmm/vm.h>
41#include <VBox/vmm/uvm.h>
42#include <VBox/version.h>
43#include <VBox/err.h>
44
45#include <VBox/log.h>
46#include <iprt/assert.h>
47#include <iprt/thread.h>
48#include <iprt/string.h>
49#include <iprt/asm.h>
50#include <iprt/alloc.h>
51#include <iprt/alloca.h>
52#include <iprt/path.h>
53#include <iprt/uuid.h>
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59/**
60 * Internal callback structure pointer.
61 *
62 * The main purpose is to define the extra data we associate
63 * with PDMUSBREGCB so we can find the VM instance and so on.
64 */
65typedef struct PDMUSBREGCBINT
66{
67 /** The callback structure. */
68 PDMUSBREGCB Core;
69 /** A bit of padding. */
70 uint32_t u32[4];
71 /** VM Handle. */
72 PVM pVM;
73} PDMUSBREGCBINT, *PPDMUSBREGCBINT;
74typedef const PDMUSBREGCBINT *PCPDMUSBREGCBINT;
75
76
77/*********************************************************************************************************************************
78* Defined Constants And Macros *
79*********************************************************************************************************************************/
80/** @def PDMUSB_ASSERT_USBINS
81 * Asserts the validity of the USB device instance.
82 */
83#ifdef VBOX_STRICT
84# define PDMUSB_ASSERT_USBINS(pUsbIns) \
85 do { \
86 AssertPtr(pUsbIns); \
87 Assert(pUsbIns->u32Version == PDM_USBINS_VERSION); \
88 Assert(pUsbIns->pvInstanceDataR3 == (void *)&pUsbIns->achInstanceData[0]); \
89 } while (0)
90#else
91# define PDMUSB_ASSERT_USBINS(pUsbIns) do { } while (0)
92#endif
93
94
95/*********************************************************************************************************************************
96* Internal Functions *
97*********************************************************************************************************************************/
98static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns);
99
100
101/*********************************************************************************************************************************
102* Global Variables *
103*********************************************************************************************************************************/
104extern const PDMUSBHLP g_pdmR3UsbHlp;
105
106
107AssertCompile(sizeof(PDMUSBINSINT) <= RT_SIZEOFMEMB(PDMUSBINS, Internal.padding));
108
109
110/**
111 * Registers a USB hub driver.
112 *
113 * @returns VBox status code.
114 * @param pVM The cross context VM structure.
115 * @param pDrvIns The driver instance of the hub.
116 * @param fVersions Indicates the kinds of USB devices that can be attached to this HUB.
117 * @param cPorts The number of ports.
118 * @param pUsbHubReg The hub callback structure that PDMUsb uses to interact with it.
119 * @param ppUsbHubHlp The helper callback structure that the hub uses to talk to PDMUsb.
120 * @thread EMT
121 */
122int pdmR3UsbRegisterHub(PVM pVM, PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
123{
124 /*
125 * Validate input.
126 */
127 /* The driver must be in the USB class. */
128 if (!(pDrvIns->pReg->fClass & PDM_DRVREG_CLASS_USB))
129 {
130 LogRel(("PDMUsb: pdmR3UsbRegisterHub: fClass=%#x expected %#x to be set\n", pDrvIns->pReg->fClass, PDM_DRVREG_CLASS_USB));
131 return VERR_INVALID_PARAMETER;
132 }
133 AssertMsgReturn(!(fVersions & ~(VUSB_STDVER_11 | VUSB_STDVER_20 | VUSB_STDVER_30)), ("%#x\n", fVersions), VERR_INVALID_PARAMETER);
134 AssertPtrReturn(ppUsbHubHlp, VERR_INVALID_POINTER);
135 AssertPtrReturn(pUsbHubReg, VERR_INVALID_POINTER);
136 AssertReturn(pUsbHubReg->u32Version == PDM_USBHUBREG_VERSION, VERR_INVALID_MAGIC);
137 AssertReturn(pUsbHubReg->u32TheEnd == PDM_USBHUBREG_VERSION, VERR_INVALID_MAGIC);
138 AssertPtrReturn(pUsbHubReg->pfnAttachDevice, VERR_INVALID_PARAMETER);
139 AssertPtrReturn(pUsbHubReg->pfnDetachDevice, VERR_INVALID_PARAMETER);
140
141 /*
142 * Check for duplicate registration and find the last hub for FIFO registration.
143 */
144 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
145
146 PPDMUSBHUB pPrev = NULL;
147 for (PPDMUSBHUB pCur = pVM->pdm.s.pUsbHubs; pCur; pCur = pCur->pNext)
148 {
149 if (pCur->pDrvIns == pDrvIns)
150 {
151 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
152 return VERR_PDM_USB_HUB_EXISTS;
153 }
154 pPrev = pCur;
155 }
156
157 /*
158 * Create an internal USB hub structure.
159 */
160 PPDMUSBHUB pHub = (PPDMUSBHUB)MMR3HeapAlloc(pVM, MM_TAG_PDM_DRIVER, sizeof(*pHub));
161 if (!pHub)
162 {
163 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
164 return VERR_NO_MEMORY;
165 }
166
167 pHub->fVersions = fVersions;
168 pHub->cPorts = cPorts;
169 pHub->cAvailablePorts = cPorts;
170 pHub->pDrvIns = pDrvIns;
171 pHub->Reg = *pUsbHubReg;
172 pHub->pNext = NULL;
173
174 /* link it */
175 if (pPrev)
176 pPrev->pNext = pHub;
177 else
178 pVM->pdm.s.pUsbHubs = pHub;
179
180 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
181
182 Log(("PDM: Registered USB hub %p/%s\n", pDrvIns, pDrvIns->pReg->szName));
183 return VINF_SUCCESS;
184}
185
186
187/**
188 * Loads one device module and call the registration entry point.
189 *
190 * @returns VBox status code.
191 * @param pVM The cross context VM structure.
192 * @param pRegCB The registration callback stuff.
193 * @param pszFilename Module filename.
194 * @param pszName Module name.
195 */
196static int pdmR3UsbLoad(PVM pVM, PCPDMUSBREGCBINT pRegCB, const char *pszFilename, const char *pszName)
197{
198 /*
199 * Load it.
200 */
201 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
202 if (RT_SUCCESS(rc))
203 {
204 /*
205 * Get the registration export and call it.
206 */
207 FNPDMVBOXUSBREGISTER *pfnVBoxUsbRegister;
208 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxUsbRegister", (void **)&pfnVBoxUsbRegister);
209 if (RT_SUCCESS(rc))
210 {
211 Log(("PDM: Calling VBoxUsbRegister (%p) of %s (%s)\n", pfnVBoxUsbRegister, pszName, pszFilename));
212 rc = pfnVBoxUsbRegister(&pRegCB->Core, VBOX_VERSION);
213 if (RT_SUCCESS(rc))
214 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
215 else
216 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
217 }
218 else
219 {
220 AssertMsgFailed(("Failed to locate 'VBoxUsbRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
221 if (rc == VERR_SYMBOL_NOT_FOUND)
222 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
223 }
224 }
225 else
226 AssertMsgFailed(("Failed to load VBoxDD!\n"));
227 return rc;
228}
229
230
231
232/**
233 * @interface_method_impl{PDMUSBREGCB,pfnRegister}
234 */
235static DECLCALLBACK(int) pdmR3UsbReg_Register(PCPDMUSBREGCB pCallbacks, PCPDMUSBREG pReg)
236{
237 /*
238 * Validate the registration structure.
239 */
240 Assert(pReg);
241 AssertMsgReturn(pReg->u32Version == PDM_USBREG_VERSION,
242 ("Unknown struct version %#x!\n", pReg->u32Version),
243 VERR_PDM_UNKNOWN_USBREG_VERSION);
244 AssertMsgReturn( pReg->szName[0]
245 && strlen(pReg->szName) < sizeof(pReg->szName)
246 && pdmR3IsValidName(pReg->szName),
247 ("Invalid name '%.*s'\n", sizeof(pReg->szName), pReg->szName),
248 VERR_PDM_INVALID_USB_REGISTRATION);
249 AssertMsgReturn((pReg->fFlags & ~(PDM_USBREG_HIGHSPEED_CAPABLE | PDM_USBREG_SUPERSPEED_CAPABLE | PDM_USBREG_SAVED_STATE_SUPPORTED)) == 0,
250 ("fFlags=%#x\n", pReg->fFlags), VERR_PDM_INVALID_USB_REGISTRATION);
251 AssertMsgReturn(pReg->cMaxInstances > 0,
252 ("Max instances %u! (USB Device %s)\n", pReg->cMaxInstances, pReg->szName),
253 VERR_PDM_INVALID_USB_REGISTRATION);
254 AssertMsgReturn(pReg->cbInstance <= _1M,
255 ("Instance size %d bytes! (USB Device %s)\n", pReg->cbInstance, pReg->szName),
256 VERR_PDM_INVALID_USB_REGISTRATION);
257 AssertMsgReturn(pReg->pfnConstruct, ("No constructor! (USB Device %s)\n", pReg->szName),
258 VERR_PDM_INVALID_USB_REGISTRATION);
259
260 /*
261 * Check for duplicate and find FIFO entry at the same time.
262 */
263 PCPDMUSBREGCBINT const pRegCB = (PCPDMUSBREGCBINT)pCallbacks;
264 PVM const pVM = pRegCB->pVM;
265 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
266
267 PPDMUSB pUsbPrev = NULL;
268 PPDMUSB pUsb = pVM->pdm.s.pUsbDevs;
269 for (; pUsb; pUsbPrev = pUsb, pUsb = pUsb->pNext)
270 AssertMsgReturnStmt(strcmp(pUsb->pReg->szName, pReg->szName),
271 ("USB Device '%s' already exists\n", pReg->szName),
272 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw),
273 VERR_PDM_USB_NAME_CLASH);
274
275 /*
276 * Allocate new device structure and insert it into the list.
277 */
278 pUsb = (PPDMUSB)MMR3HeapAlloc(pVM, MM_TAG_PDM_DEVICE, sizeof(*pUsb));
279 if (pUsb)
280 {
281 pUsb->pNext = NULL;
282 pUsb->iNextInstance = 0;
283 pUsb->pInstances = NULL;
284 pUsb->pReg = pReg;
285 pUsb->cchName = (RTUINT)strlen(pReg->szName);
286
287 if (pUsbPrev)
288 pUsbPrev->pNext = pUsb;
289 else
290 pVM->pdm.s.pUsbDevs = pUsb;
291
292 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
293 Log(("PDM: Registered USB device '%s'\n", pReg->szName));
294 return VINF_SUCCESS;
295 }
296
297 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
298 return VERR_NO_MEMORY;
299}
300
301
302/**
303 * Load USB Device modules.
304 *
305 * This is called by pdmR3DevInit() after it has loaded it's device modules.
306 *
307 * @returns VBox status code.
308 * @param pVM The cross context VM structure.
309 */
310int pdmR3UsbLoadModules(PVM pVM)
311{
312 LogFlow(("pdmR3UsbLoadModules:\n"));
313
314 AssertRelease(!(RT_UOFFSETOF(PDMUSBINS, achInstanceData) & 15));
315 AssertRelease(sizeof(pVM->pdm.s.pUsbInstances->Internal.s) <= sizeof(pVM->pdm.s.pUsbInstances->Internal.padding));
316
317 /*
318 * Initialize the callback structure.
319 */
320 PDMUSBREGCBINT RegCB;
321 RegCB.Core.u32Version = PDM_USBREG_CB_VERSION;
322 RegCB.Core.pfnRegister = pdmR3UsbReg_Register;
323 RegCB.pVM = pVM;
324
325 /*
326 * Load the builtin module
327 */
328 PCFGMNODE pUsbNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/USB/");
329 bool fLoadBuiltin;
330 int rc = CFGMR3QueryBool(pUsbNode, "LoadBuiltin", &fLoadBuiltin);
331 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
332 fLoadBuiltin = true;
333 else if (RT_FAILURE(rc))
334 {
335 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
336 return rc;
337 }
338 if (fLoadBuiltin)
339 {
340 /* make filename */
341 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
342 if (!pszFilename)
343 return VERR_NO_TMP_MEMORY;
344 rc = pdmR3UsbLoad(pVM, &RegCB, pszFilename, "VBoxDD");
345 RTMemTmpFree(pszFilename);
346 if (RT_FAILURE(rc))
347 return rc;
348 }
349
350 /*
351 * Load additional device modules.
352 */
353 PCFGMNODE pCur;
354 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
355 {
356 /*
357 * Get the name and path.
358 */
359 char szName[PDMMOD_NAME_LEN];
360 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
361 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
362 {
363 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
364 return VERR_PDM_MODULE_NAME_TOO_LONG;
365 }
366 else if (RT_FAILURE(rc))
367 {
368 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
369 return rc;
370 }
371
372 /* the path is optional, if no path the module name + path is used. */
373 char szFilename[RTPATH_MAX];
374 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
375 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
376 strcpy(szFilename, szName);
377 else if (RT_FAILURE(rc))
378 {
379 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
380 return rc;
381 }
382
383 /* prepend path? */
384 if (!RTPathHavePath(szFilename))
385 {
386 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
387 if (!psz)
388 return VERR_NO_TMP_MEMORY;
389 size_t cch = strlen(psz) + 1;
390 if (cch > sizeof(szFilename))
391 {
392 RTMemTmpFree(psz);
393 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
394 return VERR_FILENAME_TOO_LONG;
395 }
396 memcpy(szFilename, psz, cch);
397 RTMemTmpFree(psz);
398 }
399
400 /*
401 * Load the module and register it's devices.
402 */
403 rc = pdmR3UsbLoad(pVM, &RegCB, szFilename, szName);
404 if (RT_FAILURE(rc))
405 return rc;
406 }
407
408 return VINF_SUCCESS;
409}
410
411
412/**
413 * Send the init-complete notification to all the USB devices.
414 *
415 * This is called from pdmR3DevInit() after it has do its notification round.
416 *
417 * @returns VBox status code.
418 * @param pVM The cross context VM structure.
419 */
420int pdmR3UsbVMInitComplete(PVM pVM)
421{
422 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
423 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
424 {
425 if (pUsbIns->pReg->pfnVMInitComplete)
426 {
427 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
428 int rc = pUsbIns->pReg->pfnVMInitComplete(pUsbIns);
429 if (RT_FAILURE(rc))
430 {
431 AssertMsgFailed(("InitComplete on USB device '%s'/%d failed with rc=%Rrc\n",
432 pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
433 return rc;
434 }
435 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
436 }
437 }
438 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
439 return VINF_SUCCESS;
440}
441
442
443/**
444 * Lookups a device structure by name.
445 * @internal
446 */
447PPDMUSB pdmR3UsbLookup(PVM pVM, const char *pszName)
448{
449 size_t const cchName = strlen(pszName);
450
451 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
452 for (PPDMUSB pUsb = pVM->pdm.s.pUsbDevs; pUsb; pUsb = pUsb->pNext)
453 if ( pUsb->cchName == cchName
454 && !strcmp(pUsb->pReg->szName, pszName))
455 {
456 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
457 return pUsb;
458 }
459 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
460 return NULL;
461}
462
463
464/**
465 * Locates a suitable hub for the specified kind of device.
466 *
467 * @returns VINF_SUCCESS and *ppHub on success.
468 * VERR_PDM_NO_USB_HUBS or VERR_PDM_NO_USB_PORTS on failure.
469 * @param pVM The cross context VM structure.
470 * @param iUsbVersion The USB device version.
471 * @param ppHub Where to store the pointer to the USB hub.
472 */
473static int pdmR3UsbFindHub(PVM pVM, uint32_t iUsbVersion, PPDMUSBHUB *ppHub)
474{
475 *ppHub = NULL;
476 if (!pVM->pdm.s.pUsbHubs)
477 return VERR_PDM_NO_USB_HUBS;
478
479 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
480 for (PPDMUSBHUB pCur = pVM->pdm.s.pUsbHubs; pCur; pCur = pCur->pNext)
481 if (pCur->cAvailablePorts > 0)
482 {
483 /* First check for an exact match. */
484 if (pCur->fVersions & iUsbVersion)
485 {
486 *ppHub = pCur;
487 break;
488 }
489 /* For high-speed USB 2.0 devices only, allow USB 1.1 fallback. */
490 if ((iUsbVersion & VUSB_STDVER_20) && pCur->fVersions == VUSB_STDVER_11)
491 *ppHub = pCur;
492 }
493 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
494 if (*ppHub)
495 return VINF_SUCCESS;
496 return VERR_PDM_NO_USB_PORTS;
497}
498
499
500/**
501 * Translates a USB version (a bit-mask) to USB speed (enum). Picks
502 * the highest available version.
503 *
504 * @returns VUSBSPEED enum
505 *
506 * @param iUsbVersion The USB version.
507 *
508 */
509static VUSBSPEED pdmR3UsbVer2Spd(uint32_t iUsbVersion)
510{
511 VUSBSPEED enmSpd = VUSB_SPEED_UNKNOWN;
512 Assert(iUsbVersion);
513
514 if (iUsbVersion & VUSB_STDVER_30)
515 enmSpd = VUSB_SPEED_SUPER;
516 else if (iUsbVersion & VUSB_STDVER_20)
517 enmSpd = VUSB_SPEED_HIGH;
518 else if (iUsbVersion & VUSB_STDVER_11)
519 enmSpd = VUSB_SPEED_FULL; /* Can't distinguish LS vs. FS. */
520
521 return enmSpd;
522}
523
524
525/**
526 * Translates a USB speed (enum) to USB version.
527 *
528 * @returns USB version mask
529 *
530 * @param enmSpeed The USB connection speed.
531 *
532 */
533static uint32_t pdmR3UsbSpd2Ver(VUSBSPEED enmSpeed)
534{
535 uint32_t iUsbVersion = 0;
536 Assert(enmSpeed != VUSB_SPEED_UNKNOWN);
537
538 switch (enmSpeed)
539 {
540 case VUSB_SPEED_LOW:
541 case VUSB_SPEED_FULL:
542 iUsbVersion = VUSB_STDVER_11;
543 break;
544 case VUSB_SPEED_HIGH:
545 iUsbVersion = VUSB_STDVER_20;
546 break;
547 case VUSB_SPEED_SUPER:
548 case VUSB_SPEED_SUPERPLUS:
549 default:
550 iUsbVersion = VUSB_STDVER_30;
551 break;
552 }
553
554 return iUsbVersion;
555}
556
557
558/**
559 * Creates the device.
560 *
561 * @returns VBox status code.
562 * @param pVM The cross context VM structure.
563 * @param pHub The USB hub it'll be attached to.
564 * @param pUsbDev The USB device emulation.
565 * @param iInstance -1 if not called by pdmR3UsbInstantiateDevices().
566 * @param pUuid The UUID for this device.
567 * @param ppInstanceNode Pointer to the device instance pointer. This is set to NULL if inserted
568 * into the tree or cleaned up.
569 *
570 * In the pdmR3UsbInstantiateDevices() case (iInstance != -1) this is
571 * the actual instance node and will not be cleaned up.
572 *
573 * @param enmSpeed The speed the USB device is operating at.
574 * @param pszCaptureFilename Path to the file for USB traffic capturing, optional.
575 */
576static int pdmR3UsbCreateDevice(PVM pVM, PPDMUSBHUB pHub, PPDMUSB pUsbDev, int iInstance, PCRTUUID pUuid,
577 PCFGMNODE *ppInstanceNode, VUSBSPEED enmSpeed, const char *pszCaptureFilename)
578{
579 int rc;
580
581 AssertPtrReturn(ppInstanceNode, VERR_INVALID_POINTER);
582 AssertPtrReturn(*ppInstanceNode, VERR_INVALID_POINTER);
583
584 /*
585 * If not called by pdmR3UsbInstantiateDevices(), we'll have to fix
586 * the configuration now.
587 */
588 /* USB device node. */
589 PCFGMNODE pDevNode = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "USB/%s/", pUsbDev->pReg->szName);
590 if (!pDevNode)
591 {
592 rc = CFGMR3InsertNodeF(CFGMR3GetRoot(pVM), &pDevNode, "USB/%s/", pUsbDev->pReg->szName);
593 AssertRCReturn(rc, rc);
594 }
595
596 /* The instance node and number. */
597 PCFGMNODE pInstanceToDelete = NULL;
598 PCFGMNODE pInstanceNode = NULL;
599 if (iInstance == -1)
600 {
601 /** @todo r=bird: This code is bogus as it ASSUMES that all USB devices are
602 * capable of infinite number of instances. */
603 rc = VINF_SUCCESS; /* Shut up stupid incorrect uninitialized warning from Visual C++ 2010. */
604 for (unsigned c = 0; c < _2M; c++)
605 {
606 iInstance = pUsbDev->iNextInstance++;
607 rc = CFGMR3InsertNodeF(pDevNode, &pInstanceNode, "%d/", iInstance);
608 if (rc != VERR_CFGM_NODE_EXISTS)
609 break;
610 }
611 AssertRCReturn(rc, rc);
612
613 rc = CFGMR3ReplaceSubTree(pInstanceNode, *ppInstanceNode);
614 AssertRCReturn(rc, rc);
615 *ppInstanceNode = NULL;
616 pInstanceToDelete = pInstanceNode;
617 }
618 else
619 {
620 Assert(iInstance >= 0);
621 if (iInstance >= (int)pUsbDev->iNextInstance)
622 pUsbDev->iNextInstance = iInstance + 1;
623 pInstanceNode = *ppInstanceNode;
624 }
625
626 /* Make sure the instance config node exists. */
627 PCFGMNODE pConfig = CFGMR3GetChild(pInstanceNode, "Config");
628 if (!pConfig)
629 {
630 rc = CFGMR3InsertNode(pInstanceNode, "Config", &pConfig);
631 AssertRCReturn(rc, rc);
632 }
633 Assert(CFGMR3GetChild(pInstanceNode, "Config") == pConfig);
634
635 /* The global device config node. */
636 PCFGMNODE pGlobalConfig = CFGMR3GetChild(pDevNode, "GlobalConfig");
637 if (!pGlobalConfig)
638 {
639 rc = CFGMR3InsertNode(pDevNode, "GlobalConfig", &pGlobalConfig);
640 if (RT_FAILURE(rc))
641 {
642 CFGMR3RemoveNode(pInstanceToDelete);
643 AssertRCReturn(rc, rc);
644 }
645 }
646
647 /*
648 * Allocate the device instance.
649 */
650 size_t cb = RT_UOFFSETOF_DYN(PDMUSBINS, achInstanceData[pUsbDev->pReg->cbInstance]);
651 cb = RT_ALIGN_Z(cb, 16);
652 PPDMUSBINS pUsbIns;
653 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_USB, cb, (void **)&pUsbIns);
654 if (RT_FAILURE(rc))
655 {
656 AssertMsgFailed(("Failed to allocate %d bytes of instance data for USB device '%s'. rc=%Rrc\n",
657 cb, pUsbDev->pReg->szName, rc));
658 CFGMR3RemoveNode(pInstanceToDelete);
659 return rc;
660 }
661
662 /*
663 * Initialize it.
664 */
665 pUsbIns->u32Version = PDM_USBINS_VERSION;
666 //pUsbIns->Internal.s.pNext = NULL;
667 //pUsbIns->Internal.s.pPerDeviceNext = NULL;
668 pUsbIns->Internal.s.pUsbDev = pUsbDev;
669 pUsbIns->Internal.s.pVM = pVM;
670 //pUsbIns->Internal.s.pLuns = NULL;
671 pUsbIns->Internal.s.pCfg = pInstanceNode;
672 pUsbIns->Internal.s.pCfgDelete = pInstanceToDelete;
673 pUsbIns->Internal.s.pCfgGlobal = pGlobalConfig;
674 pUsbIns->Internal.s.Uuid = *pUuid;
675 //pUsbIns->Internal.s.pHub = NULL;
676 pUsbIns->Internal.s.iPort = UINT32_MAX; /* to be determined. */
677 VMSTATE const enmVMState = VMR3GetState(pVM);
678 pUsbIns->Internal.s.fVMSuspended = !VMSTATE_IS_POWERED_ON(enmVMState);
679 //pUsbIns->Internal.s.pfnAsyncNotify = NULL;
680 pUsbIns->pHlpR3 = &g_pdmR3UsbHlp;
681 pUsbIns->pReg = pUsbDev->pReg;
682 pUsbIns->pCfg = pConfig;
683 pUsbIns->pCfgGlobal = pGlobalConfig;
684 pUsbIns->iInstance = iInstance;
685 pUsbIns->pvInstanceDataR3 = &pUsbIns->achInstanceData[0];
686 pUsbIns->pszName = RTStrDup(pUsbDev->pReg->szName);
687 //pUsbIns->fTracing = 0;
688 pUsbIns->idTracing = ++pVM->pdm.s.idTracingOther;
689 pUsbIns->enmSpeed = enmSpeed;
690
691 /*
692 * Link it into all the lists.
693 */
694 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
695
696 /* The global instance FIFO. */
697 PPDMUSBINS pPrev1 = pVM->pdm.s.pUsbInstances;
698 if (!pPrev1)
699 pVM->pdm.s.pUsbInstances = pUsbIns;
700 else
701 {
702 while (pPrev1->Internal.s.pNext)
703 {
704 Assert(pPrev1->u32Version == PDM_USBINS_VERSION);
705 pPrev1 = pPrev1->Internal.s.pNext;
706 }
707 pPrev1->Internal.s.pNext = pUsbIns;
708 }
709
710 /* The per device instance FIFO. */
711 PPDMUSBINS pPrev2 = pUsbDev->pInstances;
712 if (!pPrev2)
713 pUsbDev->pInstances = pUsbIns;
714 else
715 {
716 while (pPrev2->Internal.s.pPerDeviceNext)
717 {
718 Assert(pPrev2->u32Version == PDM_USBINS_VERSION);
719 pPrev2 = pPrev2->Internal.s.pPerDeviceNext;
720 }
721 pPrev2->Internal.s.pPerDeviceNext = pUsbIns;
722 }
723
724 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
725
726 /*
727 * Call the constructor.
728 */
729 Log(("PDM: Constructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
730 rc = pUsbIns->pReg->pfnConstruct(pUsbIns, pUsbIns->iInstance, pUsbIns->pCfg, pUsbIns->pCfgGlobal);
731 if (RT_SUCCESS(rc))
732 {
733 /*
734 * Attach it to the hub.
735 */
736 Log(("PDM: Attaching it...\n"));
737 rc = pHub->Reg.pfnAttachDevice(pHub->pDrvIns, pUsbIns, pszCaptureFilename, &pUsbIns->Internal.s.iPort);
738 if (RT_SUCCESS(rc))
739 {
740 pHub->cAvailablePorts--;
741 Assert((int32_t)pHub->cAvailablePorts >= 0 && pHub->cAvailablePorts < pHub->cPorts);
742 pUsbIns->Internal.s.pHub = pHub;
743
744 /* Send the hot-plugged notification if applicable. */
745 if (VMSTATE_IS_POWERED_ON(enmVMState) && pUsbIns->pReg->pfnHotPlugged)
746 pUsbIns->pReg->pfnHotPlugged(pUsbIns);
747
748 Log(("PDM: Successfully attached USB device '%s' instance %d to hub %p\n",
749 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub));
750 return VINF_SUCCESS;
751 }
752
753 LogRel(("PDMUsb: Failed to attach USB device '%s' instance %d to hub %p: %Rrc\n",
754 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
755 }
756 else
757 {
758 AssertMsgFailed(("Failed to construct '%s'/%d! %Rra\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
759 if (rc == VERR_VERSION_MISMATCH)
760 rc = VERR_PDM_USBDEV_VERSION_MISMATCH;
761 }
762 if (VMSTATE_IS_POWERED_ON(enmVMState))
763 pdmR3UsbDestroyDevice(pVM, pUsbIns);
764 /* else: destructors are invoked later. */
765 return rc;
766}
767
768
769/**
770 * Instantiate USB devices.
771 *
772 * This is called by pdmR3DevInit() after it has instantiated the
773 * other devices and their drivers. If there aren't any hubs
774 * around, we'll silently skip the USB devices.
775 *
776 * @returns VBox status code.
777 * @param pVM The cross context VM structure.
778 */
779int pdmR3UsbInstantiateDevices(PVM pVM)
780{
781 /*
782 * Any hubs?
783 */
784 if (!pVM->pdm.s.pUsbHubs)
785 {
786 Log(("PDM: No USB hubs, skipping USB device instantiation.\n"));
787 return VINF_SUCCESS;
788 }
789
790 /*
791 * Count the device instances.
792 */
793 PCFGMNODE pCur;
794 PCFGMNODE pUsbNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "USB/");
795 PCFGMNODE pInstanceNode;
796 unsigned cUsbDevs = 0;
797 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
798 {
799 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
800 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
801 if (pInstanceNode != pGlobal)
802 cUsbDevs++;
803 }
804 if (!cUsbDevs)
805 {
806 Log(("PDM: No USB devices were configured!\n"));
807 return VINF_SUCCESS;
808 }
809 Log2(("PDM: cUsbDevs=%d!\n", cUsbDevs));
810
811 /*
812 * Collect info on each USB device instance.
813 */
814 struct USBDEVORDER
815 {
816 /** Configuration node. */
817 PCFGMNODE pNode;
818 /** Pointer to the USB device. */
819 PPDMUSB pUsbDev;
820 /** Init order. */
821 uint32_t u32Order;
822 /** VBox instance number. */
823 uint32_t iInstance;
824 /** Device UUID. */
825 RTUUID Uuid;
826 } *paUsbDevs = (struct USBDEVORDER *)alloca(sizeof(paUsbDevs[0]) * (cUsbDevs + 1)); /* (One extra for swapping) */
827 Assert(paUsbDevs);
828 int rc;
829 unsigned i = 0;
830 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
831 {
832 /* Get the device name. */
833 char szName[sizeof(paUsbDevs[0].pUsbDev->pReg->szName)];
834 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
835 AssertMsgRCReturn(rc, ("Configuration error: device name is too long (or something)! rc=%Rrc\n", rc), rc);
836
837 /* Find the device. */
838 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, szName);
839 AssertMsgReturn(pUsbDev, ("Configuration error: device '%s' not found!\n", szName), VERR_PDM_DEVICE_NOT_FOUND);
840
841 /* Configured priority or use default? */
842 uint32_t u32Order;
843 rc = CFGMR3QueryU32(pCur, "Priority", &u32Order);
844 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
845 u32Order = i << 4;
846 else
847 AssertMsgRCReturn(rc, ("Configuration error: reading \"Priority\" for the '%s' USB device failed rc=%Rrc!\n", szName, rc), rc);
848
849 /* Global config. */
850 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
851 if (!pGlobal)
852 {
853 rc = CFGMR3InsertNode(pCur, "GlobalConfig/", &pGlobal);
854 AssertMsgRCReturn(rc, ("Failed to create GlobalConfig node! rc=%Rrc\n", rc), rc);
855 CFGMR3SetRestrictedRoot(pGlobal);
856 }
857
858 /* Enumerate the device instances. */
859 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
860 {
861 if (pInstanceNode == pGlobal)
862 continue;
863
864 /* Use the configured UUID if present, create our own otherwise. */
865 char *pszUuid = NULL;
866
867 RTUuidClear(&paUsbDevs[i].Uuid);
868 rc = CFGMR3QueryStringAlloc(pInstanceNode, "UUID", &pszUuid);
869 if (RT_SUCCESS(rc))
870 {
871 AssertPtr(pszUuid);
872
873 rc = RTUuidFromStr(&paUsbDevs[i].Uuid, pszUuid);
874 AssertMsgRCReturn(rc, ("Failed to convert UUID from string! rc=%Rrc\n", rc), rc);
875 MMR3HeapFree(pszUuid);
876 }
877 else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
878 rc = RTUuidCreate(&paUsbDevs[i].Uuid);
879
880 AssertRCReturn(rc, rc);
881 paUsbDevs[i].pNode = pInstanceNode;
882 paUsbDevs[i].pUsbDev = pUsbDev;
883 paUsbDevs[i].u32Order = u32Order;
884
885 /* Get the instance number. */
886 char szInstance[32];
887 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
888 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
889 char *pszNext = NULL;
890 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paUsbDevs[i].iInstance);
891 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
892 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
893
894 /* next instance */
895 i++;
896 }
897 } /* devices */
898 Assert(i == cUsbDevs);
899
900 /*
901 * Sort the device array ascending on u32Order. (bubble)
902 */
903 unsigned c = cUsbDevs - 1;
904 while (c)
905 {
906 unsigned j = 0;
907 for (i = 0; i < c; i++)
908 if (paUsbDevs[i].u32Order > paUsbDevs[i + 1].u32Order)
909 {
910 paUsbDevs[cUsbDevs] = paUsbDevs[i + 1];
911 paUsbDevs[i + 1] = paUsbDevs[i];
912 paUsbDevs[i] = paUsbDevs[cUsbDevs];
913 j = i;
914 }
915 c = j;
916 }
917
918 /*
919 * Instantiate the devices.
920 */
921 for (i = 0; i < cUsbDevs; i++)
922 {
923 /*
924 * Make sure there is a config node and mark it as restricted.
925 */
926 PCFGMNODE pConfigNode = CFGMR3GetChild(paUsbDevs[i].pNode, "Config/");
927 if (!pConfigNode)
928 {
929 rc = CFGMR3InsertNode(paUsbDevs[i].pNode, "Config", &pConfigNode);
930 AssertMsgRCReturn(rc, ("Failed to create Config node! rc=%Rrc\n", rc), rc);
931 }
932 CFGMR3SetRestrictedRoot(pConfigNode);
933
934 /*
935 * Every emulated device must support USB 1.x hubs; optionally, high-speed USB 2.0 hubs
936 * might be also supported. This determines where to attach the device.
937 */
938 uint32_t iUsbVersion = VUSB_STDVER_11;
939
940 if (paUsbDevs[i].pUsbDev->pReg->fFlags & PDM_USBREG_HIGHSPEED_CAPABLE)
941 iUsbVersion |= VUSB_STDVER_20;
942 if (paUsbDevs[i].pUsbDev->pReg->fFlags & PDM_USBREG_SUPERSPEED_CAPABLE)
943 iUsbVersion |= VUSB_STDVER_30;
944
945 /*
946 * Find a suitable hub with free ports.
947 */
948 PPDMUSBHUB pHub;
949 rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
950 if (RT_FAILURE(rc))
951 {
952 Log(("pdmR3UsbFindHub failed %Rrc\n", rc));
953 return rc;
954 }
955
956 /*
957 * This is how we inform the device what speed it's communicating at, and hence
958 * which descriptors it should present to the guest.
959 */
960 iUsbVersion &= pHub->fVersions;
961
962 /*
963 * Create and attach the device.
964 */
965 rc = pdmR3UsbCreateDevice(pVM, pHub, paUsbDevs[i].pUsbDev, paUsbDevs[i].iInstance, &paUsbDevs[i].Uuid,
966 &paUsbDevs[i].pNode, pdmR3UsbVer2Spd(iUsbVersion), NULL);
967 if (RT_FAILURE(rc))
968 return rc;
969 } /* for device instances */
970
971 return VINF_SUCCESS;
972}
973
974
975/**
976 * Creates an emulated USB device instance at runtime.
977 *
978 * This will find an appropriate HUB for the USB device
979 * and try instantiate the emulated device.
980 *
981 * @returns VBox status code.
982 * @param pUVM The user mode VM handle.
983 * @param pszDeviceName The name of the PDM device to instantiate.
984 * @param pInstanceNode The instance CFGM node.
985 * @param pUuid The UUID to be associated with the device.
986 * @param pszCaptureFilename Path to the file for USB traffic capturing, optional.
987 *
988 * @thread EMT
989 */
990VMMR3DECL(int) PDMR3UsbCreateEmulatedDevice(PUVM pUVM, const char *pszDeviceName, PCFGMNODE pInstanceNode, PCRTUUID pUuid,
991 const char *pszCaptureFilename)
992{
993 /*
994 * Validate input.
995 */
996 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
997 PVM pVM = pUVM->pVM;
998 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
999 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1000 AssertPtrReturn(pszDeviceName, VERR_INVALID_POINTER);
1001 AssertPtrReturn(pInstanceNode, VERR_INVALID_POINTER);
1002
1003 /*
1004 * Find the device.
1005 */
1006 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, pszDeviceName);
1007 if (!pUsbDev)
1008 {
1009 LogRel(("PDMUsb: PDMR3UsbCreateEmulatedDevice: The '%s' device wasn't found\n", pszDeviceName));
1010 return VERR_PDM_NO_USBPROXY;
1011 }
1012
1013 /*
1014 * Every device must support USB 1.x hubs; optionally, high-speed USB 2.0 hubs
1015 * might be also supported. This determines where to attach the device.
1016 */
1017 uint32_t iUsbVersion = VUSB_STDVER_11;
1018 if (pUsbDev->pReg->fFlags & PDM_USBREG_HIGHSPEED_CAPABLE)
1019 iUsbVersion |= VUSB_STDVER_20;
1020 if (pUsbDev->pReg->fFlags & PDM_USBREG_SUPERSPEED_CAPABLE)
1021 iUsbVersion |= VUSB_STDVER_30;
1022
1023 /*
1024 * Find a suitable hub with free ports.
1025 */
1026 PPDMUSBHUB pHub;
1027 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
1028 if (RT_FAILURE(rc))
1029 {
1030 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
1031 return rc;
1032 }
1033
1034 /*
1035 * This is how we inform the device what speed it's communicating at, and hence
1036 * which descriptors it should present to the guest.
1037 */
1038 iUsbVersion &= pHub->fVersions;
1039
1040 /*
1041 * Create and attach the device.
1042 */
1043 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstanceNode,
1044 pdmR3UsbVer2Spd(iUsbVersion), pszCaptureFilename);
1045 AssertRCReturn(rc, rc);
1046
1047 return rc;
1048}
1049
1050
1051/**
1052 * Creates a USB proxy device instance.
1053 *
1054 * This will find an appropriate HUB for the USB device, create the necessary CFGM stuff
1055 * and try instantiate the proxy device.
1056 *
1057 * @returns VBox status code.
1058 * @param pUVM The user mode VM handle.
1059 * @param pUuid The UUID to be associated with the device.
1060 * @param pszBackend The proxy backend to use.
1061 * @param pszAddress The address string.
1062 * @param pSubTree The CFGM subtree to incorporate into the settings
1063 * (same restrictions as for CFGMR3InsertSubTree() apply),
1064 * optional.
1065 * @param enmSpeed The speed the USB device is operating at.
1066 * @param fMaskedIfs The interfaces to hide from the guest.
1067 * @param pszCaptureFilename Path to the file for USB traffic capturing, optional.
1068 */
1069VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, PCFGMNODE pSubTree,
1070 VUSBSPEED enmSpeed, uint32_t fMaskedIfs, const char *pszCaptureFilename)
1071{
1072 /*
1073 * Validate input.
1074 */
1075 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1076 PVM pVM = pUVM->pVM;
1077 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1078 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1079 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1080 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
1081 AssertReturn( enmSpeed == VUSB_SPEED_LOW
1082 || enmSpeed == VUSB_SPEED_FULL
1083 || enmSpeed == VUSB_SPEED_HIGH
1084 || enmSpeed == VUSB_SPEED_SUPER
1085 || enmSpeed == VUSB_SPEED_SUPERPLUS, VERR_INVALID_PARAMETER);
1086
1087 /*
1088 * Find the USBProxy driver.
1089 */
1090 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, "USBProxy");
1091 if (!pUsbDev)
1092 {
1093 LogRel(("PDMUsb: PDMR3UsbCreateProxyDevice: The USBProxy device class wasn't found\n"));
1094 return VERR_PDM_NO_USBPROXY;
1095 }
1096
1097 /*
1098 * Find a suitable hub with free ports.
1099 */
1100 PPDMUSBHUB pHub;
1101 uint32_t iUsbVersion = pdmR3UsbSpd2Ver(enmSpeed);
1102 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
1103 if (RT_FAILURE(rc))
1104 {
1105 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
1106 return rc;
1107 }
1108
1109 /*
1110 * Create the CFGM instance node.
1111 */
1112 PCFGMNODE pInstance = CFGMR3CreateTree(pUVM);
1113 AssertReturn(pInstance, VERR_NO_MEMORY);
1114 do /* break loop */
1115 {
1116 PCFGMNODE pConfig;
1117 rc = CFGMR3InsertNode(pInstance, "Config", &pConfig); AssertRCBreak(rc);
1118 rc = CFGMR3InsertString(pConfig, "Address", pszAddress); AssertRCBreak(rc);
1119 char szUuid[RTUUID_STR_LENGTH];
1120 rc = RTUuidToStr(pUuid, &szUuid[0], sizeof(szUuid)); AssertRCBreak(rc);
1121 rc = CFGMR3InsertString(pConfig, "UUID", szUuid); AssertRCBreak(rc);
1122 rc = CFGMR3InsertString(pConfig, "Backend", pszBackend); AssertRCBreak(rc);
1123 rc = CFGMR3InsertInteger(pConfig, "MaskedIfs", fMaskedIfs); AssertRCBreak(rc);
1124 rc = CFGMR3InsertInteger(pConfig, "Force11Device", !(pHub->fVersions & iUsbVersion)); AssertRCBreak(rc);
1125 if (pSubTree)
1126 {
1127 rc = CFGMR3InsertSubTree(pConfig, "BackendCfg", pSubTree, NULL /*ppChild*/);
1128 AssertRCBreak(rc);
1129 }
1130 } while (0); /* break loop */
1131 if (RT_FAILURE(rc))
1132 {
1133 CFGMR3RemoveNode(pInstance);
1134 LogRel(("PDMUsb: PDMR3UsbCreateProxyDevice: failed to setup CFGM config, rc=%Rrc\n", rc));
1135 return rc;
1136 }
1137
1138 if (enmSpeed == VUSB_SPEED_UNKNOWN)
1139 enmSpeed = pdmR3UsbVer2Spd(iUsbVersion);
1140
1141 /*
1142 * Finally, try to create it.
1143 */
1144 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstance, enmSpeed, pszCaptureFilename);
1145 if (RT_FAILURE(rc) && pInstance)
1146 CFGMR3RemoveNode(pInstance);
1147 return rc;
1148}
1149
1150
1151/**
1152 * Destroys a hot-plugged USB device.
1153 *
1154 * The device must be detached from the HUB at this point.
1155 *
1156 * @param pVM The cross context VM structure.
1157 * @param pUsbIns The USB device instance to destroy.
1158 * @thread EMT
1159 */
1160static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns)
1161{
1162 Assert(!pUsbIns->Internal.s.pHub);
1163
1164 /*
1165 * Do the unplug notification.
1166 */
1167 /** @todo what about the drivers? */
1168 if (pUsbIns->pReg->pfnHotUnplugged)
1169 pUsbIns->pReg->pfnHotUnplugged(pUsbIns);
1170
1171 /*
1172 * Destroy the luns with their driver chains and call the device destructor.
1173 */
1174 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
1175 while (pUsbIns->Internal.s.pLuns)
1176 {
1177 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1178 pUsbIns->Internal.s.pLuns = pLun->pNext;
1179 if (pLun->pTop)
1180 pdmR3DrvDestroyChain(pVM, pLun->pTop, PDM_TACH_FLAGS_NOT_HOT_PLUG); /* Hotplugging is handled differently here atm. */
1181 MMR3HeapFree(pLun);
1182 }
1183 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1184
1185 /* finally, the device. */
1186 if (pUsbIns->pReg->pfnDestruct)
1187 {
1188 Log(("PDM: Destructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1189 pUsbIns->pReg->pfnDestruct(pUsbIns);
1190 }
1191 TMR3TimerDestroyUsb(pVM, pUsbIns);
1192 SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
1193 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
1194#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1195 pdmR3AsyncCompletionTemplateDestroyUsb(pVM, pUsbIns);
1196#endif
1197
1198 /*
1199 * Unlink it.
1200 */
1201 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
1202
1203 /* The global instance FIFO. */
1204 if (pVM->pdm.s.pUsbInstances == pUsbIns)
1205 pVM->pdm.s.pUsbInstances = pUsbIns->Internal.s.pNext;
1206 else
1207 {
1208 PPDMUSBINS pPrev = pVM->pdm.s.pUsbInstances;
1209 while (pPrev && pPrev->Internal.s.pNext != pUsbIns)
1210 {
1211 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1212 pPrev = pPrev->Internal.s.pNext;
1213 }
1214 Assert(pPrev); Assert(pPrev != pUsbIns);
1215 if (pPrev)
1216 pPrev->Internal.s.pNext = pUsbIns->Internal.s.pNext;
1217 }
1218
1219 /* The per device instance FIFO. */
1220 PPDMUSB pUsbDev = pUsbIns->Internal.s.pUsbDev;
1221 if (pUsbDev->pInstances == pUsbIns)
1222 pUsbDev->pInstances = pUsbIns->Internal.s.pPerDeviceNext;
1223 else
1224 {
1225 PPDMUSBINS pPrev = pUsbDev->pInstances;
1226 while (pPrev && pPrev->Internal.s.pPerDeviceNext != pUsbIns)
1227 {
1228 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1229 pPrev = pPrev->Internal.s.pPerDeviceNext;
1230 }
1231 Assert(pPrev); Assert(pPrev != pUsbIns);
1232 if (pPrev)
1233 pPrev->Internal.s.pPerDeviceNext = pUsbIns->Internal.s.pPerDeviceNext;
1234 }
1235
1236 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1237
1238 /*
1239 * Trash it.
1240 */
1241 pUsbIns->u32Version = 0;
1242 pUsbIns->pReg = NULL;
1243 if (pUsbIns->pszName)
1244 {
1245 RTStrFree(pUsbIns->pszName);
1246 pUsbIns->pszName = NULL;
1247 }
1248 CFGMR3RemoveNode(pUsbIns->Internal.s.pCfgDelete);
1249 MMR3HeapFree(pUsbIns);
1250}
1251
1252
1253/**
1254 * Detaches and destroys a USB device.
1255 *
1256 * @returns VBox status code.
1257 * @param pUVM The user mode VM handle.
1258 * @param pUuid The UUID associated with the device to detach.
1259 * @thread EMT
1260 */
1261VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid)
1262{
1263 /*
1264 * Validate input.
1265 */
1266 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1267 PVM const pVM = pUVM->pVM;
1268 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1269 VM_ASSERT_EMT(pVM);
1270 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1271
1272 /*
1273 * Search the global list for it.
1274 */
1275 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1276 PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;
1277 for ( ; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1278 if (!RTUuidCompare(&pUsbIns->Internal.s.Uuid, pUuid))
1279 break;
1280 if (!pUsbIns)
1281 {
1282 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1283 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND; /** @todo VERR_PDM_USB_INSTANCE_NOT_FOUND */
1284 }
1285
1286 /*
1287 * Detach it from the HUB (if it's actually attached to one).
1288 */
1289 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
1290 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw); /** @todo would be nice to call the pfnDetachDevice owning this.. */
1291 if (pHub)
1292 {
1293 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
1294 if (RT_FAILURE(rc))
1295 {
1296 LogRel(("PDMUsb: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
1297 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
1298 return rc;
1299 }
1300
1301 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
1302 pHub->cAvailablePorts++;
1303 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
1304 pUsbIns->Internal.s.pHub = NULL;
1305 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1306 }
1307
1308 /*
1309 * Notify about unplugging and destroy the device with it's drivers.
1310 */
1311 pdmR3UsbDestroyDevice(pVM, pUsbIns);
1312
1313 return VINF_SUCCESS;
1314}
1315
1316
1317/**
1318 * Checks if there are any USB hubs attached.
1319 *
1320 * @returns true / false accordingly.
1321 * @param pUVM The user mode VM handle.
1322 */
1323VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM)
1324{
1325 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1326 PVM pVM = pUVM->pVM;
1327 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1328 return pVM->pdm.s.pUsbHubs != NULL;
1329}
1330
1331
1332/**
1333 * Locates a LUN.
1334 *
1335 * @returns VBox status code.
1336 * @param pVM The cross context VM structure.
1337 * @param pszDevice Device name.
1338 * @param iInstance Device instance.
1339 * @param iLun The Logical Unit to obtain the interface of.
1340 * @param ppLun Where to store the pointer to the LUN if found.
1341 */
1342static int pdmR3UsbFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
1343{
1344 /*
1345 * Iterate registered devices looking for the device.
1346 */
1347 size_t const cchDevice = strlen(pszDevice);
1348 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1349 for (PPDMUSB pUsbDev = pVM->pdm.s.pUsbDevs; pUsbDev; pUsbDev = pUsbDev->pNext)
1350 {
1351 if ( pUsbDev->cchName == cchDevice
1352 && !memcmp(pUsbDev->pReg->szName, pszDevice, cchDevice))
1353 {
1354 /*
1355 * Iterate device instances.
1356 */
1357 for (PPDMUSBINS pUsbIns = pUsbDev->pInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pPerDeviceNext)
1358 {
1359 if (pUsbIns->iInstance == iInstance)
1360 {
1361 /*
1362 * Iterate luns.
1363 */
1364 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1365 {
1366 if (pLun->iLun == iLun)
1367 {
1368 *ppLun = pLun;
1369 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1370 return VINF_SUCCESS;
1371 }
1372 }
1373 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1374 return VERR_PDM_LUN_NOT_FOUND;
1375 }
1376 }
1377 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1378 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1379 }
1380 }
1381 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1382 return VERR_PDM_DEVICE_NOT_FOUND;
1383}
1384
1385
1386/**
1387 * Attaches a preconfigured driver to an existing device or driver instance.
1388 *
1389 * This is used to change drivers and suchlike at runtime. The driver or device
1390 * at the end of the chain will be told to attach to whatever is configured
1391 * below it.
1392 *
1393 * @returns VBox status code.
1394 * @param pUVM The user mode VM handle.
1395 * @param pszDevice Device name.
1396 * @param iDevIns Device instance.
1397 * @param iLun The Logical Unit to obtain the interface of.
1398 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1399 * @param ppBase Where to store the base interface pointer. Optional.
1400 *
1401 * @thread EMT
1402 */
1403VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags,
1404 PPPDMIBASE ppBase)
1405{
1406 LogFlow(("PDMR3UsbDriverAttach: pszDevice=%p:{%s} iDevIns=%d iLun=%d fFlags=%#x ppBase=%p\n",
1407 pszDevice, pszDevice, iDevIns, iLun, fFlags, ppBase));
1408 if (ppBase)
1409 *ppBase = NULL;
1410 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1411 PVM const pVM = pUVM->pVM;
1412 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1413 VM_ASSERT_EMT(pVM);
1414
1415 /*
1416 * Find the LUN in question.
1417 */
1418 PPDMLUN pLun;
1419 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1420 if (RT_SUCCESS(rc))
1421 {
1422 /*
1423 * Anything attached to the LUN?
1424 */
1425 PPDMDRVINS pDrvIns = pLun->pTop;
1426 if (!pDrvIns)
1427 {
1428 /* No, ask the device to attach to the new stuff. */
1429 PPDMUSBINS pUsbIns = pLun->pUsbIns;
1430 if (pUsbIns->pReg->pfnDriverAttach)
1431 {
1432 rc = pUsbIns->pReg->pfnDriverAttach(pUsbIns, iLun, fFlags);
1433 if (RT_SUCCESS(rc) && ppBase)
1434 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
1435 }
1436 else
1437 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
1438 }
1439 else
1440 {
1441 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
1442 while (pDrvIns->Internal.s.pDown)
1443 pDrvIns = pDrvIns->Internal.s.pDown;
1444 if (pDrvIns->pReg->pfnAttach)
1445 {
1446 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
1447 if (RT_SUCCESS(rc) && ppBase)
1448 *ppBase = pDrvIns->Internal.s.pDown
1449 ? &pDrvIns->Internal.s.pDown->IBase
1450 : NULL;
1451 }
1452 else
1453 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
1454 }
1455 }
1456
1457 if (ppBase)
1458 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
1459 else
1460 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc\n", rc));
1461 return rc;
1462}
1463
1464
1465/**
1466 * Detaches the specified driver instance.
1467 *
1468 * This is used to replumb drivers at runtime for simulating hot plugging and
1469 * media changes.
1470 *
1471 * This method allows detaching drivers from
1472 * any driver or device by specifying the driver to start detaching at. The
1473 * only prerequisite is that the driver or device above implements the
1474 * pfnDetach callback (PDMDRVREG / PDMUSBREG).
1475 *
1476 * @returns VBox status code.
1477 * @param pUVM The user mode VM handle.
1478 * @param pszDevice Device name.
1479 * @param iDevIns Device instance.
1480 * @param iLun The Logical Unit in which to look for the driver.
1481 * @param pszDriver The name of the driver which to detach. If NULL
1482 * then the entire driver chain is detatched.
1483 * @param iOccurrence The occurrence of that driver in the chain. This is
1484 * usually 0.
1485 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1486 * @thread EMT
1487 */
1488VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1489 const char *pszDriver, unsigned iOccurrence, uint32_t fFlags)
1490{
1491 LogFlow(("PDMR3UsbDriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurrence=%u fFlags=%#x\n",
1492 pszDevice, pszDevice, iDevIns, iLun, pszDriver, pszDriver, iOccurrence, fFlags));
1493 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1494 PVM pVM = pUVM->pVM;
1495 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1496 VM_ASSERT_EMT(pVM);
1497 AssertPtr(pszDevice);
1498 AssertPtrNull(pszDriver);
1499 Assert(iOccurrence == 0 || pszDriver);
1500 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1501
1502 /*
1503 * Find the LUN in question.
1504 */
1505 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
1506
1507 PPDMLUN pLun;
1508 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1509 if (RT_SUCCESS(rc))
1510 {
1511 /*
1512 * Locate the driver.
1513 */
1514 PPDMDRVINS pDrvIns = pLun->pTop;
1515 if (pDrvIns)
1516 {
1517 if (pszDriver)
1518 {
1519 while (pDrvIns)
1520 {
1521 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1522 {
1523 if (iOccurrence == 0)
1524 break;
1525 iOccurrence--;
1526 }
1527 pDrvIns = pDrvIns->Internal.s.pDown;
1528 }
1529 }
1530 if (pDrvIns)
1531 {
1532 rc = pdmR3DrvDetach(pVM, pDrvIns, fFlags);
1533
1534 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1535 LogFlow(("PDMR3UsbDriverDetach: returns %Rrc (pdmR3DrvDetach)\n", rc));
1536 return rc;
1537 }
1538 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1539 }
1540 else
1541 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1542 }
1543
1544 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1545 LogFlow(("PDMR3UsbDriverDetach: returns %Rrc\n", rc));
1546 return rc;
1547}
1548
1549
1550/**
1551 * Queries the base interface of a device LUN.
1552 *
1553 * This differs from PDMR3UsbQueryLun by that it returns the interface on the
1554 * device and not the top level driver.
1555 *
1556 * @returns VBox status code.
1557 * @param pUVM The user mode VM handle.
1558 * @param pszDevice Device name.
1559 * @param iInstance Device instance.
1560 * @param iLun The Logical Unit to obtain the interface of.
1561 * @param ppBase Where to store the base interface pointer.
1562 */
1563VMMR3DECL(int) PDMR3UsbQueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1564{
1565 LogFlow(("PDMR3UsbQueryDeviceLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1566 pszDevice, pszDevice, iInstance, iLun, ppBase));
1567 *ppBase = NULL;
1568 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1569 PVM pVM = pUVM->pVM;
1570 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1571
1572 /*
1573 * Find the LUN.
1574 */
1575 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1576
1577 PPDMLUN pLun;
1578 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1579 if (RT_SUCCESS(rc))
1580 {
1581 *ppBase = pLun->pBase;
1582
1583 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1584 LogFlow(("PDMR3UsbQueryDeviceLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1585 return VINF_SUCCESS;
1586 }
1587
1588 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1589 LogFlow(("PDMR3UsbQueryDeviceLun: returns %Rrc\n", rc));
1590 return rc;
1591}
1592
1593
1594/**
1595 * Query the interface of the top level driver on a LUN.
1596 *
1597 * @returns VBox status code.
1598 * @param pUVM The user mode VM handle.
1599 * @param pszDevice Device name.
1600 * @param iInstance Device instance.
1601 * @param iLun The Logical Unit to obtain the interface of.
1602 * @param ppBase Where to store the base interface pointer.
1603 * @remark We're not doing any locking ATM, so don't try call this at times when the
1604 * device chain is known to be updated.
1605 */
1606VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1607{
1608 LogFlow(("PDMR3UsbQueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1609 pszDevice, pszDevice, iInstance, iLun, ppBase));
1610 *ppBase = NULL;
1611 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1612 PVM pVM = pUVM->pVM;
1613 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1614
1615 /*
1616 * Find the LUN.
1617 */
1618 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1619
1620 PPDMLUN pLun;
1621 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1622 if (RT_SUCCESS(rc))
1623 {
1624 if (pLun->pTop)
1625 {
1626 *ppBase = &pLun->pTop->IBase;
1627
1628 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1629 LogFlow(("PDMR3UsbQueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1630 return VINF_SUCCESS;
1631 }
1632 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1633 }
1634
1635 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1636 LogFlow(("PDMR3UsbQueryLun: returns %Rrc\n", rc));
1637 return rc;
1638}
1639
1640
1641/**
1642 * Query the interface of a named driver on a LUN.
1643 *
1644 * If the driver appears more than once in the driver chain, the first instance
1645 * is returned.
1646 *
1647 * @returns VBox status code.
1648 * @param pUVM The user mode VM handle.
1649 * @param pszDevice Device name.
1650 * @param iInstance Device instance.
1651 * @param iLun The Logical Unit to obtain the interface of.
1652 * @param pszDriver The driver name.
1653 * @param ppBase Where to store the base interface pointer.
1654 *
1655 * @remark We're not doing any locking ATM, so don't try call this at times when the
1656 * device chain is known to be updated.
1657 */
1658VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance,
1659 unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
1660{
1661 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
1662 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
1663 *ppBase = NULL;
1664 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1665 PVM pVM = pUVM->pVM;
1666 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1667
1668 /*
1669 * Find the LUN.
1670 */
1671 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1672
1673 PPDMLUN pLun;
1674 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1675 if (RT_SUCCESS(rc))
1676 {
1677 if (pLun->pTop)
1678 {
1679 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1680 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1681 {
1682 *ppBase = &pDrvIns->IBase;
1683
1684 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1685 LogFlow(("PDMR3UsbQueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1686 return VINF_SUCCESS;
1687 }
1688 rc = VERR_PDM_DRIVER_NOT_FOUND;
1689 }
1690 else
1691 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1692 }
1693
1694 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1695 LogFlow(("PDMR3UsbQueryDriverOnLun: returns %Rrc\n", rc));
1696 return rc;
1697}
1698
1699
1700/** @name USB Device Helpers
1701 * @{
1702 */
1703
1704/** @interface_method_impl{PDMUSBHLP,pfnDriverAttach} */
1705static DECLCALLBACK(int) pdmR3UsbHlp_DriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
1706 PPDMIBASE *ppBaseInterface, const char *pszDesc)
1707{
1708 PDMUSB_ASSERT_USBINS(pUsbIns);
1709 PVM pVM = pUsbIns->Internal.s.pVM;
1710 VM_ASSERT_EMT(pVM);
1711 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
1712 pUsbIns->pReg->szName, pUsbIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
1713
1714 /*
1715 * Lookup the LUN, it might already be registered.
1716 */
1717 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
1718 PPDMLUN pLunPrev = NULL;
1719 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1720 for (; pLun; pLunPrev = pLun, pLun = pLun->pNext)
1721 if (pLun->iLun == iLun)
1722 break;
1723
1724 /*
1725 * Create the LUN if if wasn't found, else check if driver is already attached to it.
1726 */
1727 if (!pLun)
1728 {
1729 if ( !pBaseInterface
1730 || !pszDesc
1731 || !*pszDesc)
1732 {
1733 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1734 Assert(pBaseInterface);
1735 Assert(pszDesc || *pszDesc);
1736 return VERR_INVALID_PARAMETER;
1737 }
1738
1739 pLun = (PPDMLUN)MMR3HeapAlloc(pVM, MM_TAG_PDM_LUN, sizeof(*pLun));
1740 if (!pLun)
1741 {
1742 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1743 return VERR_NO_MEMORY;
1744 }
1745
1746 pLun->iLun = iLun;
1747 pLun->pNext = pLunPrev ? pLunPrev->pNext : NULL;
1748 pLun->pTop = NULL;
1749 pLun->pBottom = NULL;
1750 pLun->pDevIns = NULL;
1751 pLun->pUsbIns = pUsbIns;
1752 pLun->pszDesc = pszDesc;
1753 pLun->pBase = pBaseInterface;
1754 if (!pLunPrev)
1755 pUsbIns->Internal.s.pLuns = pLun;
1756 else
1757 pLunPrev->pNext = pLun;
1758 Log(("pdmR3UsbHlp_DriverAttach: Registered LUN#%d '%s' with device '%s'/%d.\n",
1759 iLun, pszDesc, pUsbIns->pReg->szName, pUsbIns->iInstance));
1760 }
1761 else if (pLun->pTop)
1762 {
1763 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1764 AssertMsgFailed(("Already attached! The device should keep track of such things!\n"));
1765 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, VERR_PDM_DRIVER_ALREADY_ATTACHED));
1766 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1767 }
1768 Assert(pLun->pBase == pBaseInterface);
1769
1770
1771 /*
1772 * Get the attached driver configuration.
1773 */
1774 int rc;
1775 PCFGMNODE pNode = CFGMR3GetChildF(pUsbIns->Internal.s.pCfg, "LUN#%u", iLun);
1776 if (pNode)
1777 rc = pdmR3DrvInstantiate(pVM, pNode, pBaseInterface, NULL /*pDrvAbove*/, pLun, ppBaseInterface);
1778 else
1779 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1780 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1781
1782
1783 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1784 return rc;
1785}
1786
1787
1788/** @interface_method_impl{PDMUSBHLP,pfnAssertEMT} */
1789static DECLCALLBACK(bool) pdmR3UsbHlp_AssertEMT(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1790{
1791 PDMUSB_ASSERT_USBINS(pUsbIns);
1792 if (VM_IS_EMT(pUsbIns->Internal.s.pVM))
1793 return true;
1794
1795 char szMsg[100];
1796 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1797 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1798 AssertBreakpoint();
1799 return false;
1800}
1801
1802
1803/** @interface_method_impl{PDMUSBHLP,pfnAssertOther} */
1804static DECLCALLBACK(bool) pdmR3UsbHlp_AssertOther(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1805{
1806 PDMUSB_ASSERT_USBINS(pUsbIns);
1807 if (!VM_IS_EMT(pUsbIns->Internal.s.pVM))
1808 return true;
1809
1810 char szMsg[100];
1811 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1812 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1813 AssertBreakpoint();
1814 return false;
1815}
1816
1817
1818/** @interface_method_impl{PDMUSBHLP,pfnDBGFStopV} */
1819static DECLCALLBACK(int) pdmR3UsbHlp_DBGFStopV(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction,
1820 const char *pszFormat, va_list va)
1821{
1822 PDMUSB_ASSERT_USBINS(pUsbIns);
1823#ifdef LOG_ENABLED
1824 va_list va2;
1825 va_copy(va2, va);
1826 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
1827 pUsbIns->pReg->szName, pUsbIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
1828 va_end(va2);
1829#endif
1830
1831 PVM pVM = pUsbIns->Internal.s.pVM;
1832 VM_ASSERT_EMT(pVM);
1833 int rc = DBGFR3EventSrcV(pVM, DBGFEVENT_DEV_STOP, pszFile, iLine, pszFunction, pszFormat, va);
1834 if (rc == VERR_DBGF_NOT_ATTACHED)
1835 rc = VINF_SUCCESS;
1836
1837 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1838 return rc;
1839}
1840
1841
1842/** @interface_method_impl{PDMUSBHLP,pfnDBGFInfoRegisterArgv} */
1843static DECLCALLBACK(int) pdmR3UsbHlp_DBGFInfoRegisterArgv(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc,
1844 PFNDBGFINFOARGVUSB pfnHandler)
1845{
1846 PDMUSB_ASSERT_USBINS(pUsbIns);
1847 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1848 pUsbIns->pReg->szName, pUsbIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1849
1850 PVM pVM = pUsbIns->Internal.s.pVM;
1851 VM_ASSERT_EMT(pVM);
1852 int rc = DBGFR3InfoRegisterUsbArgv(pVM, pszName, pszDesc, pfnHandler, pUsbIns);
1853
1854 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1855 return rc;
1856}
1857
1858
1859/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAlloc} */
1860static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb)
1861{
1862 PDMUSB_ASSERT_USBINS(pUsbIns);
1863 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1864
1865 void *pv = MMR3HeapAlloc(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1866
1867 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1868 return pv;
1869}
1870
1871
1872/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAllocZ} */
1873static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb)
1874{
1875 PDMUSB_ASSERT_USBINS(pUsbIns);
1876 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1877
1878 void *pv = MMR3HeapAllocZ(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1879
1880 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1881 return pv;
1882}
1883
1884
1885/** @interface_method_impl{PDMUSBHLP,pfnMMHeapFree} */
1886static DECLCALLBACK(void) pdmR3UsbHlp_MMHeapFree(PPDMUSBINS pUsbIns, void *pv)
1887{
1888 PDMUSB_ASSERT_USBINS(pUsbIns); RT_NOREF(pUsbIns);
1889 LogFlow(("pdmR3UsbHlp_MMHeapFree: caller='%s'/%d: pv=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1890
1891 MMR3HeapFree(pv);
1892
1893 LogFlow(("pdmR3UsbHlp_MMHeapFree: caller='%s'/%d: returns\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1894}
1895
1896
1897/** @interface_method_impl{PDMUSBHLP,pfnPDMQueueCreate} */
1898static DECLCALLBACK(int) pdmR3UsbHlp_PDMQueueCreate(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
1899 PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
1900{
1901 PDMUSB_ASSERT_USBINS(pUsbIns);
1902 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%#x cItems=%#x cMilliesInterval=%u pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
1903 pUsbIns->pReg->szName, pUsbIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue));
1904
1905 PVM pVM = pUsbIns->Internal.s.pVM;
1906 VM_ASSERT_EMT(pVM);
1907
1908 if (pUsbIns->iInstance > 0)
1909 {
1910 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_DESC, "%s_%u", pszName, pUsbIns->iInstance);
1911 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1912 }
1913
1914 RT_NOREF5(cbItem, cItems, cMilliesInterval, pfnCallback, ppQueue);
1915 /** @todo int rc = PDMR3QueueCreateUsb(pVM, pUsbIns, cbItem, cItems, cMilliesInterval, pfnCallback, fGCEnabled, pszName, ppQueue); */
1916 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1917
1918 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *ppQueue));
1919 return rc;
1920}
1921
1922
1923/** @interface_method_impl{PDMUSBHLP,pfnSSMRegister} */
1924static DECLCALLBACK(int) pdmR3UsbHlp_SSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess,
1925 PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote,
1926 PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone,
1927 PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)
1928{
1929 PDMUSB_ASSERT_USBINS(pUsbIns);
1930 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
1931 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x\n"
1932 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoadDone=%p\n",
1933 pUsbIns->pReg->szName, pUsbIns->iInstance, uVersion, cbGuess,
1934 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1935 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1936 pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1937
1938 int rc = SSMR3RegisterUsb(pUsbIns->Internal.s.pVM, pUsbIns, pUsbIns->pReg->szName, pUsbIns->iInstance,
1939 uVersion, cbGuess,
1940 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1941 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1942 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1943
1944 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1945 return rc;
1946}
1947
1948
1949/** @interface_method_impl{PDMUSBHLP,pfnSTAMRegisterV} */
1950static DECLCALLBACK(void) pdmR3UsbHlp_STAMRegisterV(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1951 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
1952{
1953 PDMUSB_ASSERT_USBINS(pUsbIns);
1954 PVM pVM = pUsbIns->Internal.s.pVM;
1955 VM_ASSERT_EMT(pVM);
1956
1957 int rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
1958 AssertRC(rc);
1959
1960 NOREF(pVM);
1961}
1962
1963
1964/** @interface_method_impl{PDMUSBHLP,pfnTimerCreate} */
1965static DECLCALLBACK(int) pdmR3UsbHlp_TimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser,
1966 uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)
1967{
1968 PDMUSB_ASSERT_USBINS(pUsbIns);
1969 PVM pVM = pUsbIns->Internal.s.pVM;
1970 VM_ASSERT_EMT(pVM);
1971 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} phTimer=%p\n",
1972 pUsbIns->pReg->szName, pUsbIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, phTimer));
1973
1974 AssertReturn(!(fFlags & TMTIMER_FLAGS_RING0), VERR_INVALID_FLAGS);
1975 fFlags |= TMTIMER_FLAGS_NO_RING0;
1976
1977 /* Mangle the timer name if there are more than one instance of this device. */
1978 char szName[32];
1979 AssertReturn(strlen(pszDesc) < sizeof(szName) - 8, VERR_INVALID_NAME);
1980 if (pUsbIns->iInstance > 0)
1981 {
1982 RTStrPrintf(szName, sizeof(szName), "%s[%u:%s]", pszDesc, pUsbIns->iInstance, pUsbIns->Internal.s.pUsbDev->pReg->szName);
1983 pszDesc = szName;
1984 }
1985
1986 int rc = TMR3TimerCreateUsb(pVM, pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer);
1987
1988 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *phTimer=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *phTimer));
1989 return rc;
1990}
1991
1992
1993/** @interface_method_impl{PDMUSBHLP,pfnTimerFromMicro} */
1994static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)
1995{
1996 PDMUSB_ASSERT_USBINS(pUsbIns);
1997 return TMTimerFromMicro(pUsbIns->Internal.s.pVM, hTimer, cMicroSecs);
1998}
1999
2000
2001/** @interface_method_impl{PDMUSBHLP,pfnTimerFromMilli} */
2002static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromMilli(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)
2003{
2004 PDMUSB_ASSERT_USBINS(pUsbIns);
2005 return TMTimerFromMilli(pUsbIns->Internal.s.pVM, hTimer, cMilliSecs);
2006}
2007
2008
2009/** @interface_method_impl{PDMUSBHLP,pfnTimerFromNano} */
2010static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)
2011{
2012 PDMUSB_ASSERT_USBINS(pUsbIns);
2013 return TMTimerFromNano(pUsbIns->Internal.s.pVM, hTimer, cNanoSecs);
2014}
2015
2016/** @interface_method_impl{PDMUSBHLP,pfnTimerGet} */
2017static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2018{
2019 PDMUSB_ASSERT_USBINS(pUsbIns);
2020 return TMTimerGet(pUsbIns->Internal.s.pVM, hTimer);
2021}
2022
2023
2024/** @interface_method_impl{PDMUSBHLP,pfnTimerGetFreq} */
2025static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGetFreq(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2026{
2027 PDMUSB_ASSERT_USBINS(pUsbIns);
2028 return TMTimerGetFreq(pUsbIns->Internal.s.pVM, hTimer);
2029}
2030
2031
2032/** @interface_method_impl{PDMUSBHLP,pfnTimerGetNano} */
2033static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2034{
2035 PDMUSB_ASSERT_USBINS(pUsbIns);
2036 return TMTimerGetNano(pUsbIns->Internal.s.pVM, hTimer);
2037}
2038
2039
2040/** @interface_method_impl{PDMUSBHLP,pfnTimerIsActive} */
2041static DECLCALLBACK(bool) pdmR3UsbHlp_TimerIsActive(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2042{
2043 PDMUSB_ASSERT_USBINS(pUsbIns);
2044 return TMTimerIsActive(pUsbIns->Internal.s.pVM, hTimer);
2045}
2046
2047
2048/** @interface_method_impl{PDMUSBHLP,pfnTimerIsLockOwner} */
2049static DECLCALLBACK(bool) pdmR3UsbHlp_TimerIsLockOwner(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2050{
2051 PDMUSB_ASSERT_USBINS(pUsbIns);
2052 return TMTimerIsLockOwner(pUsbIns->Internal.s.pVM, hTimer);
2053}
2054
2055
2056/** @interface_method_impl{PDMUSBHLP,pfnTimerLockClock} */
2057static DECLCALLBACK(int) pdmR3UsbHlp_TimerLockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2058{
2059 PDMUSB_ASSERT_USBINS(pUsbIns);
2060 return TMTimerLock(pUsbIns->Internal.s.pVM, hTimer, VERR_IGNORED);
2061}
2062
2063
2064/** @interface_method_impl{PDMUSBHLP,pfnTimerLockClock2} */
2065static DECLCALLBACK(int) pdmR3UsbHlp_TimerLockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2066{
2067 PDMUSB_ASSERT_USBINS(pUsbIns);
2068 PVM const pVM = pUsbIns->Internal.s.pVM;
2069 int rc = TMTimerLock(pVM, hTimer, VERR_IGNORED);
2070 if (rc == VINF_SUCCESS)
2071 {
2072 rc = PDMCritSectEnter(pVM, pCritSect, VERR_IGNORED);
2073 if (rc == VINF_SUCCESS)
2074 return rc;
2075 AssertRC(rc);
2076 TMTimerUnlock(pVM, hTimer);
2077 }
2078 else
2079 AssertRC(rc);
2080 return rc;
2081}
2082
2083
2084/** @interface_method_impl{PDMUSBHLP,pfnTimerSet} */
2085static DECLCALLBACK(int) pdmR3UsbHlp_TimerSet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire)
2086{
2087 PDMUSB_ASSERT_USBINS(pUsbIns);
2088 return TMTimerSet(pUsbIns->Internal.s.pVM, hTimer, uExpire);
2089}
2090
2091
2092/** @interface_method_impl{PDMUSBHLP,pfnTimerSetFrequencyHint} */
2093static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetFrequencyHint(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz)
2094{
2095 PDMUSB_ASSERT_USBINS(pUsbIns);
2096 return TMTimerSetFrequencyHint(pUsbIns->Internal.s.pVM, hTimer, uHz);
2097}
2098
2099
2100/** @interface_method_impl{PDMUSBHLP,pfnTimerSetMicro} */
2101static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)
2102{
2103 PDMUSB_ASSERT_USBINS(pUsbIns);
2104 return TMTimerSetMicro(pUsbIns->Internal.s.pVM, hTimer, cMicrosToNext);
2105}
2106
2107
2108/** @interface_method_impl{PDMUSBHLP,pfnTimerSetMillies} */
2109static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetMillies(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)
2110{
2111 PDMUSB_ASSERT_USBINS(pUsbIns);
2112 return TMTimerSetMillies(pUsbIns->Internal.s.pVM, hTimer, cMilliesToNext);
2113}
2114
2115
2116/** @interface_method_impl{PDMUSBHLP,pfnTimerSetNano} */
2117static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)
2118{
2119 PDMUSB_ASSERT_USBINS(pUsbIns);
2120 return TMTimerSetNano(pUsbIns->Internal.s.pVM, hTimer, cNanosToNext);
2121}
2122
2123
2124/** @interface_method_impl{PDMUSBHLP,pfnTimerSetRelative} */
2125static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetRelative(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
2126{
2127 PDMUSB_ASSERT_USBINS(pUsbIns);
2128 return TMTimerSetRelative(pUsbIns->Internal.s.pVM, hTimer, cTicksToNext, pu64Now);
2129}
2130
2131
2132/** @interface_method_impl{PDMUSBHLP,pfnTimerStop} */
2133static DECLCALLBACK(int) pdmR3UsbHlp_TimerStop(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2134{
2135 PDMUSB_ASSERT_USBINS(pUsbIns);
2136 return TMTimerStop(pUsbIns->Internal.s.pVM, hTimer);
2137}
2138
2139
2140/** @interface_method_impl{PDMUSBHLP,pfnTimerUnlockClock} */
2141static DECLCALLBACK(void) pdmR3UsbHlp_TimerUnlockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2142{
2143 PDMUSB_ASSERT_USBINS(pUsbIns);
2144 TMTimerUnlock(pUsbIns->Internal.s.pVM, hTimer);
2145}
2146
2147
2148/** @interface_method_impl{PDMUSBHLP,pfnTimerUnlockClock2} */
2149static DECLCALLBACK(void) pdmR3UsbHlp_TimerUnlockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2150{
2151 PDMUSB_ASSERT_USBINS(pUsbIns);
2152 PVM const pVM = pUsbIns->Internal.s.pVM;
2153 TMTimerUnlock(pVM, hTimer);
2154 int rc = PDMCritSectLeave(pVM, pCritSect);
2155 AssertRC(rc);
2156}
2157
2158
2159/** @interface_method_impl{PDMUSBHLP,pfnTimerSetCritSect} */
2160static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetCritSect(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2161{
2162 PDMUSB_ASSERT_USBINS(pUsbIns);
2163 return TMR3TimerSetCritSect(pUsbIns->Internal.s.pVM, hTimer, pCritSect);
2164}
2165
2166
2167/** @interface_method_impl{PDMUSBHLP,pfnTimerSave} */
2168static DECLCALLBACK(int) pdmR3UsbHlp_TimerSave(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)
2169{
2170 PDMUSB_ASSERT_USBINS(pUsbIns);
2171 return TMR3TimerSave(pUsbIns->Internal.s.pVM, hTimer, pSSM);
2172}
2173
2174
2175/** @interface_method_impl{PDMUSBHLP,pfnTimerLoad} */
2176static DECLCALLBACK(int) pdmR3UsbHlp_TimerLoad(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)
2177{
2178 PDMUSB_ASSERT_USBINS(pUsbIns);
2179 return TMR3TimerLoad(pUsbIns->Internal.s.pVM, hTimer, pSSM);
2180}
2181
2182
2183/** @interface_method_impl{PDMUSBHLP,pfnTimerDestroy} */
2184static DECLCALLBACK(int) pdmR3UsbHlp_TimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2185{
2186 PDMUSB_ASSERT_USBINS(pUsbIns);
2187 return TMR3TimerDestroy(pUsbIns->Internal.s.pVM, hTimer);
2188}
2189
2190
2191/** @interface_method_impl{PDMUSBHLP,pfnVMSetErrorV} */
2192static DECLCALLBACK(int) pdmR3UsbHlp_VMSetErrorV(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
2193{
2194 PDMUSB_ASSERT_USBINS(pUsbIns);
2195 int rc2 = VMSetErrorV(pUsbIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
2196 return rc;
2197}
2198
2199
2200/** @interface_method_impl{PDMUSBHLP,pfnVMSetRuntimeErrorV} */
2201static DECLCALLBACK(int) pdmR3UsbHlp_VMSetRuntimeErrorV(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
2202{
2203 PDMUSB_ASSERT_USBINS(pUsbIns);
2204 int rc = VMSetRuntimeErrorV(pUsbIns->Internal.s.pVM, fFlags, pszErrorId, pszFormat, va);
2205 return rc;
2206}
2207
2208
2209/** @interface_method_impl{PDMUSBHLP,pfnVMState} */
2210static DECLCALLBACK(VMSTATE) pdmR3UsbHlp_VMState(PPDMUSBINS pUsbIns)
2211{
2212 PDMUSB_ASSERT_USBINS(pUsbIns);
2213
2214 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
2215
2216 LogFlow(("pdmR3UsbHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
2217 enmVMState, VMR3GetStateName(enmVMState)));
2218 return enmVMState;
2219}
2220
2221/** @interface_method_impl{PDMUSBHLP,pfnThreadCreate} */
2222static DECLCALLBACK(int) pdmR3UsbHlp_ThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread,
2223 PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
2224{
2225 PDMUSB_ASSERT_USBINS(pUsbIns);
2226 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
2227 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
2228 pUsbIns->pReg->szName, pUsbIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
2229
2230 int rc = pdmR3ThreadCreateUsb(pUsbIns->Internal.s.pVM, pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
2231
2232 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
2233 rc, *ppThread));
2234 return rc;
2235}
2236
2237
2238/** @interface_method_impl{PDMUSBHLP,pfnSetAsyncNotification} */
2239static DECLCALLBACK(int) pdmR3UsbHlp_SetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)
2240{
2241 PDMUSB_ASSERT_USBINS(pUsbIns);
2242 VM_ASSERT_EMT0(pUsbIns->Internal.s.pVM);
2243 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pfnAsyncNotify));
2244
2245 int rc = VINF_SUCCESS;
2246 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
2247 AssertStmt(!pUsbIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
2248 AssertStmt(pUsbIns->Internal.s.fVMSuspended || pUsbIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
2249 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
2250 AssertStmt( enmVMState == VMSTATE_SUSPENDING
2251 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
2252 || enmVMState == VMSTATE_SUSPENDING_LS
2253 || enmVMState == VMSTATE_RESETTING
2254 || enmVMState == VMSTATE_RESETTING_LS
2255 || enmVMState == VMSTATE_POWERING_OFF
2256 || enmVMState == VMSTATE_POWERING_OFF_LS,
2257 rc = VERR_INVALID_STATE);
2258
2259 if (RT_SUCCESS(rc))
2260 pUsbIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
2261
2262 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
2263 return rc;
2264}
2265
2266
2267/** @interface_method_impl{PDMUSBHLP,pfnAsyncNotificationCompleted} */
2268static DECLCALLBACK(void) pdmR3UsbHlp_AsyncNotificationCompleted(PPDMUSBINS pUsbIns)
2269{
2270 PDMUSB_ASSERT_USBINS(pUsbIns);
2271 PVM pVM = pUsbIns->Internal.s.pVM;
2272
2273 VMSTATE enmVMState = VMR3GetState(pVM);
2274 if ( enmVMState == VMSTATE_SUSPENDING
2275 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
2276 || enmVMState == VMSTATE_SUSPENDING_LS
2277 || enmVMState == VMSTATE_RESETTING
2278 || enmVMState == VMSTATE_RESETTING_LS
2279 || enmVMState == VMSTATE_POWERING_OFF
2280 || enmVMState == VMSTATE_POWERING_OFF_LS)
2281 {
2282 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2283 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
2284 }
2285 else
2286 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance, enmVMState));
2287}
2288
2289
2290/** @interface_method_impl{PDMUSBHLP,pfnVMGetSuspendReason} */
2291static DECLCALLBACK(VMSUSPENDREASON) pdmR3UsbHlp_VMGetSuspendReason(PPDMUSBINS pUsbIns)
2292{
2293 PDMUSB_ASSERT_USBINS(pUsbIns);
2294 PVM pVM = pUsbIns->Internal.s.pVM;
2295 VM_ASSERT_EMT(pVM);
2296 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
2297 LogFlow(("pdmR3UsbHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
2298 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
2299 return enmReason;
2300}
2301
2302
2303/** @interface_method_impl{PDMUSBHLP,pfnVMGetResumeReason} */
2304static DECLCALLBACK(VMRESUMEREASON) pdmR3UsbHlp_VMGetResumeReason(PPDMUSBINS pUsbIns)
2305{
2306 PDMUSB_ASSERT_USBINS(pUsbIns);
2307 PVM pVM = pUsbIns->Internal.s.pVM;
2308 VM_ASSERT_EMT(pVM);
2309 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
2310 LogFlow(("pdmR3UsbHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
2311 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
2312 return enmReason;
2313}
2314
2315
2316/** @interface_method_impl{PDMUSBHLP,pfnQueryGenericUserObject} */
2317static DECLCALLBACK(void *) pdmR3UsbHlp_QueryGenericUserObject(PPDMUSBINS pUsbIns, PCRTUUID pUuid)
2318{
2319 PDMUSB_ASSERT_USBINS(pUsbIns);
2320 PVM pVM = pUsbIns->Internal.s.pVM;
2321 PUVM pUVM = pVM->pUVM;
2322
2323 void *pvRet;
2324 if (pUVM->pVmm2UserMethods->pfnQueryGenericObject)
2325 pvRet = pUVM->pVmm2UserMethods->pfnQueryGenericObject(pUVM->pVmm2UserMethods, pUVM, pUuid);
2326 else
2327 pvRet = NULL;
2328
2329 Log(("pdmR3UsbHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
2330 pUsbIns->pReg->szName, pUsbIns->iInstance, pvRet, pUuid));
2331 return pvRet;
2332}
2333
2334
2335/**
2336 * The USB device helper structure.
2337 */
2338const PDMUSBHLP g_pdmR3UsbHlp =
2339{
2340 PDM_USBHLP_VERSION,
2341 pdmR3UsbHlp_DriverAttach,
2342 pdmR3UsbHlp_AssertEMT,
2343 pdmR3UsbHlp_AssertOther,
2344 pdmR3UsbHlp_DBGFStopV,
2345 pdmR3UsbHlp_DBGFInfoRegisterArgv,
2346 pdmR3UsbHlp_MMHeapAlloc,
2347 pdmR3UsbHlp_MMHeapAllocZ,
2348 pdmR3UsbHlp_MMHeapFree,
2349 pdmR3UsbHlp_PDMQueueCreate,
2350 pdmR3UsbHlp_SSMRegister,
2351 SSMR3PutStruct,
2352 SSMR3PutStructEx,
2353 SSMR3PutBool,
2354 SSMR3PutU8,
2355 SSMR3PutS8,
2356 SSMR3PutU16,
2357 SSMR3PutS16,
2358 SSMR3PutU32,
2359 SSMR3PutS32,
2360 SSMR3PutU64,
2361 SSMR3PutS64,
2362 SSMR3PutU128,
2363 SSMR3PutS128,
2364 SSMR3PutUInt,
2365 SSMR3PutSInt,
2366 SSMR3PutGCUInt,
2367 SSMR3PutGCUIntReg,
2368 SSMR3PutGCPhys32,
2369 SSMR3PutGCPhys64,
2370 SSMR3PutGCPhys,
2371 SSMR3PutGCPtr,
2372 SSMR3PutGCUIntPtr,
2373 SSMR3PutRCPtr,
2374 SSMR3PutIOPort,
2375 SSMR3PutSel,
2376 SSMR3PutMem,
2377 SSMR3PutStrZ,
2378 SSMR3GetStruct,
2379 SSMR3GetStructEx,
2380 SSMR3GetBool,
2381 SSMR3GetBoolV,
2382 SSMR3GetU8,
2383 SSMR3GetU8V,
2384 SSMR3GetS8,
2385 SSMR3GetS8V,
2386 SSMR3GetU16,
2387 SSMR3GetU16V,
2388 SSMR3GetS16,
2389 SSMR3GetS16V,
2390 SSMR3GetU32,
2391 SSMR3GetU32V,
2392 SSMR3GetS32,
2393 SSMR3GetS32V,
2394 SSMR3GetU64,
2395 SSMR3GetU64V,
2396 SSMR3GetS64,
2397 SSMR3GetS64V,
2398 SSMR3GetU128,
2399 SSMR3GetU128V,
2400 SSMR3GetS128,
2401 SSMR3GetS128V,
2402 SSMR3GetGCPhys32,
2403 SSMR3GetGCPhys32V,
2404 SSMR3GetGCPhys64,
2405 SSMR3GetGCPhys64V,
2406 SSMR3GetGCPhys,
2407 SSMR3GetGCPhysV,
2408 SSMR3GetUInt,
2409 SSMR3GetSInt,
2410 SSMR3GetGCUInt,
2411 SSMR3GetGCUIntReg,
2412 SSMR3GetGCPtr,
2413 SSMR3GetGCUIntPtr,
2414 SSMR3GetRCPtr,
2415 SSMR3GetIOPort,
2416 SSMR3GetSel,
2417 SSMR3GetMem,
2418 SSMR3GetStrZ,
2419 SSMR3GetStrZEx,
2420 SSMR3Skip,
2421 SSMR3SkipToEndOfUnit,
2422 SSMR3SetLoadError,
2423 SSMR3SetLoadErrorV,
2424 SSMR3SetCfgError,
2425 SSMR3SetCfgErrorV,
2426 SSMR3HandleGetStatus,
2427 SSMR3HandleGetAfter,
2428 SSMR3HandleIsLiveSave,
2429 SSMR3HandleMaxDowntime,
2430 SSMR3HandleHostBits,
2431 SSMR3HandleRevision,
2432 SSMR3HandleVersion,
2433 SSMR3HandleHostOSAndArch,
2434 CFGMR3Exists,
2435 CFGMR3QueryType,
2436 CFGMR3QuerySize,
2437 CFGMR3QueryInteger,
2438 CFGMR3QueryIntegerDef,
2439 CFGMR3QueryString,
2440 CFGMR3QueryStringDef,
2441 CFGMR3QueryBytes,
2442 CFGMR3QueryU64,
2443 CFGMR3QueryU64Def,
2444 CFGMR3QueryS64,
2445 CFGMR3QueryS64Def,
2446 CFGMR3QueryU32,
2447 CFGMR3QueryU32Def,
2448 CFGMR3QueryS32,
2449 CFGMR3QueryS32Def,
2450 CFGMR3QueryU16,
2451 CFGMR3QueryU16Def,
2452 CFGMR3QueryS16,
2453 CFGMR3QueryS16Def,
2454 CFGMR3QueryU8,
2455 CFGMR3QueryU8Def,
2456 CFGMR3QueryS8,
2457 CFGMR3QueryS8Def,
2458 CFGMR3QueryBool,
2459 CFGMR3QueryBoolDef,
2460 CFGMR3QueryPort,
2461 CFGMR3QueryPortDef,
2462 CFGMR3QueryUInt,
2463 CFGMR3QueryUIntDef,
2464 CFGMR3QuerySInt,
2465 CFGMR3QuerySIntDef,
2466 CFGMR3QueryGCPtr,
2467 CFGMR3QueryGCPtrDef,
2468 CFGMR3QueryGCPtrU,
2469 CFGMR3QueryGCPtrUDef,
2470 CFGMR3QueryGCPtrS,
2471 CFGMR3QueryGCPtrSDef,
2472 CFGMR3QueryStringAlloc,
2473 CFGMR3QueryStringAllocDef,
2474 CFGMR3GetParent,
2475 CFGMR3GetChild,
2476 CFGMR3GetChildF,
2477 CFGMR3GetChildFV,
2478 CFGMR3GetFirstChild,
2479 CFGMR3GetNextChild,
2480 CFGMR3GetName,
2481 CFGMR3GetNameLen,
2482 CFGMR3AreChildrenValid,
2483 CFGMR3GetFirstValue,
2484 CFGMR3GetNextValue,
2485 CFGMR3GetValueName,
2486 CFGMR3GetValueNameLen,
2487 CFGMR3GetValueType,
2488 CFGMR3AreValuesValid,
2489 CFGMR3ValidateConfig,
2490 pdmR3UsbHlp_STAMRegisterV,
2491 pdmR3UsbHlp_TimerCreate,
2492 pdmR3UsbHlp_TimerFromMicro,
2493 pdmR3UsbHlp_TimerFromMilli,
2494 pdmR3UsbHlp_TimerFromNano,
2495 pdmR3UsbHlp_TimerGet,
2496 pdmR3UsbHlp_TimerGetFreq,
2497 pdmR3UsbHlp_TimerGetNano,
2498 pdmR3UsbHlp_TimerIsActive,
2499 pdmR3UsbHlp_TimerIsLockOwner,
2500 pdmR3UsbHlp_TimerLockClock,
2501 pdmR3UsbHlp_TimerLockClock2,
2502 pdmR3UsbHlp_TimerSet,
2503 pdmR3UsbHlp_TimerSetFrequencyHint,
2504 pdmR3UsbHlp_TimerSetMicro,
2505 pdmR3UsbHlp_TimerSetMillies,
2506 pdmR3UsbHlp_TimerSetNano,
2507 pdmR3UsbHlp_TimerSetRelative,
2508 pdmR3UsbHlp_TimerStop,
2509 pdmR3UsbHlp_TimerUnlockClock,
2510 pdmR3UsbHlp_TimerUnlockClock2,
2511 pdmR3UsbHlp_TimerSetCritSect,
2512 pdmR3UsbHlp_TimerSave,
2513 pdmR3UsbHlp_TimerLoad,
2514 pdmR3UsbHlp_TimerDestroy,
2515 TMR3TimerSkip,
2516 pdmR3UsbHlp_VMSetErrorV,
2517 pdmR3UsbHlp_VMSetRuntimeErrorV,
2518 pdmR3UsbHlp_VMState,
2519 pdmR3UsbHlp_ThreadCreate,
2520 PDMR3ThreadDestroy,
2521 PDMR3ThreadIAmSuspending,
2522 PDMR3ThreadIAmRunning,
2523 PDMR3ThreadSleep,
2524 PDMR3ThreadSuspend,
2525 PDMR3ThreadResume,
2526 pdmR3UsbHlp_SetAsyncNotification,
2527 pdmR3UsbHlp_AsyncNotificationCompleted,
2528 pdmR3UsbHlp_VMGetSuspendReason,
2529 pdmR3UsbHlp_VMGetResumeReason,
2530 pdmR3UsbHlp_QueryGenericUserObject,
2531 NULL,
2532 NULL,
2533 NULL,
2534 NULL,
2535 NULL,
2536 NULL,
2537 NULL,
2538 NULL,
2539 NULL,
2540 PDM_USBHLP_VERSION
2541};
2542
2543/** @} */
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