summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/USB/VUSBInternal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/USB/VUSBInternal.h')
-rw-r--r--src/VBox/Devices/USB/VUSBInternal.h742
1 files changed, 742 insertions, 0 deletions
diff --git a/src/VBox/Devices/USB/VUSBInternal.h b/src/VBox/Devices/USB/VUSBInternal.h
new file mode 100644
index 00000000..d4ac13b7
--- /dev/null
+++ b/src/VBox/Devices/USB/VUSBInternal.h
@@ -0,0 +1,742 @@
+/* $Id: VUSBInternal.h $ */
+/** @file
+ * Virtual USB - Internal header.
+ *
+ * This subsystem implements USB devices in a host controller independent
+ * way. All the host controller code has to do is use VUSBROOTHUB for its
+ * root hub implementation and any emulated USB device may be plugged into
+ * the virtual bus.
+ */
+
+/*
+ * Copyright (C) 2006-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#ifndef VBOX_INCLUDED_SRC_USB_VUSBInternal_h
+#define VBOX_INCLUDED_SRC_USB_VUSBInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <VBox/vusb.h>
+#include <VBox/vmm/stam.h>
+#include <VBox/vmm/pdm.h>
+#include <VBox/vmm/vmapi.h>
+#include <VBox/vmm/pdmusb.h>
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/req.h>
+#include <iprt/asm.h>
+#include <iprt/list.h>
+
+#include "VUSBSniffer.h"
+
+RT_C_DECLS_BEGIN
+
+
+/** @defgroup grp_vusb_int VUSB Internals.
+ * @ingroup grp_vusb
+ * @internal
+ * @{
+ */
+
+/** @defgroup grp_vusb_int_dev Internal Device Operations, Structures and Constants.
+ * @{
+ */
+
+/** Pointer to a Virtual USB device (core). */
+typedef struct VUSBDEV *PVUSBDEV;
+/** Pointer to a VUSB root hub. */
+typedef struct VUSBROOTHUB *PVUSBROOTHUB;
+
+
+/** Number of the default control endpoint */
+#define VUSB_PIPE_DEFAULT 0
+
+/** @name Device addresses
+ * @{ */
+#define VUSB_DEFAULT_ADDRESS 0
+#define VUSB_INVALID_ADDRESS UINT8_C(0xff)
+/** @} */
+
+/** @name Feature bits (1<<FEATURE for the u16Status bit)
+ * @{ */
+#define VUSB_DEV_SELF_POWERED 0
+#define VUSB_DEV_REMOTE_WAKEUP 1
+#define VUSB_EP_HALT 0
+/** @} */
+
+/** Maximum number of endpoint addresses */
+#define VUSB_PIPE_MAX 16
+
+/**
+ * The VUSB URB data.
+ */
+typedef struct VUSBURBVUSBINT
+{
+ /** Node for one of the lists the URB can be in. */
+ RTLISTNODE NdLst;
+ /** Pointer to the URB this structure is part of. */
+ PVUSBURB pUrb;
+ /** Pointer to the original for control messages. */
+ PVUSBURB pCtrlUrb;
+ /** Pointer to the VUSB device.
+ * This may be NULL if the destination address is invalid. */
+ PVUSBDEV pDev;
+ /** Specific to the pfnFree function. */
+ void *pvFreeCtx;
+ /**
+ * Callback which will free the URB once it's reaped and completed.
+ * @param pUrb The URB.
+ */
+ DECLCALLBACKMEMBER(void, pfnFree,(PVUSBURB pUrb));
+ /** Submit timestamp. (logging only) */
+ uint64_t u64SubmitTS;
+} VUSBURBVUSBINT;
+
+/**
+ * Control-pipe stages.
+ */
+typedef enum CTLSTAGE
+{
+ /** the control pipe is in the setup stage. */
+ CTLSTAGE_SETUP = 0,
+ /** the control pipe is in the data stage. */
+ CTLSTAGE_DATA,
+ /** the control pipe is in the status stage. */
+ CTLSTAGE_STATUS
+} CTLSTAGE;
+
+/**
+ * Extra data for a control pipe.
+ *
+ * This is state information needed for the special multi-stage
+ * transfers performed on this kind of pipes.
+ */
+typedef struct vusb_ctrl_extra
+{
+ /** Current pipe stage. */
+ CTLSTAGE enmStage;
+ /** Success indicator. */
+ bool fOk;
+ /** Set if the message URB has been submitted. */
+ bool fSubmitted;
+ /** Pointer to the SETUP.
+ * This is a pointer to Urb->abData[0]. */
+ PVUSBSETUP pMsg;
+ /** Current DATA pointer.
+ * This starts at pMsg + 1 and is incremented at we read/write data. */
+ uint8_t *pbCur;
+ /** The amount of data left to read on IN operations.
+ * On OUT operations this is not used. */
+ uint32_t cbLeft;
+ /** The amount of data we can house.
+ * This starts at the default 8KB, and this structure will be reallocated to
+ * accommodate any larger request (unlikely). */
+ uint32_t cbMax;
+ /** VUSB internal data for the extra URB. */
+ VUSBURBVUSBINT VUsbExtra;
+ /** The message URB. */
+ VUSBURB Urb;
+} VUSBCTRLEXTRA, *PVUSBCTRLEXTRA;
+
+void vusbMsgFreeExtraData(PVUSBCTRLEXTRA pExtra);
+void vusbMsgResetExtraData(PVUSBCTRLEXTRA pExtra);
+
+/**
+ * A VUSB pipe
+ */
+typedef struct vusb_pipe
+{
+ PCVUSBDESCENDPOINTEX in;
+ PCVUSBDESCENDPOINTEX out;
+ /** Pointer to the extra state data required to run a control pipe. */
+ PVUSBCTRLEXTRA pCtrl;
+ /** Critical section serializing access to the extra state data for a control pipe. */
+ RTCRITSECT CritSectCtrl;
+ /** Count of active async transfers. */
+ volatile uint32_t async;
+ /** Last scheduled frame - only valid for isochronous IN endpoints. */
+ uint32_t uLastFrameIn;
+ /** Last scheduled frame - only valid for isochronous OUT endpoints. */
+ uint32_t uLastFrameOut;
+} VUSBPIPE;
+/** Pointer to a VUSB pipe structure. */
+typedef VUSBPIPE *PVUSBPIPE;
+
+
+/**
+ * Interface state and possible settings.
+ */
+typedef struct vusb_interface_state
+{
+ /** Pointer to the interface descriptor of the currently selected (active)
+ * interface. */
+ PCVUSBDESCINTERFACEEX pCurIfDesc;
+ /** Pointer to the interface settings. */
+ PCVUSBINTERFACE pIf;
+} VUSBINTERFACESTATE;
+/** Pointer to interface state. */
+typedef VUSBINTERFACESTATE *PVUSBINTERFACESTATE;
+/** Pointer to const interface state. */
+typedef const VUSBINTERFACESTATE *PCVUSBINTERFACESTATE;
+
+
+/**
+ * VUSB URB pool.
+ */
+typedef struct VUSBURBPOOL
+{
+ /** Critical section protecting the pool. */
+ RTCRITSECT CritSectPool;
+ /** Chain of free URBs by type. (Singly linked) */
+ RTLISTANCHOR aLstFreeUrbs[VUSBXFERTYPE_ELEMENTS];
+ /** The number of URBs in the pool. */
+ volatile uint32_t cUrbsInPool;
+ /** Align the size to a 8 byte boundary. */
+ uint32_t Alignment0;
+} VUSBURBPOOL;
+/** Pointer to a VUSB URB pool. */
+typedef VUSBURBPOOL *PVUSBURBPOOL;
+
+AssertCompileSizeAlignment(VUSBURBPOOL, 8);
+
+/**
+ * A Virtual USB device (core).
+ *
+ * @implements VUSBIDEVICE
+ */
+typedef struct VUSBDEV
+{
+ /** The device interface exposed to the HCI. */
+ VUSBIDEVICE IDevice;
+ /** Pointer to the PDM USB device instance. */
+ PPDMUSBINS pUsbIns;
+ /** Pointer to the roothub this device is attached to. */
+ PVUSBROOTHUB pHub;
+ /** The device state. */
+ VUSBDEVICESTATE volatile enmState;
+ /** Reference counter to protect the device structure from going away. */
+ uint32_t volatile cRefs;
+
+ /** The device address. */
+ uint8_t u8Address;
+ /** The new device address. */
+ uint8_t u8NewAddress;
+ /** The port. */
+ int16_t i16Port;
+ /** Device status. (VUSB_DEV_SELF_POWERED or not.) */
+ uint16_t u16Status;
+
+ /** Pointer to the descriptor cache.
+ * (Provided by the device thru the pfnGetDescriptorCache method.) */
+ PCPDMUSBDESCCACHE pDescCache;
+ /** Current configuration. */
+ PCVUSBDESCCONFIGEX pCurCfgDesc;
+
+ /** Current interface state (including alternate interface setting) - maximum
+ * valid index is config->bNumInterfaces
+ */
+ PVUSBINTERFACESTATE paIfStates;
+
+ /** Pipe/direction -> endpoint descriptor mapping */
+ VUSBPIPE aPipes[VUSB_PIPE_MAX];
+ /** Critical section protecting the active URB list. */
+ RTCRITSECT CritSectAsyncUrbs;
+ /** List of active async URBs. */
+ RTLISTANCHOR LstAsyncUrbs;
+
+ /** Dumper state. */
+ union VUSBDEVURBDUMPERSTATE
+ {
+ /** The current scsi command. */
+ uint8_t u8ScsiCmd;
+ } Urb;
+
+ /** The reset timer handle. */
+ TMTIMERHANDLE hResetTimer;
+ /** Reset handler arguments. */
+ void *pvArgs;
+ /** URB submit and reap thread. */
+ RTTHREAD hUrbIoThread;
+ /** Request queue for executing tasks on the I/O thread which should be done
+ * synchronous and without any other thread accessing the USB device. */
+ RTREQQUEUE hReqQueueSync;
+ /** Sniffer instance for this device if configured. */
+ VUSBSNIFFER hSniffer;
+ /** Flag whether the URB I/O thread should terminate. */
+ bool volatile fTerminate;
+ /** Flag whether the I/O thread was woken up. */
+ bool volatile fWokenUp;
+#if HC_ARCH_BITS == 32
+ /** Align the size to a 8 byte boundary. */
+ bool afAlignment0[2];
+#endif
+ /** The pool of free URBs for faster allocation. */
+ VUSBURBPOOL UrbPool;
+} VUSBDEV;
+AssertCompileSizeAlignment(VUSBDEV, 8);
+
+
+int vusbDevInit(PVUSBDEV pDev, PPDMUSBINS pUsbIns, const char *pszCaptureFilename);
+void vusbDevDestroy(PVUSBDEV pDev);
+bool vusbDevDoSelectConfig(PVUSBDEV dev, PCVUSBDESCCONFIGEX pCfg);
+void vusbDevMapEndpoint(PVUSBDEV dev, PCVUSBDESCENDPOINTEX ep);
+int vusbDevDetach(PVUSBDEV pDev);
+int vusbDevAttach(PVUSBDEV pDev, PVUSBROOTHUB pHub);
+DECLINLINE(PVUSBROOTHUB) vusbDevGetRh(PVUSBDEV pDev);
+size_t vusbDevMaxInterfaces(PVUSBDEV dev);
+
+void vusbDevSetAddress(PVUSBDEV pDev, uint8_t u8Address);
+bool vusbDevStandardRequest(PVUSBDEV pDev, int EndPt, PVUSBSETUP pSetup, void *pvBuf, uint32_t *pcbBuf);
+
+
+/** @} */
+
+
+/** @defgroup grp_vusb_int_hub Internal Hub Operations, Structures and Constants.
+ * @{
+ */
+
+
+/** @} */
+
+
+/** @defgroup grp_vusb_int_roothub Internal Root Hub Operations, Structures and Constants.
+ * @{
+ */
+
+/**
+ * Per transfer type statistics.
+ */
+typedef struct VUSBROOTHUBTYPESTATS
+{
+ STAMCOUNTER StatUrbsSubmitted;
+ STAMCOUNTER StatUrbsFailed;
+ STAMCOUNTER StatUrbsCancelled;
+
+ STAMCOUNTER StatReqBytes;
+ STAMCOUNTER StatReqReadBytes;
+ STAMCOUNTER StatReqWriteBytes;
+
+ STAMCOUNTER StatActBytes;
+ STAMCOUNTER StatActReadBytes;
+ STAMCOUNTER StatActWriteBytes;
+} VUSBROOTHUBTYPESTATS, *PVUSBROOTHUBTYPESTATS;
+
+
+
+/** Pointer to a VUSBROOTHUBLOAD struct. */
+typedef struct VUSBROOTHUBLOAD *PVUSBROOTHUBLOAD;
+
+/**
+ * The instance data of a root hub driver.
+ *
+ * This extends the generic VUSB hub.
+ *
+ * @implements VUSBIROOTHUBCONNECTOR
+ */
+typedef struct VUSBROOTHUB
+{
+ /** Pointer to the driver instance. */
+ PPDMDRVINS pDrvIns;
+ /** Pointer to the root hub port interface we're attached to. */
+ PVUSBIROOTHUBPORT pIRhPort;
+ /** Connector interface exposed upwards. */
+ VUSBIROOTHUBCONNECTOR IRhConnector;
+
+ /** Critical section protecting the device arrays. */
+ RTCRITSECT CritSectDevices;
+ /** Array of pointers to USB devices indexed by the port the device is on. */
+ PVUSBDEV apDevByPort[VUSB_DEVICES_MAX];
+ /** Array of pointers to USB devices indexed by the address assigned. */
+ PVUSBDEV apDevByAddr[VUSB_DEVICES_MAX];
+ /** Structure after a saved state load to re-attach devices. */
+ PVUSBROOTHUBLOAD pLoad;
+
+ /** Roothub device state. */
+ VUSBDEVICESTATE enmState;
+ /** Number of ports this roothub offers. */
+ uint16_t cPorts;
+ /** Number of devices attached to this roothub currently. */
+ uint16_t cDevices;
+ /** Name of the roothub. Used for logging. */
+ char *pszName;
+ /** URB pool for URBs from the roothub. */
+ VUSBURBPOOL UrbPool;
+
+#if HC_ARCH_BITS == 32
+ uint32_t Alignment0;
+#endif
+
+ /** Availability Bitmap. */
+ VUSBPORTBITMAP Bitmap;
+
+ /** Sniffer instance for the root hub. */
+ VUSBSNIFFER hSniffer;
+ /** Version of the attached Host Controller. */
+ uint32_t fHcVersions;
+ /** Size of the HCI specific data for each URB. */
+ size_t cbHci;
+ /** Size of the HCI specific TD. */
+ size_t cbHciTd;
+
+ /** The periodic frame processing thread. */
+ R3PTRTYPE(PPDMTHREAD) hThreadPeriodFrame;
+ /** Event semaphore to interact with the periodic frame processing thread. */
+ R3PTRTYPE(RTSEMEVENTMULTI) hSemEventPeriodFrame;
+ /** Event semaphore to release the thread waiting for the periodic frame processing thread to stop. */
+ R3PTRTYPE(RTSEMEVENTMULTI) hSemEventPeriodFrameStopped;
+ /** Current default frame rate for periodic frame processing thread. */
+ volatile uint32_t uFrameRateDefault;
+ /** Current frame rate (can be lower than the default frame rate if there is no activity). */
+ uint32_t uFrameRate;
+ /** How long to wait until the next frame. */
+ uint64_t nsWait;
+ /** Timestamp when the last frame was processed. */
+ uint64_t tsFrameProcessed;
+ /** Number of USB work cycles with no transfers. */
+ uint32_t cIdleCycles;
+
+ /** Flag whether a frame is currently being processed. */
+ volatile bool fFrameProcessing;
+
+#if HC_ARCH_BITS == 32
+ uint32_t Alignment1;
+#endif
+
+#ifdef LOG_ENABLED
+ /** A serial number for URBs submitted on the roothub instance.
+ * Only logging builds. */
+ uint32_t iSerial;
+ /** Alignment */
+ uint32_t Alignment2;
+#endif
+#ifdef VBOX_WITH_STATISTICS
+ VUSBROOTHUBTYPESTATS Total;
+ VUSBROOTHUBTYPESTATS aTypes[VUSBXFERTYPE_MSG];
+ STAMCOUNTER StatIsocReqPkts;
+ STAMCOUNTER StatIsocReqReadPkts;
+ STAMCOUNTER StatIsocReqWritePkts;
+ STAMCOUNTER StatIsocActPkts;
+ STAMCOUNTER StatIsocActReadPkts;
+ STAMCOUNTER StatIsocActWritePkts;
+ struct
+ {
+ STAMCOUNTER Pkts;
+ STAMCOUNTER Ok;
+ STAMCOUNTER Ok0;
+ STAMCOUNTER DataUnderrun;
+ STAMCOUNTER DataUnderrun0;
+ STAMCOUNTER DataOverrun;
+ STAMCOUNTER NotAccessed;
+ STAMCOUNTER Misc;
+ STAMCOUNTER Bytes;
+ } aStatIsocDetails[8];
+
+ STAMPROFILE StatReapAsyncUrbs;
+ STAMPROFILE StatSubmitUrb;
+ STAMCOUNTER StatFramesProcessedClbk;
+ STAMCOUNTER StatFramesProcessedThread;
+#endif
+} VUSBROOTHUB;
+AssertCompileMemberAlignment(VUSBROOTHUB, IRhConnector, 8);
+AssertCompileMemberAlignment(VUSBROOTHUB, Bitmap, 8);
+AssertCompileMemberAlignment(VUSBROOTHUB, CritSectDevices, 8);
+#ifdef VBOX_WITH_STATISTICS
+AssertCompileMemberAlignment(VUSBROOTHUB, Total, 8);
+#endif
+
+/** Converts a pointer to VUSBROOTHUB::IRhConnector to a PVUSBROOTHUB. */
+#define VUSBIROOTHUBCONNECTOR_2_VUSBROOTHUB(pInterface) (PVUSBROOTHUB)( (uintptr_t)(pInterface) - RT_UOFFSETOF(VUSBROOTHUB, IRhConnector) )
+
+/**
+ * URB cancellation modes
+ */
+typedef enum CANCELMODE
+{
+ /** complete the URB with an error (CRC). */
+ CANCELMODE_FAIL = 0,
+ /** do not change the URB contents. */
+ CANCELMODE_UNDO
+} CANCELMODE;
+
+/** @} */
+
+
+
+/** @defgroup grp_vusb_int_urb Internal URB Operations, Structures and Constants.
+ * @{ */
+int vusbUrbSubmit(PVUSBURB pUrb);
+void vusbUrbDoReapAsync(PRTLISTANCHOR pUrbLst, RTMSINTERVAL cMillies);
+void vusbUrbDoReapAsyncDev(PVUSBDEV pDev, RTMSINTERVAL cMillies);
+void vusbUrbCancel(PVUSBURB pUrb, CANCELMODE mode);
+void vusbUrbCancelAsync(PVUSBURB pUrb, CANCELMODE mode);
+void vusbUrbRipe(PVUSBURB pUrb);
+void vusbUrbCompletionRhEx(PVUSBROOTHUB pRh, PVUSBURB pUrb);
+int vusbUrbSubmitHardError(PVUSBURB pUrb);
+int vusbUrbErrorRhEx(PVUSBROOTHUB pRh, PVUSBURB pUrb);
+int vusbDevUrbIoThreadWakeup(PVUSBDEV pDev);
+int vusbDevUrbIoThreadCreate(PVUSBDEV pDev);
+int vusbDevUrbIoThreadDestroy(PVUSBDEV pDev);
+DECLHIDDEN(void) vusbDevCancelAllUrbs(PVUSBDEV pDev, bool fDetaching);
+DECLHIDDEN(int) vusbDevIoThreadExecV(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args);
+DECLHIDDEN(int) vusbDevIoThreadExec(PVUSBDEV pDev, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...);
+DECLHIDDEN(int) vusbDevIoThreadExecSync(PVUSBDEV pDev, PFNRT pfnFunction, unsigned cArgs, ...);
+DECLHIDDEN(int) vusbUrbCancelWorker(PVUSBURB pUrb, CANCELMODE enmMode);
+
+DECLHIDDEN(uint64_t) vusbRhR3ProcessFrame(PVUSBROOTHUB pThis, bool fCallback);
+
+int vusbUrbQueueAsyncRh(PVUSBURB pUrb);
+
+bool vusbDevIsDescriptorInCache(PVUSBDEV pDev, PCVUSBSETUP pSetup);
+
+/**
+ * Initializes the given URB pool.
+ *
+ * @returns VBox status code.
+ * @param pUrbPool The URB pool to initialize.
+ */
+DECLHIDDEN(int) vusbUrbPoolInit(PVUSBURBPOOL pUrbPool);
+
+/**
+ * Destroy a given URB pool freeing all ressources.
+ *
+ * @returns nothing.
+ * @param pUrbPool The URB pool to destroy.
+ */
+DECLHIDDEN(void) vusbUrbPoolDestroy(PVUSBURBPOOL pUrbPool);
+
+/**
+ * Allocate a new URB from the given URB pool.
+ *
+ * @returns Pointer to the new URB or NULL if out of memory.
+ * @param pUrbPool The URB pool to allocate from.
+ * @param enmType Type of the URB.
+ * @param enmDir The direction of the URB.
+ * @param cbData The number of bytes to allocate for the data buffer.
+ * @param cbHci Size of the data private to the HCI for each URB when allocated.
+ * @param cbHciTd Size of one transfer descriptor.
+ * @param cTds Number of transfer descriptors.
+ */
+DECLHIDDEN(PVUSBURB) vusbUrbPoolAlloc(PVUSBURBPOOL pUrbPool, VUSBXFERTYPE enmType,
+ VUSBDIRECTION enmDir, size_t cbData,
+ size_t cbHci, size_t cbHciTd, unsigned cTds);
+
+/**
+ * Frees a given URB.
+ *
+ * @returns nothing.
+ * @param pUrbPool The URB pool the URB was allocated from.
+ * @param pUrb The URB to free.
+ */
+DECLHIDDEN(void) vusbUrbPoolFree(PVUSBURBPOOL pUrbPool, PVUSBURB pUrb);
+
+#ifdef LOG_ENABLED
+/**
+ * Logs an URB in the debug log.
+ *
+ * @returns nothing.
+ * @param pUrb The URB to log.
+ * @param pszMsg Additional message to log.
+ * @param fComplete Flag whther the URB is completing.
+ */
+DECLHIDDEN(void) vusbUrbTrace(PVUSBURB pUrb, const char *pszMsg, bool fComplete);
+
+/**
+ * Return the USB direction as a string from the given enum.
+ */
+DECLHIDDEN(const char *) vusbUrbDirName(VUSBDIRECTION enmDir);
+
+/**
+ * Return the URB type as string from the given enum.
+ */
+DECLHIDDEN(const char *) vusbUrbTypeName(VUSBXFERTYPE enmType);
+
+/**
+ * Return the URB status as string from the given enum.
+ */
+DECLHIDDEN(const char *) vusbUrbStatusName(VUSBSTATUS enmStatus);
+#endif
+
+DECLINLINE(void) vusbUrbUnlink(PVUSBURB pUrb)
+{
+ PVUSBDEV pDev = pUrb->pVUsb->pDev;
+
+ RTCritSectEnter(&pDev->CritSectAsyncUrbs);
+ RTListNodeRemove(&pUrb->pVUsb->NdLst);
+ RTCritSectLeave(&pDev->CritSectAsyncUrbs);
+}
+
+
+DECLINLINE(int) vusbUrbErrorRh(PVUSBURB pUrb)
+{
+ PVUSBDEV pDev = pUrb->pVUsb->pDev;
+ PVUSBROOTHUB pRh = vusbDevGetRh(pDev);
+ AssertPtrReturn(pRh, VERR_VUSB_DEVICE_NOT_ATTACHED);
+
+ return vusbUrbErrorRhEx(pRh, pUrb);
+}
+
+
+DECLINLINE(void) vusbUrbCompletionRh(PVUSBURB pUrb)
+{
+ PVUSBROOTHUB pRh = vusbDevGetRh(pUrb->pVUsb->pDev);
+ AssertPtrReturnVoid(pRh);
+
+ vusbUrbCompletionRhEx(pRh, pUrb);
+}
+
+
+/** @def vusbUrbAssert
+ * Asserts that a URB is valid.
+ */
+#ifdef VBOX_STRICT
+# define vusbUrbAssert(pUrb) do { \
+ AssertPtr((pUrb)); \
+ AssertMsg((pUrb)->u32Magic == VUSBURB_MAGIC, ("%#x", (pUrb)->u32Magic)); \
+ AssertMsg((pUrb)->enmState > VUSBURBSTATE_INVALID && (pUrb)->enmState < VUSBURBSTATE_END, \
+ ("%d\n", (pUrb)->enmState)); \
+ } while (0)
+#else
+# define vusbUrbAssert(pUrb) do {} while (0)
+#endif
+
+/**
+ * @def VUSBDEV_ASSERT_VALID_STATE
+ * Asserts that the give device state is valid.
+ */
+#define VUSBDEV_ASSERT_VALID_STATE(enmState) \
+ AssertMsg((enmState) > VUSB_DEVICE_STATE_INVALID && (enmState) < VUSB_DEVICE_STATE_DESTROYED, ("enmState=%#x\n", enmState));
+
+/** Executes a function synchronously. */
+#define VUSB_DEV_IO_THREAD_EXEC_FLAGS_SYNC RT_BIT_32(0)
+
+/** @} */
+
+
+/**
+ * Gets the roothub of a device.
+ *
+ * @returns Pointer to the roothub instance the device is attached to.
+ * @returns NULL if not attached to any hub.
+ * @param pDev Pointer to the device in question.
+ */
+DECLINLINE(PVUSBROOTHUB) vusbDevGetRh(PVUSBDEV pDev)
+{
+ if (!pDev->pHub)
+ return NULL;
+ return pDev->pHub;
+}
+
+
+/**
+ * Returns the state of the USB device.
+ *
+ * @returns State of the USB device.
+ * @param pDev Pointer to the device.
+ */
+DECLINLINE(VUSBDEVICESTATE) vusbDevGetState(PVUSBDEV pDev)
+{
+ VUSBDEVICESTATE enmState = (VUSBDEVICESTATE)ASMAtomicReadU32((volatile uint32_t *)&pDev->enmState);
+ VUSBDEV_ASSERT_VALID_STATE(enmState);
+ return enmState;
+}
+
+
+/**
+ * Sets the given state for the USB device.
+ *
+ * @returns The old state of the device.
+ * @param pDev Pointer to the device.
+ * @param enmState The new state to set.
+ */
+DECLINLINE(VUSBDEVICESTATE) vusbDevSetState(PVUSBDEV pDev, VUSBDEVICESTATE enmState)
+{
+ VUSBDEV_ASSERT_VALID_STATE(enmState);
+ VUSBDEVICESTATE enmStateOld = (VUSBDEVICESTATE)ASMAtomicXchgU32((volatile uint32_t *)&pDev->enmState, enmState);
+ VUSBDEV_ASSERT_VALID_STATE(enmStateOld);
+ return enmStateOld;
+}
+
+
+/**
+ * Compare and exchange the states for the given USB device.
+ *
+ * @returns true if the state was changed.
+ * @returns false if the state wasn't changed.
+ * @param pDev Pointer to the device.
+ * @param enmStateNew The new state to set.
+ * @param enmStateOld The old state to compare with.
+ */
+DECLINLINE(bool) vusbDevSetStateCmp(PVUSBDEV pDev, VUSBDEVICESTATE enmStateNew, VUSBDEVICESTATE enmStateOld)
+{
+ VUSBDEV_ASSERT_VALID_STATE(enmStateNew);
+ VUSBDEV_ASSERT_VALID_STATE(enmStateOld);
+ return ASMAtomicCmpXchgU32((volatile uint32_t *)&pDev->enmState, enmStateNew, enmStateOld);
+}
+
+/**
+ * Retains the given VUSB device pointer.
+ *
+ * @returns New reference count.
+ * @param pThis The VUSB device pointer.
+ * @param pszWho Caller of the retaining.
+ */
+DECLINLINE(uint32_t) vusbDevRetain(PVUSBDEV pThis, const char *pszWho)
+{
+ AssertPtrReturn(pThis, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
+ LogFlowFunc(("pThis=%p{.cRefs=%u}[%s]\n", pThis, cRefs, pszWho)); RT_NOREF(pszWho);
+ AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+ return cRefs;
+}
+
+/**
+ * Releases the given VUSB device pointer.
+ *
+ * @returns New reference count.
+ * @retval 0 if no onw is holding a reference anymore causing the device to be destroyed.
+ * @param pThis The VUSB device pointer.
+ * @param pszWho Caller of the retaining.
+ */
+DECLINLINE(uint32_t) vusbDevRelease(PVUSBDEV pThis, const char *pszWho)
+{
+ AssertPtrReturn(pThis, UINT32_MAX);
+
+ uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
+ LogFlowFunc(("pThis=%p{.cRefs=%u}[%s]\n", pThis, cRefs, pszWho)); RT_NOREF(pszWho);
+ AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
+ if (cRefs == 0)
+ vusbDevDestroy(pThis);
+ return cRefs;
+}
+
+/** Strings for the CTLSTAGE enum values. */
+extern const char * const g_apszCtlStates[4];
+
+/** @} */
+RT_C_DECLS_END
+#endif /* !VBOX_INCLUDED_SRC_USB_VUSBInternal_h */
+