VirtualBox

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

Last change on this file since 95259 was 94369, checked in by vboxsync, 3 years ago

VMM,CFGM: Drop CFGMR3QueryPtr and CFGMR3QueryPtrDef, bugref:10053

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.1 KB
Line 
1/* $Id: PDMUsb.cpp 94369 2022-03-25 07:42:32Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, USB part.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 pSubTree The CFGM subtree to incorporate into the settings
1022 * (same restrictions as for CFGMR3InsertSubTree() apply),
1023 * optional.
1024 * @param enmSpeed The speed the USB device is operating at.
1025 * @param fMaskedIfs The interfaces to hide from the guest.
1026 * @param pszCaptureFilename Path to the file for USB traffic capturing, optional.
1027 */
1028VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, PCFGMNODE pSubTree,
1029 VUSBSPEED enmSpeed, uint32_t fMaskedIfs, const char *pszCaptureFilename)
1030{
1031 /*
1032 * Validate input.
1033 */
1034 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1035 PVM pVM = pUVM->pVM;
1036 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1037 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1038 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1039 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
1040 AssertReturn( enmSpeed == VUSB_SPEED_LOW
1041 || enmSpeed == VUSB_SPEED_FULL
1042 || enmSpeed == VUSB_SPEED_HIGH
1043 || enmSpeed == VUSB_SPEED_SUPER
1044 || enmSpeed == VUSB_SPEED_SUPERPLUS, VERR_INVALID_PARAMETER);
1045
1046 /*
1047 * Find the USBProxy driver.
1048 */
1049 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, "USBProxy");
1050 if (!pUsbDev)
1051 {
1052 LogRel(("PDMUsb: PDMR3UsbCreateProxyDevice: The USBProxy device class wasn't found\n"));
1053 return VERR_PDM_NO_USBPROXY;
1054 }
1055
1056 /*
1057 * Find a suitable hub with free ports.
1058 */
1059 PPDMUSBHUB pHub;
1060 uint32_t iUsbVersion = pdmR3UsbSpd2Ver(enmSpeed);
1061 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
1062 if (RT_FAILURE(rc))
1063 {
1064 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
1065 return rc;
1066 }
1067
1068 /*
1069 * Create the CFGM instance node.
1070 */
1071 PCFGMNODE pInstance = CFGMR3CreateTree(pUVM);
1072 AssertReturn(pInstance, VERR_NO_MEMORY);
1073 do /* break loop */
1074 {
1075 PCFGMNODE pConfig;
1076 rc = CFGMR3InsertNode(pInstance, "Config", &pConfig); AssertRCBreak(rc);
1077 rc = CFGMR3InsertString(pConfig, "Address", pszAddress); AssertRCBreak(rc);
1078 char szUuid[RTUUID_STR_LENGTH];
1079 rc = RTUuidToStr(pUuid, &szUuid[0], sizeof(szUuid)); AssertRCBreak(rc);
1080 rc = CFGMR3InsertString(pConfig, "UUID", szUuid); AssertRCBreak(rc);
1081 rc = CFGMR3InsertString(pConfig, "Backend", pszBackend); AssertRCBreak(rc);
1082 rc = CFGMR3InsertInteger(pConfig, "MaskedIfs", fMaskedIfs); AssertRCBreak(rc);
1083 rc = CFGMR3InsertInteger(pConfig, "Force11Device", !(pHub->fVersions & iUsbVersion)); AssertRCBreak(rc);
1084 if (pSubTree)
1085 {
1086 rc = CFGMR3InsertSubTree(pConfig, "BackendCfg", pSubTree, NULL /*ppChild*/);
1087 AssertRCBreak(rc);
1088 }
1089 } while (0); /* break loop */
1090 if (RT_FAILURE(rc))
1091 {
1092 CFGMR3RemoveNode(pInstance);
1093 LogRel(("PDMUsb: PDMR3UsbCreateProxyDevice: failed to setup CFGM config, rc=%Rrc\n", rc));
1094 return rc;
1095 }
1096
1097 if (enmSpeed == VUSB_SPEED_UNKNOWN)
1098 enmSpeed = pdmR3UsbVer2Spd(iUsbVersion);
1099
1100 /*
1101 * Finally, try to create it.
1102 */
1103 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstance, enmSpeed, pszCaptureFilename);
1104 if (RT_FAILURE(rc) && pInstance)
1105 CFGMR3RemoveNode(pInstance);
1106 return rc;
1107}
1108
1109
1110/**
1111 * Destroys a hot-plugged USB device.
1112 *
1113 * The device must be detached from the HUB at this point.
1114 *
1115 * @param pVM The cross context VM structure.
1116 * @param pUsbIns The USB device instance to destroy.
1117 * @thread EMT
1118 */
1119static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns)
1120{
1121 Assert(!pUsbIns->Internal.s.pHub);
1122
1123 /*
1124 * Do the unplug notification.
1125 */
1126 /** @todo what about the drivers? */
1127 if (pUsbIns->pReg->pfnHotUnplugged)
1128 pUsbIns->pReg->pfnHotUnplugged(pUsbIns);
1129
1130 /*
1131 * Destroy the luns with their driver chains and call the device destructor.
1132 */
1133 while (pUsbIns->Internal.s.pLuns)
1134 {
1135 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1136 pUsbIns->Internal.s.pLuns = pLun->pNext;
1137 if (pLun->pTop)
1138 pdmR3DrvDestroyChain(pLun->pTop, PDM_TACH_FLAGS_NOT_HOT_PLUG); /* Hotplugging is handled differently here atm. */
1139 MMR3HeapFree(pLun);
1140 }
1141
1142 /* finally, the device. */
1143 if (pUsbIns->pReg->pfnDestruct)
1144 {
1145 Log(("PDM: Destructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1146 pUsbIns->pReg->pfnDestruct(pUsbIns);
1147 }
1148 TMR3TimerDestroyUsb(pVM, pUsbIns);
1149 SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
1150 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
1151#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1152 pdmR3AsyncCompletionTemplateDestroyUsb(pVM, pUsbIns);
1153#endif
1154
1155 /*
1156 * Unlink it.
1157 */
1158 /* The global instance FIFO. */
1159 if (pVM->pdm.s.pUsbInstances == pUsbIns)
1160 pVM->pdm.s.pUsbInstances = pUsbIns->Internal.s.pNext;
1161 else
1162 {
1163 PPDMUSBINS pPrev = pVM->pdm.s.pUsbInstances;
1164 while (pPrev && pPrev->Internal.s.pNext != pUsbIns)
1165 {
1166 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1167 pPrev = pPrev->Internal.s.pNext;
1168 }
1169 Assert(pPrev); Assert(pPrev != pUsbIns);
1170 if (pPrev)
1171 pPrev->Internal.s.pNext = pUsbIns->Internal.s.pNext;
1172 }
1173
1174 /* The per device instance FIFO. */
1175 PPDMUSB pUsbDev = pUsbIns->Internal.s.pUsbDev;
1176 if (pUsbDev->pInstances == pUsbIns)
1177 pUsbDev->pInstances = pUsbIns->Internal.s.pPerDeviceNext;
1178 else
1179 {
1180 PPDMUSBINS pPrev = pUsbDev->pInstances;
1181 while (pPrev && pPrev->Internal.s.pPerDeviceNext != pUsbIns)
1182 {
1183 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1184 pPrev = pPrev->Internal.s.pPerDeviceNext;
1185 }
1186 Assert(pPrev); Assert(pPrev != pUsbIns);
1187 if (pPrev)
1188 pPrev->Internal.s.pPerDeviceNext = pUsbIns->Internal.s.pPerDeviceNext;
1189 }
1190
1191 /*
1192 * Trash it.
1193 */
1194 pUsbIns->u32Version = 0;
1195 pUsbIns->pReg = NULL;
1196 if (pUsbIns->pszName)
1197 {
1198 RTStrFree(pUsbIns->pszName);
1199 pUsbIns->pszName = NULL;
1200 }
1201 CFGMR3RemoveNode(pUsbIns->Internal.s.pCfgDelete);
1202 MMR3HeapFree(pUsbIns);
1203}
1204
1205
1206/**
1207 * Detaches and destroys a USB device.
1208 *
1209 * @returns VBox status code.
1210 * @param pUVM The user mode VM handle.
1211 * @param pUuid The UUID associated with the device to detach.
1212 * @thread EMT
1213 */
1214VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid)
1215{
1216 /*
1217 * Validate input.
1218 */
1219 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1220 PVM pVM = pUVM->pVM;
1221 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1222 VM_ASSERT_EMT(pVM);
1223 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1224
1225 /*
1226 * Search the global list for it.
1227 */
1228 PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;
1229 for ( ; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1230 if (!RTUuidCompare(&pUsbIns->Internal.s.Uuid, pUuid))
1231 break;
1232 if (!pUsbIns)
1233 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND; /** @todo VERR_PDM_USB_INSTANCE_NOT_FOUND */
1234
1235 /*
1236 * Detach it from the HUB (if it's actually attached to one).
1237 */
1238 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
1239 if (pHub)
1240 {
1241 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
1242 if (RT_FAILURE(rc))
1243 {
1244 LogRel(("PDMUsb: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
1245 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
1246 return rc;
1247 }
1248
1249 pHub->cAvailablePorts++;
1250 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
1251 pUsbIns->Internal.s.pHub = NULL;
1252 }
1253
1254 /*
1255 * Notify about unplugging and destroy the device with it's drivers.
1256 */
1257 pdmR3UsbDestroyDevice(pVM, pUsbIns);
1258
1259 return VINF_SUCCESS;
1260}
1261
1262
1263/**
1264 * Checks if there are any USB hubs attached.
1265 *
1266 * @returns true / false accordingly.
1267 * @param pUVM The user mode VM handle.
1268 */
1269VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM)
1270{
1271 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1272 PVM pVM = pUVM->pVM;
1273 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1274 return pVM->pdm.s.pUsbHubs != NULL;
1275}
1276
1277
1278/**
1279 * Locates a LUN.
1280 *
1281 * @returns VBox status code.
1282 * @param pVM The cross context VM structure.
1283 * @param pszDevice Device name.
1284 * @param iInstance Device instance.
1285 * @param iLun The Logical Unit to obtain the interface of.
1286 * @param ppLun Where to store the pointer to the LUN if found.
1287 * @thread Try only do this in EMT...
1288 */
1289static int pdmR3UsbFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
1290{
1291 /*
1292 * Iterate registered devices looking for the device.
1293 */
1294 size_t cchDevice = strlen(pszDevice);
1295 for (PPDMUSB pUsbDev = pVM->pdm.s.pUsbDevs; pUsbDev; pUsbDev = pUsbDev->pNext)
1296 {
1297 if ( pUsbDev->cchName == cchDevice
1298 && !memcmp(pUsbDev->pReg->szName, pszDevice, cchDevice))
1299 {
1300 /*
1301 * Iterate device instances.
1302 */
1303 for (PPDMUSBINS pUsbIns = pUsbDev->pInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pPerDeviceNext)
1304 {
1305 if (pUsbIns->iInstance == iInstance)
1306 {
1307 /*
1308 * Iterate luns.
1309 */
1310 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1311 {
1312 if (pLun->iLun == iLun)
1313 {
1314 *ppLun = pLun;
1315 return VINF_SUCCESS;
1316 }
1317 }
1318 return VERR_PDM_LUN_NOT_FOUND;
1319 }
1320 }
1321 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1322 }
1323 }
1324 return VERR_PDM_DEVICE_NOT_FOUND;
1325}
1326
1327
1328/**
1329 * Attaches a preconfigured driver to an existing device or driver instance.
1330 *
1331 * This is used to change drivers and suchlike at runtime. The driver or device
1332 * at the end of the chain will be told to attach to whatever is configured
1333 * below it.
1334 *
1335 * @returns VBox status code.
1336 * @param pUVM The user mode VM handle.
1337 * @param pszDevice Device name.
1338 * @param iDevIns Device instance.
1339 * @param iLun The Logical Unit to obtain the interface of.
1340 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1341 * @param ppBase Where to store the base interface pointer. Optional.
1342 *
1343 * @thread EMT
1344 */
1345VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags,
1346 PPPDMIBASE ppBase)
1347{
1348 LogFlow(("PDMR3UsbDriverAttach: pszDevice=%p:{%s} iDevIns=%d iLun=%d fFlags=%#x ppBase=%p\n",
1349 pszDevice, pszDevice, iDevIns, iLun, fFlags, ppBase));
1350 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1351 PVM pVM = pUVM->pVM;
1352 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1353 VM_ASSERT_EMT(pVM);
1354
1355 if (ppBase)
1356 *ppBase = NULL;
1357
1358 /*
1359 * Find the LUN in question.
1360 */
1361 PPDMLUN pLun;
1362 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1363 if (RT_SUCCESS(rc))
1364 {
1365 /*
1366 * Anything attached to the LUN?
1367 */
1368 PPDMDRVINS pDrvIns = pLun->pTop;
1369 if (!pDrvIns)
1370 {
1371 /* No, ask the device to attach to the new stuff. */
1372 PPDMUSBINS pUsbIns = pLun->pUsbIns;
1373 if (pUsbIns->pReg->pfnDriverAttach)
1374 {
1375 rc = pUsbIns->pReg->pfnDriverAttach(pUsbIns, iLun, fFlags);
1376 if (RT_SUCCESS(rc) && ppBase)
1377 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
1378 }
1379 else
1380 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
1381 }
1382 else
1383 {
1384 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
1385 while (pDrvIns->Internal.s.pDown)
1386 pDrvIns = pDrvIns->Internal.s.pDown;
1387 if (pDrvIns->pReg->pfnAttach)
1388 {
1389 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
1390 if (RT_SUCCESS(rc) && ppBase)
1391 *ppBase = pDrvIns->Internal.s.pDown
1392 ? &pDrvIns->Internal.s.pDown->IBase
1393 : NULL;
1394 }
1395 else
1396 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
1397 }
1398 }
1399
1400 if (ppBase)
1401 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
1402 else
1403 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc\n", rc));
1404 return rc;
1405}
1406
1407
1408/**
1409 * Detaches the specified driver instance.
1410 *
1411 * This is used to replumb drivers at runtime for simulating hot plugging and
1412 * media changes.
1413 *
1414 * This method allows detaching drivers from
1415 * any driver or device by specifying the driver to start detaching at. The
1416 * only prerequisite is that the driver or device above implements the
1417 * pfnDetach callback (PDMDRVREG / PDMUSBREG).
1418 *
1419 * @returns VBox status code.
1420 * @param pUVM The user mode VM handle.
1421 * @param pszDevice Device name.
1422 * @param iDevIns Device instance.
1423 * @param iLun The Logical Unit in which to look for the driver.
1424 * @param pszDriver The name of the driver which to detach. If NULL
1425 * then the entire driver chain is detatched.
1426 * @param iOccurrence The occurrence of that driver in the chain. This is
1427 * usually 0.
1428 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1429 * @thread EMT
1430 */
1431VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1432 const char *pszDriver, unsigned iOccurrence, uint32_t fFlags)
1433{
1434 LogFlow(("PDMR3UsbDriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurrence=%u fFlags=%#x\n",
1435 pszDevice, pszDevice, iDevIns, iLun, pszDriver, pszDriver, iOccurrence, fFlags));
1436 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1437 PVM pVM = pUVM->pVM;
1438 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1439 VM_ASSERT_EMT(pVM);
1440 AssertPtr(pszDevice);
1441 AssertPtrNull(pszDriver);
1442 Assert(iOccurrence == 0 || pszDriver);
1443 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1444
1445 /*
1446 * Find the LUN in question.
1447 */
1448 PPDMLUN pLun;
1449 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1450 if (RT_SUCCESS(rc))
1451 {
1452 /*
1453 * Locate the driver.
1454 */
1455 PPDMDRVINS pDrvIns = pLun->pTop;
1456 if (pDrvIns)
1457 {
1458 if (pszDriver)
1459 {
1460 while (pDrvIns)
1461 {
1462 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1463 {
1464 if (iOccurrence == 0)
1465 break;
1466 iOccurrence--;
1467 }
1468 pDrvIns = pDrvIns->Internal.s.pDown;
1469 }
1470 }
1471 if (pDrvIns)
1472 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1473 else
1474 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1475 }
1476 else
1477 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1478 }
1479
1480 LogFlow(("PDMR3UsbDriverDetach: returns %Rrc\n", rc));
1481 return rc;
1482}
1483
1484
1485/**
1486 * Query the interface of the top level driver on a LUN.
1487 *
1488 * @returns VBox status code.
1489 * @param pUVM The user mode VM handle.
1490 * @param pszDevice Device name.
1491 * @param iInstance Device instance.
1492 * @param iLun The Logical Unit to obtain the interface of.
1493 * @param ppBase Where to store the base interface pointer.
1494 * @remark We're not doing any locking ATM, so don't try call this at times when the
1495 * device chain is known to be updated.
1496 */
1497VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1498{
1499 LogFlow(("PDMR3UsbQueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1500 pszDevice, pszDevice, iInstance, iLun, ppBase));
1501 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1502 PVM pVM = pUVM->pVM;
1503 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1504
1505 /*
1506 * Find the LUN.
1507 */
1508 PPDMLUN pLun;
1509 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1510 if (RT_SUCCESS(rc))
1511 {
1512 if (pLun->pTop)
1513 {
1514 *ppBase = &pLun->pTop->IBase;
1515 LogFlow(("PDMR3UsbQueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1516 return VINF_SUCCESS;
1517 }
1518 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1519 }
1520 LogFlow(("PDMR3UsbQueryLun: returns %Rrc\n", rc));
1521 return rc;
1522}
1523
1524
1525/**
1526 * Query the interface of a named driver on a LUN.
1527 *
1528 * If the driver appears more than once in the driver chain, the first instance
1529 * is returned.
1530 *
1531 * @returns VBox status code.
1532 * @param pUVM The user mode VM handle.
1533 * @param pszDevice Device name.
1534 * @param iInstance Device instance.
1535 * @param iLun The Logical Unit to obtain the interface of.
1536 * @param pszDriver The driver name.
1537 * @param ppBase Where to store the base interface pointer.
1538 *
1539 * @remark We're not doing any locking ATM, so don't try call this at times when the
1540 * device chain is known to be updated.
1541 */
1542VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance,
1543 unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
1544{
1545 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
1546 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
1547 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1548 PVM pVM = pUVM->pVM;
1549 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1550
1551 /*
1552 * Find the LUN.
1553 */
1554 PPDMLUN pLun;
1555 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1556 if (RT_SUCCESS(rc))
1557 {
1558 if (pLun->pTop)
1559 {
1560 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1561 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1562 {
1563 *ppBase = &pDrvIns->IBase;
1564 LogFlow(("PDMR3UsbQueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1565 return VINF_SUCCESS;
1566
1567 }
1568 rc = VERR_PDM_DRIVER_NOT_FOUND;
1569 }
1570 else
1571 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1572 }
1573 LogFlow(("PDMR3UsbQueryDriverOnLun: returns %Rrc\n", rc));
1574 return rc;
1575}
1576
1577
1578/** @name USB Device Helpers
1579 * @{
1580 */
1581
1582/** @interface_method_impl{PDMUSBHLP,pfnDriverAttach} */
1583static DECLCALLBACK(int) pdmR3UsbHlp_DriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
1584 PPDMIBASE *ppBaseInterface, const char *pszDesc)
1585{
1586 PDMUSB_ASSERT_USBINS(pUsbIns);
1587 PVM pVM = pUsbIns->Internal.s.pVM;
1588 VM_ASSERT_EMT(pVM);
1589 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
1590 pUsbIns->pReg->szName, pUsbIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
1591
1592 /*
1593 * Lookup the LUN, it might already be registered.
1594 */
1595 PPDMLUN pLunPrev = NULL;
1596 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1597 for (; pLun; pLunPrev = pLun, pLun = pLun->pNext)
1598 if (pLun->iLun == iLun)
1599 break;
1600
1601 /*
1602 * Create the LUN if if wasn't found, else check if driver is already attached to it.
1603 */
1604 if (!pLun)
1605 {
1606 if ( !pBaseInterface
1607 || !pszDesc
1608 || !*pszDesc)
1609 {
1610 Assert(pBaseInterface);
1611 Assert(pszDesc || *pszDesc);
1612 return VERR_INVALID_PARAMETER;
1613 }
1614
1615 pLun = (PPDMLUN)MMR3HeapAlloc(pVM, MM_TAG_PDM_LUN, sizeof(*pLun));
1616 if (!pLun)
1617 return VERR_NO_MEMORY;
1618
1619 pLun->iLun = iLun;
1620 pLun->pNext = pLunPrev ? pLunPrev->pNext : NULL;
1621 pLun->pTop = NULL;
1622 pLun->pBottom = NULL;
1623 pLun->pDevIns = NULL;
1624 pLun->pUsbIns = pUsbIns;
1625 pLun->pszDesc = pszDesc;
1626 pLun->pBase = pBaseInterface;
1627 if (!pLunPrev)
1628 pUsbIns->Internal.s.pLuns = pLun;
1629 else
1630 pLunPrev->pNext = pLun;
1631 Log(("pdmR3UsbHlp_DriverAttach: Registered LUN#%d '%s' with device '%s'/%d.\n",
1632 iLun, pszDesc, pUsbIns->pReg->szName, pUsbIns->iInstance));
1633 }
1634 else if (pLun->pTop)
1635 {
1636 AssertMsgFailed(("Already attached! The device should keep track of such things!\n"));
1637 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, VERR_PDM_DRIVER_ALREADY_ATTACHED));
1638 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1639 }
1640 Assert(pLun->pBase == pBaseInterface);
1641
1642
1643 /*
1644 * Get the attached driver configuration.
1645 */
1646 int rc;
1647 PCFGMNODE pNode = CFGMR3GetChildF(pUsbIns->Internal.s.pCfg, "LUN#%u", iLun);
1648 if (pNode)
1649 rc = pdmR3DrvInstantiate(pVM, pNode, pBaseInterface, NULL /*pDrvAbove*/, pLun, ppBaseInterface);
1650 else
1651 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1652
1653
1654 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1655 return rc;
1656}
1657
1658
1659/** @interface_method_impl{PDMUSBHLP,pfnAssertEMT} */
1660static DECLCALLBACK(bool) pdmR3UsbHlp_AssertEMT(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1661{
1662 PDMUSB_ASSERT_USBINS(pUsbIns);
1663 if (VM_IS_EMT(pUsbIns->Internal.s.pVM))
1664 return true;
1665
1666 char szMsg[100];
1667 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1668 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1669 AssertBreakpoint();
1670 return false;
1671}
1672
1673
1674/** @interface_method_impl{PDMUSBHLP,pfnAssertOther} */
1675static DECLCALLBACK(bool) pdmR3UsbHlp_AssertOther(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1676{
1677 PDMUSB_ASSERT_USBINS(pUsbIns);
1678 if (!VM_IS_EMT(pUsbIns->Internal.s.pVM))
1679 return true;
1680
1681 char szMsg[100];
1682 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1683 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1684 AssertBreakpoint();
1685 return false;
1686}
1687
1688
1689/** @interface_method_impl{PDMUSBHLP,pfnDBGFStopV} */
1690static DECLCALLBACK(int) pdmR3UsbHlp_DBGFStopV(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction,
1691 const char *pszFormat, va_list va)
1692{
1693 PDMUSB_ASSERT_USBINS(pUsbIns);
1694#ifdef LOG_ENABLED
1695 va_list va2;
1696 va_copy(va2, va);
1697 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
1698 pUsbIns->pReg->szName, pUsbIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
1699 va_end(va2);
1700#endif
1701
1702 PVM pVM = pUsbIns->Internal.s.pVM;
1703 VM_ASSERT_EMT(pVM);
1704 int rc = DBGFR3EventSrcV(pVM, DBGFEVENT_DEV_STOP, pszFile, iLine, pszFunction, pszFormat, va);
1705 if (rc == VERR_DBGF_NOT_ATTACHED)
1706 rc = VINF_SUCCESS;
1707
1708 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1709 return rc;
1710}
1711
1712
1713/** @interface_method_impl{PDMUSBHLP,pfnDBGFInfoRegisterArgv} */
1714static DECLCALLBACK(int) pdmR3UsbHlp_DBGFInfoRegisterArgv(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc,
1715 PFNDBGFINFOARGVUSB pfnHandler)
1716{
1717 PDMUSB_ASSERT_USBINS(pUsbIns);
1718 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1719 pUsbIns->pReg->szName, pUsbIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1720
1721 PVM pVM = pUsbIns->Internal.s.pVM;
1722 VM_ASSERT_EMT(pVM);
1723 int rc = DBGFR3InfoRegisterUsbArgv(pVM, pszName, pszDesc, pfnHandler, pUsbIns);
1724
1725 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1726 return rc;
1727}
1728
1729
1730/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAlloc} */
1731static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb)
1732{
1733 PDMUSB_ASSERT_USBINS(pUsbIns);
1734 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1735
1736 void *pv = MMR3HeapAlloc(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1737
1738 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1739 return pv;
1740}
1741
1742
1743/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAllocZ} */
1744static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb)
1745{
1746 PDMUSB_ASSERT_USBINS(pUsbIns);
1747 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1748
1749 void *pv = MMR3HeapAllocZ(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1750
1751 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1752 return pv;
1753}
1754
1755
1756/** @interface_method_impl{PDMUSBHLP,pfnMMHeapFree} */
1757static DECLCALLBACK(void) pdmR3UsbHlp_MMHeapFree(PPDMUSBINS pUsbIns, void *pv)
1758{
1759 PDMUSB_ASSERT_USBINS(pUsbIns); RT_NOREF(pUsbIns);
1760 LogFlow(("pdmR3UsbHlp_MMHeapFree: caller='%s'/%d: pv=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1761
1762 MMR3HeapFree(pv);
1763
1764 LogFlow(("pdmR3UsbHlp_MMHeapFree: caller='%s'/%d: returns\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1765}
1766
1767
1768/** @interface_method_impl{PDMUSBHLP,pfnPDMQueueCreate} */
1769static DECLCALLBACK(int) pdmR3UsbHlp_PDMQueueCreate(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
1770 PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
1771{
1772 PDMUSB_ASSERT_USBINS(pUsbIns);
1773 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%#x cItems=%#x cMilliesInterval=%u pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
1774 pUsbIns->pReg->szName, pUsbIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue));
1775
1776 PVM pVM = pUsbIns->Internal.s.pVM;
1777 VM_ASSERT_EMT(pVM);
1778
1779 if (pUsbIns->iInstance > 0)
1780 {
1781 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_DESC, "%s_%u", pszName, pUsbIns->iInstance);
1782 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1783 }
1784
1785 RT_NOREF5(cbItem, cItems, cMilliesInterval, pfnCallback, ppQueue);
1786 /** @todo int rc = PDMR3QueueCreateUsb(pVM, pUsbIns, cbItem, cItems, cMilliesInterval, pfnCallback, fGCEnabled, pszName, ppQueue); */
1787 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1788
1789 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *ppQueue));
1790 return rc;
1791}
1792
1793
1794/** @interface_method_impl{PDMUSBHLP,pfnSSMRegister} */
1795static DECLCALLBACK(int) pdmR3UsbHlp_SSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess,
1796 PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote,
1797 PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone,
1798 PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)
1799{
1800 PDMUSB_ASSERT_USBINS(pUsbIns);
1801 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
1802 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: uVersion=%#x cbGuess=%#x\n"
1803 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoadDone=%p\n",
1804 pUsbIns->pReg->szName, pUsbIns->iInstance, uVersion, cbGuess,
1805 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1806 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1807 pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1808
1809 int rc = SSMR3RegisterUsb(pUsbIns->Internal.s.pVM, pUsbIns, pUsbIns->pReg->szName, pUsbIns->iInstance,
1810 uVersion, cbGuess,
1811 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1812 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1813 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1814
1815 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1816 return rc;
1817}
1818
1819
1820/** @interface_method_impl{PDMUSBHLP,pfnSTAMRegisterV} */
1821static DECLCALLBACK(void) pdmR3UsbHlp_STAMRegisterV(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1822 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va)
1823{
1824 PDMUSB_ASSERT_USBINS(pUsbIns);
1825 PVM pVM = pUsbIns->Internal.s.pVM;
1826 VM_ASSERT_EMT(pVM);
1827
1828 int rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va);
1829 AssertRC(rc);
1830
1831 NOREF(pVM);
1832}
1833
1834
1835/** @interface_method_impl{PDMUSBHLP,pfnTimerCreate} */
1836static DECLCALLBACK(int) pdmR3UsbHlp_TimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser,
1837 uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)
1838{
1839 PDMUSB_ASSERT_USBINS(pUsbIns);
1840 PVM pVM = pUsbIns->Internal.s.pVM;
1841 VM_ASSERT_EMT(pVM);
1842 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} phTimer=%p\n",
1843 pUsbIns->pReg->szName, pUsbIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, phTimer));
1844
1845 AssertReturn(!(fFlags & TMTIMER_FLAGS_RING0), VERR_INVALID_FLAGS);
1846 fFlags |= TMTIMER_FLAGS_NO_RING0;
1847
1848 /* Mangle the timer name if there are more than one instance of this device. */
1849 char szName[32];
1850 AssertReturn(strlen(pszDesc) < sizeof(szName) - 8, VERR_INVALID_NAME);
1851 if (pUsbIns->iInstance > 0)
1852 {
1853 RTStrPrintf(szName, sizeof(szName), "%s[%u:%s]", pszDesc, pUsbIns->iInstance, pUsbIns->Internal.s.pUsbDev->pReg->szName);
1854 pszDesc = szName;
1855 }
1856
1857 int rc = TMR3TimerCreateUsb(pVM, pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer);
1858
1859 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc *phTimer=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *phTimer));
1860 return rc;
1861}
1862
1863
1864/** @interface_method_impl{PDMUSBHLP,pfnTimerFromMicro} */
1865static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)
1866{
1867 PDMUSB_ASSERT_USBINS(pUsbIns);
1868 return TMTimerFromMicro(pUsbIns->Internal.s.pVM, hTimer, cMicroSecs);
1869}
1870
1871
1872/** @interface_method_impl{PDMUSBHLP,pfnTimerFromMilli} */
1873static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromMilli(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)
1874{
1875 PDMUSB_ASSERT_USBINS(pUsbIns);
1876 return TMTimerFromMilli(pUsbIns->Internal.s.pVM, hTimer, cMilliSecs);
1877}
1878
1879
1880/** @interface_method_impl{PDMUSBHLP,pfnTimerFromNano} */
1881static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerFromNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)
1882{
1883 PDMUSB_ASSERT_USBINS(pUsbIns);
1884 return TMTimerFromNano(pUsbIns->Internal.s.pVM, hTimer, cNanoSecs);
1885}
1886
1887/** @interface_method_impl{PDMUSBHLP,pfnTimerGet} */
1888static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1889{
1890 PDMUSB_ASSERT_USBINS(pUsbIns);
1891 return TMTimerGet(pUsbIns->Internal.s.pVM, hTimer);
1892}
1893
1894
1895/** @interface_method_impl{PDMUSBHLP,pfnTimerGetFreq} */
1896static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGetFreq(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1897{
1898 PDMUSB_ASSERT_USBINS(pUsbIns);
1899 return TMTimerGetFreq(pUsbIns->Internal.s.pVM, hTimer);
1900}
1901
1902
1903/** @interface_method_impl{PDMUSBHLP,pfnTimerGetNano} */
1904static DECLCALLBACK(uint64_t) pdmR3UsbHlp_TimerGetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1905{
1906 PDMUSB_ASSERT_USBINS(pUsbIns);
1907 return TMTimerGetNano(pUsbIns->Internal.s.pVM, hTimer);
1908}
1909
1910
1911/** @interface_method_impl{PDMUSBHLP,pfnTimerIsActive} */
1912static DECLCALLBACK(bool) pdmR3UsbHlp_TimerIsActive(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1913{
1914 PDMUSB_ASSERT_USBINS(pUsbIns);
1915 return TMTimerIsActive(pUsbIns->Internal.s.pVM, hTimer);
1916}
1917
1918
1919/** @interface_method_impl{PDMUSBHLP,pfnTimerIsLockOwner} */
1920static DECLCALLBACK(bool) pdmR3UsbHlp_TimerIsLockOwner(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1921{
1922 PDMUSB_ASSERT_USBINS(pUsbIns);
1923 return TMTimerIsLockOwner(pUsbIns->Internal.s.pVM, hTimer);
1924}
1925
1926
1927/** @interface_method_impl{PDMUSBHLP,pfnTimerLockClock} */
1928static DECLCALLBACK(int) pdmR3UsbHlp_TimerLockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
1929{
1930 PDMUSB_ASSERT_USBINS(pUsbIns);
1931 return TMTimerLock(pUsbIns->Internal.s.pVM, hTimer, VERR_IGNORED);
1932}
1933
1934
1935/** @interface_method_impl{PDMUSBHLP,pfnTimerLockClock2} */
1936static DECLCALLBACK(int) pdmR3UsbHlp_TimerLockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
1937{
1938 PDMUSB_ASSERT_USBINS(pUsbIns);
1939 PVM const pVM = pUsbIns->Internal.s.pVM;
1940 int rc = TMTimerLock(pVM, hTimer, VERR_IGNORED);
1941 if (rc == VINF_SUCCESS)
1942 {
1943 rc = PDMCritSectEnter(pVM, pCritSect, VERR_IGNORED);
1944 if (rc == VINF_SUCCESS)
1945 return rc;
1946 AssertRC(rc);
1947 TMTimerUnlock(pVM, hTimer);
1948 }
1949 else
1950 AssertRC(rc);
1951 return rc;
1952}
1953
1954
1955/** @interface_method_impl{PDMUSBHLP,pfnTimerSet} */
1956static DECLCALLBACK(int) pdmR3UsbHlp_TimerSet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire)
1957{
1958 PDMUSB_ASSERT_USBINS(pUsbIns);
1959 return TMTimerSet(pUsbIns->Internal.s.pVM, hTimer, uExpire);
1960}
1961
1962
1963/** @interface_method_impl{PDMUSBHLP,pfnTimerSetFrequencyHint} */
1964static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetFrequencyHint(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz)
1965{
1966 PDMUSB_ASSERT_USBINS(pUsbIns);
1967 return TMTimerSetFrequencyHint(pUsbIns->Internal.s.pVM, hTimer, uHz);
1968}
1969
1970
1971/** @interface_method_impl{PDMUSBHLP,pfnTimerSetMicro} */
1972static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)
1973{
1974 PDMUSB_ASSERT_USBINS(pUsbIns);
1975 return TMTimerSetMicro(pUsbIns->Internal.s.pVM, hTimer, cMicrosToNext);
1976}
1977
1978
1979/** @interface_method_impl{PDMUSBHLP,pfnTimerSetMillies} */
1980static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetMillies(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)
1981{
1982 PDMUSB_ASSERT_USBINS(pUsbIns);
1983 return TMTimerSetMillies(pUsbIns->Internal.s.pVM, hTimer, cMilliesToNext);
1984}
1985
1986
1987/** @interface_method_impl{PDMUSBHLP,pfnTimerSetNano} */
1988static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)
1989{
1990 PDMUSB_ASSERT_USBINS(pUsbIns);
1991 return TMTimerSetNano(pUsbIns->Internal.s.pVM, hTimer, cNanosToNext);
1992}
1993
1994
1995/** @interface_method_impl{PDMUSBHLP,pfnTimerSetRelative} */
1996static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetRelative(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
1997{
1998 PDMUSB_ASSERT_USBINS(pUsbIns);
1999 return TMTimerSetRelative(pUsbIns->Internal.s.pVM, hTimer, cTicksToNext, pu64Now);
2000}
2001
2002
2003/** @interface_method_impl{PDMUSBHLP,pfnTimerStop} */
2004static DECLCALLBACK(int) pdmR3UsbHlp_TimerStop(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2005{
2006 PDMUSB_ASSERT_USBINS(pUsbIns);
2007 return TMTimerStop(pUsbIns->Internal.s.pVM, hTimer);
2008}
2009
2010
2011/** @interface_method_impl{PDMUSBHLP,pfnTimerUnlockClock} */
2012static DECLCALLBACK(void) pdmR3UsbHlp_TimerUnlockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2013{
2014 PDMUSB_ASSERT_USBINS(pUsbIns);
2015 TMTimerUnlock(pUsbIns->Internal.s.pVM, hTimer);
2016}
2017
2018
2019/** @interface_method_impl{PDMUSBHLP,pfnTimerUnlockClock2} */
2020static DECLCALLBACK(void) pdmR3UsbHlp_TimerUnlockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2021{
2022 PDMUSB_ASSERT_USBINS(pUsbIns);
2023 PVM const pVM = pUsbIns->Internal.s.pVM;
2024 TMTimerUnlock(pVM, hTimer);
2025 int rc = PDMCritSectLeave(pVM, pCritSect);
2026 AssertRC(rc);
2027}
2028
2029
2030/** @interface_method_impl{PDMUSBHLP,pfnTimerSetCritSect} */
2031static DECLCALLBACK(int) pdmR3UsbHlp_TimerSetCritSect(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)
2032{
2033 PDMUSB_ASSERT_USBINS(pUsbIns);
2034 return TMR3TimerSetCritSect(pUsbIns->Internal.s.pVM, hTimer, pCritSect);
2035}
2036
2037
2038/** @interface_method_impl{PDMUSBHLP,pfnTimerSave} */
2039static DECLCALLBACK(int) pdmR3UsbHlp_TimerSave(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)
2040{
2041 PDMUSB_ASSERT_USBINS(pUsbIns);
2042 return TMR3TimerSave(pUsbIns->Internal.s.pVM, hTimer, pSSM);
2043}
2044
2045
2046/** @interface_method_impl{PDMUSBHLP,pfnTimerLoad} */
2047static DECLCALLBACK(int) pdmR3UsbHlp_TimerLoad(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)
2048{
2049 PDMUSB_ASSERT_USBINS(pUsbIns);
2050 return TMR3TimerLoad(pUsbIns->Internal.s.pVM, hTimer, pSSM);
2051}
2052
2053
2054/** @interface_method_impl{PDMUSBHLP,pfnTimerDestroy} */
2055static DECLCALLBACK(int) pdmR3UsbHlp_TimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)
2056{
2057 PDMUSB_ASSERT_USBINS(pUsbIns);
2058 return TMR3TimerDestroy(pUsbIns->Internal.s.pVM, hTimer);
2059}
2060
2061
2062/** @interface_method_impl{PDMUSBHLP,pfnVMSetErrorV} */
2063static DECLCALLBACK(int) pdmR3UsbHlp_VMSetErrorV(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
2064{
2065 PDMUSB_ASSERT_USBINS(pUsbIns);
2066 int rc2 = VMSetErrorV(pUsbIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
2067 return rc;
2068}
2069
2070
2071/** @interface_method_impl{PDMUSBHLP,pfnVMSetRuntimeErrorV} */
2072static DECLCALLBACK(int) pdmR3UsbHlp_VMSetRuntimeErrorV(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
2073{
2074 PDMUSB_ASSERT_USBINS(pUsbIns);
2075 int rc = VMSetRuntimeErrorV(pUsbIns->Internal.s.pVM, fFlags, pszErrorId, pszFormat, va);
2076 return rc;
2077}
2078
2079
2080/** @interface_method_impl{PDMUSBHLP,pfnVMState} */
2081static DECLCALLBACK(VMSTATE) pdmR3UsbHlp_VMState(PPDMUSBINS pUsbIns)
2082{
2083 PDMUSB_ASSERT_USBINS(pUsbIns);
2084
2085 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
2086
2087 LogFlow(("pdmR3UsbHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
2088 enmVMState, VMR3GetStateName(enmVMState)));
2089 return enmVMState;
2090}
2091
2092/** @interface_method_impl{PDMUSBHLP,pfnThreadCreate} */
2093static DECLCALLBACK(int) pdmR3UsbHlp_ThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread,
2094 PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
2095{
2096 PDMUSB_ASSERT_USBINS(pUsbIns);
2097 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
2098 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
2099 pUsbIns->pReg->szName, pUsbIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
2100
2101 int rc = pdmR3ThreadCreateUsb(pUsbIns->Internal.s.pVM, pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
2102
2103 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
2104 rc, *ppThread));
2105 return rc;
2106}
2107
2108
2109/** @interface_method_impl{PDMUSBHLP,pfnSetAsyncNotification} */
2110static DECLCALLBACK(int) pdmR3UsbHlp_SetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)
2111{
2112 PDMUSB_ASSERT_USBINS(pUsbIns);
2113 VM_ASSERT_EMT0(pUsbIns->Internal.s.pVM);
2114 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pfnAsyncNotify));
2115
2116 int rc = VINF_SUCCESS;
2117 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
2118 AssertStmt(!pUsbIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
2119 AssertStmt(pUsbIns->Internal.s.fVMSuspended || pUsbIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
2120 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
2121 AssertStmt( enmVMState == VMSTATE_SUSPENDING
2122 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
2123 || enmVMState == VMSTATE_SUSPENDING_LS
2124 || enmVMState == VMSTATE_RESETTING
2125 || enmVMState == VMSTATE_RESETTING_LS
2126 || enmVMState == VMSTATE_POWERING_OFF
2127 || enmVMState == VMSTATE_POWERING_OFF_LS,
2128 rc = VERR_INVALID_STATE);
2129
2130 if (RT_SUCCESS(rc))
2131 pUsbIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
2132
2133 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
2134 return rc;
2135}
2136
2137
2138/** @interface_method_impl{PDMUSBHLP,pfnAsyncNotificationCompleted} */
2139static DECLCALLBACK(void) pdmR3UsbHlp_AsyncNotificationCompleted(PPDMUSBINS pUsbIns)
2140{
2141 PDMUSB_ASSERT_USBINS(pUsbIns);
2142 PVM pVM = pUsbIns->Internal.s.pVM;
2143
2144 VMSTATE enmVMState = VMR3GetState(pVM);
2145 if ( enmVMState == VMSTATE_SUSPENDING
2146 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
2147 || enmVMState == VMSTATE_SUSPENDING_LS
2148 || enmVMState == VMSTATE_RESETTING
2149 || enmVMState == VMSTATE_RESETTING_LS
2150 || enmVMState == VMSTATE_POWERING_OFF
2151 || enmVMState == VMSTATE_POWERING_OFF_LS)
2152 {
2153 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
2154 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
2155 }
2156 else
2157 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance, enmVMState));
2158}
2159
2160
2161/** @interface_method_impl{PDMUSBHLP,pfnVMGetSuspendReason} */
2162static DECLCALLBACK(VMSUSPENDREASON) pdmR3UsbHlp_VMGetSuspendReason(PPDMUSBINS pUsbIns)
2163{
2164 PDMUSB_ASSERT_USBINS(pUsbIns);
2165 PVM pVM = pUsbIns->Internal.s.pVM;
2166 VM_ASSERT_EMT(pVM);
2167 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
2168 LogFlow(("pdmR3UsbHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
2169 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
2170 return enmReason;
2171}
2172
2173
2174/** @interface_method_impl{PDMUSBHLP,pfnVMGetResumeReason} */
2175static DECLCALLBACK(VMRESUMEREASON) pdmR3UsbHlp_VMGetResumeReason(PPDMUSBINS pUsbIns)
2176{
2177 PDMUSB_ASSERT_USBINS(pUsbIns);
2178 PVM pVM = pUsbIns->Internal.s.pVM;
2179 VM_ASSERT_EMT(pVM);
2180 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
2181 LogFlow(("pdmR3UsbHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
2182 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
2183 return enmReason;
2184}
2185
2186
2187/** @interface_method_impl{PDMUSBHLP,pfnQueryGenericUserObject} */
2188static DECLCALLBACK(void *) pdmR3UsbHlp_QueryGenericUserObject(PPDMUSBINS pUsbIns, PCRTUUID pUuid)
2189{
2190 PDMUSB_ASSERT_USBINS(pUsbIns);
2191 PVM pVM = pUsbIns->Internal.s.pVM;
2192 PUVM pUVM = pVM->pUVM;
2193
2194 void *pvRet;
2195 if (pUVM->pVmm2UserMethods->pfnQueryGenericObject)
2196 pvRet = pUVM->pVmm2UserMethods->pfnQueryGenericObject(pUVM->pVmm2UserMethods, pUVM, pUuid);
2197 else
2198 pvRet = NULL;
2199
2200 Log(("pdmR3UsbHlp_QueryGenericUserObject: caller='%s'/%d: returns %#p for %RTuuid\n",
2201 pUsbIns->pReg->szName, pUsbIns->iInstance, pvRet, pUuid));
2202 return pvRet;
2203}
2204
2205
2206/**
2207 * The USB device helper structure.
2208 */
2209const PDMUSBHLP g_pdmR3UsbHlp =
2210{
2211 PDM_USBHLP_VERSION,
2212 pdmR3UsbHlp_DriverAttach,
2213 pdmR3UsbHlp_AssertEMT,
2214 pdmR3UsbHlp_AssertOther,
2215 pdmR3UsbHlp_DBGFStopV,
2216 pdmR3UsbHlp_DBGFInfoRegisterArgv,
2217 pdmR3UsbHlp_MMHeapAlloc,
2218 pdmR3UsbHlp_MMHeapAllocZ,
2219 pdmR3UsbHlp_MMHeapFree,
2220 pdmR3UsbHlp_PDMQueueCreate,
2221 pdmR3UsbHlp_SSMRegister,
2222 SSMR3PutStruct,
2223 SSMR3PutStructEx,
2224 SSMR3PutBool,
2225 SSMR3PutU8,
2226 SSMR3PutS8,
2227 SSMR3PutU16,
2228 SSMR3PutS16,
2229 SSMR3PutU32,
2230 SSMR3PutS32,
2231 SSMR3PutU64,
2232 SSMR3PutS64,
2233 SSMR3PutU128,
2234 SSMR3PutS128,
2235 SSMR3PutUInt,
2236 SSMR3PutSInt,
2237 SSMR3PutGCUInt,
2238 SSMR3PutGCUIntReg,
2239 SSMR3PutGCPhys32,
2240 SSMR3PutGCPhys64,
2241 SSMR3PutGCPhys,
2242 SSMR3PutGCPtr,
2243 SSMR3PutGCUIntPtr,
2244 SSMR3PutRCPtr,
2245 SSMR3PutIOPort,
2246 SSMR3PutSel,
2247 SSMR3PutMem,
2248 SSMR3PutStrZ,
2249 SSMR3GetStruct,
2250 SSMR3GetStructEx,
2251 SSMR3GetBool,
2252 SSMR3GetBoolV,
2253 SSMR3GetU8,
2254 SSMR3GetU8V,
2255 SSMR3GetS8,
2256 SSMR3GetS8V,
2257 SSMR3GetU16,
2258 SSMR3GetU16V,
2259 SSMR3GetS16,
2260 SSMR3GetS16V,
2261 SSMR3GetU32,
2262 SSMR3GetU32V,
2263 SSMR3GetS32,
2264 SSMR3GetS32V,
2265 SSMR3GetU64,
2266 SSMR3GetU64V,
2267 SSMR3GetS64,
2268 SSMR3GetS64V,
2269 SSMR3GetU128,
2270 SSMR3GetU128V,
2271 SSMR3GetS128,
2272 SSMR3GetS128V,
2273 SSMR3GetGCPhys32,
2274 SSMR3GetGCPhys32V,
2275 SSMR3GetGCPhys64,
2276 SSMR3GetGCPhys64V,
2277 SSMR3GetGCPhys,
2278 SSMR3GetGCPhysV,
2279 SSMR3GetUInt,
2280 SSMR3GetSInt,
2281 SSMR3GetGCUInt,
2282 SSMR3GetGCUIntReg,
2283 SSMR3GetGCPtr,
2284 SSMR3GetGCUIntPtr,
2285 SSMR3GetRCPtr,
2286 SSMR3GetIOPort,
2287 SSMR3GetSel,
2288 SSMR3GetMem,
2289 SSMR3GetStrZ,
2290 SSMR3GetStrZEx,
2291 SSMR3Skip,
2292 SSMR3SkipToEndOfUnit,
2293 SSMR3SetLoadError,
2294 SSMR3SetLoadErrorV,
2295 SSMR3SetCfgError,
2296 SSMR3SetCfgErrorV,
2297 SSMR3HandleGetStatus,
2298 SSMR3HandleGetAfter,
2299 SSMR3HandleIsLiveSave,
2300 SSMR3HandleMaxDowntime,
2301 SSMR3HandleHostBits,
2302 SSMR3HandleRevision,
2303 SSMR3HandleVersion,
2304 SSMR3HandleHostOSAndArch,
2305 CFGMR3Exists,
2306 CFGMR3QueryType,
2307 CFGMR3QuerySize,
2308 CFGMR3QueryInteger,
2309 CFGMR3QueryIntegerDef,
2310 CFGMR3QueryString,
2311 CFGMR3QueryStringDef,
2312 CFGMR3QueryBytes,
2313 CFGMR3QueryU64,
2314 CFGMR3QueryU64Def,
2315 CFGMR3QueryS64,
2316 CFGMR3QueryS64Def,
2317 CFGMR3QueryU32,
2318 CFGMR3QueryU32Def,
2319 CFGMR3QueryS32,
2320 CFGMR3QueryS32Def,
2321 CFGMR3QueryU16,
2322 CFGMR3QueryU16Def,
2323 CFGMR3QueryS16,
2324 CFGMR3QueryS16Def,
2325 CFGMR3QueryU8,
2326 CFGMR3QueryU8Def,
2327 CFGMR3QueryS8,
2328 CFGMR3QueryS8Def,
2329 CFGMR3QueryBool,
2330 CFGMR3QueryBoolDef,
2331 CFGMR3QueryPort,
2332 CFGMR3QueryPortDef,
2333 CFGMR3QueryUInt,
2334 CFGMR3QueryUIntDef,
2335 CFGMR3QuerySInt,
2336 CFGMR3QuerySIntDef,
2337 CFGMR3QueryGCPtr,
2338 CFGMR3QueryGCPtrDef,
2339 CFGMR3QueryGCPtrU,
2340 CFGMR3QueryGCPtrUDef,
2341 CFGMR3QueryGCPtrS,
2342 CFGMR3QueryGCPtrSDef,
2343 CFGMR3QueryStringAlloc,
2344 CFGMR3QueryStringAllocDef,
2345 CFGMR3GetParent,
2346 CFGMR3GetChild,
2347 CFGMR3GetChildF,
2348 CFGMR3GetChildFV,
2349 CFGMR3GetFirstChild,
2350 CFGMR3GetNextChild,
2351 CFGMR3GetName,
2352 CFGMR3GetNameLen,
2353 CFGMR3AreChildrenValid,
2354 CFGMR3GetFirstValue,
2355 CFGMR3GetNextValue,
2356 CFGMR3GetValueName,
2357 CFGMR3GetValueNameLen,
2358 CFGMR3GetValueType,
2359 CFGMR3AreValuesValid,
2360 CFGMR3ValidateConfig,
2361 pdmR3UsbHlp_STAMRegisterV,
2362 pdmR3UsbHlp_TimerCreate,
2363 pdmR3UsbHlp_TimerFromMicro,
2364 pdmR3UsbHlp_TimerFromMilli,
2365 pdmR3UsbHlp_TimerFromNano,
2366 pdmR3UsbHlp_TimerGet,
2367 pdmR3UsbHlp_TimerGetFreq,
2368 pdmR3UsbHlp_TimerGetNano,
2369 pdmR3UsbHlp_TimerIsActive,
2370 pdmR3UsbHlp_TimerIsLockOwner,
2371 pdmR3UsbHlp_TimerLockClock,
2372 pdmR3UsbHlp_TimerLockClock2,
2373 pdmR3UsbHlp_TimerSet,
2374 pdmR3UsbHlp_TimerSetFrequencyHint,
2375 pdmR3UsbHlp_TimerSetMicro,
2376 pdmR3UsbHlp_TimerSetMillies,
2377 pdmR3UsbHlp_TimerSetNano,
2378 pdmR3UsbHlp_TimerSetRelative,
2379 pdmR3UsbHlp_TimerStop,
2380 pdmR3UsbHlp_TimerUnlockClock,
2381 pdmR3UsbHlp_TimerUnlockClock2,
2382 pdmR3UsbHlp_TimerSetCritSect,
2383 pdmR3UsbHlp_TimerSave,
2384 pdmR3UsbHlp_TimerLoad,
2385 pdmR3UsbHlp_TimerDestroy,
2386 TMR3TimerSkip,
2387 pdmR3UsbHlp_VMSetErrorV,
2388 pdmR3UsbHlp_VMSetRuntimeErrorV,
2389 pdmR3UsbHlp_VMState,
2390 pdmR3UsbHlp_ThreadCreate,
2391 PDMR3ThreadDestroy,
2392 PDMR3ThreadIAmSuspending,
2393 PDMR3ThreadIAmRunning,
2394 PDMR3ThreadSleep,
2395 PDMR3ThreadSuspend,
2396 PDMR3ThreadResume,
2397 pdmR3UsbHlp_SetAsyncNotification,
2398 pdmR3UsbHlp_AsyncNotificationCompleted,
2399 pdmR3UsbHlp_VMGetSuspendReason,
2400 pdmR3UsbHlp_VMGetResumeReason,
2401 pdmR3UsbHlp_QueryGenericUserObject,
2402 NULL,
2403 NULL,
2404 NULL,
2405 NULL,
2406 NULL,
2407 NULL,
2408 NULL,
2409 NULL,
2410 NULL,
2411 PDM_USBHLP_VERSION
2412};
2413
2414/** @} */
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