VirtualBox

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

Last change on this file since 44124 was 43814, checked in by vboxsync, 12 years ago

PDMUSB: Support attaching virtual USB devices to EHCI.

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