VirtualBox

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

Last change on this file since 27855 was 26970, checked in by vboxsync, 15 years ago

Export code for handling virtual USB devices to OSE, mainly for emulating USB mouse and USB keyboard. This does NOT include support for passing through USB host devices!

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