VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/DrvVUSBRootHub.cpp@ 57037

Last change on this file since 57037 was 56454, checked in by vboxsync, 10 years ago

Commit r100743 and r100913 to trunk which should improve pass through of USB sound devices

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.2 KB
Line 
1/* $Id: DrvVUSBRootHub.cpp 56454 2015-06-16 13:57:21Z vboxsync $ */
2/** @file
3 * Virtual USB - Root Hub Driver.
4 */
5
6/*
7 * Copyright (C) 2005-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_dev_vusb VUSB - Virtual USB
20 *
21 * @todo read thru this and correct typos. Merge with old docs.
22 *
23 *
24 * The Virtual USB component glues USB devices and host controllers together.
25 * The VUSB takes the form of a PDM driver which is attached to the HCI. USB
26 * devices are created by, attached to, and managed by the VUSB roothub. The
27 * VUSB also exposes an interface which is used by Main to attach and detach
28 * proxied USB devices.
29 *
30 *
31 * @section sec_dev_vusb_urb The Life of an URB
32 *
33 * The URB is created when the HCI calls the roothub (VUSB) method pfnNewUrb.
34 * VUSB has a pool of URBs, if no free URBs are available a new one is
35 * allocated. The returned URB starts life in the ALLOCATED state and all
36 * fields are initialized with sensible defaults.
37 *
38 * The HCI then copies any request data into the URB if it's an host2dev
39 * transfer. It then submits the URB by calling the pfnSubmitUrb roothub
40 * method.
41 *
42 * pfnSubmitUrb will start by checking if it knows the device address, and if
43 * it doesn't the URB is completed with a device-not-ready error. When the
44 * device address is known to it, action is taken based on the kind of
45 * transfer it is. There are four kinds of transfers: 1. control, 2. bulk,
46 * 3. interrupt, and 4. isochronous. In either case something eventually ends
47 * up being submitted to the device.
48 *
49 *
50 * If an URB fails submitting, may or may not be completed. This depends on
51 * heuristics in some cases and on the kind of failure in others. If
52 * pfnSubmitUrb returns a failure, the HCI should retry submitting it at a
53 * later time. If pfnSubmitUrb returns success the URB is submitted, and it
54 * can even been completed.
55 *
56 * The URB is in the IN_FLIGHT state from the time it's successfully submitted
57 * and till it's reaped or cancelled.
58 *
59 * When an URB transfer or in some case submit failure occurs, the pfnXferError
60 * callback of the HCI is consulted about what to do. If pfnXferError indicates
61 * that the URB should be retried, pfnSubmitUrb will fail. If it indicates that
62 * it should fail, the URB will be completed.
63 *
64 * Completing an URB means that the URB status is set and the HCI
65 * pfnXferCompletion callback is invoked with the URB. The HCI is the supposed
66 * to report the transfer status to the guest OS. After completion the URB
67 * is freed and returned to the pool, unless it was cancelled. If it was
68 * cancelled it will have to await reaping before it's actually freed.
69 *
70 *
71 * @subsection subsec_dev_vusb_urb_ctrl Control
72 *
73 * The control transfer is the most complex one, from VUSB's point of view,
74 * with its three stages and being bi-directional. A control transfer starts
75 * with a SETUP packet containing the request description and two basic
76 * parameters. It is followed by zero or more DATA packets which either picks
77 * up incoming data (dev2host) or supplies the request data (host2dev). This
78 * can then be followed by a STATUS packet which gets the status of the whole
79 * transfer.
80 *
81 * What makes the control transfer complicated is that for a host2dev request
82 * the URB is assembled from the SETUP and DATA stage, and for a dev2host
83 * request the returned data must be kept around for the DATA stage. For both
84 * transfer directions the status of the transfer has to be kept around for
85 * the STATUS stage.
86 *
87 * To complicate matters further, VUSB must intercept and in some cases emulate
88 * some of the standard requests in order to keep the virtual device state
89 * correct and provide the correct virtualization of a device.
90 *
91 * @subsection subsec_dev_vusb_urb_bulk Bulk and Interrupt
92 *
93 * The bulk and interrupt transfer types are relativly simple compared to the
94 * control transfer. VUSB is not inspecting the request content or anything,
95 * but passes it down the device.
96 *
97 * @subsection subsec_dev_vusb_urb_bulk Isochronous
98 *
99 * This kind of transfers hasn't yet been implemented.
100 *
101 */
102
103
104/** @page pg_dev_vusb_old VUSB - Virtual USB Core
105 *
106 * The virtual USB core is controlled by the roothub and the underlying HCI
107 * emulator, it is responsible for device addressing, managing configurations,
108 * interfaces and endpoints, assembling and splitting multi-part control
109 * messages and in general acts as a middle layer between the USB device
110 * emulation code and USB HCI emulation code.
111 *
112 * All USB devices are represented by a struct vusb_dev. This structure
113 * contains things like the device state, device address, all the configuration
114 * descriptors, the currently selected configuration and a mapping between
115 * endpoint addresses and endpoint descriptors.
116 *
117 * Each vusb_dev also has a pointer to a vusb_dev_ops structure which serves as
118 * the virtual method table and includes a virtual constructor and destructor.
119 * After a vusb_dev is created it may be attached to a hub device such as a
120 * roothub (using vusbHubAttach). Although each hub structure has cPorts
121 * and cDevices fields, it is the responsibility of the hub device to allocate
122 * a free port for the new device.
123 *
124 * Devices can chose one of two interfaces for dealing with requests, the
125 * synchronous interface or the asynchronous interface. The synchronous
126 * interface is much simpler and ought to be used for devices which are
127 * unlikely to sleep for long periods in order to serve requests. The
128 * asynchronous interface on the other hand is more difficult to use but is
129 * useful for the USB proxy or if one were to write a mass storage device
130 * emulator. Currently the synchronous interface only supports control and bulk
131 * endpoints and is no longer used by anything.
132 *
133 * In order to use the asynchronous interface, the queue_urb, cancel_urb and
134 * pfnUrbReap fields must be set in the devices vusb_dev_ops structure. The
135 * queue_urb method is used to submit a request to a device without blocking,
136 * it returns 1 if successful and 0 on any kind of failure. A successfully
137 * queued URB is completed when the pfnUrbReap method returns it. Each function
138 * address is reference counted so that pfnUrbReap will only be called if there
139 * are URBs outstanding. For a roothub to reap an URB from any one of it's
140 * devices, the vusbRhReapAsyncUrbs() function is used.
141 *
142 * There are four types of messages an URB may contain:
143 * -# Control - represents a single packet of a multi-packet control
144 * transfer, these are only really used by the host controller to
145 * submit the parts to the usb core.
146 * -# Message - the usb core assembles multiple control transfers in
147 * to single message transfers. In this case the data buffer
148 * contains the setup packet in little endian followed by the full
149 * buffer. In the case of an host-to-device control message, the
150 * message packet is created when the STATUS transfer is seen. In
151 * the case of device-to-host messages, the message packet is
152 * created after the SETUP transfer is seen. Also, certain control
153 * requests never go the real device and get handled synchronously.
154 * -# Bulk - Currently the only endpoint type that does error checking
155 * and endpoint halting.
156 * -# Interrupt - The only non-periodic type supported.
157 *
158 * Hubs are special cases of devices, they have a number of downstream ports
159 * that other devices can be attached to and removed from.
160 *
161 * After a device has been attached (vusbHubAttach):
162 * -# The hub attach method is called, which sends a hub status
163 * change message to the OS.
164 * -# The OS resets the device, and it appears on the default
165 * address with it's config 0 selected (a pseudo-config that
166 * contains only 1 interface with 1 endpoint - the default
167 * message pipe).
168 * -# The OS assigns the device a new address and selects an
169 * appropriate config.
170 * -# The device is ready.
171 *
172 * After a device has been detached (vusbDevDetach):
173 * -# All pending URBs are cancelled.
174 * -# The devices address is unassigned.
175 * -# The hub detach method is called which signals the OS
176 * of the status change.
177 * -# The OS unlinks the ED's for that device.
178 *
179 * A device can also request detachment from within its own methods by
180 * calling vusbDevUnplugged().
181 *
182 * Roothubs are responsible for driving the whole system, they are special
183 * cases of hubs and as such implement attach and detach methods, each one
184 * is described by a struct vusb_roothub. Once a roothub has submitted an
185 * URB to the USB core, a number of callbacks to the roothub are required
186 * for when the URB completes, since the roothub typically wants to inform
187 * the OS when transfers are completed.
188 *
189 * There are four callbacks to be concerned with:
190 * -# prepare - This is called after the URB is successfully queued.
191 * -# completion - This is called after the URB completed.
192 * -# error - This is called if the URB errored, some systems have
193 * automatic resubmission of failed requests, so this callback
194 * should keep track of the error count and return 1 if the count
195 * is above the number of allowed resubmissions.
196 * -# halt_ep - This is called after errors on bulk pipes in order
197 * to halt the pipe.
198 *
199 */
200
201/*******************************************************************************
202* Header Files *
203*******************************************************************************/
204#define LOG_GROUP LOG_GROUP_DRV_VUSB
205#include <VBox/vmm/pdm.h>
206#include <VBox/vmm/vmapi.h>
207#include <VBox/err.h>
208#include <iprt/alloc.h>
209#include <VBox/log.h>
210#include <iprt/time.h>
211#include <iprt/thread.h>
212#include <iprt/semaphore.h>
213#include <iprt/string.h>
214#include <iprt/assert.h>
215#include <iprt/asm.h>
216#include <iprt/uuid.h>
217#include "VUSBInternal.h"
218#include "VBoxDD.h"
219
220
221
222/**
223 * Attaches a device to a specific hub.
224 *
225 * This function is called by the vusb_add_device() and vusbRhAttachDevice().
226 *
227 * @returns VBox status code.
228 * @param pHub The hub to attach it to.
229 * @param pDev The device to attach.
230 * @thread EMT
231 */
232static int vusbHubAttach(PVUSBHUB pHub, PVUSBDEV pDev)
233{
234 LogFlow(("vusbHubAttach: pHub=%p[%s] pDev=%p[%s]\n", pHub, pHub->pszName, pDev, pDev->pUsbIns->pszName));
235 AssertMsg(pDev->enmState == VUSB_DEVICE_STATE_DETACHED, ("enmState=%d\n", pDev->enmState));
236
237 pDev->pHub = pHub;
238 pDev->enmState = VUSB_DEVICE_STATE_ATTACHED;
239
240 /* noone else ever messes with the default pipe while we are attached */
241 vusbDevMapEndpoint(pDev, &g_Endpoint0);
242 vusbDevDoSelectConfig(pDev, &g_Config0);
243
244 int rc = pHub->pOps->pfnAttach(pHub, pDev);
245 if (RT_FAILURE(rc))
246 {
247 pDev->pHub = NULL;
248 pDev->enmState = VUSB_DEVICE_STATE_DETACHED;
249 }
250 return rc;
251}
252
253
254/* -=-=-=-=-=- PDMUSBHUBREG methods -=-=-=-=-=- */
255
256/** @copydoc PDMUSBHUBREG::pfnAttachDevice */
257static DECLCALLBACK(int) vusbPDMHubAttachDevice(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, const char *pszCaptureFilename, uint32_t *piPort)
258{
259 PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
260
261 /*
262 * Allocate a new VUSB device and initialize it.
263 */
264 PVUSBDEV pDev = (PVUSBDEV)RTMemAllocZ(sizeof(*pDev));
265 AssertReturn(pDev, VERR_NO_MEMORY);
266 int rc = vusbDevInit(pDev, pUsbIns, pszCaptureFilename);
267 if (RT_SUCCESS(rc))
268 {
269 pUsbIns->pvVUsbDev2 = pDev;
270 rc = vusbHubAttach(&pThis->Hub, pDev);
271 if (RT_SUCCESS(rc))
272 {
273 *piPort = UINT32_MAX; ///@todo implement piPort
274 return rc;
275 }
276
277 RTMemFree(pDev->paIfStates);
278 pUsbIns->pvVUsbDev2 = NULL;
279 }
280 RTMemFree(pDev);
281 return rc;
282}
283
284
285/** @copydoc PDMUSBHUBREG::pfnDetachDevice */
286static DECLCALLBACK(int) vusbPDMHubDetachDevice(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, uint32_t iPort)
287{
288 PVUSBDEV pDev = (PVUSBDEV)pUsbIns->pvVUsbDev2;
289 Assert(pDev);
290 vusbDevDestroy(pDev);
291 RTMemFree(pDev);
292 pUsbIns->pvVUsbDev2 = NULL;
293 return VINF_SUCCESS;
294}
295
296/**
297 * The hub registration structure.
298 */
299static const PDMUSBHUBREG g_vusbHubReg =
300{
301 PDM_USBHUBREG_VERSION,
302 vusbPDMHubAttachDevice,
303 vusbPDMHubDetachDevice,
304 PDM_USBHUBREG_VERSION
305};
306
307
308/* -=-=-=-=-=- VUSBIROOTHUBCONNECTOR methods -=-=-=-=-=- */
309
310
311/**
312 * Finds an device attached to a roothub by it's address.
313 *
314 * @returns Pointer to the device.
315 * @returns NULL if not found.
316 * @param pRh Pointer to the root hub.
317 * @param Address The device address.
318 */
319static PVUSBDEV vusbRhFindDevByAddress(PVUSBROOTHUB pRh, uint8_t Address)
320{
321 unsigned iHash = vusbHashAddress(Address);
322 for (PVUSBDEV pDev = pRh->apAddrHash[iHash]; pDev; pDev = pDev->pNextHash)
323 if (pDev->u8Address == Address)
324 return pDev;
325 return NULL;
326}
327
328
329/**
330 * Callback for freeing an URB.
331 * @param pUrb The URB to free.
332 */
333static DECLCALLBACK(void) vusbRhFreeUrb(PVUSBURB pUrb)
334{
335 /*
336 * Assert sanity.
337 */
338 vusbUrbAssert(pUrb);
339 PVUSBROOTHUB pRh = (PVUSBROOTHUB)pUrb->VUsb.pvFreeCtx;
340 Assert(pRh);
341
342 /*
343 * Free the URB description (logging builds only).
344 */
345 if (pUrb->pszDesc)
346 {
347 RTStrFree(pUrb->pszDesc);
348 pUrb->pszDesc = NULL;
349 }
350
351 /*
352 * Put it into the LIFO of free URBs.
353 * (No ppPrev is needed here.)
354 */
355 RTCritSectEnter(&pRh->CritSectFreeUrbs);
356 pUrb->enmState = VUSBURBSTATE_FREE;
357 pUrb->VUsb.ppPrev = NULL;
358 pUrb->VUsb.pNext = pRh->pFreeUrbs;
359 pRh->pFreeUrbs = pUrb;
360 Assert(pRh->pFreeUrbs->enmState == VUSBURBSTATE_FREE);
361 RTCritSectLeave(&pRh->CritSectFreeUrbs);
362}
363
364
365/**
366 * Worker routine for vusbRhConnNewUrb() and vusbDevNewIsocUrb().
367 */
368PVUSBURB vusbRhNewUrb(PVUSBROOTHUB pRh, uint8_t DstAddress, uint32_t cbData, uint32_t cTds)
369{
370 /*
371 * Reuse or allocate a new URB.
372 */
373 /** @todo try find a best fit, MSD which submits rather big URBs intermixed with small control
374 * messages ends up with a 2+ of these big URBs when a single one is sufficient. */
375 /** @todo The allocations should be done by the device, at least as an option, since the devices
376 * frequently wish to associate their own stuff with the in-flight URB or need special buffering
377 * (isochronous on Darwin for instance). */
378 RTCritSectEnter(&pRh->CritSectFreeUrbs);
379 PVUSBURB pUrbPrev = NULL;
380 PVUSBURB pUrb = pRh->pFreeUrbs;
381 while (pUrb)
382 {
383 if ( pUrb->VUsb.cbDataAllocated >= cbData
384 && pUrb->VUsb.cTdsAllocated >= cTds)
385 break;
386 pUrbPrev = pUrb;
387 pUrb = pUrb->VUsb.pNext;
388 }
389 if (pUrb)
390 {
391 if (pUrbPrev)
392 pUrbPrev->VUsb.pNext = pUrb->VUsb.pNext;
393 else
394 pRh->pFreeUrbs = pUrb->VUsb.pNext;
395 Assert(pUrb->u32Magic == VUSBURB_MAGIC);
396 Assert(pUrb->VUsb.pvFreeCtx == pRh);
397 Assert(pUrb->VUsb.pfnFree == vusbRhFreeUrb);
398 Assert(pUrb->enmState == VUSBURBSTATE_FREE);
399 Assert(!pUrb->VUsb.pNext || pUrb->VUsb.pNext->enmState == VUSBURBSTATE_FREE);
400 }
401 else
402 {
403 /* allocate a new one. */
404 uint32_t cbDataAllocated = cbData <= _4K ? RT_ALIGN_32(cbData, _1K)
405 : cbData <= _32K ? RT_ALIGN_32(cbData, _4K)
406 : RT_ALIGN_32(cbData, 16*_1K);
407 uint32_t cTdsAllocated = RT_ALIGN_32(cTds, 16);
408
409 pUrb = (PVUSBURB)RTMemAlloc( RT_OFFSETOF(VUSBURB, abData[cbDataAllocated + 16])
410 + sizeof(pUrb->Hci.paTds[0]) * cTdsAllocated);
411 if (RT_UNLIKELY(!pUrb))
412 {
413 RTCritSectLeave(&pRh->CritSectFreeUrbs);
414 AssertLogRelFailedReturn(NULL);
415 }
416
417 pRh->cUrbsInPool++;
418 pUrb->u32Magic = VUSBURB_MAGIC;
419 pUrb->VUsb.pvFreeCtx = pRh;
420 pUrb->VUsb.pfnFree = vusbRhFreeUrb;
421 pUrb->VUsb.cbDataAllocated = cbDataAllocated;
422 pUrb->VUsb.cTdsAllocated = cTdsAllocated;
423 pUrb->Hci.paTds = (VUSBURB::VUSBURBHCI::VUSBURBHCITD *)(&pUrb->abData[cbDataAllocated + 16]);
424 }
425 RTCritSectLeave(&pRh->CritSectFreeUrbs);
426
427 /*
428 * (Re)init the URB
429 */
430 pUrb->enmState = VUSBURBSTATE_ALLOCATED;
431 pUrb->fCompleting = false;
432 pUrb->pszDesc = NULL;
433 pUrb->VUsb.pNext = NULL;
434 pUrb->VUsb.ppPrev = NULL;
435 pUrb->VUsb.pCtrlUrb = NULL;
436 pUrb->VUsb.u64SubmitTS = 0;
437 pUrb->VUsb.pDev = vusbRhFindDevByAddress(pRh, DstAddress);
438 pUrb->Hci.EdAddr = ~0;
439 pUrb->Hci.cTds = cTds;
440 pUrb->Hci.pNext = NULL;
441 pUrb->Hci.u32FrameNo = 0;
442 pUrb->Hci.fUnlinked = false;
443 pUrb->Dev.pvPrivate = NULL;
444 pUrb->Dev.pNext = NULL;
445 pUrb->pUsbIns = pUrb->VUsb.pDev ? pUrb->VUsb.pDev->pUsbIns : NULL;
446 pUrb->DstAddress = DstAddress;
447 pUrb->EndPt = ~0;
448 pUrb->enmType = VUSBXFERTYPE_INVALID;
449 pUrb->enmDir = VUSBDIRECTION_INVALID;
450 pUrb->fShortNotOk = false;
451 pUrb->enmStatus = VUSBSTATUS_INVALID;
452 pUrb->cbData = cbData;
453 return pUrb;
454}
455
456
457/** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */
458static DECLCALLBACK(PVUSBURB) vusbRhConnNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t cbData, uint32_t cTds)
459{
460 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
461 return vusbRhNewUrb(pRh, DstAddress, cbData, cTds);
462}
463
464
465/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSubmitUrb */
466static DECLCALLBACK(int) vusbRhSubmitUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, PPDMLED pLed)
467{
468 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
469 STAM_PROFILE_START(&pRh->StatSubmitUrb, a);
470
471#ifdef VBOX_WITH_STATISTICS
472 /*
473 * Total and per-type submit statistics.
474 */
475 Assert(pUrb->enmType >= 0 && pUrb->enmType < (int)RT_ELEMENTS(pRh->aTypes));
476 STAM_COUNTER_INC(&pRh->Total.StatUrbsSubmitted);
477 STAM_COUNTER_INC(&pRh->aTypes[pUrb->enmType].StatUrbsSubmitted);
478
479 STAM_COUNTER_ADD(&pRh->Total.StatReqBytes, pUrb->cbData);
480 STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatReqBytes, pUrb->cbData);
481 if (pUrb->enmDir == VUSBDIRECTION_IN)
482 {
483 STAM_COUNTER_ADD(&pRh->Total.StatReqReadBytes, pUrb->cbData);
484 STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatReqReadBytes, pUrb->cbData);
485 }
486 else
487 {
488 STAM_COUNTER_ADD(&pRh->Total.StatReqWriteBytes, pUrb->cbData);
489 STAM_COUNTER_ADD(&pRh->aTypes[pUrb->enmType].StatReqWriteBytes, pUrb->cbData);
490 }
491
492 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
493 {
494 STAM_COUNTER_ADD(&pRh->StatIsocReqPkts, pUrb->cIsocPkts);
495 if (pUrb->enmDir == VUSBDIRECTION_IN)
496 STAM_COUNTER_ADD(&pRh->StatIsocReqReadPkts, pUrb->cIsocPkts);
497 else
498 STAM_COUNTER_ADD(&pRh->StatIsocReqWritePkts, pUrb->cIsocPkts);
499 }
500#endif
501
502 /* If there is a sniffer on the roothub record the URB there. */
503 if (pRh->hSniffer != VUSBSNIFFER_NIL)
504 {
505 int rc = VUSBSnifferRecordEvent(pRh->hSniffer, pUrb, VUSBSNIFFEREVENT_SUBMIT);
506 if (RT_FAILURE(rc))
507 LogRel(("VUSB: Capturing URB submit event on the root hub failed with %Rrc\n", rc));
508 }
509
510 /*
511 * The device was resolved when we allocated the URB.
512 * Submit it to the device if we found it, if not fail with device-not-ready.
513 */
514 int rc;
515 if ( pUrb->VUsb.pDev
516 && pUrb->pUsbIns)
517 {
518 switch (pUrb->enmDir)
519 {
520 case VUSBDIRECTION_IN:
521 pLed->Asserted.s.fReading = pLed->Actual.s.fReading = 1;
522 rc = vusbUrbSubmit(pUrb);
523 pLed->Actual.s.fReading = 0;
524 break;
525 case VUSBDIRECTION_OUT:
526 pLed->Asserted.s.fWriting = pLed->Actual.s.fWriting = 1;
527 rc = vusbUrbSubmit(pUrb);
528 pLed->Actual.s.fWriting = 0;
529 break;
530 default:
531 rc = vusbUrbSubmit(pUrb);
532 break;
533 }
534
535 if (RT_FAILURE(rc))
536 {
537 LogFlow(("vusbRhSubmitUrb: freeing pUrb=%p\n", pUrb));
538 pUrb->VUsb.pfnFree(pUrb);
539 }
540 }
541 else
542 {
543 pUrb->VUsb.pDev = &pRh->Hub.Dev;
544 Log(("vusb: pRh=%p: SUBMIT: Address %i not found!!!\n", pRh, pUrb->DstAddress));
545
546 pUrb->enmState = VUSBURBSTATE_REAPED;
547 pUrb->enmStatus = VUSBSTATUS_DNR;
548 vusbUrbCompletionRh(pUrb);
549 rc = VINF_SUCCESS;
550 }
551
552 STAM_PROFILE_STOP(&pRh->StatSubmitUrb, a);
553 return rc;
554}
555
556
557static DECLCALLBACK(int) vusbRhReapAsyncUrbsWorker(PVUSBDEV pDev, RTMSINTERVAL cMillies)
558{
559 if (!cMillies)
560 vusbUrbDoReapAsync(pDev->pAsyncUrbHead, 0);
561 else
562 {
563 uint64_t u64Start = RTTimeMilliTS();
564 do
565 {
566 vusbUrbDoReapAsync(pDev->pAsyncUrbHead, RT_MIN(cMillies >> 8, 10));
567 } while ( pDev->pAsyncUrbHead
568 && RTTimeMilliTS() - u64Start < cMillies);
569 }
570
571 return VINF_SUCCESS;
572}
573
574/** @copydoc VUSBIROOTHUBCONNECTOR::pfnReapAsyncUrbs */
575static DECLCALLBACK(void) vusbRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, RTMSINTERVAL cMillies)
576{
577 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
578 PVUSBDEV pDev = (PVUSBDEV)pDevice;
579
580 if (!pDev->pAsyncUrbHead)
581 return;
582
583 STAM_PROFILE_START(&pRh->StatReapAsyncUrbs, a);
584 int rc = vusbDevIoThreadExecSync(pDev, (PFNRT)vusbRhReapAsyncUrbsWorker, 2, pDev, cMillies);
585 AssertRC(rc);
586 STAM_PROFILE_STOP(&pRh->StatReapAsyncUrbs, a);
587}
588
589
590/** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelUrbsEp */
591static DECLCALLBACK(int) vusbRhCancelUrbsEp(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)
592{
593 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
594 AssertReturn(pRh, VERR_INVALID_PARAMETER);
595 AssertReturn(pUrb, VERR_INVALID_PARAMETER);
596
597 //@todo: This method of URB canceling may not work on non-Linux hosts.
598 /*
599 * Cancel and reap the URB(s) on an endpoint.
600 */
601 LogFlow(("vusbRhCancelUrbsEp: pRh=%p pUrb=%p\n", pRh, pUrb));
602
603 vusbUrbCancelAsync(pUrb, CANCELMODE_UNDO);
604
605 /* The reaper thread will take care of completing the URB. */
606
607 return VINF_SUCCESS;
608}
609
610/**
611 * Worker doing the actual cancelling of all outstanding URBs on the device I/O thread.
612 *
613 * @returns VBox status code.
614 * @param pDev USB device instance data.
615 */
616static DECLCALLBACK(int) vusbRhCancelAllUrbsWorker(PVUSBDEV pDev)
617{
618 /*
619 * Cancel the URBS.
620 *
621 * Not using th CritAsyncUrbs critical section here is safe
622 * as the I/O thread is the only thread accessing this struture at the
623 * moment.
624 */
625 PVUSBURB pUrb = pDev->pAsyncUrbHead;
626
627 while (pUrb)
628 {
629 PVUSBURB pNext = pUrb->VUsb.pNext;
630 /* Call the worker directly. */
631 vusbUrbCancelWorker(pUrb, CANCELMODE_FAIL);
632 pUrb = pNext;
633 }
634
635 return VINF_SUCCESS;
636}
637
638/** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelAllUrbs */
639static DECLCALLBACK(void) vusbRhCancelAllUrbs(PVUSBIROOTHUBCONNECTOR pInterface)
640{
641 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
642
643 RTCritSectEnter(&pRh->CritSectDevices);
644 PVUSBDEV pDev = pRh->pDevices;
645 while (pDev)
646 {
647 vusbDevIoThreadExecSync(pDev, (PFNRT)vusbRhCancelAllUrbsWorker, 1, pDev);
648 pDev = pDev->pNext;
649 }
650 RTCritSectLeave(&pRh->CritSectDevices);
651}
652
653/**
654 * Worker doing the actual cancelling of all outstanding per-EP URBs on the
655 * device I/O thread.
656 *
657 * @returns VBox status code.
658 * @param pDev USB device instance data.
659 * @param EndPt Endpoint number.
660 * @param enmDir Endpoint direction.
661 */
662static DECLCALLBACK(int) vusbRhAbortEpWorker(PVUSBDEV pDev, int EndPt, VUSBDIRECTION enmDir)
663{
664 /*
665 * Iterate the URBs, find ones corresponding to given EP, and cancel them.
666 */
667 PVUSBURB pUrb = pDev->pAsyncUrbHead;
668 while (pUrb)
669 {
670 PVUSBURB pNext = pUrb->VUsb.pNext;
671
672 Assert(pUrb->VUsb.pDev == pDev);
673
674 if (pUrb->EndPt == EndPt && pUrb->enmDir == enmDir)
675 {
676 LogFlow(("%s: vusbRhAbortEpWorker: CANCELING URB\n", pUrb->pszDesc));
677 int rc = vusbUrbCancelWorker(pUrb, CANCELMODE_UNDO);
678 AssertRC(rc);
679 }
680 pUrb = pNext;
681 }
682
683 return VINF_SUCCESS;
684}
685
686
687/** @copydoc VUSBIROOTHUBCONNECTOR::pfnAbortEp */
688static DECLCALLBACK(int) vusbRhAbortEp(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice, int EndPt, VUSBDIRECTION enmDir)
689{
690 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
691 if (&pRh->Hub != ((PVUSBDEV)pDevice)->pHub)
692 AssertFailedReturn(VERR_INVALID_PARAMETER);
693
694 RTCritSectEnter(&pRh->CritSectDevices);
695 PVUSBDEV pDev = (PVUSBDEV)pDevice;
696 vusbDevIoThreadExecSync(pDev, (PFNRT)vusbRhAbortEpWorker, 3, pDev, EndPt, enmDir);
697 RTCritSectLeave(&pRh->CritSectDevices);
698
699 /* The reaper thread will take care of completing the URB. */
700
701 return VINF_SUCCESS;
702}
703
704
705/** @copydoc VUSBIROOTHUBCONNECTOR::pfnAttachDevice */
706static DECLCALLBACK(int) vusbRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
707{
708 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
709 return vusbHubAttach(&pRh->Hub, (PVUSBDEV)pDevice);
710}
711
712
713/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDetachDevice */
714static DECLCALLBACK(int) vusbRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
715{
716 PVUSBROOTHUB pRh = VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface);
717 if (&pRh->Hub != ((PVUSBDEV)pDevice)->pHub)
718 AssertFailedReturn(VERR_INVALID_PARAMETER);
719 return vusbDevDetach((PVUSBDEV)pDevice);
720}
721
722
723/* -=-=-=-=-=- VUSB Device methods (for the root hub) -=-=-=-=-=- */
724
725
726/**
727 * @copydoc VUSBIDEVICE::pfnReset
728 */
729static DECLCALLBACK(int) vusbRhDevReset(PVUSBIDEVICE pInterface, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
730{
731 PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
732 Assert(!pfnDone);
733 return pRh->pIRhPort->pfnReset(pRh->pIRhPort, fResetOnLinux); /** @todo change rc from bool to vbox status everywhere! */
734}
735
736
737/**
738 * @copydoc VUSBIDEVICE::pfnPowerOn
739 */
740static DECLCALLBACK(int) vusbRhDevPowerOn(PVUSBIDEVICE pInterface)
741{
742 PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
743 LogFlow(("vusbRhDevPowerOn: pRh=%p\n", pRh));
744
745 Assert( pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_DETACHED
746 && pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_RESET);
747
748 if (pRh->Hub.Dev.enmState == VUSB_DEVICE_STATE_ATTACHED)
749 pRh->Hub.Dev.enmState = VUSB_DEVICE_STATE_POWERED;
750
751 return VINF_SUCCESS;
752}
753
754
755/**
756 * @copydoc VUSBIDEVICE::pfnPowerOff
757 */
758static DECLCALLBACK(int) vusbRhDevPowerOff(PVUSBIDEVICE pInterface)
759{
760 PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
761 LogFlow(("vusbRhDevPowerOff: pRh=%p\n", pRh));
762
763 Assert( pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_DETACHED
764 && pRh->Hub.Dev.enmState != VUSB_DEVICE_STATE_RESET);
765
766 /*
767 * Cancel all URBs and reap them.
768 */
769 VUSBIRhCancelAllUrbs(&pRh->IRhConnector);
770 RTCritSectEnter(&pRh->CritSectDevices);
771 PVUSBDEV pDev = pRh->pDevices;
772 while (pDev)
773 {
774 VUSBIRhReapAsyncUrbs(&pRh->IRhConnector, (PVUSBIDEVICE)pDev, 0);
775 pDev = pDev->pNext;
776 }
777 RTCritSectLeave(&pRh->CritSectDevices);
778
779 pRh->Hub.Dev.enmState = VUSB_DEVICE_STATE_ATTACHED;
780 return VINF_SUCCESS;
781}
782
783/**
784 * @copydoc VUSBIDEVICE::pfnGetState
785 */
786DECLCALLBACK(VUSBDEVICESTATE) vusbRhDevGetState(PVUSBIDEVICE pInterface)
787{
788 PVUSBROOTHUB pRh = RT_FROM_MEMBER(pInterface, VUSBROOTHUB, Hub.Dev.IDevice);
789 return pRh->Hub.Dev.enmState;
790}
791
792
793
794
795/* -=-=-=-=-=- VUSB Hub methods -=-=-=-=-=- */
796
797
798/**
799 * Attach the device to the hub.
800 * Port assignments and all such stuff is up to this routine.
801 *
802 * @returns VBox status code.
803 * @param pHub Pointer to the hub.
804 * @param pDev Pointer to the device.
805 */
806static int vusbRhHubOpAttach(PVUSBHUB pHub, PVUSBDEV pDev)
807{
808 PVUSBROOTHUB pRh = (PVUSBROOTHUB)pHub;
809
810 /*
811 * Assign a port.
812 */
813 int iPort = ASMBitFirstSet(&pRh->Bitmap, sizeof(pRh->Bitmap) * 8);
814 if (iPort < 0)
815 {
816 LogRel(("VUSB: No ports available!\n"));
817 return VERR_VUSB_NO_PORTS;
818 }
819 ASMBitClear(&pRh->Bitmap, iPort);
820 pHub->cDevices++;
821 pDev->i16Port = iPort;
822
823 /*
824 * Call the HCI attach routine and let it have its say before the device is
825 * linked into the device list of this hub.
826 */
827 int rc = pRh->pIRhPort->pfnAttach(pRh->pIRhPort, &pDev->IDevice, iPort);
828 if (RT_SUCCESS(rc))
829 {
830 RTCritSectEnter(&pRh->CritSectDevices);
831 pDev->pNext = pRh->pDevices;
832 pRh->pDevices = pDev;
833 RTCritSectLeave(&pRh->CritSectDevices);
834 LogRel(("VUSB: Attached '%s' to port %d\n", pDev->pUsbIns->pszName, iPort));
835 }
836 else
837 {
838 ASMBitSet(&pRh->Bitmap, iPort);
839 pHub->cDevices--;
840 pDev->i16Port = -1;
841 LogRel(("VUSB: Failed to attach '%s' to port %d, rc=%Rrc\n", pDev->pUsbIns->pszName, iPort, rc));
842 }
843 return rc;
844}
845
846
847/**
848 * Detach the device from the hub.
849 *
850 * @returns VBox status code.
851 * @param pHub Pointer to the hub.
852 * @param pDev Pointer to the device.
853 */
854static void vusbRhHubOpDetach(PVUSBHUB pHub, PVUSBDEV pDev)
855{
856 PVUSBROOTHUB pRh = (PVUSBROOTHUB)pHub;
857 Assert(pDev->i16Port != -1);
858
859 /*
860 * Check that it's attached and unlink it from the linked list.
861 */
862 RTCritSectEnter(&pRh->CritSectDevices);
863 if (pRh->pDevices != pDev)
864 {
865 PVUSBDEV pPrev = pRh->pDevices;
866 while (pPrev && pPrev->pNext != pDev)
867 pPrev = pPrev->pNext;
868 Assert(pPrev);
869 pPrev->pNext = pDev->pNext;
870 }
871 else
872 pRh->pDevices = pDev->pNext;
873 pDev->pNext = NULL;
874 RTCritSectLeave(&pRh->CritSectDevices);
875
876 /*
877 * Detach the device and mark the port as available.
878 */
879 unsigned uPort = pDev->i16Port;
880 pRh->pIRhPort->pfnDetach(pRh->pIRhPort, &pDev->IDevice, uPort);
881 LogRel(("VUSB: Detached '%s' from port %u\n", pDev->pUsbIns->pszName, uPort));
882 ASMBitSet(&pRh->Bitmap, uPort);
883 pHub->cDevices--;
884}
885
886
887/**
888 * The Hub methods implemented by the root hub.
889 */
890static const VUSBHUBOPS s_VUsbRhHubOps =
891{
892 vusbRhHubOpAttach,
893 vusbRhHubOpDetach
894};
895
896
897
898/* -=-=-=-=-=- PDM Base interface methods -=-=-=-=-=- */
899
900
901/**
902 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
903 */
904static DECLCALLBACK(void *) vusbRhQueryInterface(PPDMIBASE pInterface, const char *pszIID)
905{
906 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
907 PVUSBROOTHUB pRh = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
908
909 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
910 PDMIBASE_RETURN_INTERFACE(pszIID, VUSBIROOTHUBCONNECTOR, &pRh->IRhConnector);
911 PDMIBASE_RETURN_INTERFACE(pszIID, VUSBIDEVICE, &pRh->Hub.Dev.IDevice);
912 return NULL;
913}
914
915
916/* -=-=-=-=-=- PDM Driver methods -=-=-=-=-=- */
917
918
919/**
920 * Destruct a driver instance.
921 *
922 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
923 * resources can be freed correctly.
924 *
925 * @param pDrvIns The driver instance data.
926 */
927static DECLCALLBACK(void) vusbRhDestruct(PPDMDRVINS pDrvIns)
928{
929 PVUSBROOTHUB pRh = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
930 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
931
932 /*
933 * Free all URBs.
934 */
935 while (pRh->pFreeUrbs)
936 {
937 PVUSBURB pUrb = pRh->pFreeUrbs;
938 pRh->pFreeUrbs = pUrb->VUsb.pNext;
939
940 pUrb->u32Magic = 0;
941 pUrb->enmState = VUSBURBSTATE_INVALID;
942 pUrb->VUsb.pNext = NULL;
943 RTMemFree(pUrb);
944 }
945 if (pRh->Hub.pszName)
946 {
947 RTStrFree(pRh->Hub.pszName);
948 pRh->Hub.pszName = NULL;
949 }
950 if (pRh->hSniffer != VUSBSNIFFER_NIL)
951 VUSBSnifferDestroy(pRh->hSniffer);
952 RTCritSectDelete(&pRh->CritSectDevices);
953 RTCritSectDelete(&pRh->CritSectFreeUrbs);
954}
955
956
957/**
958 * Construct a root hub driver instance.
959 *
960 * @copydoc FNPDMDRVCONSTRUCT
961 */
962static DECLCALLBACK(int) vusbRhConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
963{
964 LogFlow(("vusbRhConstruct: Instance %d\n", pDrvIns->iInstance));
965 PVUSBROOTHUB pThis = PDMINS_2_DATA(pDrvIns, PVUSBROOTHUB);
966 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
967
968 /*
969 * Validate configuration.
970 */
971 if (!CFGMR3AreValuesValid(pCfg, "CaptureFilename\0"))
972 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
973
974 /*
975 * Check that there are no drivers below us.
976 */
977 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
978 ("Configuration error: Not possible to attach anything to this driver!\n"),
979 VERR_PDM_DRVINS_NO_ATTACH);
980
981 /*
982 * Initialize the critical sections.
983 */
984 int rc = RTCritSectInit(&pThis->CritSectDevices);
985 if (RT_FAILURE(rc))
986 return rc;
987
988 rc = RTCritSectInit(&pThis->CritSectFreeUrbs);
989 if (RT_FAILURE(rc))
990 return rc;
991
992 char *pszCaptureFilename = NULL;
993 rc = CFGMR3QueryStringAlloc(pCfg, "CaptureFilename", &pszCaptureFilename);
994 if ( RT_FAILURE(rc)
995 && rc != VERR_CFGM_VALUE_NOT_FOUND)
996 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
997 N_("Configuration error: Failed to query value of \"CaptureFilename\""));
998
999 /*
1000 * Initialize the data members.
1001 */
1002 pDrvIns->IBase.pfnQueryInterface = vusbRhQueryInterface;
1003 /* the usb device */
1004 pThis->Hub.Dev.enmState = VUSB_DEVICE_STATE_ATTACHED;
1005 pThis->Hub.Dev.u8Address = VUSB_INVALID_ADDRESS;
1006 pThis->Hub.Dev.u8NewAddress = VUSB_INVALID_ADDRESS;
1007 pThis->Hub.Dev.i16Port = -1;
1008 pThis->Hub.Dev.IDevice.pfnReset = vusbRhDevReset;
1009 pThis->Hub.Dev.IDevice.pfnPowerOn = vusbRhDevPowerOn;
1010 pThis->Hub.Dev.IDevice.pfnPowerOff = vusbRhDevPowerOff;
1011 pThis->Hub.Dev.IDevice.pfnGetState = vusbRhDevGetState;
1012 /* the hub */
1013 pThis->Hub.pOps = &s_VUsbRhHubOps;
1014 pThis->Hub.pRootHub = pThis;
1015 //pThis->hub.cPorts - later
1016 pThis->Hub.cDevices = 0;
1017 pThis->Hub.Dev.pHub = &pThis->Hub;
1018 RTStrAPrintf(&pThis->Hub.pszName, "RootHub#%d", pDrvIns->iInstance);
1019 /* misc */
1020 pThis->pDrvIns = pDrvIns;
1021 /* the connector */
1022 pThis->IRhConnector.pfnNewUrb = vusbRhConnNewUrb;
1023 pThis->IRhConnector.pfnSubmitUrb = vusbRhSubmitUrb;
1024 pThis->IRhConnector.pfnReapAsyncUrbs= vusbRhReapAsyncUrbs;
1025 pThis->IRhConnector.pfnCancelUrbsEp = vusbRhCancelUrbsEp;
1026 pThis->IRhConnector.pfnCancelAllUrbs= vusbRhCancelAllUrbs;
1027 pThis->IRhConnector.pfnAbortEp = vusbRhAbortEp;
1028 pThis->IRhConnector.pfnAttachDevice = vusbRhAttachDevice;
1029 pThis->IRhConnector.pfnDetachDevice = vusbRhDetachDevice;
1030 pThis->hSniffer = VUSBSNIFFER_NIL;
1031 /*
1032 * Resolve interface(s).
1033 */
1034 pThis->pIRhPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, VUSBIROOTHUBPORT);
1035 AssertMsgReturn(pThis->pIRhPort, ("Configuration error: the device/driver above us doesn't expose any VUSBIROOTHUBPORT interface!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
1036
1037 /*
1038 * Get number of ports and the availability bitmap.
1039 * ASSUME that the number of ports reported now at creation time is the max number.
1040 */
1041 pThis->Hub.cPorts = pThis->pIRhPort->pfnGetAvailablePorts(pThis->pIRhPort, &pThis->Bitmap);
1042 Log(("vusbRhConstruct: cPorts=%d\n", pThis->Hub.cPorts));
1043
1044 /*
1045 * Get the USB version of the attached HC.
1046 * ASSUME that version 2.0 implies high-speed.
1047 */
1048 pThis->fHcVersions = pThis->pIRhPort->pfnGetUSBVersions(pThis->pIRhPort);
1049 Log(("vusbRhConstruct: fHcVersions=%u\n", pThis->fHcVersions));
1050
1051 if (pszCaptureFilename)
1052 {
1053 rc = VUSBSnifferCreate(&pThis->hSniffer, 0, pszCaptureFilename, NULL);
1054 if (RT_FAILURE(rc))
1055 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1056 N_("VUSBSniffer cannot open '%s' for writing. The directory must exist and it must be writable for the current user"),
1057 pszCaptureFilename);
1058
1059 MMR3HeapFree(pszCaptureFilename);
1060 }
1061
1062 /*
1063 * Register ourselves as a USB hub.
1064 * The current implementation uses the VUSBIRHCONFIG interface for communication.
1065 */
1066 PCPDMUSBHUBHLP pHlp; /* not used currently */
1067 rc = PDMDrvHlpUSBRegisterHub(pDrvIns, pThis->fHcVersions, pThis->Hub.cPorts, &g_vusbHubReg, &pHlp);
1068 if (RT_FAILURE(rc))
1069 return rc;
1070
1071 /*
1072 * Statistics. (It requires a 30" monitor or extremely tiny fonts to edit this "table".)
1073 */
1074#ifdef VBOX_WITH_STATISTICS
1075 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "The number of URBs submitted.", "/VUSB/%d/UrbsSubmitted", pDrvIns->iInstance);
1076 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Bulk transfer.", "/VUSB/%d/UrbsSubmitted/Bulk", pDrvIns->iInstance);
1077 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Control transfer.", "/VUSB/%d/UrbsSubmitted/Ctrl", pDrvIns->iInstance);
1078 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Interrupt transfer.", "/VUSB/%d/UrbsSubmitted/Intr", pDrvIns->iInstance);
1079 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Isochronous transfer.", "/VUSB/%d/UrbsSubmitted/Isoc", pDrvIns->iInstance);
1080
1081 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "The number of URBs cancelled. (included in failed)", "/VUSB/%d/UrbsCancelled", pDrvIns->iInstance);
1082 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Bulk transfer.", "/VUSB/%d/UrbsCancelled/Bulk", pDrvIns->iInstance);
1083 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Control transfer.", "/VUSB/%d/UrbsCancelled/Ctrl", pDrvIns->iInstance);
1084 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Interrupt transfer.", "/VUSB/%d/UrbsCancelled/Intr", pDrvIns->iInstance);
1085 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Isochronous transfer.", "/VUSB/%d/UrbsCancelled/Isoc", pDrvIns->iInstance);
1086
1087 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "The number of URBs failing.", "/VUSB/%d/UrbsFailed", pDrvIns->iInstance);
1088 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Bulk transfer.", "/VUSB/%d/UrbsFailed/Bulk", pDrvIns->iInstance);
1089 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Control transfer.", "/VUSB/%d/UrbsFailed/Ctrl", pDrvIns->iInstance);
1090 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Interrupt transfer.", "/VUSB/%d/UrbsFailed/Intr", pDrvIns->iInstance);
1091 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Isochronous transfer.", "/VUSB/%d/UrbsFailed/Isoc", pDrvIns->iInstance);
1092
1093 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total requested transfer.", "/VUSB/%d/ReqBytes", pDrvIns->iInstance);
1094 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Bulk transfer.", "/VUSB/%d/ReqBytes/Bulk", pDrvIns->iInstance);
1095 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Control transfer.", "/VUSB/%d/ReqBytes/Ctrl", pDrvIns->iInstance);
1096 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Interrupt transfer.", "/VUSB/%d/ReqBytes/Intr", pDrvIns->iInstance);
1097 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Isochronous transfer.", "/VUSB/%d/ReqBytes/Isoc", pDrvIns->iInstance);
1098
1099 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total requested read transfer.", "/VUSB/%d/ReqReadBytes", pDrvIns->iInstance);
1100 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Bulk transfer.", "/VUSB/%d/ReqReadBytes/Bulk", pDrvIns->iInstance);
1101 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Control transfer.", "/VUSB/%d/ReqReadBytes/Ctrl", pDrvIns->iInstance);
1102 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Interrupt transfer.", "/VUSB/%d/ReqReadBytes/Intr", pDrvIns->iInstance);
1103 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Isochronous transfer.", "/VUSB/%d/ReqReadBytes/Isoc", pDrvIns->iInstance);
1104
1105 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total requested write transfer.", "/VUSB/%d/ReqWriteBytes", pDrvIns->iInstance);
1106 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Bulk transfer.", "/VUSB/%d/ReqWriteBytes/Bulk", pDrvIns->iInstance);
1107 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Control transfer.", "/VUSB/%d/ReqWriteBytes/Ctrl", pDrvIns->iInstance);
1108 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Interrupt transfer.", "/VUSB/%d/ReqWriteBytes/Intr", pDrvIns->iInstance);
1109 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Isochronous transfer.", "/VUSB/%d/ReqWriteBytes/Isoc", pDrvIns->iInstance);
1110
1111 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Actual total transfer.", "/VUSB/%d/ActBytes", pDrvIns->iInstance);
1112 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Bulk transfer.", "/VUSB/%d/ActBytes/Bulk", pDrvIns->iInstance);
1113 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Control transfer.", "/VUSB/%d/ActBytes/Ctrl", pDrvIns->iInstance);
1114 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Interrupt transfer.", "/VUSB/%d/ActBytes/Intr", pDrvIns->iInstance);
1115 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Isochronous transfer.", "/VUSB/%d/ActBytes/Isoc", pDrvIns->iInstance);
1116
1117 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Actual total read transfer.", "/VUSB/%d/ActReadBytes", pDrvIns->iInstance);
1118 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Bulk transfer.", "/VUSB/%d/ActReadBytes/Bulk", pDrvIns->iInstance);
1119 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Control transfer.", "/VUSB/%d/ActReadBytes/Ctrl", pDrvIns->iInstance);
1120 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Interrupt transfer.", "/VUSB/%d/ActReadBytes/Intr", pDrvIns->iInstance);
1121 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Isochronous transfer.", "/VUSB/%d/ActReadBytes/Isoc", pDrvIns->iInstance);
1122
1123 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->Total.StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Actual total write transfer.", "/VUSB/%d/ActWriteBytes", pDrvIns->iInstance);
1124 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Bulk transfer.", "/VUSB/%d/ActWriteBytes/Bulk", pDrvIns->iInstance);
1125 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Control transfer.", "/VUSB/%d/ActWriteBytes/Ctrl", pDrvIns->iInstance);
1126 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Interrupt transfer.", "/VUSB/%d/ActWriteBytes/Intr", pDrvIns->iInstance);
1127 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Isochronous transfer.", "/VUSB/%d/ActWriteBytes/Isoc", pDrvIns->iInstance);
1128
1129 /* bulk */
1130 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of submitted URBs.", "/VUSB/%d/Bulk/Urbs", pDrvIns->iInstance);
1131 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of failed URBs.", "/VUSB/%d/Bulk/UrbsFailed", pDrvIns->iInstance);
1132 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of cancelled URBs.", "/VUSB/%d/Bulk/UrbsFailed/Cancelled", pDrvIns->iInstance);
1133 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of bytes transferred.", "/VUSB/%d/Bulk/ActBytes", pDrvIns->iInstance);
1134 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Bulk/ActBytes/Read", pDrvIns->iInstance);
1135 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Bulk/ActBytes/Write", pDrvIns->iInstance);
1136 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Requested number of bytes.", "/VUSB/%d/Bulk/ReqBytes", pDrvIns->iInstance);
1137 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Bulk/ReqBytes/Read", pDrvIns->iInstance);
1138 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_BULK].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Bulk/ReqBytes/Write", pDrvIns->iInstance);
1139
1140 /* control */
1141 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of submitted URBs.", "/VUSB/%d/Ctrl/Urbs", pDrvIns->iInstance);
1142 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of failed URBs.", "/VUSB/%d/Ctrl/UrbsFailed", pDrvIns->iInstance);
1143 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of cancelled URBs.", "/VUSB/%d/Ctrl/UrbsFailed/Cancelled", pDrvIns->iInstance);
1144 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of bytes transferred.", "/VUSB/%d/Ctrl/ActBytes", pDrvIns->iInstance);
1145 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Ctrl/ActBytes/Read", pDrvIns->iInstance);
1146 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Ctrl/ActBytes/Write", pDrvIns->iInstance);
1147 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Requested number of bytes.", "/VUSB/%d/Ctrl/ReqBytes", pDrvIns->iInstance);
1148 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Ctrl/ReqBytes/Read", pDrvIns->iInstance);
1149 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_CTRL].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Ctrl/ReqBytes/Write", pDrvIns->iInstance);
1150
1151 /* interrupt */
1152 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of submitted URBs.", "/VUSB/%d/Intr/Urbs", pDrvIns->iInstance);
1153 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of failed URBs.", "/VUSB/%d/Intr/UrbsFailed", pDrvIns->iInstance);
1154 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of cancelled URBs.", "/VUSB/%d/Intr/UrbsFailed/Cancelled", pDrvIns->iInstance);
1155 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of bytes transferred.", "/VUSB/%d/Intr/ActBytes", pDrvIns->iInstance);
1156 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Intr/ActBytes/Read", pDrvIns->iInstance);
1157 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Intr/ActBytes/Write", pDrvIns->iInstance);
1158 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Requested number of bytes.", "/VUSB/%d/Intr/ReqBytes", pDrvIns->iInstance);
1159 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Intr/ReqBytes/Read", pDrvIns->iInstance);
1160 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_INTR].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Intr/ReqBytes/Write", pDrvIns->iInstance);
1161
1162 /* isochronous */
1163 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatUrbsSubmitted, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of submitted URBs.", "/VUSB/%d/Isoc/Urbs", pDrvIns->iInstance);
1164 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatUrbsFailed, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of failed URBs.", "/VUSB/%d/Isoc/UrbsFailed", pDrvIns->iInstance);
1165 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatUrbsCancelled, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of cancelled URBs.", "/VUSB/%d/Isoc/UrbsFailed/Cancelled", pDrvIns->iInstance);
1166 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatActBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of bytes transferred.", "/VUSB/%d/Isoc/ActBytes", pDrvIns->iInstance);
1167 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatActReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Isoc/ActBytes/Read", pDrvIns->iInstance);
1168 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatActWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Isoc/ActBytes/Write", pDrvIns->iInstance);
1169 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatReqBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Requested number of bytes.", "/VUSB/%d/Isoc/ReqBytes", pDrvIns->iInstance);
1170 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatReqReadBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Read.", "/VUSB/%d/Isoc/ReqBytes/Read", pDrvIns->iInstance);
1171 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aTypes[VUSBXFERTYPE_ISOC].StatReqWriteBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Write.", "/VUSB/%d/Isoc/ReqBytes/Write", pDrvIns->iInstance);
1172 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatIsocActPkts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of isochronous packets returning data.", "/VUSB/%d/Isoc/ActPkts", pDrvIns->iInstance);
1173 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatIsocActReadPkts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Read.", "/VUSB/%d/Isoc/ActPkts/Read", pDrvIns->iInstance);
1174 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatIsocActWritePkts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Write.", "/VUSB/%d/Isoc/ActPkts/Write", pDrvIns->iInstance);
1175 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatIsocReqPkts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Requested number of isochronous packets.", "/VUSB/%d/Isoc/ReqPkts", pDrvIns->iInstance);
1176 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatIsocReqReadPkts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Read.", "/VUSB/%d/Isoc/ReqPkts/Read", pDrvIns->iInstance);
1177 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatIsocReqWritePkts, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Write.", "/VUSB/%d/Isoc/ReqPkts/Write", pDrvIns->iInstance);
1178
1179 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aStatIsocDetails); i++)
1180 {
1181 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].Pkts, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d", pDrvIns->iInstance, i);
1182 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].Ok, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/Ok", pDrvIns->iInstance, i);
1183 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].Ok0, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/Ok0", pDrvIns->iInstance, i);
1184 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].DataUnderrun, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/DataUnderrun", pDrvIns->iInstance, i);
1185 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].DataUnderrun0, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/DataUnderrun0", pDrvIns->iInstance, i);
1186 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].DataOverrun, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/DataOverrun", pDrvIns->iInstance, i);
1187 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].NotAccessed, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/NotAccessed", pDrvIns->iInstance, i);
1188 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].Misc, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_COUNT, ".", "/VUSB/%d/Isoc/%d/Misc", pDrvIns->iInstance, i);
1189 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->aStatIsocDetails[i].Bytes, STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_BYTES, ".", "/VUSB/%d/Isoc/%d/Bytes", pDrvIns->iInstance, i);
1190 }
1191
1192 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReapAsyncUrbs, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Profiling the vusbRhReapAsyncUrbs body (omitting calls when nothing is in-flight).", "/VUSB/%d/ReapAsyncUrbs", pDrvIns->iInstance);
1193 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatSubmitUrb, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Profiling the vusbRhSubmitUrb body.", "/VUSB/%d/SubmitUrb", pDrvIns->iInstance);
1194#endif
1195 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->cUrbsInPool, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "The number of URBs in the pool.", "/VUSB/%d/cUrbsInPool", pDrvIns->iInstance);
1196
1197 return VINF_SUCCESS;
1198}
1199
1200
1201/**
1202 * VUSB Root Hub driver registration record.
1203 */
1204const PDMDRVREG g_DrvVUSBRootHub =
1205{
1206 /* u32Version */
1207 PDM_DRVREG_VERSION,
1208 /* szName */
1209 "VUSBRootHub",
1210 /* szRCMod */
1211 "",
1212 /* szR0Mod */
1213 "",
1214 /* pszDescription */
1215 "VUSB Root Hub Driver.",
1216 /* fFlags */
1217 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1218 /* fClass. */
1219 PDM_DRVREG_CLASS_USB,
1220 /* cMaxInstances */
1221 ~0U,
1222 /* cbInstance */
1223 sizeof(VUSBROOTHUB),
1224 /* pfnConstruct */
1225 vusbRhConstruct,
1226 /* pfnDestruct */
1227 vusbRhDestruct,
1228 /* pfnRelocate */
1229 NULL,
1230 /* pfnIOCtl */
1231 NULL,
1232 /* pfnPowerOn */
1233 NULL,
1234 /* pfnReset */
1235 NULL,
1236 /* pfnSuspend */
1237 NULL,
1238 /* pfnResume */
1239 NULL,
1240 /* pfnAttach */
1241 NULL,
1242 /* pfnDetach */
1243 NULL,
1244 /* pfnPowerOff */
1245 NULL,
1246 /* pfnSoftReset */
1247 NULL,
1248 /* u32EndVersion */
1249 PDM_DRVREG_VERSION
1250};
1251
1252/*
1253 * Local Variables:
1254 * mode: c
1255 * c-file-style: "bsd"
1256 * c-basic-offset: 4
1257 * tab-width: 4
1258 * indent-tabs-mode: s
1259 * End:
1260 */
1261
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