VirtualBox

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

Last change on this file since 80253 was 80191, checked in by vboxsync, 6 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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