VirtualBox

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

最後變更 在這個檔案從26970是 26970,由 vboxsync 提交於 15 年 前

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!

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 49.9 KB
 
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/** @} */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette