VirtualBox

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

Last change on this file since 102869 was 98122, checked in by vboxsync, 23 months ago

VMM/PDM: Fixed assertion in PDMR3ResumeUsb after attaching a virtual MSD.

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