VirtualBox

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

Last change on this file since 92392 was 92155, checked in by vboxsync, 3 years ago

VMM/PDMUsb: Add thread helpers to the helper callback table, bugref:10074

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