VirtualBox

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

Last change on this file since 97231 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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