VirtualBox

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

Last change on this file since 106952 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.6 KB
Line 
1/* $Id: PDMUsb.cpp 106061 2024-09-16 14:03:52Z 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 * Query the interface of the top level driver on a LUN.
1552 *
1553 * @returns VBox status code.
1554 * @param pUVM The user mode VM handle.
1555 * @param pszDevice Device name.
1556 * @param iInstance Device instance.
1557 * @param iLun The Logical Unit to obtain the interface of.
1558 * @param ppBase Where to store the base interface pointer.
1559 * @remark We're not doing any locking ATM, so don't try call this at times when the
1560 * device chain is known to be updated.
1561 */
1562VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1563{
1564 LogFlow(("PDMR3UsbQueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1565 pszDevice, pszDevice, iInstance, iLun, ppBase));
1566 *ppBase = NULL;
1567 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1568 PVM pVM = pUVM->pVM;
1569 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1570
1571 /*
1572 * Find the LUN.
1573 */
1574 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1575
1576 PPDMLUN pLun;
1577 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1578 if (RT_SUCCESS(rc))
1579 {
1580 if (pLun->pTop)
1581 {
1582 *ppBase = &pLun->pTop->IBase;
1583
1584 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1585 LogFlow(("PDMR3UsbQueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1586 return VINF_SUCCESS;
1587 }
1588 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1589 }
1590
1591 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1592 LogFlow(("PDMR3UsbQueryLun: returns %Rrc\n", rc));
1593 return rc;
1594}
1595
1596
1597/**
1598 * Query the interface of a named driver on a LUN.
1599 *
1600 * If the driver appears more than once in the driver chain, the first instance
1601 * is returned.
1602 *
1603 * @returns VBox status code.
1604 * @param pUVM The user mode VM handle.
1605 * @param pszDevice Device name.
1606 * @param iInstance Device instance.
1607 * @param iLun The Logical Unit to obtain the interface of.
1608 * @param pszDriver The driver name.
1609 * @param ppBase Where to store the base interface pointer.
1610 *
1611 * @remark We're not doing any locking ATM, so don't try call this at times when the
1612 * device chain is known to be updated.
1613 */
1614VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance,
1615 unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
1616{
1617 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
1618 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
1619 *ppBase = NULL;
1620 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1621 PVM pVM = pUVM->pVM;
1622 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1623
1624 /*
1625 * Find the LUN.
1626 */
1627 RTCritSectRwEnterShared(&pVM->pdm.s.CoreListCritSectRw);
1628
1629 PPDMLUN pLun;
1630 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1631 if (RT_SUCCESS(rc))
1632 {
1633 if (pLun->pTop)
1634 {
1635 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1636 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1637 {
1638 *ppBase = &pDrvIns->IBase;
1639
1640 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1641 LogFlow(("PDMR3UsbQueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1642 return VINF_SUCCESS;
1643 }
1644 rc = VERR_PDM_DRIVER_NOT_FOUND;
1645 }
1646 else
1647 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1648 }
1649
1650 RTCritSectRwLeaveShared(&pVM->pdm.s.CoreListCritSectRw);
1651 LogFlow(("PDMR3UsbQueryDriverOnLun: returns %Rrc\n", rc));
1652 return rc;
1653}
1654
1655
1656/** @name USB Device Helpers
1657 * @{
1658 */
1659
1660/** @interface_method_impl{PDMUSBHLP,pfnDriverAttach} */
1661static DECLCALLBACK(int) pdmR3UsbHlp_DriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
1662 PPDMIBASE *ppBaseInterface, const char *pszDesc)
1663{
1664 PDMUSB_ASSERT_USBINS(pUsbIns);
1665 PVM pVM = pUsbIns->Internal.s.pVM;
1666 VM_ASSERT_EMT(pVM);
1667 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
1668 pUsbIns->pReg->szName, pUsbIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
1669
1670 /*
1671 * Lookup the LUN, it might already be registered.
1672 */
1673 RTCritSectRwEnterExcl(&pVM->pdm.s.CoreListCritSectRw);
1674 PPDMLUN pLunPrev = NULL;
1675 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1676 for (; pLun; pLunPrev = pLun, pLun = pLun->pNext)
1677 if (pLun->iLun == iLun)
1678 break;
1679
1680 /*
1681 * Create the LUN if if wasn't found, else check if driver is already attached to it.
1682 */
1683 if (!pLun)
1684 {
1685 if ( !pBaseInterface
1686 || !pszDesc
1687 || !*pszDesc)
1688 {
1689 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1690 Assert(pBaseInterface);
1691 Assert(pszDesc || *pszDesc);
1692 return VERR_INVALID_PARAMETER;
1693 }
1694
1695 pLun = (PPDMLUN)MMR3HeapAlloc(pVM, MM_TAG_PDM_LUN, sizeof(*pLun));
1696 if (!pLun)
1697 {
1698 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1699 return VERR_NO_MEMORY;
1700 }
1701
1702 pLun->iLun = iLun;
1703 pLun->pNext = pLunPrev ? pLunPrev->pNext : NULL;
1704 pLun->pTop = NULL;
1705 pLun->pBottom = NULL;
1706 pLun->pDevIns = NULL;
1707 pLun->pUsbIns = pUsbIns;
1708 pLun->pszDesc = pszDesc;
1709 pLun->pBase = pBaseInterface;
1710 if (!pLunPrev)
1711 pUsbIns->Internal.s.pLuns = pLun;
1712 else
1713 pLunPrev->pNext = pLun;
1714 Log(("pdmR3UsbHlp_DriverAttach: Registered LUN#%d '%s' with device '%s'/%d.\n",
1715 iLun, pszDesc, pUsbIns->pReg->szName, pUsbIns->iInstance));
1716 }
1717 else if (pLun->pTop)
1718 {
1719 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1720 AssertMsgFailed(("Already attached! The device should keep track of such things!\n"));
1721 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, VERR_PDM_DRIVER_ALREADY_ATTACHED));
1722 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1723 }
1724 Assert(pLun->pBase == pBaseInterface);
1725
1726
1727 /*
1728 * Get the attached driver configuration.
1729 */
1730 int rc;
1731 PCFGMNODE pNode = CFGMR3GetChildF(pUsbIns->Internal.s.pCfg, "LUN#%u", iLun);
1732 if (pNode)
1733 rc = pdmR3DrvInstantiate(pVM, pNode, pBaseInterface, NULL /*pDrvAbove*/, pLun, ppBaseInterface);
1734 else
1735 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1736 RTCritSectRwLeaveExcl(&pVM->pdm.s.CoreListCritSectRw);
1737
1738
1739 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1740 return rc;
1741}
1742
1743
1744/** @interface_method_impl{PDMUSBHLP,pfnAssertEMT} */
1745static DECLCALLBACK(bool) pdmR3UsbHlp_AssertEMT(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1746{
1747 PDMUSB_ASSERT_USBINS(pUsbIns);
1748 if (VM_IS_EMT(pUsbIns->Internal.s.pVM))
1749 return true;
1750
1751 char szMsg[100];
1752 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1753 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1754 AssertBreakpoint();
1755 return false;
1756}
1757
1758
1759/** @interface_method_impl{PDMUSBHLP,pfnAssertOther} */
1760static DECLCALLBACK(bool) pdmR3UsbHlp_AssertOther(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1761{
1762 PDMUSB_ASSERT_USBINS(pUsbIns);
1763 if (!VM_IS_EMT(pUsbIns->Internal.s.pVM))
1764 return true;
1765
1766 char szMsg[100];
1767 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1768 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1769 AssertBreakpoint();
1770 return false;
1771}
1772
1773
1774/** @interface_method_impl{PDMUSBHLP,pfnDBGFStopV} */
1775static DECLCALLBACK(int) pdmR3UsbHlp_DBGFStopV(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction,
1776 const char *pszFormat, va_list va)
1777{
1778 PDMUSB_ASSERT_USBINS(pUsbIns);
1779#ifdef LOG_ENABLED
1780 va_list va2;
1781 va_copy(va2, va);
1782 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
1783 pUsbIns->pReg->szName, pUsbIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
1784 va_end(va2);
1785#endif
1786
1787 PVM pVM = pUsbIns->Internal.s.pVM;
1788 VM_ASSERT_EMT(pVM);
1789 int rc = DBGFR3EventSrcV(pVM, DBGFEVENT_DEV_STOP, pszFile, iLine, pszFunction, pszFormat, va);
1790 if (rc == VERR_DBGF_NOT_ATTACHED)
1791 rc = VINF_SUCCESS;
1792
1793 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1794 return rc;
1795}
1796
1797
1798/** @interface_method_impl{PDMUSBHLP,pfnDBGFInfoRegisterArgv} */
1799static DECLCALLBACK(int) pdmR3UsbHlp_DBGFInfoRegisterArgv(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc,
1800 PFNDBGFINFOARGVUSB pfnHandler)
1801{
1802 PDMUSB_ASSERT_USBINS(pUsbIns);
1803 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1804 pUsbIns->pReg->szName, pUsbIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1805
1806 PVM pVM = pUsbIns->Internal.s.pVM;
1807 VM_ASSERT_EMT(pVM);
1808 int rc = DBGFR3InfoRegisterUsbArgv(pVM, pszName, pszDesc, pfnHandler, pUsbIns);
1809
1810 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1811 return rc;
1812}
1813
1814
1815/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAlloc} */
1816static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb)
1817{
1818 PDMUSB_ASSERT_USBINS(pUsbIns);
1819 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1820
1821 void *pv = MMR3HeapAlloc(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1822
1823 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1824 return pv;
1825}
1826
1827
1828/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAllocZ} */
1829static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb)
1830{
1831 PDMUSB_ASSERT_USBINS(pUsbIns);
1832 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1833
1834 void *pv = MMR3HeapAllocZ(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1835
1836 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1837 return pv;
1838}
1839
1840
1841/** @interface_method_impl{PDMUSBHLP,pfnMMHeapFree} */
1842static DECLCALLBACK(void) pdmR3UsbHlp_MMHeapFree(PPDMUSBINS pUsbIns, void *pv)
1843{
1844 PDMUSB_ASSERT_USBINS(pUsbIns); RT_NOREF(pUsbIns);
1845 LogFlow(("pdmR3UsbHlp_MMHeapFree: caller='%s'/%d: pv=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1846
1847 MMR3HeapFree(pv);
1848
1849 LogFlow(("pdmR3UsbHlp_MMHeapFree: caller='%s'/%d: returns\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1850}
1851
1852
1853/** @interface_method_impl{PDMUSBHLP,pfnPDMQueueCreate} */
1854static DECLCALLBACK(int) pdmR3UsbHlp_PDMQueueCreate(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
1855 PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
1856{
1857 PDMUSB_ASSERT_USBINS(pUsbIns);
1858 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%#x cItems=%#x cMilliesInterval=%u pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
1859 pUsbIns->pReg->szName, pUsbIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue));
1860
1861 PVM pVM = pUsbIns->Internal.s.pVM;
1862 VM_ASSERT_EMT(pVM);
1863
1864 if (pUsbIns->iInstance > 0)
1865 {
1866 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_DESC, "%s_%u", pszName, pUsbIns->iInstance);
1867 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1868 }
1869
1870 RT_NOREF5(cbItem, cItems, cMilliesInterval, pfnCallback, ppQueue);
1871 /** @todo int rc = PDMR3QueueCreateUsb(pVM, pUsbIns, cbItem, cItems, cMilliesInterval, pfnCallback, fGCEnabled, pszName, ppQueue); */
1872 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1873
1874 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *ppQueue));
1875 return rc;
1876}
1877
1878
1879/** @interface_method_impl{PDMUSBHLP,pfnSSMRegister} */
1880static DECLCALLBACK(int) pdmR3UsbHlp_SSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess,
1881 PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote,
1882 PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone,
1883 PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)
1884{
1885 PDMUSB_ASSERT_USBINS(pUsbIns);
1886 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
1887 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x\n"
1888 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoadDone=%p\n",
1889 pUsbIns->pReg->szName, pUsbIns->iInstance, uVersion, cbGuess,
1890 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1891 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1892 pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1893
1894 int rc = SSMR3RegisterUsb(pUsbIns->Internal.s.pVM, pUsbIns, pUsbIns->pReg->szName, pUsbIns->iInstance,
1895 uVersion, cbGuess,
1896 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1897 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1898 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1899
1900 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1901 return rc;
1902}
1903
1904
1905/** @interface_method_impl{PDMUSBHLP,pfnSTAMRegisterV} */
1906static DECLCALLBACK(void) pdmR3UsbHlp_STAMRegisterV(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1907 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
1908{
1909 PDMUSB_ASSERT_USBINS(pUsbIns);
1910 PVM pVM = pUsbIns->Internal.s.pVM;
1911 VM_ASSERT_EMT(pVM);
1912
1913 int rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
1914 AssertRC(rc);
1915
1916 NOREF(pVM);
1917}
1918
1919
1920/** @interface_method_impl{PDMUSBHLP,pfnTimerCreate} */
1921static DECLCALLBACK(int) pdmR3UsbHlp_TimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser,
1922 uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)
1923{
1924 PDMUSB_ASSERT_USBINS(pUsbIns);
1925 PVM pVM = pUsbIns->Internal.s.pVM;
1926 VM_ASSERT_EMT(pVM);
1927 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} phTimer=%p\n",
1928 pUsbIns->pReg->szName, pUsbIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, phTimer));
1929
1930 AssertReturn(!(fFlags & TMTIMER_FLAGS_RING0), VERR_INVALID_FLAGS);
1931 fFlags |= TMTIMER_FLAGS_NO_RING0;
1932
1933 /* Mangle the timer name if there are more than one instance of this device. */
1934 char szName[32];
1935 AssertReturn(strlen(pszDesc) < sizeof(szName) - 8, VERR_INVALID_NAME);
1936 if (pUsbIns->iInstance > 0)
1937 {
1938 RTStrPrintf(szName, sizeof(szName), "%s[%u:%s]", pszDesc, pUsbIns->iInstance, pUsbIns->Internal.s.pUsbDev->pReg->szName);
1939 pszDesc = szName;
1940 }
1941
1942 int rc = TMR3TimerCreateUsb(pVM, pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer);
1943
1944 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *phTimer=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *phTimer));
1945 return rc;
1946}
1947
1948
1949/** @interface_method_impl{PDMUSBHLP,pfnTimerFromMicro} */
1950static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)
1951{
1952 PDMUSB_ASSERT_USBINS(pUsbIns);
1953 return TMTimerFromMicro(pUsbIns->Internal.s.pVM, hTimer, cMicroSecs);
1954}
1955
1956
1957/** @interface_method_impl{PDMUSBHLP,pfnTimerFromMilli} */
1958static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromMilli(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)
1959{
1960 PDMUSB_ASSERT_USBINS(pUsbIns);
1961 return TMTimerFromMilli(pUsbIns->Internal.s.pVM, hTimer, cMilliSecs);
1962}
1963
1964
1965/** @interface_method_impl{PDMUSBHLP,pfnTimerFromNano} */
1966static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)
1967{
1968 PDMUSB_ASSERT_USBINS(pUsbIns);
1969 return TMTimerFromNano(pUsbIns->Internal.s.pVM, hTimer, cNanoSecs);
1970}
1971
1972/** @interface_method_impl{PDMUSBHLP,pfnTimerGet} */
1973static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1974{
1975 PDMUSB_ASSERT_USBINS(pUsbIns);
1976 return TMTimerGet(pUsbIns->Internal.s.pVM, hTimer);
1977}
1978
1979
1980/** @interface_method_impl{PDMUSBHLP,pfnTimerGetFreq} */
1981static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGetFreq(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1982{
1983 PDMUSB_ASSERT_USBINS(pUsbIns);
1984 return TMTimerGetFreq(pUsbIns->Internal.s.pVM, hTimer);
1985}
1986
1987
1988/** @interface_method_impl{PDMUSBHLP,pfnTimerGetNano} */
1989static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1990{
1991 PDMUSB_ASSERT_USBINS(pUsbIns);
1992 return TMTimerGetNano(pUsbIns->Internal.s.pVM, hTimer);
1993}
1994
1995
1996/** @interface_method_impl{PDMUSBHLP,pfnTimerIsActive} */
1997static DECLCALLBACK(bool) pdmR3UsbHlp_TimerIsActive(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1998{
1999 PDMUSB_ASSERT_USBINS(pUsbIns);
2000 return TMTimerIsActive(pUsbIns->Internal.s.pVM, hTimer);
2001}
2002
2003
2004/** @interface_method_impl{PDMUSBHLP,pfnTimerIsLockOwner} */
2005static DECLCALLBACK(bool) pdmR3UsbHlp_TimerIsLockOwner(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2006{
2007 PDMUSB_ASSERT_USBINS(pUsbIns);
2008 return TMTimerIsLockOwner(pUsbIns->Internal.s.pVM, hTimer);
2009}
2010
2011
2012/** @interface_method_impl{PDMUSBHLP,pfnTimerLockClock} */
2013static DECLCALLBACK(int) pdmR3UsbHlp_TimerLockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2014{
2015 PDMUSB_ASSERT_USBINS(pUsbIns);
2016 return TMTimerLock(pUsbIns->Internal.s.pVM, hTimer, VERR_IGNORED);
2017}
2018
2019
2020/** @interface_method_impl{PDMUSBHLP,pfnTimerLockClock2} */
2021static DECLCALLBACK(int) pdmR3UsbHlp_TimerLockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2022{
2023 PDMUSB_ASSERT_USBINS(pUsbIns);
2024 PVM const pVM = pUsbIns->Internal.s.pVM;
2025 int rc = TMTimerLock(pVM, hTimer, VERR_IGNORED);
2026 if (rc == VINF_SUCCESS)
2027 {
2028 rc = PDMCritSectEnter(pVM, pCritSect, VERR_IGNORED);
2029 if (rc == VINF_SUCCESS)
2030 return rc;
2031 AssertRC(rc);
2032 TMTimerUnlock(pVM, hTimer);
2033 }
2034 else
2035 AssertRC(rc);
2036 return rc;
2037}
2038
2039
2040/** @interface_method_impl{PDMUSBHLP,pfnTimerSet} */
2041static DECLCALLBACK(int) pdmR3UsbHlp_TimerSet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire)
2042{
2043 PDMUSB_ASSERT_USBINS(pUsbIns);
2044 return TMTimerSet(pUsbIns->Internal.s.pVM, hTimer, uExpire);
2045}
2046
2047
2048/** @interface_method_impl{PDMUSBHLP,pfnTimerSetFrequencyHint} */
2049static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetFrequencyHint(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz)
2050{
2051 PDMUSB_ASSERT_USBINS(pUsbIns);
2052 return TMTimerSetFrequencyHint(pUsbIns->Internal.s.pVM, hTimer, uHz);
2053}
2054
2055
2056/** @interface_method_impl{PDMUSBHLP,pfnTimerSetMicro} */
2057static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)
2058{
2059 PDMUSB_ASSERT_USBINS(pUsbIns);
2060 return TMTimerSetMicro(pUsbIns->Internal.s.pVM, hTimer, cMicrosToNext);
2061}
2062
2063
2064/** @interface_method_impl{PDMUSBHLP,pfnTimerSetMillies} */
2065static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetMillies(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)
2066{
2067 PDMUSB_ASSERT_USBINS(pUsbIns);
2068 return TMTimerSetMillies(pUsbIns->Internal.s.pVM, hTimer, cMilliesToNext);
2069}
2070
2071
2072/** @interface_method_impl{PDMUSBHLP,pfnTimerSetNano} */
2073static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)
2074{
2075 PDMUSB_ASSERT_USBINS(pUsbIns);
2076 return TMTimerSetNano(pUsbIns->Internal.s.pVM, hTimer, cNanosToNext);
2077}
2078
2079
2080/** @interface_method_impl{PDMUSBHLP,pfnTimerSetRelative} */
2081static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetRelative(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
2082{
2083 PDMUSB_ASSERT_USBINS(pUsbIns);
2084 return TMTimerSetRelative(pUsbIns->Internal.s.pVM, hTimer, cTicksToNext, pu64Now);
2085}
2086
2087
2088/** @interface_method_impl{PDMUSBHLP,pfnTimerStop} */
2089static DECLCALLBACK(int) pdmR3UsbHlp_TimerStop(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2090{
2091 PDMUSB_ASSERT_USBINS(pUsbIns);
2092 return TMTimerStop(pUsbIns->Internal.s.pVM, hTimer);
2093}
2094
2095
2096/** @interface_method_impl{PDMUSBHLP,pfnTimerUnlockClock} */
2097static DECLCALLBACK(void) pdmR3UsbHlp_TimerUnlockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2098{
2099 PDMUSB_ASSERT_USBINS(pUsbIns);
2100 TMTimerUnlock(pUsbIns->Internal.s.pVM, hTimer);
2101}
2102
2103
2104/** @interface_method_impl{PDMUSBHLP,pfnTimerUnlockClock2} */
2105static DECLCALLBACK(void) pdmR3UsbHlp_TimerUnlockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2106{
2107 PDMUSB_ASSERT_USBINS(pUsbIns);
2108 PVM const pVM = pUsbIns->Internal.s.pVM;
2109 TMTimerUnlock(pVM, hTimer);
2110 int rc = PDMCritSectLeave(pVM, pCritSect);
2111 AssertRC(rc);
2112}
2113
2114
2115/** @interface_method_impl{PDMUSBHLP,pfnTimerSetCritSect} */
2116static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetCritSect(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2117{
2118 PDMUSB_ASSERT_USBINS(pUsbIns);
2119 return TMR3TimerSetCritSect(pUsbIns->Internal.s.pVM, hTimer, pCritSect);
2120}
2121
2122
2123/** @interface_method_impl{PDMUSBHLP,pfnTimerSave} */
2124static DECLCALLBACK(int) pdmR3UsbHlp_TimerSave(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)
2125{
2126 PDMUSB_ASSERT_USBINS(pUsbIns);
2127 return TMR3TimerSave(pUsbIns->Internal.s.pVM, hTimer, pSSM);
2128}
2129
2130
2131/** @interface_method_impl{PDMUSBHLP,pfnTimerLoad} */
2132static DECLCALLBACK(int) pdmR3UsbHlp_TimerLoad(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)
2133{
2134 PDMUSB_ASSERT_USBINS(pUsbIns);
2135 return TMR3TimerLoad(pUsbIns->Internal.s.pVM, hTimer, pSSM);
2136}
2137
2138
2139/** @interface_method_impl{PDMUSBHLP,pfnTimerDestroy} */
2140static DECLCALLBACK(int) pdmR3UsbHlp_TimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2141{
2142 PDMUSB_ASSERT_USBINS(pUsbIns);
2143 return TMR3TimerDestroy(pUsbIns->Internal.s.pVM, hTimer);
2144}
2145
2146
2147/** @interface_method_impl{PDMUSBHLP,pfnVMSetErrorV} */
2148static DECLCALLBACK(int) pdmR3UsbHlp_VMSetErrorV(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
2149{
2150 PDMUSB_ASSERT_USBINS(pUsbIns);
2151 int rc2 = VMSetErrorV(pUsbIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
2152 return rc;
2153}
2154
2155
2156/** @interface_method_impl{PDMUSBHLP,pfnVMSetRuntimeErrorV} */
2157static DECLCALLBACK(int) pdmR3UsbHlp_VMSetRuntimeErrorV(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
2158{
2159 PDMUSB_ASSERT_USBINS(pUsbIns);
2160 int rc = VMSetRuntimeErrorV(pUsbIns->Internal.s.pVM, fFlags, pszErrorId, pszFormat, va);
2161 return rc;
2162}
2163
2164
2165/** @interface_method_impl{PDMUSBHLP,pfnVMState} */
2166static DECLCALLBACK(VMSTATE) pdmR3UsbHlp_VMState(PPDMUSBINS pUsbIns)
2167{
2168 PDMUSB_ASSERT_USBINS(pUsbIns);
2169
2170 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
2171
2172 LogFlow(("pdmR3UsbHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
2173 enmVMState, VMR3GetStateName(enmVMState)));
2174 return enmVMState;
2175}
2176
2177/** @interface_method_impl{PDMUSBHLP,pfnThreadCreate} */
2178static DECLCALLBACK(int) pdmR3UsbHlp_ThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread,
2179 PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
2180{
2181 PDMUSB_ASSERT_USBINS(pUsbIns);
2182 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
2183 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
2184 pUsbIns->pReg->szName, pUsbIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
2185
2186 int rc = pdmR3ThreadCreateUsb(pUsbIns->Internal.s.pVM, pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
2187
2188 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
2189 rc, *ppThread));
2190 return rc;
2191}
2192
2193
2194/** @interface_method_impl{PDMUSBHLP,pfnSetAsyncNotification} */
2195static DECLCALLBACK(int) pdmR3UsbHlp_SetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)
2196{
2197 PDMUSB_ASSERT_USBINS(pUsbIns);
2198 VM_ASSERT_EMT0(pUsbIns->Internal.s.pVM);
2199 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pfnAsyncNotify));
2200
2201 int rc = VINF_SUCCESS;
2202 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
2203 AssertStmt(!pUsbIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
2204 AssertStmt(pUsbIns->Internal.s.fVMSuspended || pUsbIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
2205 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
2206 AssertStmt( enmVMState == VMSTATE_SUSPENDING
2207 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
2208 || enmVMState == VMSTATE_SUSPENDING_LS
2209 || enmVMState == VMSTATE_RESETTING
2210 || enmVMState == VMSTATE_RESETTING_LS
2211 || enmVMState == VMSTATE_POWERING_OFF
2212 || enmVMState == VMSTATE_POWERING_OFF_LS,
2213 rc = VERR_INVALID_STATE);
2214
2215 if (RT_SUCCESS(rc))
2216 pUsbIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
2217
2218 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
2219 return rc;
2220}
2221
2222
2223/** @interface_method_impl{PDMUSBHLP,pfnAsyncNotificationCompleted} */
2224static DECLCALLBACK(void) pdmR3UsbHlp_AsyncNotificationCompleted(PPDMUSBINS pUsbIns)
2225{
2226 PDMUSB_ASSERT_USBINS(pUsbIns);
2227 PVM pVM = pUsbIns->Internal.s.pVM;
2228
2229 VMSTATE enmVMState = VMR3GetState(pVM);
2230 if ( enmVMState == VMSTATE_SUSPENDING
2231 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
2232 || enmVMState == VMSTATE_SUSPENDING_LS
2233 || enmVMState == VMSTATE_RESETTING
2234 || enmVMState == VMSTATE_RESETTING_LS
2235 || enmVMState == VMSTATE_POWERING_OFF
2236 || enmVMState == VMSTATE_POWERING_OFF_LS)
2237 {
2238 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2239 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
2240 }
2241 else
2242 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance, enmVMState));
2243}
2244
2245
2246/** @interface_method_impl{PDMUSBHLP,pfnVMGetSuspendReason} */
2247static DECLCALLBACK(VMSUSPENDREASON) pdmR3UsbHlp_VMGetSuspendReason(PPDMUSBINS pUsbIns)
2248{
2249 PDMUSB_ASSERT_USBINS(pUsbIns);
2250 PVM pVM = pUsbIns->Internal.s.pVM;
2251 VM_ASSERT_EMT(pVM);
2252 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
2253 LogFlow(("pdmR3UsbHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
2254 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
2255 return enmReason;
2256}
2257
2258
2259/** @interface_method_impl{PDMUSBHLP,pfnVMGetResumeReason} */
2260static DECLCALLBACK(VMRESUMEREASON) pdmR3UsbHlp_VMGetResumeReason(PPDMUSBINS pUsbIns)
2261{
2262 PDMUSB_ASSERT_USBINS(pUsbIns);
2263 PVM pVM = pUsbIns->Internal.s.pVM;
2264 VM_ASSERT_EMT(pVM);
2265 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
2266 LogFlow(("pdmR3UsbHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
2267 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
2268 return enmReason;
2269}
2270
2271
2272/** @interface_method_impl{PDMUSBHLP,pfnQueryGenericUserObject} */
2273static DECLCALLBACK(void *) pdmR3UsbHlp_QueryGenericUserObject(PPDMUSBINS pUsbIns, PCRTUUID pUuid)
2274{
2275 PDMUSB_ASSERT_USBINS(pUsbIns);
2276 PVM pVM = pUsbIns->Internal.s.pVM;
2277 PUVM pUVM = pVM->pUVM;
2278
2279 void *pvRet;
2280 if (pUVM->pVmm2UserMethods->pfnQueryGenericObject)
2281 pvRet = pUVM->pVmm2UserMethods->pfnQueryGenericObject(pUVM->pVmm2UserMethods, pUVM, pUuid);
2282 else
2283 pvRet = NULL;
2284
2285 Log(("pdmR3UsbHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
2286 pUsbIns->pReg->szName, pUsbIns->iInstance, pvRet, pUuid));
2287 return pvRet;
2288}
2289
2290
2291/**
2292 * The USB device helper structure.
2293 */
2294const PDMUSBHLP g_pdmR3UsbHlp =
2295{
2296 PDM_USBHLP_VERSION,
2297 pdmR3UsbHlp_DriverAttach,
2298 pdmR3UsbHlp_AssertEMT,
2299 pdmR3UsbHlp_AssertOther,
2300 pdmR3UsbHlp_DBGFStopV,
2301 pdmR3UsbHlp_DBGFInfoRegisterArgv,
2302 pdmR3UsbHlp_MMHeapAlloc,
2303 pdmR3UsbHlp_MMHeapAllocZ,
2304 pdmR3UsbHlp_MMHeapFree,
2305 pdmR3UsbHlp_PDMQueueCreate,
2306 pdmR3UsbHlp_SSMRegister,
2307 SSMR3PutStruct,
2308 SSMR3PutStructEx,
2309 SSMR3PutBool,
2310 SSMR3PutU8,
2311 SSMR3PutS8,
2312 SSMR3PutU16,
2313 SSMR3PutS16,
2314 SSMR3PutU32,
2315 SSMR3PutS32,
2316 SSMR3PutU64,
2317 SSMR3PutS64,
2318 SSMR3PutU128,
2319 SSMR3PutS128,
2320 SSMR3PutUInt,
2321 SSMR3PutSInt,
2322 SSMR3PutGCUInt,
2323 SSMR3PutGCUIntReg,
2324 SSMR3PutGCPhys32,
2325 SSMR3PutGCPhys64,
2326 SSMR3PutGCPhys,
2327 SSMR3PutGCPtr,
2328 SSMR3PutGCUIntPtr,
2329 SSMR3PutRCPtr,
2330 SSMR3PutIOPort,
2331 SSMR3PutSel,
2332 SSMR3PutMem,
2333 SSMR3PutStrZ,
2334 SSMR3GetStruct,
2335 SSMR3GetStructEx,
2336 SSMR3GetBool,
2337 SSMR3GetBoolV,
2338 SSMR3GetU8,
2339 SSMR3GetU8V,
2340 SSMR3GetS8,
2341 SSMR3GetS8V,
2342 SSMR3GetU16,
2343 SSMR3GetU16V,
2344 SSMR3GetS16,
2345 SSMR3GetS16V,
2346 SSMR3GetU32,
2347 SSMR3GetU32V,
2348 SSMR3GetS32,
2349 SSMR3GetS32V,
2350 SSMR3GetU64,
2351 SSMR3GetU64V,
2352 SSMR3GetS64,
2353 SSMR3GetS64V,
2354 SSMR3GetU128,
2355 SSMR3GetU128V,
2356 SSMR3GetS128,
2357 SSMR3GetS128V,
2358 SSMR3GetGCPhys32,
2359 SSMR3GetGCPhys32V,
2360 SSMR3GetGCPhys64,
2361 SSMR3GetGCPhys64V,
2362 SSMR3GetGCPhys,
2363 SSMR3GetGCPhysV,
2364 SSMR3GetUInt,
2365 SSMR3GetSInt,
2366 SSMR3GetGCUInt,
2367 SSMR3GetGCUIntReg,
2368 SSMR3GetGCPtr,
2369 SSMR3GetGCUIntPtr,
2370 SSMR3GetRCPtr,
2371 SSMR3GetIOPort,
2372 SSMR3GetSel,
2373 SSMR3GetMem,
2374 SSMR3GetStrZ,
2375 SSMR3GetStrZEx,
2376 SSMR3Skip,
2377 SSMR3SkipToEndOfUnit,
2378 SSMR3SetLoadError,
2379 SSMR3SetLoadErrorV,
2380 SSMR3SetCfgError,
2381 SSMR3SetCfgErrorV,
2382 SSMR3HandleGetStatus,
2383 SSMR3HandleGetAfter,
2384 SSMR3HandleIsLiveSave,
2385 SSMR3HandleMaxDowntime,
2386 SSMR3HandleHostBits,
2387 SSMR3HandleRevision,
2388 SSMR3HandleVersion,
2389 SSMR3HandleHostOSAndArch,
2390 CFGMR3Exists,
2391 CFGMR3QueryType,
2392 CFGMR3QuerySize,
2393 CFGMR3QueryInteger,
2394 CFGMR3QueryIntegerDef,
2395 CFGMR3QueryString,
2396 CFGMR3QueryStringDef,
2397 CFGMR3QueryBytes,
2398 CFGMR3QueryU64,
2399 CFGMR3QueryU64Def,
2400 CFGMR3QueryS64,
2401 CFGMR3QueryS64Def,
2402 CFGMR3QueryU32,
2403 CFGMR3QueryU32Def,
2404 CFGMR3QueryS32,
2405 CFGMR3QueryS32Def,
2406 CFGMR3QueryU16,
2407 CFGMR3QueryU16Def,
2408 CFGMR3QueryS16,
2409 CFGMR3QueryS16Def,
2410 CFGMR3QueryU8,
2411 CFGMR3QueryU8Def,
2412 CFGMR3QueryS8,
2413 CFGMR3QueryS8Def,
2414 CFGMR3QueryBool,
2415 CFGMR3QueryBoolDef,
2416 CFGMR3QueryPort,
2417 CFGMR3QueryPortDef,
2418 CFGMR3QueryUInt,
2419 CFGMR3QueryUIntDef,
2420 CFGMR3QuerySInt,
2421 CFGMR3QuerySIntDef,
2422 CFGMR3QueryGCPtr,
2423 CFGMR3QueryGCPtrDef,
2424 CFGMR3QueryGCPtrU,
2425 CFGMR3QueryGCPtrUDef,
2426 CFGMR3QueryGCPtrS,
2427 CFGMR3QueryGCPtrSDef,
2428 CFGMR3QueryStringAlloc,
2429 CFGMR3QueryStringAllocDef,
2430 CFGMR3GetParent,
2431 CFGMR3GetChild,
2432 CFGMR3GetChildF,
2433 CFGMR3GetChildFV,
2434 CFGMR3GetFirstChild,
2435 CFGMR3GetNextChild,
2436 CFGMR3GetName,
2437 CFGMR3GetNameLen,
2438 CFGMR3AreChildrenValid,
2439 CFGMR3GetFirstValue,
2440 CFGMR3GetNextValue,
2441 CFGMR3GetValueName,
2442 CFGMR3GetValueNameLen,
2443 CFGMR3GetValueType,
2444 CFGMR3AreValuesValid,
2445 CFGMR3ValidateConfig,
2446 pdmR3UsbHlp_STAMRegisterV,
2447 pdmR3UsbHlp_TimerCreate,
2448 pdmR3UsbHlp_TimerFromMicro,
2449 pdmR3UsbHlp_TimerFromMilli,
2450 pdmR3UsbHlp_TimerFromNano,
2451 pdmR3UsbHlp_TimerGet,
2452 pdmR3UsbHlp_TimerGetFreq,
2453 pdmR3UsbHlp_TimerGetNano,
2454 pdmR3UsbHlp_TimerIsActive,
2455 pdmR3UsbHlp_TimerIsLockOwner,
2456 pdmR3UsbHlp_TimerLockClock,
2457 pdmR3UsbHlp_TimerLockClock2,
2458 pdmR3UsbHlp_TimerSet,
2459 pdmR3UsbHlp_TimerSetFrequencyHint,
2460 pdmR3UsbHlp_TimerSetMicro,
2461 pdmR3UsbHlp_TimerSetMillies,
2462 pdmR3UsbHlp_TimerSetNano,
2463 pdmR3UsbHlp_TimerSetRelative,
2464 pdmR3UsbHlp_TimerStop,
2465 pdmR3UsbHlp_TimerUnlockClock,
2466 pdmR3UsbHlp_TimerUnlockClock2,
2467 pdmR3UsbHlp_TimerSetCritSect,
2468 pdmR3UsbHlp_TimerSave,
2469 pdmR3UsbHlp_TimerLoad,
2470 pdmR3UsbHlp_TimerDestroy,
2471 TMR3TimerSkip,
2472 pdmR3UsbHlp_VMSetErrorV,
2473 pdmR3UsbHlp_VMSetRuntimeErrorV,
2474 pdmR3UsbHlp_VMState,
2475 pdmR3UsbHlp_ThreadCreate,
2476 PDMR3ThreadDestroy,
2477 PDMR3ThreadIAmSuspending,
2478 PDMR3ThreadIAmRunning,
2479 PDMR3ThreadSleep,
2480 PDMR3ThreadSuspend,
2481 PDMR3ThreadResume,
2482 pdmR3UsbHlp_SetAsyncNotification,
2483 pdmR3UsbHlp_AsyncNotificationCompleted,
2484 pdmR3UsbHlp_VMGetSuspendReason,
2485 pdmR3UsbHlp_VMGetResumeReason,
2486 pdmR3UsbHlp_QueryGenericUserObject,
2487 NULL,
2488 NULL,
2489 NULL,
2490 NULL,
2491 NULL,
2492 NULL,
2493 NULL,
2494 NULL,
2495 NULL,
2496 PDM_USBHLP_VERSION
2497};
2498
2499/** @} */
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