VirtualBox

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

Last change on this file since 35810 was 35810, checked in by vboxsync, 14 years ago

VMM: Replace most VERR_VERSION_MISMATCH by more specific error statuses. Translating the errors returned by device, driver and USB device constructors into specific ones for the benefit of old extension pack and misc use of the status.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.6 KB
Line 
1/* $Id: PDMUsb.cpp 35810 2011-02-01 13:00:24Z vboxsync $ */
2/** @file
3 * PDM - Pluggable Device and Driver Manager, USB part.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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/version.h>
32#include <VBox/err.h>
33
34#include <VBox/log.h>
35#include <iprt/assert.h>
36#include <iprt/thread.h>
37#include <iprt/string.h>
38#include <iprt/asm.h>
39#include <iprt/alloc.h>
40#include <iprt/alloca.h>
41#include <iprt/path.h>
42#include <iprt/uuid.h>
43
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48/**
49 * Internal callback structure pointer.
50 *
51 * The main purpose is to define the extra data we associate
52 * with PDMUSBREGCB so we can find the VM instance and so on.
53 */
54typedef struct PDMUSBREGCBINT
55{
56 /** The callback structure. */
57 PDMUSBREGCB Core;
58 /** A bit of padding. */
59 uint32_t u32[4];
60 /** VM Handle. */
61 PVM pVM;
62} PDMUSBREGCBINT, *PPDMUSBREGCBINT;
63typedef const PDMUSBREGCBINT *PCPDMUSBREGCBINT;
64
65
66/*******************************************************************************
67* Defined Constants And Macros *
68*******************************************************************************/
69/** @def PDMUSB_ASSERT_USBINS
70 * Asserts the validity of the USB device instance.
71 */
72#ifdef VBOX_STRICT
73# define PDMUSB_ASSERT_USBINS(pUsbIns) \
74 do { \
75 AssertPtr(pUsbIns); \
76 Assert(pUsbIns->u32Version == PDM_USBINS_VERSION); \
77 Assert(pUsbIns->pvInstanceDataR3 == (void *)&pUsbIns->achInstanceData[0]); \
78 } while (0)
79#else
80# define PDMUSB_ASSERT_USBINS(pUsbIns) do { } while (0)
81#endif
82
83
84/*******************************************************************************
85* Internal Functions *
86*******************************************************************************/
87static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns);
88
89
90/*******************************************************************************
91* Global Variables *
92*******************************************************************************/
93extern const PDMUSBHLP g_pdmR3UsbHlp;
94
95
96AssertCompile(sizeof(PDMUSBINSINT) <= RT_SIZEOFMEMB(PDMUSBINS, Internal.padding));
97
98
99/**
100 * Registers a USB hub driver.
101 *
102 * @returns VBox status code.
103 * @param pVM The VM handle.
104 * @param pDrvIns The driver instance of the hub.
105 * @param fVersions Indicates the kinds of USB devices that can be attached to this HUB.
106 * @param cPorts The number of ports.
107 * @param pUsbHubReg The hub callback structure that PDMUsb uses to interact with it.
108 * @param ppUsbHubHlp The helper callback structure that the hub uses to talk to PDMUsb.
109 * @thread EMT
110 */
111int pdmR3UsbRegisterHub(PVM pVM, PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)
112{
113 /*
114 * Validate input.
115 */
116 /* The driver must be in the USB class. */
117 if (!(pDrvIns->pReg->fClass & PDM_DRVREG_CLASS_USB))
118 {
119 LogRel(("pdmR3UsbRegisterHub: fClass=%#x expected %#x to be set\n", pDrvIns->pReg->fClass, PDM_DRVREG_CLASS_USB));
120 return VERR_INVALID_PARAMETER;
121 }
122 AssertMsgReturn(!(fVersions & ~(VUSB_STDVER_11 | VUSB_STDVER_20)), ("%#x\n", fVersions), VERR_INVALID_PARAMETER);
123 AssertPtrReturn(ppUsbHubHlp, VERR_INVALID_POINTER);
124 AssertPtrReturn(pUsbHubReg, VERR_INVALID_POINTER);
125 AssertReturn(pUsbHubReg->u32Version == PDM_USBHUBREG_VERSION, VERR_INVALID_MAGIC);
126 AssertReturn(pUsbHubReg->u32TheEnd == PDM_USBHUBREG_VERSION, VERR_INVALID_MAGIC);
127 AssertPtrReturn(pUsbHubReg->pfnAttachDevice, VERR_INVALID_PARAMETER);
128 AssertPtrReturn(pUsbHubReg->pfnDetachDevice, VERR_INVALID_PARAMETER);
129
130 /*
131 * Check for duplicate registration and find the last hub for FIFO registration.
132 */
133 PPDMUSBHUB pPrev = NULL;
134 for (PPDMUSBHUB pCur = pVM->pdm.s.pUsbHubs; pCur; pCur = pCur->pNext)
135 {
136 if (pCur->pDrvIns == pDrvIns)
137 return VERR_PDM_USB_HUB_EXISTS;
138 pPrev = pCur;
139 }
140
141 /*
142 * Create an internal USB hub structure.
143 */
144 PPDMUSBHUB pHub = (PPDMUSBHUB)MMR3HeapAlloc(pVM, MM_TAG_PDM_DRIVER, sizeof(*pHub));
145 if (!pHub)
146 return VERR_NO_MEMORY;
147
148 pHub->fVersions = fVersions;
149 pHub->cPorts = cPorts;
150 pHub->cAvailablePorts = cPorts;
151 pHub->pDrvIns = pDrvIns;
152 pHub->Reg = *pUsbHubReg;
153 pHub->pNext = NULL;
154
155 /* link it */
156 if (pPrev)
157 pPrev->pNext = pHub;
158 else
159 pVM->pdm.s.pUsbHubs = pHub;
160
161 Log(("PDM: Registered USB hub %p/%s\n", pDrvIns, pDrvIns->pReg->szName));
162 return VINF_SUCCESS;
163}
164
165
166/**
167 * Loads one device module and call the registration entry point.
168 *
169 * @returns VBox status code.
170 * @param pVM VM handle.
171 * @param pRegCB The registration callback stuff.
172 * @param pszFilename Module filename.
173 * @param pszName Module name.
174 */
175static int pdmR3UsbLoad(PVM pVM, PCPDMUSBREGCBINT pRegCB, const char *pszFilename, const char *pszName)
176{
177 /*
178 * Load it.
179 */
180 int rc = pdmR3LoadR3U(pVM->pUVM, pszFilename, pszName);
181 if (RT_SUCCESS(rc))
182 {
183 /*
184 * Get the registration export and call it.
185 */
186 FNPDMVBOXUSBREGISTER *pfnVBoxUsbRegister;
187 rc = PDMR3LdrGetSymbolR3(pVM, pszName, "VBoxUsbRegister", (void **)&pfnVBoxUsbRegister);
188 if (RT_SUCCESS(rc))
189 {
190 Log(("PDM: Calling VBoxUsbRegister (%p) of %s (%s)\n", pfnVBoxUsbRegister, pszName, pszFilename));
191 rc = pfnVBoxUsbRegister(&pRegCB->Core, VBOX_VERSION);
192 if (RT_SUCCESS(rc))
193 Log(("PDM: Successfully loaded device module %s (%s).\n", pszName, pszFilename));
194 else
195 AssertMsgFailed(("VBoxDevicesRegister failed with rc=%Rrc for module %s (%s)\n", rc, pszName, pszFilename));
196 }
197 else
198 {
199 AssertMsgFailed(("Failed to locate 'VBoxUsbRegister' in %s (%s) rc=%Rrc\n", pszName, pszFilename, rc));
200 if (rc == VERR_SYMBOL_NOT_FOUND)
201 rc = VERR_PDM_NO_REGISTRATION_EXPORT;
202 }
203 }
204 else
205 AssertMsgFailed(("Failed to load VBoxDD!\n"));
206 return rc;
207}
208
209
210
211/**
212 * @interface_method_impl{PDMUSBREGCB,pfnRegister}
213 */
214static DECLCALLBACK(int) pdmR3UsbReg_Register(PCPDMUSBREGCB pCallbacks, PCPDMUSBREG pReg)
215{
216 /*
217 * Validate the registration structure.
218 */
219 Assert(pReg);
220 AssertMsgReturn(pReg->u32Version == PDM_USBREG_VERSION,
221 ("Unknown struct version %#x!\n", pReg->u32Version),
222 VERR_PDM_UNKNOWN_USBREG_VERSION);
223 AssertMsgReturn( pReg->szName[0]
224 && strlen(pReg->szName) < sizeof(pReg->szName),
225 ("Invalid name '%s'\n", pReg->szName),
226 VERR_PDM_INVALID_USB_REGISTRATION);
227 AssertMsgReturn(pReg->fFlags == 0, ("fFlags=%#x\n", pReg->fFlags), VERR_PDM_INVALID_USB_REGISTRATION);
228 AssertMsgReturn(pReg->cMaxInstances > 0,
229 ("Max instances %u! (USB Device %s)\n", pReg->cMaxInstances, pReg->szName),
230 VERR_PDM_INVALID_USB_REGISTRATION);
231 AssertMsgReturn(pReg->cbInstance <= _1M,
232 ("Instance size %d bytes! (USB Device %s)\n", pReg->cbInstance, pReg->szName),
233 VERR_PDM_INVALID_USB_REGISTRATION);
234 AssertMsgReturn(pReg->pfnConstruct, ("No constructor! (USB Device %s)\n", pReg->szName),
235 VERR_PDM_INVALID_USB_REGISTRATION);
236
237 /*
238 * Check for duplicate and find FIFO entry at the same time.
239 */
240 PCPDMUSBREGCBINT pRegCB = (PCPDMUSBREGCBINT)pCallbacks;
241 PPDMUSB pUsbPrev = NULL;
242 PPDMUSB pUsb = pRegCB->pVM->pdm.s.pUsbDevs;
243 for (; pUsb; pUsbPrev = pUsb, pUsb = pUsb->pNext)
244 AssertMsgReturn(strcmp(pUsb->pReg->szName, pReg->szName),
245 ("USB Device '%s' already exists\n", pReg->szName),
246 VERR_PDM_USB_NAME_CLASH);
247
248 /*
249 * Allocate new device structure and insert it into the list.
250 */
251 pUsb = (PPDMUSB)MMR3HeapAlloc(pRegCB->pVM, MM_TAG_PDM_DEVICE, sizeof(*pUsb));
252 if (pUsb)
253 {
254 pUsb->pNext = NULL;
255 pUsb->iNextInstance = 0;
256 pUsb->pInstances = NULL;
257 pUsb->pReg = pReg;
258 pUsb->cchName = (RTUINT)strlen(pReg->szName);
259
260 if (pUsbPrev)
261 pUsbPrev->pNext = pUsb;
262 else
263 pRegCB->pVM->pdm.s.pUsbDevs = pUsb;
264 Log(("PDM: Registered USB device '%s'\n", pReg->szName));
265 return VINF_SUCCESS;
266 }
267 return VERR_NO_MEMORY;
268}
269
270
271/**
272 * Load USB Device modules.
273 *
274 * This is called by pdmR3DevInit() after it has loaded it's device modules.
275 *
276 * @returns VBox status code.
277 * @param pVM The VM handle.
278 */
279int pdmR3UsbLoadModules(PVM pVM)
280{
281 LogFlow(("pdmR3UsbLoadModules:\n"));
282
283 AssertRelease(!(RT_OFFSETOF(PDMUSBINS, achInstanceData) & 15));
284 AssertRelease(sizeof(pVM->pdm.s.pUsbInstances->Internal.s) <= sizeof(pVM->pdm.s.pUsbInstances->Internal.padding));
285
286 /*
287 * Initialize the callback structure.
288 */
289 PDMUSBREGCBINT RegCB;
290 RegCB.Core.u32Version = PDM_USBREG_CB_VERSION;
291 RegCB.Core.pfnRegister = pdmR3UsbReg_Register;
292 RegCB.pVM = pVM;
293
294 /*
295 * Load the builtin module
296 */
297 PCFGMNODE pUsbNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "PDM/USB/");
298 bool fLoadBuiltin;
299 int rc = CFGMR3QueryBool(pUsbNode, "LoadBuiltin", &fLoadBuiltin);
300 if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT)
301 fLoadBuiltin = true;
302 else if (RT_FAILURE(rc))
303 {
304 AssertMsgFailed(("Configuration error: Querying boolean \"LoadBuiltin\" failed with %Rrc\n", rc));
305 return rc;
306 }
307 if (fLoadBuiltin)
308 {
309 /* make filename */
310 char *pszFilename = pdmR3FileR3("VBoxDD", true /*fShared*/);
311 if (!pszFilename)
312 return VERR_NO_TMP_MEMORY;
313 rc = pdmR3UsbLoad(pVM, &RegCB, pszFilename, "VBoxDD");
314 RTMemTmpFree(pszFilename);
315 if (RT_FAILURE(rc))
316 return rc;
317 }
318
319 /*
320 * Load additional device modules.
321 */
322 PCFGMNODE pCur;
323 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
324 {
325 /*
326 * Get the name and path.
327 */
328 char szName[PDMMOD_NAME_LEN];
329 rc = CFGMR3GetName(pCur, &szName[0], sizeof(szName));
330 if (rc == VERR_CFGM_NOT_ENOUGH_SPACE)
331 {
332 AssertMsgFailed(("configuration error: The module name is too long, cchName=%zu.\n", CFGMR3GetNameLen(pCur)));
333 return VERR_PDM_MODULE_NAME_TOO_LONG;
334 }
335 else if (RT_FAILURE(rc))
336 {
337 AssertMsgFailed(("CFGMR3GetName -> %Rrc.\n", rc));
338 return rc;
339 }
340
341 /* the path is optional, if no path the module name + path is used. */
342 char szFilename[RTPATH_MAX];
343 rc = CFGMR3QueryString(pCur, "Path", &szFilename[0], sizeof(szFilename));
344 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
345 strcpy(szFilename, szName);
346 else if (RT_FAILURE(rc))
347 {
348 AssertMsgFailed(("configuration error: Failure to query the module path, rc=%Rrc.\n", rc));
349 return rc;
350 }
351
352 /* prepend path? */
353 if (!RTPathHavePath(szFilename))
354 {
355 char *psz = pdmR3FileR3(szFilename, false /*fShared*/);
356 if (!psz)
357 return VERR_NO_TMP_MEMORY;
358 size_t cch = strlen(psz) + 1;
359 if (cch > sizeof(szFilename))
360 {
361 RTMemTmpFree(psz);
362 AssertMsgFailed(("Filename too long! cch=%d '%s'\n", cch, psz));
363 return VERR_FILENAME_TOO_LONG;
364 }
365 memcpy(szFilename, psz, cch);
366 RTMemTmpFree(psz);
367 }
368
369 /*
370 * Load the module and register it's devices.
371 */
372 rc = pdmR3UsbLoad(pVM, &RegCB, szFilename, szName);
373 if (RT_FAILURE(rc))
374 return rc;
375 }
376
377 return VINF_SUCCESS;
378}
379
380
381/**
382 * Send the init-complete notification to all the USB devices.
383 *
384 * This is called from pdmR3DevInit() after it has do its notification round.
385 *
386 * @returns VBox status code.
387 * @param pVM The VM handle.
388 */
389int pdmR3UsbVMInitComplete(PVM pVM)
390{
391 for (PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
392 {
393 if (pUsbIns->pReg->pfnVMInitComplete)
394 {
395 int rc = pUsbIns->pReg->pfnVMInitComplete(pUsbIns);
396 if (RT_FAILURE(rc))
397 {
398 AssertMsgFailed(("InitComplete on USB device '%s'/%d failed with rc=%Rrc\n",
399 pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
400 return rc;
401 }
402 }
403 }
404 return VINF_SUCCESS;
405}
406
407
408/**
409 * Lookups a device structure by name.
410 * @internal
411 */
412PPDMUSB pdmR3UsbLookup(PVM pVM, const char *pszName)
413{
414 size_t cchName = strlen(pszName);
415 for (PPDMUSB pUsb = pVM->pdm.s.pUsbDevs; pUsb; pUsb = pUsb->pNext)
416 if ( pUsb->cchName == cchName
417 && !strcmp(pUsb->pReg->szName, pszName))
418 return pUsb;
419 return NULL;
420}
421
422
423/**
424 * Locates a suitable hub for the specified kind of device.
425 *
426 * @returns VINF_SUCCESS and *ppHub on success.
427 * VERR_PDM_NO_USB_HUBS or VERR_PDM_NO_USB_PORTS on failure.
428 * @param pVM The VM handle.
429 * @param iUsbVersion The USB device version.
430 * @param ppHub Where to store the pointer to the USB hub.
431 */
432static int pdmR3UsbFindHub(PVM pVM, uint32_t iUsbVersion, PPDMUSBHUB *ppHub)
433{
434 *ppHub = NULL;
435 if (!pVM->pdm.s.pUsbHubs)
436 return VERR_PDM_NO_USB_HUBS;
437
438 for (PPDMUSBHUB pCur = pVM->pdm.s.pUsbHubs; pCur; pCur = pCur->pNext)
439 if ( pCur->cAvailablePorts > 0
440 && ( (pCur->fVersions & iUsbVersion)
441 || pCur->fVersions == VUSB_STDVER_11))
442 {
443 *ppHub = pCur;
444 if (pCur->fVersions & iUsbVersion)
445 break;
446 }
447 if (*ppHub)
448 return VINF_SUCCESS;
449 return VERR_PDM_NO_USB_PORTS;
450}
451
452
453/**
454 * Creates the device.
455 *
456 * @returns VBox status code.
457 * @param pVM The VM handle.
458 * @param pUsbDev The USB device emulation.
459 * @param iInstance -1 if not called by pdmR3UsbInstantiateDevices().
460 * @param pUuid The UUID for this device.
461 * @param pInstanceNode The instance CFGM node. NULL if not called by pdmR3UsbInstantiateDevices().
462 * @param ppConfig Pointer to the device configuration pointer. This is set to NULL if inserted
463 * into the tree or cleaned up.
464 *
465 * In the pdmR3UsbInstantiateDevices() case (pInstanceNode != NULL) this is
466 * the actual config node and will not be cleaned up.
467 *
468 * @parma iUsbVersion The USB version preferred by the device.
469 */
470static int pdmR3UsbCreateDevice(PVM pVM, PPDMUSBHUB pHub, PPDMUSB pUsbDev, int iInstance, PCRTUUID pUuid, PCFGMNODE pInstanceNode, PCFGMNODE *ppConfig, uint32_t iUsbVersion)
471{
472 const bool fAtRuntime = pInstanceNode == NULL;
473 int rc;
474
475 /*
476 * If not called by pdmR3UsbInstantiateDevices(), we'll have to fix
477 * the configuration now.
478 */
479 /* USB device node. */
480 PCFGMNODE pDevNode = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "USB/%s/", pUsbDev->pReg->szName);
481 if (!pDevNode)
482 {
483 rc = CFGMR3InsertNodeF(CFGMR3GetRoot(pVM), &pDevNode, "USB/%s/", pUsbDev->pReg->szName);
484 AssertRCReturn(rc, rc);
485 }
486
487 /* The instance node and number. */
488 if (!pInstanceNode)
489 {
490 for (unsigned c = 0; c < _2M; c++)
491 {
492 iInstance = pUsbDev->iNextInstance++;
493 rc = CFGMR3InsertNodeF(pDevNode, &pInstanceNode, "%d/", iInstance);
494 if (rc != VERR_CFGM_NODE_EXISTS)
495 break;
496 }
497 AssertRCReturn(rc, rc);
498 }
499 else
500 {
501 Assert(iInstance >= 0);
502 if (iInstance >= (int)pUsbDev->iNextInstance)
503 pUsbDev->iNextInstance = iInstance + 1;
504 }
505
506 /* The instance config node. */
507 PCFGMNODE pConfigToDelete = NULL;
508 PCFGMNODE pConfig = NULL;
509 if (!ppConfig || !*ppConfig)
510 {
511 rc = CFGMR3InsertNode(pInstanceNode, "Config", &pConfig);
512 AssertRCReturn(rc, rc);
513 }
514 else if (fAtRuntime)
515 {
516 rc = CFGMR3InsertSubTree(pInstanceNode, "Config", *ppConfig, &pConfig);
517 AssertRCReturn(rc, rc);
518 *ppConfig = NULL;
519 pConfigToDelete = pConfig;
520 }
521 else
522 pConfig = *ppConfig;
523 Assert(CFGMR3GetChild(pInstanceNode, "Config") == pConfig);
524
525 /* The global device config node. */
526 PCFGMNODE pGlobalConfig = CFGMR3GetChild(pDevNode, "GlobalConfig");
527 if (!pGlobalConfig)
528 {
529 rc = CFGMR3InsertNode(pDevNode, "GlobalConfig", &pGlobalConfig);
530 if (RT_FAILURE(rc))
531 {
532 CFGMR3RemoveNode(pConfigToDelete);
533 AssertRCReturn(rc, rc);
534 }
535 }
536
537 /*
538 * Allocate the device instance.
539 */
540 size_t cb = RT_OFFSETOF(PDMUSBINS, achInstanceData[pUsbDev->pReg->cbInstance]);
541 cb = RT_ALIGN_Z(cb, 16);
542 PPDMUSBINS pUsbIns;
543 rc = MMR3HeapAllocZEx(pVM, MM_TAG_PDM_USB, cb, (void **)&pUsbIns);
544 if (RT_FAILURE(rc))
545 {
546 AssertMsgFailed(("Failed to allocate %d bytes of instance data for USB device '%s'. rc=%Rrc\n",
547 cb, pUsbDev->pReg->szName, rc));
548 CFGMR3RemoveNode(pConfigToDelete);
549 return rc;
550 }
551
552 /*
553 * Initialize it.
554 */
555 pUsbIns->u32Version = PDM_USBINS_VERSION;
556 //pUsbIns->Internal.s.pNext = NULL;
557 //pUsbIns->Internal.s.pPerDeviceNext = NULL;
558 pUsbIns->Internal.s.pUsbDev = pUsbDev;
559 pUsbIns->Internal.s.pVM = pVM;
560 //pUsbIns->Internal.s.pLuns = NULL;
561 pUsbIns->Internal.s.pCfg = pInstanceNode;
562 pUsbIns->Internal.s.pCfgDelete = pConfigToDelete;
563 pUsbIns->Internal.s.pCfgGlobal = pGlobalConfig;
564 pUsbIns->Internal.s.Uuid = *pUuid;
565 //pUsbIns->Internal.s.pHub = NULL;
566 pUsbIns->Internal.s.iPort = UINT32_MAX; /* to be determined. */
567 pUsbIns->Internal.s.fVMSuspended = true;
568 //pUsbIns->Internal.s.pfnAsyncNotify = NULL;
569 pUsbIns->pHlpR3 = &g_pdmR3UsbHlp;
570 pUsbIns->pReg = pUsbDev->pReg;
571 pUsbIns->pCfg = pConfig;
572 pUsbIns->pCfgGlobal = pGlobalConfig;
573 pUsbIns->iInstance = iInstance;
574 pUsbIns->pvInstanceDataR3 = &pUsbIns->achInstanceData[0];
575 pUsbIns->pszName = RTStrDup(pUsbDev->pReg->szName);
576
577 /*
578 * Link it into all the lists.
579 */
580 /* The global instance FIFO. */
581 PPDMUSBINS pPrev1 = pVM->pdm.s.pUsbInstances;
582 if (!pPrev1)
583 pVM->pdm.s.pUsbInstances = pUsbIns;
584 else
585 {
586 while (pPrev1->Internal.s.pNext)
587 {
588 Assert(pPrev1->u32Version == PDM_USBINS_VERSION);
589 pPrev1 = pPrev1->Internal.s.pNext;
590 }
591 pPrev1->Internal.s.pNext = pUsbIns;
592 }
593
594 /* The per device instance FIFO. */
595 PPDMUSBINS pPrev2 = pUsbDev->pInstances;
596 if (!pPrev2)
597 pUsbDev->pInstances = pUsbIns;
598 else
599 {
600 while (pPrev2->Internal.s.pPerDeviceNext)
601 {
602 Assert(pPrev2->u32Version == PDM_USBINS_VERSION);
603 pPrev2 = pPrev2->Internal.s.pPerDeviceNext;
604 }
605 pPrev2->Internal.s.pPerDeviceNext = pUsbIns;
606 }
607
608 /*
609 * Call the constructor.
610 */
611 Log(("PDM: Constructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
612 rc = pUsbIns->pReg->pfnConstruct(pUsbIns, pUsbIns->iInstance, pUsbIns->pCfg, pUsbIns->pCfgGlobal);
613 if (RT_SUCCESS(rc))
614 {
615 /*
616 * Attach it to the hub.
617 */
618 Log(("PDM: Attaching it...\n"));
619 rc = pHub->Reg.pfnAttachDevice(pHub->pDrvIns, pUsbIns, &pUsbIns->Internal.s.iPort);
620 if (RT_SUCCESS(rc))
621 {
622 pHub->cAvailablePorts--;
623 Assert((int32_t)pHub->cAvailablePorts >= 0 && pHub->cAvailablePorts < pHub->cPorts);
624 pUsbIns->Internal.s.pHub = pHub;
625
626 /* Send the hot-plugged notification if applicable. */
627 if (fAtRuntime && pUsbIns->pReg->pfnHotPlugged)
628 pUsbIns->pReg->pfnHotPlugged(pUsbIns);
629
630 Log(("PDM: Successfully attached USB device '%s' instance %d to hub %p\n",
631 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub));
632 return VINF_SUCCESS;
633 }
634
635 LogRel(("PDM: Failed to attach USB device '%s' instance %d to hub %p: %Rrc\n",
636 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
637 }
638 else
639 {
640 AssertMsgFailed(("Failed to construct '%s'/%d! %Rra\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
641 if (rc == VERR_VERSION_MISMATCH)
642 rc = VERR_PDM_DRIVER_VERSION_MISMATCH;
643 }
644 if (fAtRuntime)
645 pdmR3UsbDestroyDevice(pVM, pUsbIns);
646 /* else: destructors are invoked later. */
647 return rc;
648}
649
650
651/**
652 * Instantiate USB devices.
653 *
654 * This is called by pdmR3DevInit() after it has instantiated the
655 * other devices and their drivers. If there aren't any hubs
656 * around, we'll silently skip the USB devices.
657 *
658 * @returns VBox status code.
659 * @param pVM
660 */
661int pdmR3UsbInstantiateDevices(PVM pVM)
662{
663 /*
664 * Any hubs?
665 */
666 if (!pVM->pdm.s.pUsbHubs)
667 {
668 Log(("PDM: No USB hubs, skipping USB device instantiation.\n"));
669 return VINF_SUCCESS;
670 }
671
672 /*
673 * Count the device instances.
674 */
675 PCFGMNODE pCur;
676 PCFGMNODE pUsbNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "USB/");
677 PCFGMNODE pInstanceNode;
678 unsigned cUsbDevs = 0;
679 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
680 {
681 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
682 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
683 if (pInstanceNode != pGlobal)
684 cUsbDevs++;
685 }
686 if (!cUsbDevs)
687 {
688 Log(("PDM: No USB devices were configured!\n"));
689 return VINF_SUCCESS;
690 }
691 Log2(("PDM: cUsbDevs=%d!\n", cUsbDevs));
692
693 /*
694 * Collect info on each USB device instance.
695 */
696 struct USBDEVORDER
697 {
698 /** Configuration node. */
699 PCFGMNODE pNode;
700 /** Pointer to the USB device. */
701 PPDMUSB pUsbDev;
702 /** Init order. */
703 uint32_t u32Order;
704 /** VBox instance number. */
705 uint32_t iInstance;
706 } *paUsbDevs = (struct USBDEVORDER *)alloca(sizeof(paUsbDevs[0]) * (cUsbDevs + 1)); /* (One extra for swapping) */
707 Assert(paUsbDevs);
708 int rc;
709 unsigned i = 0;
710 for (pCur = CFGMR3GetFirstChild(pUsbNode); pCur; pCur = CFGMR3GetNextChild(pCur))
711 {
712 /* Get the device name. */
713 char szName[sizeof(paUsbDevs[0].pUsbDev->pReg->szName)];
714 rc = CFGMR3GetName(pCur, szName, sizeof(szName));
715 AssertMsgRCReturn(rc, ("Configuration error: device name is too long (or something)! rc=%Rrc\n", rc), rc);
716
717 /* Find the device. */
718 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, szName);
719 AssertMsgReturn(pUsbDev, ("Configuration error: device '%s' not found!\n", szName), VERR_PDM_DEVICE_NOT_FOUND);
720
721 /* Configured priority or use default? */
722 uint32_t u32Order;
723 rc = CFGMR3QueryU32(pCur, "Priority", &u32Order);
724 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
725 u32Order = i << 4;
726 else
727 AssertMsgRCReturn(rc, ("Configuration error: reading \"Priority\" for the '%s' USB device failed rc=%Rrc!\n", szName, rc), rc);
728
729 /* Global config. */
730 PCFGMNODE pGlobal = CFGMR3GetChild(pCur, "GlobalConfig/");
731 if (!pGlobal)
732 {
733 rc = CFGMR3InsertNode(pCur, "GlobalConfig/", &pGlobal);
734 AssertMsgRCReturn(rc, ("Failed to create GlobalConfig node! rc=%Rrc\n", rc), rc);
735 CFGMR3SetRestrictedRoot(pGlobal);
736 }
737
738 /* Enumerate the device instances. */
739 for (pInstanceNode = CFGMR3GetFirstChild(pCur); pInstanceNode; pInstanceNode = CFGMR3GetNextChild(pInstanceNode))
740 {
741 if (pInstanceNode == pGlobal)
742 continue;
743
744 paUsbDevs[i].pNode = pInstanceNode;
745 paUsbDevs[i].pUsbDev = pUsbDev;
746 paUsbDevs[i].u32Order = u32Order;
747
748 /* Get the instance number. */
749 char szInstance[32];
750 rc = CFGMR3GetName(pInstanceNode, szInstance, sizeof(szInstance));
751 AssertMsgRCReturn(rc, ("Configuration error: instance name is too long (or something)! rc=%Rrc\n", rc), rc);
752 char *pszNext = NULL;
753 rc = RTStrToUInt32Ex(szInstance, &pszNext, 0, &paUsbDevs[i].iInstance);
754 AssertMsgRCReturn(rc, ("Configuration error: RTStrToInt32Ex failed on the instance name '%s'! rc=%Rrc\n", szInstance, rc), rc);
755 AssertMsgReturn(!*pszNext, ("Configuration error: the instance name '%s' isn't all digits. (%s)\n", szInstance, pszNext), VERR_INVALID_PARAMETER);
756
757 /* next instance */
758 i++;
759 }
760 } /* devices */
761 Assert(i == cUsbDevs);
762
763 /*
764 * Sort the device array ascending on u32Order. (bubble)
765 */
766 unsigned c = cUsbDevs - 1;
767 while (c)
768 {
769 unsigned j = 0;
770 for (i = 0; i < c; i++)
771 if (paUsbDevs[i].u32Order > paUsbDevs[i + 1].u32Order)
772 {
773 paUsbDevs[cUsbDevs] = paUsbDevs[i + 1];
774 paUsbDevs[i + 1] = paUsbDevs[i];
775 paUsbDevs[i] = paUsbDevs[cUsbDevs];
776 j = i;
777 }
778 c = j;
779 }
780
781 /*
782 * Instantiate the devices.
783 */
784 for (i = 0; i < cUsbDevs; i++)
785 {
786 /*
787 * Make sure there is a config node and mark it as restricted.
788 */
789 PCFGMNODE pConfigNode = CFGMR3GetChild(paUsbDevs[i].pNode, "Config/");
790 if (!pConfigNode)
791 {
792 rc = CFGMR3InsertNode(paUsbDevs[i].pNode, "Config", &pConfigNode);
793 AssertMsgRCReturn(rc, ("Failed to create Config node! rc=%Rrc\n", rc), rc);
794 }
795 CFGMR3SetRestrictedRoot(pConfigNode);
796
797 /** @todo
798 * Figure out the USB version from the USB device registration and the configuration.
799 */
800 uint32_t iUsbVersion = VUSB_STDVER_11;
801
802 /*
803 * Find a suitable hub with free ports.
804 */
805 PPDMUSBHUB pHub;
806 rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
807 if (RT_FAILURE(rc))
808 {
809 Log(("pdmR3UsbFindHub failed %Rrc\n", rc));
810 return rc;
811 }
812
813 /*
814 * Create and attach the device.
815 */
816 RTUUID Uuid;
817 rc = RTUuidCreate(&Uuid);
818 AssertRCReturn(rc, rc);
819 rc = pdmR3UsbCreateDevice(pVM, pHub, paUsbDevs[i].pUsbDev, paUsbDevs[i].iInstance, &Uuid, paUsbDevs[i].pNode, &pConfigNode, iUsbVersion);
820 if (RT_FAILURE(rc))
821 return rc;
822 } /* for device instances */
823
824 return VINF_SUCCESS;
825}
826
827
828/**
829 * Creates a USB proxy device instance.
830 *
831 * This will find an appropriate HUB for the USB device, create the necessary CFGM stuff
832 * and try instantiate the proxy device.
833 *
834 * @returns VBox status code.
835 * @param pVM The VM handle.
836 * @param pUuid The UUID to be associated with the device.
837 * @param fRemote Whether it's a remove or local device.
838 * @param pszAddress The address string.
839 * @param pvBackend Pointer to the backend.
840 * @param iUsbVersion The preferred USB version.
841 * @param fMaskedIfs The interfaces to hide from the guest.
842 */
843VMMR3DECL(int) PDMR3USBCreateProxyDevice(PVM pVM, PCRTUUID pUuid, bool fRemote, const char *pszAddress, void *pvBackend,
844 uint32_t iUsbVersion, uint32_t fMaskedIfs)
845{
846 /*
847 * Validate input.
848 */
849 VM_ASSERT_EMT(pVM);
850 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
851 AssertPtrReturn(pszAddress, VERR_INVALID_POINTER);
852 AssertReturn( iUsbVersion == VUSB_STDVER_20
853 || iUsbVersion == VUSB_STDVER_11, VERR_INVALID_PARAMETER);
854
855 /*
856 * Find the USBProxy driver.
857 */
858 PPDMUSB pUsbDev = pdmR3UsbLookup(pVM, "USBProxy");
859 if (!pUsbDev)
860 {
861 LogRel(("PDMR3USBCreateProxyDevice: The USBProxy device class wasn't found\n"));
862 return VERR_PDM_NO_USBPROXY;
863 }
864
865 /*
866 * Find a suitable hub with free ports.
867 */
868 PPDMUSBHUB pHub;
869 int rc = pdmR3UsbFindHub(pVM, iUsbVersion, &pHub);
870 if (RT_FAILURE(rc))
871 {
872 Log(("pdmR3UsbFindHub: failed %Rrc\n", rc));
873 return rc;
874 }
875
876 /*
877 * Create the CFGM configuration node.
878 */
879 PCFGMNODE pConfig = CFGMR3CreateTree(pVM);
880 AssertReturn(pConfig, VERR_NO_MEMORY);
881 do /* break loop */
882 {
883 rc = CFGMR3InsertString(pConfig, "Address", pszAddress); AssertRCBreak(rc);
884 char szUuid[RTUUID_STR_LENGTH];
885 rc = RTUuidToStr(pUuid, &szUuid[0], sizeof(szUuid)); AssertRCBreak(rc);
886 rc = CFGMR3InsertString(pConfig, "UUID", szUuid); AssertRCBreak(rc);
887 rc = CFGMR3InsertInteger(pConfig, "Remote", fRemote); AssertRCBreak(rc);
888 rc = CFGMR3InsertInteger(pConfig, "USBVersion", iUsbVersion); AssertRCBreak(rc);
889 rc = CFGMR3InsertInteger(pConfig, "pvBackend", (uintptr_t)pvBackend); AssertRCBreak(rc);
890 rc = CFGMR3InsertInteger(pConfig, "MaskedIfs", fMaskedIfs); AssertRCBreak(rc);
891 rc = CFGMR3InsertInteger(pConfig, "Force11Device", !(pHub->fVersions & iUsbVersion)); AssertRCBreak(rc);
892 } while (0); /* break loop */
893 if (RT_FAILURE(rc))
894 {
895 CFGMR3RemoveNode(pConfig);
896 LogRel(("PDMR3USBCreateProxyDevice: failed to setup CFGM config, rc=%Rrc\n", rc));
897 return rc;
898 }
899
900 /*
901 * Finally, try create it.
902 */
903 rc = pdmR3UsbCreateDevice(pVM, pHub, pUsbDev, -1, pUuid, NULL, &pConfig, iUsbVersion);
904 if (RT_FAILURE(rc) && pConfig)
905 CFGMR3RemoveNode(pConfig);
906 return rc;
907}
908
909
910/**
911 * Destroys a hot-plugged USB device.
912 *
913 * The device must be detached from the HUB at this point.
914 *
915 * @param pVM Pointer to the shared VM structure.
916 * @param pUsbIns The USB device instance to destroy.
917 * @thread EMT
918 */
919static void pdmR3UsbDestroyDevice(PVM pVM, PPDMUSBINS pUsbIns)
920{
921 Assert(!pUsbIns->Internal.s.pHub);
922
923 /*
924 * Do the unplug notification.
925 */
926 /** @todo what about the drivers? */
927 if (pUsbIns->pReg->pfnHotUnplugged)
928 pUsbIns->pReg->pfnHotUnplugged(pUsbIns);
929
930 /*
931 * Destroy the luns with their driver chains and call the device destructor.
932 */
933 while (pUsbIns->Internal.s.pLuns)
934 {
935 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
936 pUsbIns->Internal.s.pLuns = pLun->pNext;
937 if (pLun->pTop)
938 pdmR3DrvDestroyChain(pLun->pTop, PDM_TACH_FLAGS_NOT_HOT_PLUG); /* Hotplugging is handled differently here atm. */
939 MMR3HeapFree(pLun);
940 }
941
942 /* finally, the device. */
943 if (pUsbIns->pReg->pfnDestruct)
944 {
945 Log(("PDM: Destructing USB device '%s' instance %d...\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
946 pUsbIns->pReg->pfnDestruct(pUsbIns);
947 }
948 //TMR3TimerDestroyUsb(pVM, pUsbIns);
949 //SSMR3DeregisterUsb(pVM, pUsbIns, NULL, 0);
950 pdmR3ThreadDestroyUsb(pVM, pUsbIns);
951
952 /*
953 * Unlink it.
954 */
955 /* The global instance FIFO. */
956 if (pVM->pdm.s.pUsbInstances == pUsbIns)
957 pVM->pdm.s.pUsbInstances = pUsbIns->Internal.s.pNext;
958 else
959 {
960 PPDMUSBINS pPrev = pVM->pdm.s.pUsbInstances;
961 while (pPrev && pPrev->Internal.s.pNext != pUsbIns)
962 {
963 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
964 pPrev = pPrev->Internal.s.pNext;
965 }
966 Assert(pPrev); Assert(pPrev != pUsbIns);
967 if (pPrev)
968 pPrev->Internal.s.pNext = pUsbIns->Internal.s.pNext;
969 }
970
971 /* The per device instance FIFO. */
972 PPDMUSB pUsbDev = pUsbIns->Internal.s.pUsbDev;
973 if (pUsbDev->pInstances == pUsbIns)
974 pUsbDev->pInstances = pUsbIns->Internal.s.pPerDeviceNext;
975 else
976 {
977 PPDMUSBINS pPrev = pUsbDev->pInstances;
978 while (pPrev && pPrev->Internal.s.pPerDeviceNext != pUsbIns)
979 {
980 Assert(pPrev->u32Version == PDM_USBINS_VERSION);
981 pPrev = pPrev->Internal.s.pPerDeviceNext;
982 }
983 Assert(pPrev); Assert(pPrev != pUsbIns);
984 if (pPrev)
985 pPrev->Internal.s.pPerDeviceNext = pUsbIns->Internal.s.pPerDeviceNext;
986 }
987
988 /*
989 * Trash it.
990 */
991 pUsbIns->u32Version = 0;
992 pUsbIns->pReg = NULL;
993 if (pUsbIns->pszName)
994 {
995 RTStrFree(pUsbIns->pszName);
996 pUsbIns->pszName = NULL;
997 }
998 CFGMR3RemoveNode(pUsbIns->Internal.s.pCfgDelete);
999 MMR3HeapFree(pUsbIns);
1000}
1001
1002
1003/**
1004 * Detaches and destroys a USB device.
1005 *
1006 * @returns VBox status code.
1007 * @param pVM The VM handle.
1008 * @param pUuid The UUID associated with the device to detach.
1009 * @thread EMT
1010 */
1011VMMR3DECL(int) PDMR3USBDetachDevice(PVM pVM, PCRTUUID pUuid)
1012{
1013 /*
1014 * Validate input.
1015 */
1016 VM_ASSERT_EMT(pVM);
1017 AssertPtrReturn(pUuid, VERR_INVALID_POINTER);
1018 AssertPtrReturn(pVM, VERR_INVALID_POINTER);
1019
1020 /*
1021 * Search the global list for it.
1022 */
1023 PPDMUSBINS pUsbIns = pVM->pdm.s.pUsbInstances;
1024 for ( ; pUsbIns; pUsbIns = pUsbIns->Internal.s.pNext)
1025 if (!RTUuidCompare(&pUsbIns->Internal.s.Uuid, pUuid))
1026 break;
1027 if (!pUsbIns)
1028 return VERR_PDM_DEVICE_INSTANCE_NOT_FOUND; /** @todo VERR_PDM_USB_INSTANCE_NOT_FOUND */
1029
1030 /*
1031 * Detach it from the HUB (if it's actually attached to one).
1032 */
1033 PPDMUSBHUB pHub = pUsbIns->Internal.s.pHub;
1034 if (pHub)
1035 {
1036 int rc = pHub->Reg.pfnDetachDevice(pHub->pDrvIns, pUsbIns, pUsbIns->Internal.s.iPort);
1037 if (RT_FAILURE(rc))
1038 {
1039 LogRel(("PDM: Failed to detach USB device '%s' instance %d from %p: %Rrc\n",
1040 pUsbIns->pReg->szName, pUsbIns->iInstance, pHub, rc));
1041 return rc;
1042 }
1043
1044 pHub->cAvailablePorts++;
1045 Assert(pHub->cAvailablePorts > 0 && pHub->cAvailablePorts <= pHub->cPorts);
1046 pUsbIns->Internal.s.pHub = NULL;
1047 }
1048
1049 /*
1050 * Notify about unplugging and destroy the device with it's drivers.
1051 */
1052 pdmR3UsbDestroyDevice(pVM, pUsbIns);
1053
1054 return VINF_SUCCESS;
1055}
1056
1057
1058/**
1059 * Checks if there are any USB hubs attached.
1060 *
1061 * @returns true / false accordingly.
1062 * @param pVM Pointer to the shared VM structure.
1063 */
1064VMMR3DECL(bool) PDMR3USBHasHub(PVM pVM)
1065{
1066 return pVM->pdm.s.pUsbHubs != NULL;
1067}
1068
1069
1070/** @name USB Device Helpers
1071 * @{
1072 */
1073
1074/** @interface_method_impl{PDMUSBHLPR3,pfnDriverAttach} */
1075static DECLCALLBACK(int) pdmR3UsbHlp_DriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc)
1076{
1077 PDMUSB_ASSERT_USBINS(pUsbIns);
1078 PVM pVM = pUsbIns->Internal.s.pVM;
1079 VM_ASSERT_EMT(pVM);
1080 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: iLun=%d pBaseInterface=%p ppBaseInterface=%p pszDesc=%p:{%s}\n",
1081 pUsbIns->pReg->szName, pUsbIns->iInstance, iLun, pBaseInterface, ppBaseInterface, pszDesc, pszDesc));
1082
1083 /*
1084 * Lookup the LUN, it might already be registered.
1085 */
1086 PPDMLUN pLunPrev = NULL;
1087 PPDMLUN pLun = pUsbIns->Internal.s.pLuns;
1088 for (; pLun; pLunPrev = pLun, pLun = pLun->pNext)
1089 if (pLun->iLun == iLun)
1090 break;
1091
1092 /*
1093 * Create the LUN if if wasn't found, else check if driver is already attached to it.
1094 */
1095 if (!pLun)
1096 {
1097 if ( !pBaseInterface
1098 || !pszDesc
1099 || !*pszDesc)
1100 {
1101 Assert(pBaseInterface);
1102 Assert(pszDesc || *pszDesc);
1103 return VERR_INVALID_PARAMETER;
1104 }
1105
1106 pLun = (PPDMLUN)MMR3HeapAlloc(pVM, MM_TAG_PDM_LUN, sizeof(*pLun));
1107 if (!pLun)
1108 return VERR_NO_MEMORY;
1109
1110 pLun->iLun = iLun;
1111 pLun->pNext = pLunPrev ? pLunPrev->pNext : NULL;
1112 pLun->pTop = NULL;
1113 pLun->pBottom = NULL;
1114 pLun->pDevIns = NULL;
1115 pLun->pUsbIns = pUsbIns;
1116 pLun->pszDesc = pszDesc;
1117 pLun->pBase = pBaseInterface;
1118 if (!pLunPrev)
1119 pUsbIns->Internal.s.pLuns = pLun;
1120 else
1121 pLunPrev->pNext = pLun;
1122 Log(("pdmR3UsbHlp_DriverAttach: Registered LUN#%d '%s' with device '%s'/%d.\n",
1123 iLun, pszDesc, pUsbIns->pReg->szName, pUsbIns->iInstance));
1124 }
1125 else if (pLun->pTop)
1126 {
1127 AssertMsgFailed(("Already attached! The device should keep track of such things!\n"));
1128 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, VERR_PDM_DRIVER_ALREADY_ATTACHED));
1129 return VERR_PDM_DRIVER_ALREADY_ATTACHED;
1130 }
1131 Assert(pLun->pBase == pBaseInterface);
1132
1133
1134 /*
1135 * Get the attached driver configuration.
1136 */
1137 int rc;
1138 PCFGMNODE pNode = CFGMR3GetChildF(pUsbIns->Internal.s.pCfg, "LUN#%u", iLun);
1139 if (pNode)
1140 rc = pdmR3DrvInstantiate(pVM, pNode, pBaseInterface, NULL /*pDrvAbove*/, pLun, ppBaseInterface);
1141 else
1142 rc = VERR_PDM_NO_ATTACHED_DRIVER;
1143
1144
1145 LogFlow(("pdmR3UsbHlp_DriverAttach: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1146 return rc;
1147}
1148
1149
1150/** @interface_method_impl{PDMUSBHLP,pfnAssertEMT} */
1151static DECLCALLBACK(bool) pdmR3UsbHlp_AssertEMT(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1152{
1153 PDMUSB_ASSERT_USBINS(pUsbIns);
1154 if (VM_IS_EMT(pUsbIns->Internal.s.pVM))
1155 return true;
1156
1157 char szMsg[100];
1158 RTStrPrintf(szMsg, sizeof(szMsg), "AssertEMT '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1159 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1160 AssertBreakpoint();
1161 return false;
1162}
1163
1164
1165/** @interface_method_impl{PDMUSBHLP,pfnAssertOther} */
1166static DECLCALLBACK(bool) pdmR3UsbHlp_AssertOther(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)
1167{
1168 PDMUSB_ASSERT_USBINS(pUsbIns);
1169 if (!VM_IS_EMT(pUsbIns->Internal.s.pVM))
1170 return true;
1171
1172 char szMsg[100];
1173 RTStrPrintf(szMsg, sizeof(szMsg), "AssertOther '%s'/%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance);
1174 RTAssertMsg1Weak(szMsg, iLine, pszFile, pszFunction);
1175 AssertBreakpoint();
1176 return false;
1177}
1178
1179
1180/** @interface_method_impl{PDMUSBHLP,pfnDBGFStopV} */
1181static DECLCALLBACK(int) pdmR3UsbHlp_DBGFStopV(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction, const char *pszFormat, va_list args)
1182{
1183 PDMUSB_ASSERT_USBINS(pUsbIns);
1184#ifdef LOG_ENABLED
1185 va_list va2;
1186 va_copy(va2, args);
1187 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: pszFile=%p:{%s} iLine=%d pszFunction=%p:{%s} pszFormat=%p:{%s} (%N)\n",
1188 pUsbIns->pReg->szName, pUsbIns->iInstance, pszFile, pszFile, iLine, pszFunction, pszFunction, pszFormat, pszFormat, pszFormat, &va2));
1189 va_end(va2);
1190#endif
1191
1192 PVM pVM = pUsbIns->Internal.s.pVM;
1193 VM_ASSERT_EMT(pVM);
1194 int rc = DBGFR3EventSrcV(pVM, DBGFEVENT_DEV_STOP, pszFile, iLine, pszFunction, pszFormat, args);
1195 if (rc == VERR_DBGF_NOT_ATTACHED)
1196 rc = VINF_SUCCESS;
1197
1198 LogFlow(("pdmR3UsbHlp_DBGFStopV: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1199 return rc;
1200}
1201
1202
1203/** @interface_method_impl{PDMUSBHLP,pfnDBGFInfoRegister} */
1204static DECLCALLBACK(int) pdmR3UsbHlp_DBGFInfoRegister(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERUSB pfnHandler)
1205{
1206 PDMUSB_ASSERT_USBINS(pUsbIns);
1207 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: pszName=%p:{%s} pszDesc=%p:{%s} pfnHandler=%p\n",
1208 pUsbIns->pReg->szName, pUsbIns->iInstance, pszName, pszName, pszDesc, pszDesc, pfnHandler));
1209
1210 PVM pVM = pUsbIns->Internal.s.pVM;
1211 VM_ASSERT_EMT(pVM);
1212 /** @todo int rc = DBGFR3InfoRegisterUsb(pVM, pszName, pszDesc, pfnHandler, pUsbIns); */
1213 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1214
1215 LogFlow(("pdmR3UsbHlp_DBGFInfoRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1216 return rc;
1217}
1218
1219
1220/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAlloc} */
1221static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb)
1222{
1223 PDMUSB_ASSERT_USBINS(pUsbIns);
1224 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1225
1226 void *pv = MMR3HeapAlloc(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1227
1228 LogFlow(("pdmR3UsbHlp_MMHeapAlloc: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1229 return pv;
1230}
1231
1232
1233/** @interface_method_impl{PDMUSBHLP,pfnMMHeapAllocZ} */
1234static DECLCALLBACK(void *) pdmR3UsbHlp_MMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb)
1235{
1236 PDMUSB_ASSERT_USBINS(pUsbIns);
1237 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: cb=%#x\n", pUsbIns->pReg->szName, pUsbIns->iInstance, cb));
1238
1239 void *pv = MMR3HeapAllocZ(pUsbIns->Internal.s.pVM, MM_TAG_PDM_USB_USER, cb);
1240
1241 LogFlow(("pdmR3UsbHlp_MMHeapAllocZ: caller='%s'/%d: returns %p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pv));
1242 return pv;
1243}
1244
1245
1246/** @interface_method_impl{PDMUSBHLP,pfnPDMQueueCreate} */
1247static DECLCALLBACK(int) pdmR3UsbHlp_PDMQueueCreate(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval,
1248 PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)
1249{
1250 PDMUSB_ASSERT_USBINS(pUsbIns);
1251 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: cbItem=%#x cItems=%#x cMilliesInterval=%u pfnCallback=%p pszName=%p:{%s} ppQueue=%p\n",
1252 pUsbIns->pReg->szName, pUsbIns->iInstance, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, pszName, ppQueue));
1253
1254 PVM pVM = pUsbIns->Internal.s.pVM;
1255 VM_ASSERT_EMT(pVM);
1256
1257 if (pUsbIns->iInstance > 0)
1258 {
1259 pszName = MMR3HeapAPrintf(pVM, MM_TAG_PDM_DEVICE_DESC, "%s_%u", pszName, pUsbIns->iInstance);
1260 AssertLogRelReturn(pszName, VERR_NO_MEMORY);
1261 }
1262
1263 /** @todo int rc = PDMR3QueueCreateUsb(pVM, pUsbIns, cbItem, cItems, cMilliesInterval, pfnCallback, fGCEnabled, pszName, ppQueue); */
1264 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1265
1266 LogFlow(("pdmR3UsbHlp_PDMQueueCreate: caller='%s'/%d: returns %Rrc *ppQueue=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc, *ppQueue));
1267 return rc;
1268}
1269
1270
1271/** @interface_method_impl{PDMUSBHLP,pfnSSMRegister} */
1272static DECLCALLBACK(int) pdmR3UsbHlp_SSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess,
1273 PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote,
1274 PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone,
1275 PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)
1276{
1277 PDMUSB_ASSERT_USBINS(pUsbIns);
1278 VM_ASSERT_EMT(pUsbIns->Internal.s.pVM);
1279 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: uVersion=#x cbGuess=%#x\n"
1280 " pfnLivePrep=%p pfnLiveExec=%p pfnLiveVote=%p pfnSavePrep=%p pfnSaveExec=%p pfnSaveDone=%p pszLoadPrep=%p pfnLoadExec=%p pfnLoadDone=%p\n",
1281 pUsbIns->pReg->szName, pUsbIns->iInstance, uVersion, cbGuess,
1282 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1283 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1284 pfnLoadPrep, pfnLoadExec, pfnLoadDone));
1285
1286 /** @todo
1287 int rc = SSMR3RegisterUsb(pUsbIns->Internal.s.pVM, pUsbIns, pUsbIns->pReg->szName, pUsbIns->iInstance,
1288 uVersion, cbGuess,
1289 pfnLivePrep, pfnLiveExec, pfnLiveVote,
1290 pfnSavePrep, pfnSaveExec, pfnSaveDone,
1291 pfnLoadPrep, pfnLoadExec, pfnLoadDone); */
1292 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1293
1294 LogFlow(("pdmR3UsbHlp_SSMRegister: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1295 return rc;
1296}
1297
1298
1299/** @interface_method_impl{PDMUSBHLP,pfnSTAMRegisterV} */
1300static DECLCALLBACK(void) pdmR3UsbHlp_STAMRegisterV(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility,
1301 STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list args)
1302{
1303 PDMUSB_ASSERT_USBINS(pUsbIns);
1304 PVM pVM = pUsbIns->Internal.s.pVM;
1305 VM_ASSERT_EMT(pVM);
1306
1307 int rc = STAMR3RegisterV(pVM, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, args);
1308 AssertRC(rc);
1309
1310 NOREF(pVM);
1311}
1312
1313
1314/** @interface_method_impl{PDMUSBHLP,pfnTMTimerCreate} */
1315static DECLCALLBACK(int) pdmR3UsbHlp_TMTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser,
1316 uint32_t fFlags, const char *pszDesc, PPTMTIMERR3 ppTimer)
1317{
1318 PDMUSB_ASSERT_USBINS(pUsbIns);
1319 PVM pVM = pUsbIns->Internal.s.pVM;
1320 VM_ASSERT_EMT(pVM);
1321 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: enmClock=%d pfnCallback=%p pvUser=%p fFlags=%#x pszDesc=%p:{%s} ppTimer=%p\n",
1322 pUsbIns->pReg->szName, pUsbIns->iInstance, enmClock, pfnCallback, pvUser, fFlags, pszDesc, pszDesc, ppTimer));
1323
1324 if (pUsbIns->iInstance > 0) /** @todo use a string cache here later. */
1325 {
1326 char *pszDesc2 = MMR3HeapAPrintf(pVM, MM_TAG_PDM_USB_DESC, "%s [%u]", pszDesc, pUsbIns->iInstance);
1327 if (pszDesc2)
1328 pszDesc = pszDesc2;
1329 }
1330
1331 /** @todo
1332 int rc = TMR3TimerCreateUsb(pVM, pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, ppTimer); */
1333 int rc = VERR_NOT_IMPLEMENTED; AssertFailed();
1334
1335 LogFlow(("pdmR3UsbHlp_TMTimerCreate: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1336 return rc;
1337}
1338
1339
1340/** @interface_method_impl{PDMUSBHLP,pfnVMSetErrorV} */
1341static DECLCALLBACK(int) pdmR3UsbHlp_VMSetErrorV(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
1342{
1343 PDMUSB_ASSERT_USBINS(pUsbIns);
1344 int rc2 = VMSetErrorV(pUsbIns->Internal.s.pVM, rc, RT_SRC_POS_ARGS, pszFormat, va); Assert(rc2 == rc); NOREF(rc2);
1345 return rc;
1346}
1347
1348
1349/** @interface_method_impl{PDMUSBHLP,pfnVMSetRuntimeErrorV} */
1350static DECLCALLBACK(int) pdmR3UsbHlp_VMSetRuntimeErrorV(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, const char *pszFormat, va_list va)
1351{
1352 PDMUSB_ASSERT_USBINS(pUsbIns);
1353 int rc = VMSetRuntimeErrorV(pUsbIns->Internal.s.pVM, fFlags, pszErrorId, pszFormat, va);
1354 return rc;
1355}
1356
1357
1358/** @interface_method_impl{PDMUSBHLP,pfnVMState} */
1359static DECLCALLBACK(VMSTATE) pdmR3UsbHlp_VMState(PPDMUSBINS pUsbIns)
1360{
1361 PDMUSB_ASSERT_USBINS(pUsbIns);
1362
1363 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
1364
1365 LogFlow(("pdmR3UsbHlp_VMState: caller='%s'/%d: returns %d (%s)\n", pUsbIns->pReg->szName, pUsbIns->iInstance,
1366 enmVMState, VMR3GetStateName(enmVMState)));
1367 return enmVMState;
1368}
1369
1370
1371/** @interface_method_impl{PDMUSBHLP,pfnSetAsyncNotification} */
1372static DECLCALLBACK(int) pdmR3UsbHlp_SetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)
1373{
1374 PDMUSB_ASSERT_USBINS(pUsbIns);
1375 VM_ASSERT_EMT0(pUsbIns->Internal.s.pVM);
1376 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: pfnAsyncNotify=%p\n", pUsbIns->pReg->szName, pUsbIns->iInstance, pfnAsyncNotify));
1377
1378 int rc = VINF_SUCCESS;
1379 AssertStmt(pfnAsyncNotify, rc = VERR_INVALID_PARAMETER);
1380 AssertStmt(!pUsbIns->Internal.s.pfnAsyncNotify, rc = VERR_WRONG_ORDER);
1381 AssertStmt(pUsbIns->Internal.s.fVMSuspended || pUsbIns->Internal.s.fVMReset, rc = VERR_WRONG_ORDER);
1382 VMSTATE enmVMState = VMR3GetState(pUsbIns->Internal.s.pVM);
1383 AssertStmt( enmVMState == VMSTATE_SUSPENDING
1384 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1385 || enmVMState == VMSTATE_SUSPENDING_LS
1386 || enmVMState == VMSTATE_RESETTING
1387 || enmVMState == VMSTATE_RESETTING_LS
1388 || enmVMState == VMSTATE_POWERING_OFF
1389 || enmVMState == VMSTATE_POWERING_OFF_LS,
1390 rc = VERR_INVALID_STATE);
1391
1392 if (RT_SUCCESS(rc))
1393 pUsbIns->Internal.s.pfnAsyncNotify = pfnAsyncNotify;
1394
1395 LogFlow(("pdmR3UsbHlp_SetAsyncNotification: caller='%s'/%d: returns %Rrc\n", pUsbIns->pReg->szName, pUsbIns->iInstance, rc));
1396 return rc;
1397}
1398
1399
1400/** @interface_method_impl{PDMUSBHLP,pfnAsyncNotificationCompleted} */
1401static DECLCALLBACK(void) pdmR3UsbHlp_AsyncNotificationCompleted(PPDMUSBINS pUsbIns)
1402{
1403 PDMUSB_ASSERT_USBINS(pUsbIns);
1404 PVM pVM = pUsbIns->Internal.s.pVM;
1405
1406 VMSTATE enmVMState = VMR3GetState(pVM);
1407 if ( enmVMState == VMSTATE_SUSPENDING
1408 || enmVMState == VMSTATE_SUSPENDING_EXT_LS
1409 || enmVMState == VMSTATE_SUSPENDING_LS
1410 || enmVMState == VMSTATE_RESETTING
1411 || enmVMState == VMSTATE_RESETTING_LS
1412 || enmVMState == VMSTATE_POWERING_OFF
1413 || enmVMState == VMSTATE_POWERING_OFF_LS)
1414 {
1415 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d:\n", pUsbIns->pReg->szName, pUsbIns->iInstance));
1416 VMR3AsyncPdmNotificationWakeupU(pVM->pUVM);
1417 }
1418 else
1419 LogFlow(("pdmR3UsbHlp_AsyncNotificationCompleted: caller='%s'/%d: enmVMState=%d\n", pUsbIns->pReg->szName, pUsbIns->iInstance, enmVMState));
1420}
1421
1422
1423/**
1424 * The USB device helper structure.
1425 */
1426const PDMUSBHLP g_pdmR3UsbHlp =
1427{
1428 PDM_USBHLP_VERSION,
1429 pdmR3UsbHlp_DriverAttach,
1430 pdmR3UsbHlp_AssertEMT,
1431 pdmR3UsbHlp_AssertOther,
1432 pdmR3UsbHlp_DBGFStopV,
1433 pdmR3UsbHlp_DBGFInfoRegister,
1434 pdmR3UsbHlp_MMHeapAlloc,
1435 pdmR3UsbHlp_MMHeapAllocZ,
1436 pdmR3UsbHlp_PDMQueueCreate,
1437 pdmR3UsbHlp_SSMRegister,
1438 pdmR3UsbHlp_STAMRegisterV,
1439 pdmR3UsbHlp_TMTimerCreate,
1440 pdmR3UsbHlp_VMSetErrorV,
1441 pdmR3UsbHlp_VMSetRuntimeErrorV,
1442 pdmR3UsbHlp_VMState,
1443 pdmR3UsbHlp_SetAsyncNotification,
1444 pdmR3UsbHlp_AsyncNotificationCompleted,
1445 PDM_USBHLP_VERSION
1446};
1447
1448/** @} */
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