VirtualBox

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

Last change on this file since 72453 was 70322, checked in by vboxsync, 7 years ago

USB: When capturing devices, provide the speed rather than USB port version, since the speed provides a superset of the information (bugref:7280).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.4 KB
Line 
1/* $Id: PDMUsb.cpp 70322 2017-12-22 16:53:41Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, USB part.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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_OFFSETOF(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_OFFSETOF(PDMUSBINS, achInstanceData[pUsbDev->pReg->cbInstance]);
612 cb = RT_ALIGN_Z(cb, 16);
613 PPDMUSBINS pUsbIns;
614 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_USB, cb, (void **)&pUsbIns);
615 if (RT_FAILURE(rc))
616 {
617 AssertMsgFailed(("Failed to allocate %d bytes of instance data for USB device '%s'. rc=%Rrc\n",
618 cb, pUsbDev->pReg->szName, rc));
619 CFGMR3RemoveNode(pInstanceToDelete);
620 return rc;
621 }
622
623 /*
624 * Initialize it.
625 */
626 pUsbIns->u32Version = PDM_USBINS_VERSION;
627 //pUsbIns->Internal.s.pNext = NULL;
628 //pUsbIns->Internal.s.pPerDeviceNext = NULL;
629 pUsbIns->Internal.s.pUsbDev = pUsbDev;
630 pUsbIns->Internal.s.pVM = pVM;
631 //pUsbIns->Internal.s.pLuns = NULL;
632 pUsbIns->Internal.s.pCfg = pInstanceNode;
633 pUsbIns->Internal.s.pCfgDelete = pInstanceToDelete;
634 pUsbIns->Internal.s.pCfgGlobal = pGlobalConfig;
635 pUsbIns->Internal.s.Uuid = *pUuid;
636 //pUsbIns->Internal.s.pHub = NULL;
637 pUsbIns->Internal.s.iPort = UINT32_MAX; /* to be determined. */
638 /* Set the flag accordingly.
639 * Otherwise VMPowerOff, VMSuspend will not be called for devices attached at runtime.
640 */
641 pUsbIns->Internal.s.fVMSuspended = !fAtRuntime;
642 //pUsbIns->Internal.s.pfnAsyncNotify = NULL;
643 pUsbIns->pHlpR3 = &g_pdmR3UsbHlp;
644 pUsbIns->pReg = pUsbDev->pReg;
645 pUsbIns->pCfg = pConfig;
646 pUsbIns->pCfgGlobal = pGlobalConfig;
647 pUsbIns->iInstance = iInstance;
648 pUsbIns->pvInstanceDataR3 = &pUsbIns->achInstanceData[0];
649 pUsbIns->pszName = RTStrDup(pUsbDev->pReg->szName);
650 //pUsbIns->fTracing = 0;
651 pUsbIns->idTracing = ++pVM->pdm.s.idTracingOther;
652 pUsbIns->enmSpeed = enmSpeed;
653
654 /*
655 * Link it into all the lists.
656 */
657 /* The global instance FIFO. */
658 PPDMUSBINS pPrev1 = pVM->pdm.s.pUsbInstances;
659 if (!pPrev1)
660 pVM->pdm.s.pUsbInstances = pUsbIns;
661 else
662 {
663 while (pPrev1->Internal.s.pNext)
664 {
665 Assert(pPrev1->u32Version == PDM_USBINS_VERSION);
666 pPrev1 = pPrev1->Internal.s.pNext;
667 }
668 pPrev1->Internal.s.pNext = pUsbIns;
669 }
670
671 /* The per device instance FIFO. */
672 PPDMUSBINS pPrev2 = pUsbDev->pInstances;
673 if (!pPrev2)
674 pUsbDev->pInstances = pUsbIns;
675 else
676 {
677 while (pPrev2->Internal.s.pPerDeviceNext)
678 {
679 Assert(pPrev2->u32Version == PDM_USBINS_VERSION);
680 pPrev2 = pPrev2->Internal.s.pPerDeviceNext;
681 }
682 pPrev2->Internal.s.pPerDeviceNext = pUsbIns;
683 }
684
685 /*
686 * Call the constructor.
687 */
688 Log(("PDM: Constructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
689 rc = pUsbIns->pReg->pfnConstruct(pUsbIns, pUsbIns->iInstance, pUsbIns->pCfg, pUsbIns->pCfgGlobal);
690 if (RT_SUCCESS(rc))
691 {
692 /*
693 * Attach it to the hub.
694 */
695 Log(("PDM: Attaching it...\n"));
696 rc = pHub->Reg.pfnAttachDevice(pHub->pDrvIns, pUsbIns, pszCaptureFilename, &pUsbIns->Internal.s.iPort);
697 if (RT_SUCCESS(rc))
698 {
699 pHub->cAvailablePorts--;
700 Assert((int32_t)pHub->cAvailablePorts >= 0 && pHub->cAvailablePorts < pHub->cPorts);
701 pUsbIns->Internal.s.pHub = pHub;
702
703 /* Send the hot-plugged notification if applicable. */
704 if (fAtRuntime && pUsbIns->pReg->pfnHotPlugged)
705 pUsbIns->pReg->pfnHotPlugged(pUsbIns);
706
707 Log(("PDM: Successfully attached USB device '%s' instance %d to hub %p\n",
708 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub));
709 return VINF_SUCCESS;
710 }
711
712 LogRel(("PDMUsb: Failed to attach USB device '%s' instance %d to hub %p: %Rrc\n",
713 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
714 }
715 else
716 {
717 AssertMsgFailed(("Failed to construct '%s'/%d! %Rra\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
718 if (rc == VERR_VERSION_MISMATCH)
719 rc = VERR_PDM_USBDEV_VERSION_MISMATCH;
720 }
721 if (fAtRuntime)
722 pdmR3UsbDestroyDevice(pVM, pUsbIns);
723 /* else: destructors are invoked later. */
724 return rc;
725}
726
727
728/**
729 * Instantiate USB devices.
730 *
731 * This is called by pdmR3DevInit() after it has instantiated the
732 * other devices and their drivers. If there aren't any hubs
733 * around, we'll silently skip the USB devices.
734 *
735 * @returns VBox status code.
736 * @param pVM The cross context VM structure.
737 */
738int pdmR3UsbInstantiateDevices(PVM pVM)
739{
740 /*
741 * Any hubs?
742 */
743 if (!pVM->pdm.s.pUsbHubs)
744 {
745 Log(("PDM: No USB hubs, skipping USB device instantiation.\n"));
746 return VINF_SUCCESS;
747 }
748
749 /*
750 * Count the device instances.
751 */
752 PCFGMNODE pCur;
753 PCFGMNODE pUsbNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "USB/");
754 PCFGMNODE pInstanceNode;
755 unsigned cUsbDevs = 0;
756 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
757 {
758 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
759 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
760 if (pInstanceNode != pGlobal)
761 cUsbDevs++;
762 }
763 if (!cUsbDevs)
764 {
765 Log(("PDM: No USB devices were configured!\n"));
766 return VINF_SUCCESS;
767 }
768 Log2(("PDM: cUsbDevs=%d!\n", cUsbDevs));
769
770 /*
771 * Collect info on each USB device instance.
772 */
773 struct USBDEVORDER
774 {
775 /** Configuration node. */
776 PCFGMNODE pNode;
777 /** Pointer to the USB device. */
778 PPDMUSB pUsbDev;
779 /** Init order. */
780 uint32_t u32Order;
781 /** VBox instance number. */
782 uint32_t iInstance;
783 /** Device UUID. */
784 RTUUID Uuid;
785 } *paUsbDevs = (struct USBDEVORDER *)alloca(sizeof(paUsbDevs[0]) * (cUsbDevs + 1)); /* (One extra for swapping) */
786 Assert(paUsbDevs);
787 int rc;
788 unsigned i = 0;
789 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
790 {
791 /* Get the device name. */
792 char szName[sizeof(paUsbDevs[0].pUsbDev->pReg->szName)];
793 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
794 AssertMsgRCReturn(rc, ("Configuration error: device name is too long (or something)! rc=%Rrc\n", rc), rc);
795
796 /* Find the device. */
797 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, szName);
798 AssertMsgReturn(pUsbDev, ("Configuration error: device '%s' not found!\n", szName), VERR_PDM_DEVICE_NOT_FOUND);
799
800 /* Configured priority or use default? */
801 uint32_t u32Order;
802 rc = CFGMR3QueryU32(pCur, "Priority", &u32Order);
803 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
804 u32Order = i << 4;
805 else
806 AssertMsgRCReturn(rc, ("Configuration error: reading \"Priority\" for the '%s' USB device failed rc=%Rrc!\n", szName, rc), rc);
807
808 /* Global config. */
809 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
810 if (!pGlobal)
811 {
812 rc = CFGMR3InsertNode(pCur, "GlobalConfig/", &pGlobal);
813 AssertMsgRCReturn(rc, ("Failed to create GlobalConfig node! rc=%Rrc\n", rc), rc);
814 CFGMR3SetRestrictedRoot(pGlobal);
815 }
816
817 /* Enumerate the device instances. */
818 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
819 {
820 if (pInstanceNode == pGlobal)
821 continue;
822
823 /* Use the configured UUID if present, create our own otherwise. */
824 char *pszUuid = NULL;
825
826 RTUuidClear(&paUsbDevs[i].Uuid);
827 rc = CFGMR3QueryStringAlloc(pInstanceNode, "UUID", &pszUuid);
828 if (RT_SUCCESS(rc))
829 {
830 AssertPtr(pszUuid);
831
832 rc = RTUuidFromStr(&paUsbDevs[i].Uuid, pszUuid);
833 AssertMsgRCReturn(rc, ("Failed to convert UUID from string! rc=%Rrc\n", rc), rc);
834 MMR3HeapFree(pszUuid);
835 }
836 else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
837 rc = RTUuidCreate(&paUsbDevs[i].Uuid);
838
839 AssertRCReturn(rc, rc);
840 paUsbDevs[i].pNode = pInstanceNode;
841 paUsbDevs[i].pUsbDev = pUsbDev;
842 paUsbDevs[i].u32Order = u32Order;
843
844 /* Get the instance number. */
845 char szInstance[32];
846 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
847 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
848 char *pszNext = NULL;
849 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paUsbDevs[i].iInstance);
850 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
851 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
852
853 /* next instance */
854 i++;
855 }
856 } /* devices */
857 Assert(i == cUsbDevs);
858
859 /*
860 * Sort the device array ascending on u32Order. (bubble)
861 */
862 unsigned c = cUsbDevs - 1;
863 while (c)
864 {
865 unsigned j = 0;
866 for (i = 0; i < c; i++)
867 if (paUsbDevs[i].u32Order > paUsbDevs[i + 1].u32Order)
868 {
869 paUsbDevs[cUsbDevs] = paUsbDevs[i + 1];
870 paUsbDevs[i + 1] = paUsbDevs[i];
871 paUsbDevs[i] = paUsbDevs[cUsbDevs];
872 j = i;
873 }
874 c = j;
875 }
876
877 /*
878 * Instantiate the devices.
879 */
880 for (i = 0; i < cUsbDevs; i++)
881 {
882 /*
883 * Make sure there is a config node and mark it as restricted.
884 */
885 PCFGMNODE pConfigNode = CFGMR3GetChild(paUsbDevs[i].pNode, "Config/");
886 if (!pConfigNode)
887 {
888 rc = CFGMR3InsertNode(paUsbDevs[i].pNode, "Config", &pConfigNode);
889 AssertMsgRCReturn(rc, ("Failed to create Config node! rc=%Rrc\n", rc), rc);
890 }
891 CFGMR3SetRestrictedRoot(pConfigNode);
892
893 /*
894 * Every emulated device must support USB 1.x hubs; optionally, high-speed USB 2.0 hubs
895 * might be also supported. This determines where to attach the device.
896 */
897 uint32_t iUsbVersion = VUSB_STDVER_11;
898
899 if (paUsbDevs[i].pUsbDev->pReg->fFlags & PDM_USBREG_HIGHSPEED_CAPABLE)
900 iUsbVersion |= VUSB_STDVER_20;
901 if (paUsbDevs[i].pUsbDev->pReg->fFlags & PDM_USBREG_SUPERSPEED_CAPABLE)
902 iUsbVersion |= VUSB_STDVER_30;
903
904 /*
905 * Find a suitable hub with free ports.
906 */
907 PPDMUSBHUB pHub;
908 rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
909 if (RT_FAILURE(rc))
910 {
911 Log(("pdmR3UsbFindHub failed %Rrc\n", rc));
912 return rc;
913 }
914
915 /*
916 * This is how we inform the device what speed it's communicating at, and hence
917 * which descriptors it should present to the guest.
918 */
919 iUsbVersion &= pHub->fVersions;
920
921 /*
922 * Create and attach the device.
923 */
924 rc = pdmR3UsbCreateDevice(pVM, pHub, paUsbDevs[i].pUsbDev, paUsbDevs[i].iInstance, &paUsbDevs[i].Uuid,
925 &paUsbDevs[i].pNode, pdmR3UsbVer2Spd(iUsbVersion), NULL);
926 if (RT_FAILURE(rc))
927 return rc;
928 } /* for device instances */
929
930 return VINF_SUCCESS;
931}
932
933
934/**
935 * Creates an emulated USB device instance at runtime.
936 *
937 * This will find an appropriate HUB for the USB device
938 * and try instantiate the emulated device.
939 *
940 * @returns VBox status code.
941 * @param pUVM The user mode VM handle.
942 * @param pszDeviceName The name of the PDM device to instantiate.
943 * @param pInstanceNode The instance CFGM node.
944 * @param pUuid The UUID to be associated with the device.
945 * @param pszCaptureFilename Path to the file for USB traffic capturing, optional.
946 *
947 * @thread EMT
948 */
949VMMR3DECL(int) PDMR3UsbCreateEmulatedDevice(PUVM pUVM, const char *pszDeviceName, PCFGMNODE pInstanceNode, PCRTUUID pUuid,
950 const char *pszCaptureFilename)
951{
952 /*
953 * Validate input.
954 */
955 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
956 PVM pVM = pUVM->pVM;
957 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
958 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
959 AssertPtrReturn(pszDeviceName, VERR_INVALID_POINTER);
960 AssertPtrReturn(pInstanceNode, VERR_INVALID_POINTER);
961
962 /*
963 * Find the device.
964 */
965 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, pszDeviceName);
966 if (!pUsbDev)
967 {
968 LogRel(("PDMUsb: PDMR3UsbCreateEmulatedDevice: The '%s' device wasn't found\n", pszDeviceName));
969 return VERR_PDM_NO_USBPROXY;
970 }
971
972 /*
973 * Every device must support USB 1.x hubs; optionally, high-speed USB 2.0 hubs
974 * might be also supported. This determines where to attach the device.
975 */
976 uint32_t iUsbVersion = VUSB_STDVER_11;
977 if (pUsbDev->pReg->fFlags & PDM_USBREG_HIGHSPEED_CAPABLE)
978 iUsbVersion |= VUSB_STDVER_20;
979 if (pUsbDev->pReg->fFlags & PDM_USBREG_SUPERSPEED_CAPABLE)
980 iUsbVersion |= VUSB_STDVER_30;
981
982 /*
983 * Find a suitable hub with free ports.
984 */
985 PPDMUSBHUB pHub;
986 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
987 if (RT_FAILURE(rc))
988 {
989 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
990 return rc;
991 }
992
993 /*
994 * This is how we inform the device what speed it's communicating at, and hence
995 * which descriptors it should present to the guest.
996 */
997 iUsbVersion &= pHub->fVersions;
998
999 /*
1000 * Create and attach the device.
1001 */
1002 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstanceNode,
1003 pdmR3UsbVer2Spd(iUsbVersion), pszCaptureFilename);
1004 AssertRCReturn(rc, rc);
1005
1006 return rc;
1007}
1008
1009
1010/**
1011 * Creates a USB proxy device instance.
1012 *
1013 * This will find an appropriate HUB for the USB device, create the necessary CFGM stuff
1014 * and try instantiate the proxy device.
1015 *
1016 * @returns VBox status code.
1017 * @param pUVM The user mode VM handle.
1018 * @param pUuid The UUID to be associated with the device.
1019 * @param pszBackend The proxy backend to use.
1020 * @param pszAddress The address string.
1021 * @param pvBackend Pointer to the backend.
1022 * @param enmSpeed The speed the USB device is operating at.
1023 * @param fMaskedIfs The interfaces to hide from the guest.
1024 * @param pszCaptureFilename Path to the file for USB traffic capturing, optional.
1025 */
1026VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, void *pvBackend,
1027 VUSBSPEED enmSpeed, uint32_t fMaskedIfs, const char *pszCaptureFilename)
1028{
1029 /*
1030 * Validate input.
1031 */
1032 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1033 PVM pVM = pUVM->pVM;
1034 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1035 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
1036 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1037 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
1038 AssertReturn( enmSpeed == VUSB_SPEED_LOW
1039 || enmSpeed == VUSB_SPEED_FULL
1040 || enmSpeed == VUSB_SPEED_HIGH
1041 || enmSpeed == VUSB_SPEED_SUPER
1042 || enmSpeed == VUSB_SPEED_SUPERPLUS, VERR_INVALID_PARAMETER);
1043
1044 /*
1045 * Find the USBProxy driver.
1046 */
1047 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, "USBProxy");
1048 if (!pUsbDev)
1049 {
1050 LogRel(("PDMUsb: PDMR3UsbCreateProxyDevice: The USBProxy device class wasn't found\n"));
1051 return VERR_PDM_NO_USBPROXY;
1052 }
1053
1054 /*
1055 * Find a suitable hub with free ports.
1056 */
1057 PPDMUSBHUB pHub;
1058 uint32_t iUsbVersion = pdmR3UsbSpd2Ver(enmSpeed);
1059 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
1060 if (RT_FAILURE(rc))
1061 {
1062 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
1063 return rc;
1064 }
1065
1066 /*
1067 * Create the CFGM instance node.
1068 */
1069 PCFGMNODE pInstance = CFGMR3CreateTree(pUVM);
1070 AssertReturn(pInstance, VERR_NO_MEMORY);
1071 do /* break loop */
1072 {
1073 PCFGMNODE pConfig;
1074 rc = CFGMR3InsertNode(pInstance, "Config", &pConfig); AssertRCBreak(rc);
1075 rc = CFGMR3InsertString(pConfig, "Address", pszAddress); AssertRCBreak(rc);
1076 char szUuid[RTUUID_STR_LENGTH];
1077 rc = RTUuidToStr(pUuid, &szUuid[0], sizeof(szUuid)); AssertRCBreak(rc);
1078 rc = CFGMR3InsertString(pConfig, "UUID", szUuid); AssertRCBreak(rc);
1079 rc = CFGMR3InsertString(pConfig, "Backend", pszBackend); AssertRCBreak(rc);
1080 rc = CFGMR3InsertInteger(pConfig, "pvBackend", (uintptr_t)pvBackend); AssertRCBreak(rc);
1081 rc = CFGMR3InsertInteger(pConfig, "MaskedIfs", fMaskedIfs); AssertRCBreak(rc);
1082 rc = CFGMR3InsertInteger(pConfig, "Force11Device", !(pHub->fVersions & iUsbVersion)); AssertRCBreak(rc);
1083 } while (0); /* break loop */
1084 if (RT_FAILURE(rc))
1085 {
1086 CFGMR3RemoveNode(pInstance);
1087 LogRel(("PDMUsb: PDMR3UsbCreateProxyDevice: failed to setup CFGM config, rc=%Rrc\n", rc));
1088 return rc;
1089 }
1090
1091 if (enmSpeed == VUSB_SPEED_UNKNOWN)
1092 enmSpeed = pdmR3UsbVer2Spd(iUsbVersion);
1093
1094 /*
1095 * Finally, try to create it.
1096 */
1097 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstance, enmSpeed, pszCaptureFilename);
1098 if (RT_FAILURE(rc) && pInstance)
1099 CFGMR3RemoveNode(pInstance);
1100 return rc;
1101}
1102
1103
1104/**
1105 * Destroys a hot-plugged USB device.
1106 *
1107 * The device must be detached from the HUB at this point.
1108 *
1109 * @param pVM The cross context VM structure.
1110 * @param pUsbIns The USB device instance to destroy.
1111 * @thread EMT
1112 */
1113static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns)
1114{
1115 Assert(!pUsbIns->Internal.s.pHub);
1116
1117 /*
1118 * Do the unplug notification.
1119 */
1120 /** @todo what about the drivers? */
1121 if (pUsbIns->pReg->pfnHotUnplugged)
1122 pUsbIns->pReg->pfnHotUnplugged(pUsbIns);
1123
1124 /*
1125 * Destroy the luns with their driver chains and call the device destructor.
1126 */
1127 while (pUsbIns->Internal.s.pLuns)
1128 {
1129 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1130 pUsbIns->Internal.s.pLuns = pLun->pNext;
1131 if (pLun->pTop)
1132 pdmR3DrvDestroyChain(pLun->pTop, PDM_TACH_FLAGS_NOT_HOT_PLUG); /* Hotplugging is handled differently here atm. */
1133 MMR3HeapFree(pLun);
1134 }
1135
1136 /* finally, the device. */
1137 if (pUsbIns->pReg->pfnDestruct)
1138 {
1139 Log(("PDM: Destructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1140 pUsbIns->pReg->pfnDestruct(pUsbIns);
1141 }
1142 TMR3TimerDestroyUsb(pVM, pUsbIns);
1143 SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
1144 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
1145#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1146 pdmR3AsyncCompletionTemplateDestroyUsb(pVM, pUsbIns);
1147#endif
1148
1149 /*
1150 * Unlink it.
1151 */
1152 /* The global instance FIFO. */
1153 if (pVM->pdm.s.pUsbInstances == pUsbIns)
1154 pVM->pdm.s.pUsbInstances = pUsbIns->Internal.s.pNext;
1155 else
1156 {
1157 PPDMUSBINS pPrev = pVM->pdm.s.pUsbInstances;
1158 while (pPrev && pPrev->Internal.s.pNext != pUsbIns)
1159 {
1160 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1161 pPrev = pPrev->Internal.s.pNext;
1162 }
1163 Assert(pPrev); Assert(pPrev != pUsbIns);
1164 if (pPrev)
1165 pPrev->Internal.s.pNext = pUsbIns->Internal.s.pNext;
1166 }
1167
1168 /* The per device instance FIFO. */
1169 PPDMUSB pUsbDev = pUsbIns->Internal.s.pUsbDev;
1170 if (pUsbDev->pInstances == pUsbIns)
1171 pUsbDev->pInstances = pUsbIns->Internal.s.pPerDeviceNext;
1172 else
1173 {
1174 PPDMUSBINS pPrev = pUsbDev->pInstances;
1175 while (pPrev && pPrev->Internal.s.pPerDeviceNext != pUsbIns)
1176 {
1177 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1178 pPrev = pPrev->Internal.s.pPerDeviceNext;
1179 }
1180 Assert(pPrev); Assert(pPrev != pUsbIns);
1181 if (pPrev)
1182 pPrev->Internal.s.pPerDeviceNext = pUsbIns->Internal.s.pPerDeviceNext;
1183 }
1184
1185 /*
1186 * Trash it.
1187 */
1188 pUsbIns->u32Version = 0;
1189 pUsbIns->pReg = NULL;
1190 if (pUsbIns->pszName)
1191 {
1192 RTStrFree(pUsbIns->pszName);
1193 pUsbIns->pszName = NULL;
1194 }
1195 CFGMR3RemoveNode(pUsbIns->Internal.s.pCfgDelete);
1196 MMR3HeapFree(pUsbIns);
1197}
1198
1199
1200/**
1201 * Detaches and destroys a USB device.
1202 *
1203 * @returns VBox status code.
1204 * @param pUVM The user mode VM handle.
1205 * @param pUuid The UUID associated with the device to detach.
1206 * @thread EMT
1207 */
1208VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid)
1209{
1210 /*
1211 * Validate input.
1212 */
1213 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1214 PVM pVM = pUVM->pVM;
1215 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1216 VM_ASSERT_EMT(pVM);
1217 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1218
1219 /*
1220 * Search the global list for it.
1221 */
1222 PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;
1223 for ( ; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1224 if (!RTUuidCompare(&pUsbIns->Internal.s.Uuid, pUuid))
1225 break;
1226 if (!pUsbIns)
1227 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND; /** @todo VERR_PDM_USB_INSTANCE_NOT_FOUND */
1228
1229 /*
1230 * Detach it from the HUB (if it's actually attached to one).
1231 */
1232 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
1233 if (pHub)
1234 {
1235 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
1236 if (RT_FAILURE(rc))
1237 {
1238 LogRel(("PDMUsb: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
1239 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
1240 return rc;
1241 }
1242
1243 pHub->cAvailablePorts++;
1244 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
1245 pUsbIns->Internal.s.pHub = NULL;
1246 }
1247
1248 /*
1249 * Notify about unplugging and destroy the device with it's drivers.
1250 */
1251 pdmR3UsbDestroyDevice(pVM, pUsbIns);
1252
1253 return VINF_SUCCESS;
1254}
1255
1256
1257/**
1258 * Checks if there are any USB hubs attached.
1259 *
1260 * @returns true / false accordingly.
1261 * @param pUVM The user mode VM handle.
1262 */
1263VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM)
1264{
1265 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1266 PVM pVM = pUVM->pVM;
1267 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1268 return pVM->pdm.s.pUsbHubs != NULL;
1269}
1270
1271
1272/**
1273 * Locates a LUN.
1274 *
1275 * @returns VBox status code.
1276 * @param pVM The cross context VM structure.
1277 * @param pszDevice Device name.
1278 * @param iInstance Device instance.
1279 * @param iLun The Logical Unit to obtain the interface of.
1280 * @param ppLun Where to store the pointer to the LUN if found.
1281 * @thread Try only do this in EMT...
1282 */
1283static int pdmR3UsbFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
1284{
1285 /*
1286 * Iterate registered devices looking for the device.
1287 */
1288 size_t cchDevice = strlen(pszDevice);
1289 for (PPDMUSB pUsbDev = pVM->pdm.s.pUsbDevs; pUsbDev; pUsbDev = pUsbDev->pNext)
1290 {
1291 if ( pUsbDev->cchName == cchDevice
1292 && !memcmp(pUsbDev->pReg->szName, pszDevice, cchDevice))
1293 {
1294 /*
1295 * Iterate device instances.
1296 */
1297 for (PPDMUSBINS pUsbIns = pUsbDev->pInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pPerDeviceNext)
1298 {
1299 if (pUsbIns->iInstance == iInstance)
1300 {
1301 /*
1302 * Iterate luns.
1303 */
1304 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1305 {
1306 if (pLun->iLun == iLun)
1307 {
1308 *ppLun = pLun;
1309 return VINF_SUCCESS;
1310 }
1311 }
1312 return VERR_PDM_LUN_NOT_FOUND;
1313 }
1314 }
1315 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1316 }
1317 }
1318 return VERR_PDM_DEVICE_NOT_FOUND;
1319}
1320
1321
1322/**
1323 * Attaches a preconfigured driver to an existing device or driver instance.
1324 *
1325 * This is used to change drivers and suchlike at runtime. The driver or device
1326 * at the end of the chain will be told to attach to whatever is configured
1327 * below it.
1328 *
1329 * @returns VBox status code.
1330 * @param pUVM The user mode VM handle.
1331 * @param pszDevice Device name.
1332 * @param iDevIns Device instance.
1333 * @param iLun The Logical Unit to obtain the interface of.
1334 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1335 * @param ppBase Where to store the base interface pointer. Optional.
1336 *
1337 * @thread EMT
1338 */
1339VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags,
1340 PPPDMIBASE ppBase)
1341{
1342 LogFlow(("PDMR3UsbDriverAttach: pszDevice=%p:{%s} iDevIns=%d iLun=%d fFlags=%#x ppBase=%p\n",
1343 pszDevice, pszDevice, iDevIns, iLun, fFlags, ppBase));
1344 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1345 PVM pVM = pUVM->pVM;
1346 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1347 VM_ASSERT_EMT(pVM);
1348
1349 if (ppBase)
1350 *ppBase = NULL;
1351
1352 /*
1353 * Find the LUN in question.
1354 */
1355 PPDMLUN pLun;
1356 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1357 if (RT_SUCCESS(rc))
1358 {
1359 /*
1360 * Anything attached to the LUN?
1361 */
1362 PPDMDRVINS pDrvIns = pLun->pTop;
1363 if (!pDrvIns)
1364 {
1365 /* No, ask the device to attach to the new stuff. */
1366 PPDMUSBINS pUsbIns = pLun->pUsbIns;
1367 if (pUsbIns->pReg->pfnDriverAttach)
1368 {
1369 rc = pUsbIns->pReg->pfnDriverAttach(pUsbIns, iLun, fFlags);
1370 if (RT_SUCCESS(rc) && ppBase)
1371 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
1372 }
1373 else
1374 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
1375 }
1376 else
1377 {
1378 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
1379 while (pDrvIns->Internal.s.pDown)
1380 pDrvIns = pDrvIns->Internal.s.pDown;
1381 if (pDrvIns->pReg->pfnAttach)
1382 {
1383 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
1384 if (RT_SUCCESS(rc) && ppBase)
1385 *ppBase = pDrvIns->Internal.s.pDown
1386 ? &pDrvIns->Internal.s.pDown->IBase
1387 : NULL;
1388 }
1389 else
1390 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
1391 }
1392 }
1393
1394 if (ppBase)
1395 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
1396 else
1397 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc\n", rc));
1398 return rc;
1399}
1400
1401
1402/**
1403 * Detaches the specified driver instance.
1404 *
1405 * This is used to replumb drivers at runtime for simulating hot plugging and
1406 * media changes.
1407 *
1408 * This method allows detaching drivers from
1409 * any driver or device by specifying the driver to start detaching at. The
1410 * only prerequisite is that the driver or device above implements the
1411 * pfnDetach callback (PDMDRVREG / PDMUSBREG).
1412 *
1413 * @returns VBox status code.
1414 * @param pUVM The user mode VM handle.
1415 * @param pszDevice Device name.
1416 * @param iDevIns Device instance.
1417 * @param iLun The Logical Unit in which to look for the driver.
1418 * @param pszDriver The name of the driver which to detach. If NULL
1419 * then the entire driver chain is detatched.
1420 * @param iOccurrence The occurrence of that driver in the chain. This is
1421 * usually 0.
1422 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1423 * @thread EMT
1424 */
1425VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1426 const char *pszDriver, unsigned iOccurrence, uint32_t fFlags)
1427{
1428 LogFlow(("PDMR3UsbDriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurrence=%u fFlags=%#x\n",
1429 pszDevice, pszDevice, iDevIns, iLun, pszDriver, pszDriver, iOccurrence, fFlags));
1430 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1431 PVM pVM = pUVM->pVM;
1432 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1433 VM_ASSERT_EMT(pVM);
1434 AssertPtr(pszDevice);
1435 AssertPtrNull(pszDriver);
1436 Assert(iOccurrence == 0 || pszDriver);
1437 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1438
1439 /*
1440 * Find the LUN in question.
1441 */
1442 PPDMLUN pLun;
1443 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1444 if (RT_SUCCESS(rc))
1445 {
1446 /*
1447 * Locate the driver.
1448 */
1449 PPDMDRVINS pDrvIns = pLun->pTop;
1450 if (pDrvIns)
1451 {
1452 if (pszDriver)
1453 {
1454 while (pDrvIns)
1455 {
1456 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1457 {
1458 if (iOccurrence == 0)
1459 break;
1460 iOccurrence--;
1461 }
1462 pDrvIns = pDrvIns->Internal.s.pDown;
1463 }
1464 }
1465 if (pDrvIns)
1466 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1467 else
1468 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1469 }
1470 else
1471 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1472 }
1473
1474 LogFlow(("PDMR3UsbDriverDetach: returns %Rrc\n", rc));
1475 return rc;
1476}
1477
1478
1479/**
1480 * Query the interface of the top level driver on a LUN.
1481 *
1482 * @returns VBox status code.
1483 * @param pUVM The user mode VM handle.
1484 * @param pszDevice Device name.
1485 * @param iInstance Device instance.
1486 * @param iLun The Logical Unit to obtain the interface of.
1487 * @param ppBase Where to store the base interface pointer.
1488 * @remark We're not doing any locking ATM, so don't try call this at times when the
1489 * device chain is known to be updated.
1490 */
1491VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase)
1492{
1493 LogFlow(("PDMR3UsbQueryLun: pszDevice=%p:{%s} iInstance=%u iLun=%u ppBase=%p\n",
1494 pszDevice, pszDevice, iInstance, iLun, ppBase));
1495 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1496 PVM pVM = pUVM->pVM;
1497 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1498
1499 /*
1500 * Find the LUN.
1501 */
1502 PPDMLUN pLun;
1503 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1504 if (RT_SUCCESS(rc))
1505 {
1506 if (pLun->pTop)
1507 {
1508 *ppBase = &pLun->pTop->IBase;
1509 LogFlow(("PDMR3UsbQueryLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1510 return VINF_SUCCESS;
1511 }
1512 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1513 }
1514 LogFlow(("PDMR3UsbQueryLun: returns %Rrc\n", rc));
1515 return rc;
1516}
1517
1518
1519/**
1520 * Query the interface of a named driver on a LUN.
1521 *
1522 * If the driver appears more than once in the driver chain, the first instance
1523 * is returned.
1524 *
1525 * @returns VBox status code.
1526 * @param pUVM The user mode VM handle.
1527 * @param pszDevice Device name.
1528 * @param iInstance Device instance.
1529 * @param iLun The Logical Unit to obtain the interface of.
1530 * @param pszDriver The driver name.
1531 * @param ppBase Where to store the base interface pointer.
1532 *
1533 * @remark We're not doing any locking ATM, so don't try call this at times when the
1534 * device chain is known to be updated.
1535 */
1536VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance,
1537 unsigned iLun, const char *pszDriver, PPPDMIBASE ppBase)
1538{
1539 LogFlow(("PDMR3QueryDriverOnLun: pszDevice=%p:{%s} iInstance=%u iLun=%u pszDriver=%p:{%s} ppBase=%p\n",
1540 pszDevice, pszDevice, iInstance, iLun, pszDriver, pszDriver, ppBase));
1541 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1542 PVM pVM = pUVM->pVM;
1543 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1544
1545 /*
1546 * Find the LUN.
1547 */
1548 PPDMLUN pLun;
1549 int rc = pdmR3UsbFindLun(pVM, pszDevice, iInstance, iLun, &pLun);
1550 if (RT_SUCCESS(rc))
1551 {
1552 if (pLun->pTop)
1553 {
1554 for (PPDMDRVINS pDrvIns = pLun->pTop; pDrvIns; pDrvIns = pDrvIns->Internal.s.pDown)
1555 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1556 {
1557 *ppBase = &pDrvIns->IBase;
1558 LogFlow(("PDMR3UsbQueryDriverOnLun: return %Rrc and *ppBase=%p\n", VINF_SUCCESS, *ppBase));
1559 return VINF_SUCCESS;
1560
1561 }
1562 rc = VERR_PDM_DRIVER_NOT_FOUND;
1563 }
1564 else
1565 rc = VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1566 }
1567 LogFlow(("PDMR3UsbQueryDriverOnLun: returns %Rrc\n", rc));
1568 return rc;
1569}
1570
1571
1572/** @name USB Device Helpers
1573 * @{
1574 */
1575
1576/** @interface_method_impl{PDMUSBHLP,pfnDriverAttach} */
1577static DECLCALLBACK(int) pdmR3UsbHlp_DriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
1578 PPDMIBASE *ppBaseInterface, const char *pszDesc)
1579{
1580 PDMUSB_ASSERT_USBINS(pUsbIns);
1581 PVM pVM = pUsbIns->Internal.s.pVM;
1582 VM_ASSERT_EMT(pVM);
1583 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
1584 pUsbIns->pReg->szName, pUsbIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
1585
1586 /*
1587 * Lookup the LUN, it might already be registered.
1588 */
1589 PPDMLUN pLunPrev = NULL;
1590 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1591 for (; pLun; pLunPrev = pLun, pLun = pLun->pNext)
1592 if (pLun->iLun == iLun)
1593 break;
1594
1595 /*
1596 * Create the LUN if if wasn't found, else check if driver is already attached to it.
1597 */
1598 if (!pLun)
1599 {
1600 if ( !pBaseInterface
1601 || !pszDesc
1602 || !*pszDesc)
1603 {
1604 Assert(pBaseInterface);
1605 Assert(pszDesc || *pszDesc);
1606 return VERR_INVALID_PARAMETER;
1607 }
1608
1609 pLun = (PPDMLUN)MMR3HeapAlloc(pVM, MM_TAG_PDM_LUN, sizeof(*pLun));
1610 if (!pLun)
1611 return VERR_NO_MEMORY;
1612
1613 pLun->iLun = iLun;
1614 pLun->pNext = pLunPrev ? pLunPrev->pNext : NULL;
1615 pLun->pTop = NULL;
1616 pLun->pBottom = NULL;
1617 pLun->pDevIns = NULL;
1618 pLun->pUsbIns = pUsbIns;
1619 pLun->pszDesc = pszDesc;
1620 pLun->pBase = pBaseInterface;
1621 if (!pLunPrev)
1622 pUsbIns->Internal.s.pLuns = pLun;
1623 else
1624 pLunPrev->pNext = pLun;
1625 Log(("pdmR3UsbHlp_DriverAttach: Registered LUN#%d '%s' with device '%s'/%d.\n",
1626 iLun, pszDesc, pUsbIns->pReg->szName, pUsbIns->iInstance));
1627 }
1628 else if (pLun->pTop)
1629 {
1630 AssertMsgFailed(("Already attached! The device should keep track of such things!\n"));
1631 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, VERR_PDM_DRIVER_ALREADY_ATTACHED));
1632 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1633 }
1634 Assert(pLun->pBase == pBaseInterface);
1635
1636
1637 /*
1638 * Get the attached driver configuration.
1639 */
1640 int rc;
1641 PCFGMNODE pNode = CFGMR3GetChildF(pUsbIns->Internal.s.pCfg, "LUN#%u", iLun);
1642 if (pNode)
1643 rc = pdmR3DrvInstantiate(pVM, pNode, pBaseInterface, NULL /*pDrvAbove*/, pLun, ppBaseInterface);
1644 else
1645 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1646
1647
1648 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1649 return rc;
1650}
1651
1652
1653/** @interface_method_impl{PDMUSBHLP,pfnAssertEMT} */
1654static DECLCALLBACK(bool) pdmR3UsbHlp_AssertEMT(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1655{
1656 PDMUSB_ASSERT_USBINS(pUsbIns);
1657 if (VM_IS_EMT(pUsbIns->Internal.s.pVM))
1658 return true;
1659
1660 char szMsg[100];
1661 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1662 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1663 AssertBreakpoint();
1664 return false;
1665}
1666
1667
1668/** @interface_method_impl{PDMUSBHLP,pfnAssertOther} */
1669static DECLCALLBACK(bool) pdmR3UsbHlp_AssertOther(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1670{
1671 PDMUSB_ASSERT_USBINS(pUsbIns);
1672 if (!VM_IS_EMT(pUsbIns->Internal.s.pVM))
1673 return true;
1674
1675 char szMsg[100];
1676 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1677 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1678 AssertBreakpoint();
1679 return false;
1680}
1681
1682
1683/** @interface_method_impl{PDMUSBHLP,pfnDBGFStopV} */
1684static DECLCALLBACK(int) pdmR3UsbHlp_DBGFStopV(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction,
1685 const char *pszFormat, va_list va)
1686{
1687 PDMUSB_ASSERT_USBINS(pUsbIns);
1688#ifdef LOG_ENABLED
1689 va_list va2;
1690 va_copy(va2, va);
1691 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
1692 pUsbIns->pReg->szName, pUsbIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
1693 va_end(va2);
1694#endif
1695
1696 PVM pVM = pUsbIns->Internal.s.pVM;
1697 VM_ASSERT_EMT(pVM);
1698 int rc = DBGFR3EventSrcV(pVM, DBGFEVENT_DEV_STOP, pszFile, iLine, pszFunction, pszFormat, va);
1699 if (rc == VERR_DBGF_NOT_ATTACHED)
1700 rc = VINF_SUCCESS;
1701
1702 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1703 return rc;
1704}
1705
1706
1707/** @interface_method_impl{PDMUSBHLP,pfnDBGFInfoRegister} */
1708static DECLCALLBACK(int) pdmR3UsbHlp_DBGFInfoRegister(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc,
1709 PFNDBGFHANDLERUSB pfnHandler)
1710{
1711 PDMUSB_ASSERT_USBINS(pUsbIns);
1712 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1713 pUsbIns->pReg->szName, pUsbIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1714
1715 PVM pVM = pUsbIns->Internal.s.pVM;
1716 VM_ASSERT_EMT(pVM);
1717 RT_NOREF4(pVM, pfnHandler, pszDesc, pszName); /** @todo int rc = DBGFR3InfoRegisterUsb(pVM, pszName, pszDesc, pfnHandler, pUsbIns); */
1718 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
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_DBGFInfoRegister,
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