VirtualBox

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

Last change on this file since 50653 was 49092, checked in by vboxsync, 11 years ago

VUSB,EHCI,OHCI: Add a method to query whether a device is emulated or not. Required for working saved states when using the MSD device

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.3 KB
Line 
1/* $Id: PDMUsb.cpp 49092 2013-10-14 22:01:16Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, USB part.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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 Pointer to the VM.
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(("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)), ("%#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 Pointer to the VM.
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_EMULATED_DEVICE)) == 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 Pointer to the VM.
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 Pointer to the VM.
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 Pointer to the VM.
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 && ( (pCur->fVersions & iUsbVersion)
444 || pCur->fVersions == VUSB_STDVER_11))
445 {
446 *ppHub = pCur;
447 if (pCur->fVersions & iUsbVersion)
448 break;
449 }
450 if (*ppHub)
451 return VINF_SUCCESS;
452 return VERR_PDM_NO_USB_PORTS;
453}
454
455
456/**
457 * Creates the device.
458 *
459 * @returns VBox status code.
460 * @param pVM Pointer to the VM.
461 * @param pUsbDev The USB device emulation.
462 * @param iInstance -1 if not called by pdmR3UsbInstantiateDevices().
463 * @param pUuid The UUID for this device.
464 * @param ppInstanceNode Pointer to the device instance pointer. This is set to NULL if inserted
465 * into the tree or cleaned up.
466 *
467 * In the pdmR3UsbInstantiateDevices() case (iInstance != -1) this is
468 * the actual instance node and will not be cleaned up.
469 *
470 * @parma iUsbVersion The USB version preferred by the device.
471 */
472static int pdmR3UsbCreateDevice(PVM pVM, PPDMUSBHUB pHub, PPDMUSB pUsbDev, int iInstance, PCRTUUID pUuid,
473 PCFGMNODE *ppInstanceNode, uint32_t iUsbVersion)
474{
475 const bool fAtRuntime = iInstance == -1;
476 int rc;
477
478 AssertPtrReturn(ppInstanceNode, VERR_INVALID_POINTER);
479 AssertPtrReturn(*ppInstanceNode, VERR_INVALID_POINTER);
480
481 /*
482 * If not called by pdmR3UsbInstantiateDevices(), we'll have to fix
483 * the configuration now.
484 */
485 /* USB device node. */
486 PCFGMNODE pDevNode = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "USB/%s/", pUsbDev->pReg->szName);
487 if (!pDevNode)
488 {
489 rc = CFGMR3InsertNodeF(CFGMR3GetRoot(pVM), &pDevNode, "USB/%s/", pUsbDev->pReg->szName);
490 AssertRCReturn(rc, rc);
491 }
492
493 /* The instance node and number. */
494 PCFGMNODE pInstanceToDelete = NULL;
495 PCFGMNODE pInstanceNode = NULL;
496 if (fAtRuntime)
497 {
498 /** @todo r=bird: This code is bogus as it ASSUMES that all USB devices are
499 * capable of infinite number of instances. */
500 for (unsigned c = 0; c < _2M; c++)
501 {
502 iInstance = pUsbDev->iNextInstance++;
503 rc = CFGMR3InsertNodeF(pDevNode, &pInstanceNode, "%d/", iInstance);
504 if (rc != VERR_CFGM_NODE_EXISTS)
505 break;
506 }
507 AssertRCReturn(rc, rc);
508
509 rc = CFGMR3ReplaceSubTree(pInstanceNode, *ppInstanceNode);
510 AssertRCReturn(rc, rc);
511 *ppInstanceNode = NULL;
512 pInstanceToDelete = pInstanceNode;
513 }
514 else
515 {
516 Assert(iInstance >= 0);
517 if (iInstance >= (int)pUsbDev->iNextInstance)
518 pUsbDev->iNextInstance = iInstance + 1;
519 pInstanceNode = *ppInstanceNode;
520 }
521
522 /* Make sure the instance config node exists. */
523 PCFGMNODE pConfig = CFGMR3GetChild(pInstanceNode, "Config");
524 if (!pConfig)
525 {
526 rc = CFGMR3InsertNode(pInstanceNode, "Config", &pConfig);
527 AssertRCReturn(rc, rc);
528 }
529 Assert(CFGMR3GetChild(pInstanceNode, "Config") == pConfig);
530
531 /* The global device config node. */
532 PCFGMNODE pGlobalConfig = CFGMR3GetChild(pDevNode, "GlobalConfig");
533 if (!pGlobalConfig)
534 {
535 rc = CFGMR3InsertNode(pDevNode, "GlobalConfig", &pGlobalConfig);
536 if (RT_FAILURE(rc))
537 {
538 CFGMR3RemoveNode(pInstanceToDelete);
539 AssertRCReturn(rc, rc);
540 }
541 }
542
543 /*
544 * Allocate the device instance.
545 */
546 size_t cb = RT_OFFSETOF(PDMUSBINS, achInstanceData[pUsbDev->pReg->cbInstance]);
547 cb = RT_ALIGN_Z(cb, 16);
548 PPDMUSBINS pUsbIns;
549 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_USB, cb, (void **)&pUsbIns);
550 if (RT_FAILURE(rc))
551 {
552 AssertMsgFailed(("Failed to allocate %d bytes of instance data for USB device '%s'. rc=%Rrc\n",
553 cb, pUsbDev->pReg->szName, rc));
554 CFGMR3RemoveNode(pInstanceToDelete);
555 return rc;
556 }
557
558 /*
559 * Initialize it.
560 */
561 pUsbIns->u32Version = PDM_USBINS_VERSION;
562 //pUsbIns->Internal.s.pNext = NULL;
563 //pUsbIns->Internal.s.pPerDeviceNext = NULL;
564 pUsbIns->Internal.s.pUsbDev = pUsbDev;
565 pUsbIns->Internal.s.pVM = pVM;
566 //pUsbIns->Internal.s.pLuns = NULL;
567 pUsbIns->Internal.s.pCfg = pInstanceNode;
568 pUsbIns->Internal.s.pCfgDelete = pInstanceToDelete;
569 pUsbIns->Internal.s.pCfgGlobal = pGlobalConfig;
570 pUsbIns->Internal.s.Uuid = *pUuid;
571 //pUsbIns->Internal.s.pHub = NULL;
572 pUsbIns->Internal.s.iPort = UINT32_MAX; /* to be determined. */
573 /* Set the flag accordingly.
574 * Oherwise VMPowerOff, VMSuspend will not be called for devices attached at runtime.
575 */
576 pUsbIns->Internal.s.fVMSuspended = !fAtRuntime;
577 //pUsbIns->Internal.s.pfnAsyncNotify = NULL;
578 pUsbIns->pHlpR3 = &g_pdmR3UsbHlp;
579 pUsbIns->pReg = pUsbDev->pReg;
580 pUsbIns->pCfg = pConfig;
581 pUsbIns->pCfgGlobal = pGlobalConfig;
582 pUsbIns->iInstance = iInstance;
583 pUsbIns->pvInstanceDataR3 = &pUsbIns->achInstanceData[0];
584 pUsbIns->pszName = RTStrDup(pUsbDev->pReg->szName);
585 //pUsbIns->fTracing = 0;
586 pUsbIns->idTracing = ++pVM->pdm.s.idTracingOther;
587 pUsbIns->iUsbHubVersion = iUsbVersion;
588
589 /*
590 * Link it into all the lists.
591 */
592 /* The global instance FIFO. */
593 PPDMUSBINS pPrev1 = pVM->pdm.s.pUsbInstances;
594 if (!pPrev1)
595 pVM->pdm.s.pUsbInstances = pUsbIns;
596 else
597 {
598 while (pPrev1->Internal.s.pNext)
599 {
600 Assert(pPrev1->u32Version == PDM_USBINS_VERSION);
601 pPrev1 = pPrev1->Internal.s.pNext;
602 }
603 pPrev1->Internal.s.pNext = pUsbIns;
604 }
605
606 /* The per device instance FIFO. */
607 PPDMUSBINS pPrev2 = pUsbDev->pInstances;
608 if (!pPrev2)
609 pUsbDev->pInstances = pUsbIns;
610 else
611 {
612 while (pPrev2->Internal.s.pPerDeviceNext)
613 {
614 Assert(pPrev2->u32Version == PDM_USBINS_VERSION);
615 pPrev2 = pPrev2->Internal.s.pPerDeviceNext;
616 }
617 pPrev2->Internal.s.pPerDeviceNext = pUsbIns;
618 }
619
620 /*
621 * Call the constructor.
622 */
623 Log(("PDM: Constructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
624 rc = pUsbIns->pReg->pfnConstruct(pUsbIns, pUsbIns->iInstance, pUsbIns->pCfg, pUsbIns->pCfgGlobal);
625 if (RT_SUCCESS(rc))
626 {
627 /*
628 * Attach it to the hub.
629 */
630 Log(("PDM: Attaching it...\n"));
631 rc = pHub->Reg.pfnAttachDevice(pHub->pDrvIns, pUsbIns, &pUsbIns->Internal.s.iPort);
632 if (RT_SUCCESS(rc))
633 {
634 pHub->cAvailablePorts--;
635 Assert((int32_t)pHub->cAvailablePorts >= 0 && pHub->cAvailablePorts < pHub->cPorts);
636 pUsbIns->Internal.s.pHub = pHub;
637
638 /* Send the hot-plugged notification if applicable. */
639 if (fAtRuntime && pUsbIns->pReg->pfnHotPlugged)
640 pUsbIns->pReg->pfnHotPlugged(pUsbIns);
641
642 Log(("PDM: Successfully attached USB device '%s' instance %d to hub %p\n",
643 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub));
644 return VINF_SUCCESS;
645 }
646
647 LogRel(("PDM: Failed to attach USB device '%s' instance %d to hub %p: %Rrc\n",
648 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
649 }
650 else
651 {
652 AssertMsgFailed(("Failed to construct '%s'/%d! %Rra\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
653 if (rc == VERR_VERSION_MISMATCH)
654 rc = VERR_PDM_DRIVER_VERSION_MISMATCH;
655 }
656 if (fAtRuntime)
657 pdmR3UsbDestroyDevice(pVM, pUsbIns);
658 /* else: destructors are invoked later. */
659 return rc;
660}
661
662
663/**
664 * Instantiate USB devices.
665 *
666 * This is called by pdmR3DevInit() after it has instantiated the
667 * other devices and their drivers. If there aren't any hubs
668 * around, we'll silently skip the USB devices.
669 *
670 * @returns VBox status code.
671 * @param pVM
672 */
673int pdmR3UsbInstantiateDevices(PVM pVM)
674{
675 /*
676 * Any hubs?
677 */
678 if (!pVM->pdm.s.pUsbHubs)
679 {
680 Log(("PDM: No USB hubs, skipping USB device instantiation.\n"));
681 return VINF_SUCCESS;
682 }
683
684 /*
685 * Count the device instances.
686 */
687 PCFGMNODE pCur;
688 PCFGMNODE pUsbNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "USB/");
689 PCFGMNODE pInstanceNode;
690 unsigned cUsbDevs = 0;
691 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
692 {
693 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
694 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
695 if (pInstanceNode != pGlobal)
696 cUsbDevs++;
697 }
698 if (!cUsbDevs)
699 {
700 Log(("PDM: No USB devices were configured!\n"));
701 return VINF_SUCCESS;
702 }
703 Log2(("PDM: cUsbDevs=%d!\n", cUsbDevs));
704
705 /*
706 * Collect info on each USB device instance.
707 */
708 struct USBDEVORDER
709 {
710 /** Configuration node. */
711 PCFGMNODE pNode;
712 /** Pointer to the USB device. */
713 PPDMUSB pUsbDev;
714 /** Init order. */
715 uint32_t u32Order;
716 /** VBox instance number. */
717 uint32_t iInstance;
718 /** Device UUID. */
719 RTUUID Uuid;
720 } *paUsbDevs = (struct USBDEVORDER *)alloca(sizeof(paUsbDevs[0]) * (cUsbDevs + 1)); /* (One extra for swapping) */
721 Assert(paUsbDevs);
722 int rc;
723 unsigned i = 0;
724 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
725 {
726 /* Get the device name. */
727 char szName[sizeof(paUsbDevs[0].pUsbDev->pReg->szName)];
728 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
729 AssertMsgRCReturn(rc, ("Configuration error: device name is too long (or something)! rc=%Rrc\n", rc), rc);
730
731 /* Find the device. */
732 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, szName);
733 AssertMsgReturn(pUsbDev, ("Configuration error: device '%s' not found!\n", szName), VERR_PDM_DEVICE_NOT_FOUND);
734
735 /* Configured priority or use default? */
736 uint32_t u32Order;
737 rc = CFGMR3QueryU32(pCur, "Priority", &u32Order);
738 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
739 u32Order = i << 4;
740 else
741 AssertMsgRCReturn(rc, ("Configuration error: reading \"Priority\" for the '%s' USB device failed rc=%Rrc!\n", szName, rc), rc);
742
743 /* Global config. */
744 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
745 if (!pGlobal)
746 {
747 rc = CFGMR3InsertNode(pCur, "GlobalConfig/", &pGlobal);
748 AssertMsgRCReturn(rc, ("Failed to create GlobalConfig node! rc=%Rrc\n", rc), rc);
749 CFGMR3SetRestrictedRoot(pGlobal);
750 }
751
752 /* Enumerate the device instances. */
753 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
754 {
755 if (pInstanceNode == pGlobal)
756 continue;
757
758 /* Use the configured UUID if present, create our own otherwise. */
759 char *pszUuid = NULL;
760
761 RTUuidClear(&paUsbDevs[i].Uuid);
762 rc = CFGMR3QueryStringAlloc(pInstanceNode, "UUID", &pszUuid);
763 if (RT_SUCCESS(rc))
764 {
765 AssertPtr(pszUuid);
766
767 rc = RTUuidFromStr(&paUsbDevs[i].Uuid, pszUuid);
768 AssertMsgRCReturn(rc, ("Failed to convert UUID from string! rc=%Rrc\n", rc), rc);
769 MMR3HeapFree(pszUuid);
770 }
771 else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
772 rc = RTUuidCreate(&paUsbDevs[i].Uuid);
773
774 AssertRCReturn(rc, rc);
775 paUsbDevs[i].pNode = pInstanceNode;
776 paUsbDevs[i].pUsbDev = pUsbDev;
777 paUsbDevs[i].u32Order = u32Order;
778
779 /* Get the instance number. */
780 char szInstance[32];
781 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
782 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
783 char *pszNext = NULL;
784 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paUsbDevs[i].iInstance);
785 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
786 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
787
788 /* next instance */
789 i++;
790 }
791 } /* devices */
792 Assert(i == cUsbDevs);
793
794 /*
795 * Sort the device array ascending on u32Order. (bubble)
796 */
797 unsigned c = cUsbDevs - 1;
798 while (c)
799 {
800 unsigned j = 0;
801 for (i = 0; i < c; i++)
802 if (paUsbDevs[i].u32Order > paUsbDevs[i + 1].u32Order)
803 {
804 paUsbDevs[cUsbDevs] = paUsbDevs[i + 1];
805 paUsbDevs[i + 1] = paUsbDevs[i];
806 paUsbDevs[i] = paUsbDevs[cUsbDevs];
807 j = i;
808 }
809 c = j;
810 }
811
812 /*
813 * Instantiate the devices.
814 */
815 for (i = 0; i < cUsbDevs; i++)
816 {
817 /*
818 * Make sure there is a config node and mark it as restricted.
819 */
820 PCFGMNODE pConfigNode = CFGMR3GetChild(paUsbDevs[i].pNode, "Config/");
821 if (!pConfigNode)
822 {
823 rc = CFGMR3InsertNode(paUsbDevs[i].pNode, "Config", &pConfigNode);
824 AssertMsgRCReturn(rc, ("Failed to create Config node! rc=%Rrc\n", rc), rc);
825 }
826 CFGMR3SetRestrictedRoot(pConfigNode);
827
828 /*
829 * Every device must support USB 1.x hubs; optionally, high-speed USB 2.0 hubs
830 * might be also supported. This determines where to attach the device.
831 */
832 uint32_t iUsbVersion = VUSB_STDVER_11;
833
834 if (paUsbDevs[i].pUsbDev->pReg->fFlags & PDM_USBREG_HIGHSPEED_CAPABLE)
835 iUsbVersion |= VUSB_STDVER_20;
836
837 /*
838 * Find a suitable hub with free ports.
839 */
840 PPDMUSBHUB pHub;
841 rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
842 if (RT_FAILURE(rc))
843 {
844 Log(("pdmR3UsbFindHub failed %Rrc\n", rc));
845 return rc;
846 }
847
848 /*
849 * This is how we inform the device what speed it's communicating at, and hence
850 * which descriptors it should present to the guest.
851 */
852 iUsbVersion &= pHub->fVersions;
853
854 /*
855 * Create and attach the device.
856 */
857 rc = pdmR3UsbCreateDevice(pVM, pHub, paUsbDevs[i].pUsbDev, paUsbDevs[i].iInstance, &paUsbDevs[i].Uuid,
858 &paUsbDevs[i].pNode, iUsbVersion);
859 if (RT_FAILURE(rc))
860 return rc;
861 } /* for device instances */
862
863 return VINF_SUCCESS;
864}
865
866
867/**
868 * Creates an emulated USB device instance at runtime.
869 *
870 * This will find an appropriate HUB for the USB device
871 * and try instantiate the emulated device.
872 *
873 * @returns VBox status code.
874 * @param pUVM The user mode VM handle.
875 * @param pszDeviceName The name of the PDM device to instantiate.
876 * @param pInstanceNode The instance CFGM node.
877 * @param pUuid The UUID to be associated with the device.
878 *
879 * @thread EMT
880 */
881VMMR3DECL(int) PDMR3UsbCreateEmulatedDevice(PUVM pUVM, const char *pszDeviceName, PCFGMNODE pInstanceNode, PCRTUUID pUuid)
882{
883 /*
884 * Validate input.
885 */
886 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
887 PVM pVM = pUVM->pVM;
888 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
889 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
890 AssertPtrReturn(pszDeviceName, VERR_INVALID_POINTER);
891 AssertPtrReturn(pInstanceNode, VERR_INVALID_POINTER);
892
893 /*
894 * Find the device.
895 */
896 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, pszDeviceName);
897 if (!pUsbDev)
898 {
899 LogRel(("PDMR3UsbCreateEmulatedDevice: The '%s' device wasn't found\n", pszDeviceName));
900 return VERR_PDM_NO_USBPROXY;
901 }
902
903 /*
904 * Every device must support USB 1.x hubs; optionally, high-speed USB 2.0 hubs
905 * might be also supported. This determines where to attach the device.
906 */
907 uint32_t iUsbVersion = VUSB_STDVER_11;
908 if (pUsbDev->pReg->fFlags & PDM_USBREG_HIGHSPEED_CAPABLE)
909 iUsbVersion |= VUSB_STDVER_20;
910
911 /*
912 * Find a suitable hub with free ports.
913 */
914 PPDMUSBHUB pHub;
915 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
916 if (RT_FAILURE(rc))
917 {
918 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
919 return rc;
920 }
921
922 /*
923 * This is how we inform the device what speed it's communicating at, and hence
924 * which descriptors it should present to the guest.
925 */
926 iUsbVersion &= pHub->fVersions;
927
928 /*
929 * Create and attach the device.
930 */
931 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstanceNode, iUsbVersion);
932 AssertRCReturn(rc, rc);
933
934 return rc;
935}
936
937
938/**
939 * Creates a USB proxy device instance.
940 *
941 * This will find an appropriate HUB for the USB device, create the necessary CFGM stuff
942 * and try instantiate the proxy device.
943 *
944 * @returns VBox status code.
945 * @param pUVM The user mode VM handle.
946 * @param pUuid The UUID to be associated with the device.
947 * @param fRemote Whether it's a remove or local device.
948 * @param pszAddress The address string.
949 * @param pvBackend Pointer to the backend.
950 * @param iUsbVersion The preferred USB version.
951 * @param fMaskedIfs The interfaces to hide from the guest.
952 */
953VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, bool fRemote, const char *pszAddress, void *pvBackend,
954 uint32_t iUsbVersion, uint32_t fMaskedIfs)
955{
956 /*
957 * Validate input.
958 */
959 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
960 PVM pVM = pUVM->pVM;
961 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
962 VM_ASSERT_EMT_RETURN(pVM, VERR_VM_THREAD_NOT_EMT);
963 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
964 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
965 AssertReturn( iUsbVersion == VUSB_STDVER_20
966 || iUsbVersion == VUSB_STDVER_11, VERR_INVALID_PARAMETER);
967
968 /*
969 * Find the USBProxy driver.
970 */
971 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, "USBProxy");
972 if (!pUsbDev)
973 {
974 LogRel(("PDMR3UsbCreateProxyDevice: The USBProxy device class wasn't found\n"));
975 return VERR_PDM_NO_USBPROXY;
976 }
977
978 /*
979 * Find a suitable hub with free ports.
980 */
981 PPDMUSBHUB pHub;
982 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
983 if (RT_FAILURE(rc))
984 {
985 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
986 return rc;
987 }
988
989 /*
990 * Create the CFGM instance node.
991 */
992 PCFGMNODE pInstance = CFGMR3CreateTree(pUVM);
993 AssertReturn(pInstance, VERR_NO_MEMORY);
994 do /* break loop */
995 {
996 PCFGMNODE pConfig;
997 rc = CFGMR3InsertNode(pInstance, "Config", &pConfig); AssertRCBreak(rc);
998 rc = CFGMR3InsertString(pConfig, "Address", pszAddress); AssertRCBreak(rc);
999 char szUuid[RTUUID_STR_LENGTH];
1000 rc = RTUuidToStr(pUuid, &szUuid[0], sizeof(szUuid)); AssertRCBreak(rc);
1001 rc = CFGMR3InsertString(pConfig, "UUID", szUuid); AssertRCBreak(rc);
1002 rc = CFGMR3InsertInteger(pConfig, "Remote", fRemote); AssertRCBreak(rc);
1003 rc = CFGMR3InsertInteger(pConfig, "USBVersion", iUsbVersion); AssertRCBreak(rc);
1004 rc = CFGMR3InsertInteger(pConfig, "pvBackend", (uintptr_t)pvBackend); AssertRCBreak(rc);
1005 rc = CFGMR3InsertInteger(pConfig, "MaskedIfs", fMaskedIfs); AssertRCBreak(rc);
1006 rc = CFGMR3InsertInteger(pConfig, "Force11Device", !(pHub->fVersions & iUsbVersion)); AssertRCBreak(rc);
1007 } while (0); /* break loop */
1008 if (RT_FAILURE(rc))
1009 {
1010 CFGMR3RemoveNode(pInstance);
1011 LogRel(("PDMR3UsbCreateProxyDevice: failed to setup CFGM config, rc=%Rrc\n", rc));
1012 return rc;
1013 }
1014
1015 /*
1016 * Finally, try to create it.
1017 */
1018 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, &pInstance, iUsbVersion);
1019 if (RT_FAILURE(rc) && pInstance)
1020 CFGMR3RemoveNode(pInstance);
1021 return rc;
1022}
1023
1024
1025/**
1026 * Destroys a hot-plugged USB device.
1027 *
1028 * The device must be detached from the HUB at this point.
1029 *
1030 * @param pVM Pointer to the VM.
1031 * @param pUsbIns The USB device instance to destroy.
1032 * @thread EMT
1033 */
1034static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns)
1035{
1036 Assert(!pUsbIns->Internal.s.pHub);
1037
1038 /*
1039 * Do the unplug notification.
1040 */
1041 /** @todo what about the drivers? */
1042 if (pUsbIns->pReg->pfnHotUnplugged)
1043 pUsbIns->pReg->pfnHotUnplugged(pUsbIns);
1044
1045 /*
1046 * Destroy the luns with their driver chains and call the device destructor.
1047 */
1048 while (pUsbIns->Internal.s.pLuns)
1049 {
1050 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1051 pUsbIns->Internal.s.pLuns = pLun->pNext;
1052 if (pLun->pTop)
1053 pdmR3DrvDestroyChain(pLun->pTop, PDM_TACH_FLAGS_NOT_HOT_PLUG); /* Hotplugging is handled differently here atm. */
1054 MMR3HeapFree(pLun);
1055 }
1056
1057 /* finally, the device. */
1058 if (pUsbIns->pReg->pfnDestruct)
1059 {
1060 Log(("PDM: Destructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1061 pUsbIns->pReg->pfnDestruct(pUsbIns);
1062 }
1063 TMR3TimerDestroyUsb(pVM, pUsbIns);
1064 SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
1065 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
1066#ifdef VBOX_WITH_PDM_ASYNC_COMPLETION
1067 pdmR3AsyncCompletionTemplateDestroyUsb(pVM, pUsbIns);
1068#endif
1069
1070 /*
1071 * Unlink it.
1072 */
1073 /* The global instance FIFO. */
1074 if (pVM->pdm.s.pUsbInstances == pUsbIns)
1075 pVM->pdm.s.pUsbInstances = pUsbIns->Internal.s.pNext;
1076 else
1077 {
1078 PPDMUSBINS pPrev = pVM->pdm.s.pUsbInstances;
1079 while (pPrev && pPrev->Internal.s.pNext != pUsbIns)
1080 {
1081 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1082 pPrev = pPrev->Internal.s.pNext;
1083 }
1084 Assert(pPrev); Assert(pPrev != pUsbIns);
1085 if (pPrev)
1086 pPrev->Internal.s.pNext = pUsbIns->Internal.s.pNext;
1087 }
1088
1089 /* The per device instance FIFO. */
1090 PPDMUSB pUsbDev = pUsbIns->Internal.s.pUsbDev;
1091 if (pUsbDev->pInstances == pUsbIns)
1092 pUsbDev->pInstances = pUsbIns->Internal.s.pPerDeviceNext;
1093 else
1094 {
1095 PPDMUSBINS pPrev = pUsbDev->pInstances;
1096 while (pPrev && pPrev->Internal.s.pPerDeviceNext != pUsbIns)
1097 {
1098 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
1099 pPrev = pPrev->Internal.s.pPerDeviceNext;
1100 }
1101 Assert(pPrev); Assert(pPrev != pUsbIns);
1102 if (pPrev)
1103 pPrev->Internal.s.pPerDeviceNext = pUsbIns->Internal.s.pPerDeviceNext;
1104 }
1105
1106 /*
1107 * Trash it.
1108 */
1109 pUsbIns->u32Version = 0;
1110 pUsbIns->pReg = NULL;
1111 if (pUsbIns->pszName)
1112 {
1113 RTStrFree(pUsbIns->pszName);
1114 pUsbIns->pszName = NULL;
1115 }
1116 CFGMR3RemoveNode(pUsbIns->Internal.s.pCfgDelete);
1117 MMR3HeapFree(pUsbIns);
1118}
1119
1120
1121/**
1122 * Detaches and destroys a USB device.
1123 *
1124 * @returns VBox status code.
1125 * @param pUVM The user mode VM handle.
1126 * @param pUuid The UUID associated with the device to detach.
1127 * @thread EMT
1128 */
1129VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid)
1130{
1131 /*
1132 * Validate input.
1133 */
1134 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1135 PVM pVM = pUVM->pVM;
1136 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1137 VM_ASSERT_EMT(pVM);
1138 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1139
1140 /*
1141 * Search the global list for it.
1142 */
1143 PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;
1144 for ( ; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1145 if (!RTUuidCompare(&pUsbIns->Internal.s.Uuid, pUuid))
1146 break;
1147 if (!pUsbIns)
1148 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND; /** @todo VERR_PDM_USB_INSTANCE_NOT_FOUND */
1149
1150 /*
1151 * Detach it from the HUB (if it's actually attached to one).
1152 */
1153 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
1154 if (pHub)
1155 {
1156 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
1157 if (RT_FAILURE(rc))
1158 {
1159 LogRel(("PDM: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
1160 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
1161 return rc;
1162 }
1163
1164 pHub->cAvailablePorts++;
1165 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
1166 pUsbIns->Internal.s.pHub = NULL;
1167 }
1168
1169 /*
1170 * Notify about unplugging and destroy the device with it's drivers.
1171 */
1172 pdmR3UsbDestroyDevice(pVM, pUsbIns);
1173
1174 return VINF_SUCCESS;
1175}
1176
1177
1178/**
1179 * Checks if there are any USB hubs attached.
1180 *
1181 * @returns true / false accordingly.
1182 * @param pUVM The user mode VM handle.
1183 */
1184VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM)
1185{
1186 UVM_ASSERT_VALID_EXT_RETURN(pUVM, false);
1187 PVM pVM = pUVM->pVM;
1188 VM_ASSERT_VALID_EXT_RETURN(pVM, false);
1189 return pVM->pdm.s.pUsbHubs != NULL;
1190}
1191
1192
1193/**
1194 * Locates a LUN.
1195 *
1196 * @returns VBox status code.
1197 * @param pVM Pointer to the VM.
1198 * @param pszDevice Device name.
1199 * @param iInstance Device instance.
1200 * @param iLun The Logical Unit to obtain the interface of.
1201 * @param ppLun Where to store the pointer to the LUN if found.
1202 * @thread Try only do this in EMT...
1203 */
1204static int pdmR3UsbFindLun(PVM pVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMLUN ppLun)
1205{
1206 /*
1207 * Iterate registered devices looking for the device.
1208 */
1209 size_t cchDevice = strlen(pszDevice);
1210 for (PPDMUSB pUsbDev = pVM->pdm.s.pUsbDevs; pUsbDev; pUsbDev = pUsbDev->pNext)
1211 {
1212 if ( pUsbDev->cchName == cchDevice
1213 && !memcmp(pUsbDev->pReg->szName, pszDevice, cchDevice))
1214 {
1215 /*
1216 * Iterate device instances.
1217 */
1218 for (PPDMUSBINS pUsbIns = pUsbDev->pInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pPerDeviceNext)
1219 {
1220 if (pUsbIns->iInstance == iInstance)
1221 {
1222 /*
1223 * Iterate luns.
1224 */
1225 for (PPDMLUN pLun = pUsbIns->Internal.s.pLuns; pLun; pLun = pLun->pNext)
1226 {
1227 if (pLun->iLun == iLun)
1228 {
1229 *ppLun = pLun;
1230 return VINF_SUCCESS;
1231 }
1232 }
1233 return VERR_PDM_LUN_NOT_FOUND;
1234 }
1235 }
1236 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND;
1237 }
1238 }
1239 return VERR_PDM_DEVICE_NOT_FOUND;
1240}
1241
1242
1243/**
1244 * Attaches a preconfigured driver to an existing device or driver instance.
1245 *
1246 * This is used to change drivers and suchlike at runtime. The driver or device
1247 * at the end of the chain will be told to attach to whatever is configured
1248 * below it.
1249 *
1250 * @returns VBox status code.
1251 * @param pUVM The user mode VM handle.
1252 * @param pszDevice Device name.
1253 * @param iInstance Device instance.
1254 * @param iLun The Logical Unit to obtain the interface of.
1255 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1256 * @param ppBase Where to store the base interface pointer. Optional.
1257 *
1258 * @thread EMT
1259 */
1260VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags,
1261 PPPDMIBASE ppBase)
1262{
1263 LogFlow(("PDMR3UsbDriverAttach: pszDevice=%p:{%s} iDevIns=%d iLun=%d fFlags=%#x ppBase=%p\n",
1264 pszDevice, pszDevice, iDevIns, iLun, fFlags, ppBase));
1265 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1266 PVM pVM = pUVM->pVM;
1267 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1268 VM_ASSERT_EMT(pVM);
1269
1270 if (ppBase)
1271 *ppBase = NULL;
1272
1273 /*
1274 * Find the LUN in question.
1275 */
1276 PPDMLUN pLun;
1277 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1278 if (RT_SUCCESS(rc))
1279 {
1280 /*
1281 * Anything attached to the LUN?
1282 */
1283 PPDMDRVINS pDrvIns = pLun->pTop;
1284 if (!pDrvIns)
1285 {
1286 /* No, ask the device to attach to the new stuff. */
1287 PPDMUSBINS pUsbIns = pLun->pUsbIns;
1288 if (pUsbIns->pReg->pfnDriverAttach)
1289 {
1290 rc = pUsbIns->pReg->pfnDriverAttach(pUsbIns, iLun, fFlags);
1291 if (RT_SUCCESS(rc) && ppBase)
1292 *ppBase = pLun->pTop ? &pLun->pTop->IBase : NULL;
1293 }
1294 else
1295 rc = VERR_PDM_DEVICE_NO_RT_ATTACH;
1296 }
1297 else
1298 {
1299 /* Yes, find the bottom most driver and ask it to attach to the new stuff. */
1300 while (pDrvIns->Internal.s.pDown)
1301 pDrvIns = pDrvIns->Internal.s.pDown;
1302 if (pDrvIns->pReg->pfnAttach)
1303 {
1304 rc = pDrvIns->pReg->pfnAttach(pDrvIns, fFlags);
1305 if (RT_SUCCESS(rc) && ppBase)
1306 *ppBase = pDrvIns->Internal.s.pDown
1307 ? &pDrvIns->Internal.s.pDown->IBase
1308 : NULL;
1309 }
1310 else
1311 rc = VERR_PDM_DRIVER_NO_RT_ATTACH;
1312 }
1313 }
1314
1315 if (ppBase)
1316 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc *ppBase=%p\n", rc, *ppBase));
1317 else
1318 LogFlow(("PDMR3UsbDriverAttach: returns %Rrc\n", rc));
1319 return rc;
1320}
1321
1322
1323/**
1324 * Detaches the specified driver instance.
1325 *
1326 * This is used to replumb drivers at runtime for simulating hot plugging and
1327 * media changes.
1328 *
1329 * This method allows detaching drivers from
1330 * any driver or device by specifying the driver to start detaching at. The
1331 * only prerequisite is that the driver or device above implements the
1332 * pfnDetach callback (PDMDRVREG / PDMUSBREG).
1333 *
1334 * @returns VBox status code.
1335 * @param pUVM The user mode VM handle.
1336 * @param pszDevice Device name.
1337 * @param iDevIns Device instance.
1338 * @param iLun The Logical Unit in which to look for the driver.
1339 * @param pszDriver The name of the driver which to detach. If NULL
1340 * then the entire driver chain is detatched.
1341 * @param iOccurance The occurrence of that driver in the chain. This is
1342 * usually 0.
1343 * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines.
1344 * @thread EMT
1345 */
1346VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun,
1347 const char *pszDriver, unsigned iOccurance, uint32_t fFlags)
1348{
1349 LogFlow(("PDMR3UsbDriverDetach: pszDevice=%p:{%s} iDevIns=%u iLun=%u pszDriver=%p:{%s} iOccurance=%u fFlags=%#x\n",
1350 pszDevice, pszDevice, iDevIns, iLun, pszDriver, iOccurance, fFlags));
1351 UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
1352 PVM pVM = pUVM->pVM;
1353 VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
1354 VM_ASSERT_EMT(pVM);
1355 AssertPtr(pszDevice);
1356 AssertPtrNull(pszDriver);
1357 Assert(iOccurance == 0 || pszDriver);
1358 Assert(!(fFlags & ~(PDM_TACH_FLAGS_NOT_HOT_PLUG)));
1359
1360 /*
1361 * Find the LUN in question.
1362 */
1363 PPDMLUN pLun;
1364 int rc = pdmR3UsbFindLun(pVM, pszDevice, iDevIns, iLun, &pLun);
1365 if (RT_SUCCESS(rc))
1366 {
1367 /*
1368 * Locate the driver.
1369 */
1370 PPDMDRVINS pDrvIns = pLun->pTop;
1371 if (pDrvIns)
1372 {
1373 if (pszDriver)
1374 {
1375 while (pDrvIns)
1376 {
1377 if (!strcmp(pDrvIns->pReg->szName, pszDriver))
1378 {
1379 if (iOccurance == 0)
1380 break;
1381 iOccurance--;
1382 }
1383 pDrvIns = pDrvIns->Internal.s.pDown;
1384 }
1385 }
1386 if (pDrvIns)
1387 rc = pdmR3DrvDetach(pDrvIns, fFlags);
1388 else
1389 rc = VERR_PDM_DRIVER_INSTANCE_NOT_FOUND;
1390 }
1391 else
1392 rc = VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN;
1393 }
1394
1395 LogFlow(("PDMR3UsbDriverDetach: returns %Rrc\n", rc));
1396 return rc;
1397}
1398
1399
1400/** @name USB Device Helpers
1401 * @{
1402 */
1403
1404/** @interface_method_impl{PDMUSBHLPR3,pfnDriverAttach} */
1405static DECLCALLBACK(int) pdmR3UsbHlp_DriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface,
1406 PPDMIBASE *ppBaseInterface, const char *pszDesc)
1407{
1408 PDMUSB_ASSERT_USBINS(pUsbIns);
1409 PVM pVM = pUsbIns->Internal.s.pVM;
1410 VM_ASSERT_EMT(pVM);
1411 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
1412 pUsbIns->pReg->szName, pUsbIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
1413
1414 /*
1415 * Lookup the LUN, it might already be registered.
1416 */
1417 PPDMLUN pLunPrev = NULL;
1418 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1419 for (; pLun; pLunPrev = pLun, pLun = pLun->pNext)
1420 if (pLun->iLun == iLun)
1421 break;
1422
1423 /*
1424 * Create the LUN if if wasn't found, else check if driver is already attached to it.
1425 */
1426 if (!pLun)
1427 {
1428 if ( !pBaseInterface
1429 || !pszDesc
1430 || !*pszDesc)
1431 {
1432 Assert(pBaseInterface);
1433 Assert(pszDesc || *pszDesc);
1434 return VERR_INVALID_PARAMETER;
1435 }
1436
1437 pLun = (PPDMLUN)MMR3HeapAlloc(pVM, MM_TAG_PDM_LUN, sizeof(*pLun));
1438 if (!pLun)
1439 return VERR_NO_MEMORY;
1440
1441 pLun->iLun = iLun;
1442 pLun->pNext = pLunPrev ? pLunPrev->pNext : NULL;
1443 pLun->pTop = NULL;
1444 pLun->pBottom = NULL;
1445 pLun->pDevIns = NULL;
1446 pLun->pUsbIns = pUsbIns;
1447 pLun->pszDesc = pszDesc;
1448 pLun->pBase = pBaseInterface;
1449 if (!pLunPrev)
1450 pUsbIns->Internal.s.pLuns = pLun;
1451 else
1452 pLunPrev->pNext = pLun;
1453 Log(("pdmR3UsbHlp_DriverAttach: Registered LUN#%d '%s' with device '%s'/%d.\n",
1454 iLun, pszDesc, pUsbIns->pReg->szName, pUsbIns->iInstance));
1455 }
1456 else if (pLun->pTop)
1457 {
1458 AssertMsgFailed(("Already attached! The device should keep track of such things!\n"));
1459 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, VERR_PDM_DRIVER_ALREADY_ATTACHED));
1460 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1461 }
1462 Assert(pLun->pBase == pBaseInterface);
1463
1464
1465 /*
1466 * Get the attached driver configuration.
1467 */
1468 int rc;
1469 PCFGMNODE pNode = CFGMR3GetChildF(pUsbIns->Internal.s.pCfg, "LUN#%u", iLun);
1470 if (pNode)
1471 rc = pdmR3DrvInstantiate(pVM, pNode, pBaseInterface, NULL /*pDrvAbove*/, pLun, ppBaseInterface);
1472 else
1473 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1474
1475
1476 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1477 return rc;
1478}
1479
1480
1481/** @interface_method_impl{PDMUSBHLP,pfnAssertEMT} */
1482static DECLCALLBACK(bool) pdmR3UsbHlp_AssertEMT(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1483{
1484 PDMUSB_ASSERT_USBINS(pUsbIns);
1485 if (VM_IS_EMT(pUsbIns->Internal.s.pVM))
1486 return true;
1487
1488 char szMsg[100];
1489 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1490 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1491 AssertBreakpoint();
1492 return false;
1493}
1494
1495
1496/** @interface_method_impl{PDMUSBHLP,pfnAssertOther} */
1497static DECLCALLBACK(bool) pdmR3UsbHlp_AssertOther(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1498{
1499 PDMUSB_ASSERT_USBINS(pUsbIns);
1500 if (!VM_IS_EMT(pUsbIns->Internal.s.pVM))
1501 return true;
1502
1503 char szMsg[100];
1504 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1505 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1506 AssertBreakpoint();
1507 return false;
1508}
1509
1510
1511/** @interface_method_impl{PDMUSBHLP,pfnDBGFStopV} */
1512static DECLCALLBACK(int) pdmR3UsbHlp_DBGFStopV(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list args)
1513{
1514 PDMUSB_ASSERT_USBINS(pUsbIns);
1515#ifdef LOG_ENABLED
1516 va_list va2;
1517 va_copy(va2, args);
1518 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
1519 pUsbIns->pReg->szName, pUsbIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
1520 va_end(va2);
1521#endif
1522
1523 PVM pVM = pUsbIns->Internal.s.pVM;
1524 VM_ASSERT_EMT(pVM);
1525 int rc = DBGFR3EventSrcV(pVM, DBGFEVENT_DEV_STOP, pszFile, iLine, pszFunction, pszFormat, args);
1526 if (rc == VERR_DBGF_NOT_ATTACHED)
1527 rc = VINF_SUCCESS;
1528
1529 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1530 return rc;
1531}
1532
1533
1534/** @interface_method_impl{PDMUSBHLP,pfnDBGFInfoRegister} */
1535static DECLCALLBACK(int) pdmR3UsbHlp_DBGFInfoRegister(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERUSB pfnHandler)
1536{
1537 PDMUSB_ASSERT_USBINS(pUsbIns);
1538 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1539 pUsbIns->pReg->szName, pUsbIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1540
1541 PVM pVM = pUsbIns->Internal.s.pVM;
1542 VM_ASSERT_EMT(pVM);
1543 NOREF(pVM); /** @todo int rc = DBGFR3InfoRegisterUsb(pVM, pszName, pszDesc, pfnHandler, pUsbIns); */
1544 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1545
1546 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1547 return rc;
1548}
1549
1550
1551/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAlloc} */
1552static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb)
1553{
1554 PDMUSB_ASSERT_USBINS(pUsbIns);
1555 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1556
1557 void *pv = MMR3HeapAlloc(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1558
1559 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1560 return pv;
1561}
1562
1563
1564/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAllocZ} */
1565static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb)
1566{
1567 PDMUSB_ASSERT_USBINS(pUsbIns);
1568 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1569
1570 void *pv = MMR3HeapAllocZ(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1571
1572 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1573 return pv;
1574}
1575
1576
1577/** @interface_method_impl{PDMUSBHLP,pfnPDMQueueCreate} */
1578static DECLCALLBACK(int) pdmR3UsbHlp_PDMQueueCreate(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
1579 PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
1580{
1581 PDMUSB_ASSERT_USBINS(pUsbIns);
1582 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%#x cItems=%#x cMilliesInterval=%u pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
1583 pUsbIns->pReg->szName, pUsbIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue));
1584
1585 PVM pVM = pUsbIns->Internal.s.pVM;
1586 VM_ASSERT_EMT(pVM);
1587
1588 if (pUsbIns->iInstance > 0)
1589 {
1590 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_DESC, "%s_%u", pszName, pUsbIns->iInstance);
1591 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1592 }
1593
1594 /** @todo int rc = PDMR3QueueCreateUsb(pVM, pUsbIns, cbItem, cItems, cMilliesInterval, pfnCallback, fGCEnabled, pszName, ppQueue); */
1595 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1596
1597 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *ppQueue));
1598 return rc;
1599}
1600
1601
1602/** @interface_method_impl{PDMUSBHLP,pfnSSMRegister} */
1603static DECLCALLBACK(int) pdmR3UsbHlp_SSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess,
1604 PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote,
1605 PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone,
1606 PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)
1607{
1608 PDMUSB_ASSERT_USBINS(pUsbIns);
1609 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
1610 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: uVersion=#x cbGuess=%#x\n"
1611 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoadDone=%p\n",
1612 pUsbIns->pReg->szName, pUsbIns->iInstance, uVersion, cbGuess,
1613 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1614 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1615 pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1616
1617 int rc = SSMR3RegisterUsb(pUsbIns->Internal.s.pVM, pUsbIns, pUsbIns->pReg->szName, pUsbIns->iInstance,
1618 uVersion, cbGuess,
1619 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1620 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1621 pfnLoadPrep, pfnLoadExec, pfnLoadDone);
1622
1623 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1624 return rc;
1625}
1626
1627
1628/** @interface_method_impl{PDMUSBHLP,pfnSTAMRegisterV} */
1629static DECLCALLBACK(void) pdmR3UsbHlp_STAMRegisterV(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1630 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1631{
1632 PDMUSB_ASSERT_USBINS(pUsbIns);
1633 PVM pVM = pUsbIns->Internal.s.pVM;
1634 VM_ASSERT_EMT(pVM);
1635
1636 int rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1637 AssertRC(rc);
1638
1639 NOREF(pVM);
1640}
1641
1642
1643/** @interface_method_impl{PDMUSBHLP,pfnTMTimerCreate} */
1644static DECLCALLBACK(int) pdmR3UsbHlp_TMTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser,
1645 uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)
1646{
1647 PDMUSB_ASSERT_USBINS(pUsbIns);
1648 PVM pVM = pUsbIns->Internal.s.pVM;
1649 VM_ASSERT_EMT(pVM);
1650 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} ppTimer=%p\n",
1651 pUsbIns->pReg->szName, pUsbIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, ppTimer));
1652
1653 if (pUsbIns->iInstance > 0) /** @todo use a string cache here later. */
1654 {
1655 char *pszDesc2 = MMR3HeapAPrintf(pVM, MM_TAG_PDM_USB_DESC, "%s [%u]", pszDesc, pUsbIns->iInstance);
1656 if (pszDesc2)
1657 pszDesc = pszDesc2;
1658 }
1659
1660 int rc = TMR3TimerCreateUsb(pVM, pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer);
1661
1662 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1663 return rc;
1664}
1665
1666
1667/** @interface_method_impl{PDMUSBHLP,pfnVMSetErrorV} */
1668static DECLCALLBACK(int) pdmR3UsbHlp_VMSetErrorV(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
1669{
1670 PDMUSB_ASSERT_USBINS(pUsbIns);
1671 int rc2 = VMSetErrorV(pUsbIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
1672 return rc;
1673}
1674
1675
1676/** @interface_method_impl{PDMUSBHLP,pfnVMSetRuntimeErrorV} */
1677static DECLCALLBACK(int) pdmR3UsbHlp_VMSetRuntimeErrorV(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
1678{
1679 PDMUSB_ASSERT_USBINS(pUsbIns);
1680 int rc = VMSetRuntimeErrorV(pUsbIns->Internal.s.pVM, fFlags, pszErrorId, pszFormat, va);
1681 return rc;
1682}
1683
1684
1685/** @interface_method_impl{PDMUSBHLP,pfnVMState} */
1686static DECLCALLBACK(VMSTATE) pdmR3UsbHlp_VMState(PPDMUSBINS pUsbIns)
1687{
1688 PDMUSB_ASSERT_USBINS(pUsbIns);
1689
1690 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
1691
1692 LogFlow(("pdmR3UsbHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
1693 enmVMState, VMR3GetStateName(enmVMState)));
1694 return enmVMState;
1695}
1696
1697/** @interface_method_impl{PDMUSBHLP,pfnThreadCreate} */
1698static DECLCALLBACK(int) pdmR3UsbHlp_ThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread,
1699 PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)
1700{
1701 PDMUSB_ASSERT_USBINS(pUsbIns);
1702 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
1703 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: ppThread=%p pvUser=%p pfnThread=%p pfnWakeup=%p cbStack=%#zx enmType=%d pszName=%p:{%s}\n",
1704 pUsbIns->pReg->szName, pUsbIns->iInstance, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName, pszName));
1705
1706 int rc = pdmR3ThreadCreateUsb(pUsbIns->Internal.s.pVM, pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName);
1707
1708 LogFlow(("pdmR3UsbHlp_ThreadCreate: caller='%s'/%d: returns %Rrc *ppThread=%RTthrd\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
1709 rc, *ppThread));
1710 return rc;
1711}
1712
1713
1714/** @interface_method_impl{PDMUSBHLP,pfnSetAsyncNotification} */
1715static DECLCALLBACK(int) pdmR3UsbHlp_SetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)
1716{
1717 PDMUSB_ASSERT_USBINS(pUsbIns);
1718 VM_ASSERT_EMT0(pUsbIns->Internal.s.pVM);
1719 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pfnAsyncNotify));
1720
1721 int rc = VINF_SUCCESS;
1722 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1723 AssertStmt(!pUsbIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1724 AssertStmt(pUsbIns->Internal.s.fVMSuspended || pUsbIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1725 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
1726 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1727 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1728 || enmVMState == VMSTATE_SUSPENDING_LS
1729 || enmVMState == VMSTATE_RESETTING
1730 || enmVMState == VMSTATE_RESETTING_LS
1731 || enmVMState == VMSTATE_POWERING_OFF
1732 || enmVMState == VMSTATE_POWERING_OFF_LS,
1733 rc = VERR_INVALID_STATE);
1734
1735 if (RT_SUCCESS(rc))
1736 pUsbIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1737
1738 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1739 return rc;
1740}
1741
1742
1743/** @interface_method_impl{PDMUSBHLP,pfnAsyncNotificationCompleted} */
1744static DECLCALLBACK(void) pdmR3UsbHlp_AsyncNotificationCompleted(PPDMUSBINS pUsbIns)
1745{
1746 PDMUSB_ASSERT_USBINS(pUsbIns);
1747 PVM pVM = pUsbIns->Internal.s.pVM;
1748
1749 VMSTATE enmVMState = VMR3GetState(pVM);
1750 if ( enmVMState == VMSTATE_SUSPENDING
1751 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1752 || enmVMState == VMSTATE_SUSPENDING_LS
1753 || enmVMState == VMSTATE_RESETTING
1754 || enmVMState == VMSTATE_RESETTING_LS
1755 || enmVMState == VMSTATE_POWERING_OFF
1756 || enmVMState == VMSTATE_POWERING_OFF_LS)
1757 {
1758 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1759 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1760 }
1761 else
1762 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance, enmVMState));
1763}
1764
1765
1766/** @interface_method_impl{PDMUSBHLP,pfnVMGetSuspendReason} */
1767static DECLCALLBACK(VMSUSPENDREASON) pdmR3UsbHlp_VMGetSuspendReason(PPDMUSBINS pUsbIns)
1768{
1769 PDMUSB_ASSERT_USBINS(pUsbIns);
1770 PVM pVM = pUsbIns->Internal.s.pVM;
1771 VM_ASSERT_EMT(pVM);
1772 VMSUSPENDREASON enmReason = VMR3GetSuspendReason(pVM->pUVM);
1773 LogFlow(("pdmR3UsbHlp_VMGetSuspendReason: caller='%s'/%d: returns %d\n",
1774 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
1775 return enmReason;
1776}
1777
1778
1779/** @interface_method_impl{PDMUSBHLP,pfnVMGetResumeReason} */
1780static DECLCALLBACK(VMRESUMEREASON) pdmR3UsbHlp_VMGetResumeReason(PPDMUSBINS pUsbIns)
1781{
1782 PDMUSB_ASSERT_USBINS(pUsbIns);
1783 PVM pVM = pUsbIns->Internal.s.pVM;
1784 VM_ASSERT_EMT(pVM);
1785 VMRESUMEREASON enmReason = VMR3GetResumeReason(pVM->pUVM);
1786 LogFlow(("pdmR3UsbHlp_VMGetResumeReason: caller='%s'/%d: returns %d\n",
1787 pUsbIns->pReg->szName, pUsbIns->iInstance, enmReason));
1788 return enmReason;
1789}
1790
1791
1792/**
1793 * The USB device helper structure.
1794 */
1795const PDMUSBHLP g_pdmR3UsbHlp =
1796{
1797 PDM_USBHLP_VERSION,
1798 pdmR3UsbHlp_DriverAttach,
1799 pdmR3UsbHlp_AssertEMT,
1800 pdmR3UsbHlp_AssertOther,
1801 pdmR3UsbHlp_DBGFStopV,
1802 pdmR3UsbHlp_DBGFInfoRegister,
1803 pdmR3UsbHlp_MMHeapAlloc,
1804 pdmR3UsbHlp_MMHeapAllocZ,
1805 pdmR3UsbHlp_PDMQueueCreate,
1806 pdmR3UsbHlp_SSMRegister,
1807 pdmR3UsbHlp_STAMRegisterV,
1808 pdmR3UsbHlp_TMTimerCreate,
1809 pdmR3UsbHlp_VMSetErrorV,
1810 pdmR3UsbHlp_VMSetRuntimeErrorV,
1811 pdmR3UsbHlp_VMState,
1812 pdmR3UsbHlp_ThreadCreate,
1813 pdmR3UsbHlp_SetAsyncNotification,
1814 pdmR3UsbHlp_AsyncNotificationCompleted,
1815 pdmR3UsbHlp_VMGetSuspendReason,
1816 pdmR3UsbHlp_VMGetResumeReason,
1817 NULL,
1818 NULL,
1819 NULL,
1820 NULL,
1821 NULL,
1822 NULL,
1823 NULL,
1824 NULL,
1825 NULL,
1826 NULL,
1827 PDM_USBHLP_VERSION
1828};
1829
1830/** @} */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use