summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/include/HostUSBDeviceImpl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Main/include/HostUSBDeviceImpl.h')
-rw-r--r--src/VBox/Main/include/HostUSBDeviceImpl.h327
1 files changed, 327 insertions, 0 deletions
diff --git a/src/VBox/Main/include/HostUSBDeviceImpl.h b/src/VBox/Main/include/HostUSBDeviceImpl.h
new file mode 100644
index 00000000..431abb7b
--- /dev/null
+++ b/src/VBox/Main/include/HostUSBDeviceImpl.h
@@ -0,0 +1,327 @@
+/* $Id: HostUSBDeviceImpl.h $ */
+/** @file
+ * VirtualBox IHostUSBDevice COM interface implementation.
+ */
+
+/*
+ * 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 MAIN_INCLUDED_HostUSBDeviceImpl_h
+#define MAIN_INCLUDED_HostUSBDeviceImpl_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include "VirtualBoxBase.h"
+#include "USBDeviceFilterImpl.h"
+#include <VBox/usb.h>
+#include "HostUSBDeviceWrap.h"
+
+class SessionMachine;
+class USBProxyBackend;
+
+/**
+ * The unified state machine of HostUSBDevice.
+ *
+ * This is a super set of USBDEVICESTATE / USBDeviceState_T that
+ * includes additional states for tracking state transitions.
+ *
+ * @remarks
+ * The CapturingForVM and CapturingForProxy states have been merged
+ * into Capturing with a destination state (AttachingToVM or HeldByProxy).
+ *
+ * The DetachingFromVM state is a merge of DetachingFromVMToProxy and
+ * DetachingFromVMToHost and uses the destination state (HeldByProxy
+ * or ReleasingToHost) like Capturing.
+ *
+ * The *AwaitingDetach and *AwaitingReattach substates (optionally used
+ * in Capturing, AttachingToVM, DetachingFromVM and ReleasingToHost) are
+ * implemented via a substate kHostUSBDeviceSubState.
+ */
+typedef enum
+{
+ /** The device is unsupported (HUB).
+ * Next Host: PhysDetached.
+ * Next VBox: No change permitted.
+ */
+ kHostUSBDeviceState_Unsupported = USBDEVICESTATE_UNSUPPORTED,
+ /** The device is used exclusivly by the host or is inaccessible for some other reason.
+ * Next Host: Capturable, Unused, PhysDetached.
+ * Run filters.
+ * Next VBox: No change permitted.
+ */
+ kHostUSBDeviceState_UsedByHost = USBDEVICESTATE_USED_BY_HOST,
+ /** The device is used by the host but can be captured.
+ * Next Host: Unsupported, UsedByHost, Unused, PhysDetached.
+ * Run filters if Unused (for wildcard filters).
+ * Next VBox: CapturingForVM, CapturingForProxy.
+ */
+ kHostUSBDeviceState_Capturable = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE,
+ /** The device is not used by the host and can be captured.
+ * Next Host: UsedByHost, Capturable, PhysDetached
+ * Don't run any filters (done on state entry).
+ * Next VBox: CapturingForVM, CapturingForProxy.
+ */
+ kHostUSBDeviceState_Unused = USBDEVICESTATE_UNUSED,
+ /** The device is held captive by the proxy.
+ * Next Host: PhysDetached
+ * Next VBox: ReleasingHeld, AttachingToVM
+ */
+ kHostUSBDeviceState_HeldByProxy = USBDEVICESTATE_HELD_BY_PROXY,
+ /** The device is in use by a VM.
+ * Next Host: PhysDetachingFromVM
+ * Next VBox: DetachingFromVM
+ */
+ kHostUSBDeviceState_UsedByVM = USBDEVICESTATE_USED_BY_GUEST,
+ /** The device has been detach from both the host and VMs.
+ * This is the final state. */
+ kHostUSBDeviceState_PhysDetached = 9,
+
+
+ /** The start of the transitional states. */
+ kHostUSBDeviceState_FirstTransitional,
+
+ /** The device is being seized from the host, either for HeldByProxy or for AttachToVM.
+ *
+ * On some hosts we will need to re-enumerate the in which case the sub-state
+ * is employed to track this progress. On others, this is synchronous or faked, and
+ * will will then leave the device in this state and poke the service thread to do
+ * the completion state change.
+ *
+ * Next Host: PhysDetached.
+ * Next VBox: HeldByProxy or AttachingToVM on success,
+ * previous state (Unused or Capturable) or UsedByHost on failure.
+ */
+ kHostUSBDeviceState_Capturing = kHostUSBDeviceState_FirstTransitional,
+
+ /** The device is being released back to the host, following VM or Proxy usage.
+ * Most hosts needs to re-enumerate the device and will therefore employ the
+ * sub-state as during capturing. On the others we'll just leave it to the usb
+ * service thread to advance the device state.
+ *
+ * Next Host: Unused, UsedByHost, Capturable.
+ * No filters.
+ * Next VBox: PhysDetached (timeout), HeldByProxy (failure).
+ */
+ kHostUSBDeviceState_ReleasingToHost,
+
+ /** The device is being attached to a VM.
+ *
+ * This requires IPC to the VM and we will not advance the state until
+ * that completes.
+ *
+ * Next Host: PhysDetachingFromVM.
+ * Next VBox: UsedByGuest, HeldByProxy (failure).
+ */
+ kHostUSBDeviceState_AttachingToVM,
+
+ /** The device is being detached from a VM and will be returned to the proxy or host.
+ *
+ * This involves IPC and may or may not also require re-enumeration of the
+ * device. Which means that it might transition directly into the ReleasingToHost state
+ * because the client (VM) will do the actual re-enumeration.
+ *
+ * Next Host: PhysDetachingFromVM (?) or just PhysDetached.
+ * Next VBox: ReleasingToHost, HeldByProxy.
+ */
+ kHostUSBDeviceState_DetachingFromVM,
+
+ /** The device has been physically removed while a VM used it.
+ *
+ * This is the device state while VBoxSVC is doing IPC to the client (VM) telling it
+ * to detach it.
+ *
+ * Next Host: None.
+ * Next VBox: PhysDetached
+ */
+ kHostUSBDeviceState_PhysDetachingFromVM,
+
+ /** Just an invalid state value for use as default for some methods. */
+ kHostUSBDeviceState_Invalid = 0x7fff
+} HostUSBDeviceState;
+
+
+/**
+ * Sub-state for dealing with device re-enumeration.
+ */
+typedef enum
+{
+ /** Not in any sub-state. */
+ kHostUSBDeviceSubState_Default = 0,
+ /** Awaiting a logical device detach following a device re-enumeration. */
+ kHostUSBDeviceSubState_AwaitingDetach,
+ /** Awaiting a logical device re-attach following a device re-enumeration. */
+ kHostUSBDeviceSubState_AwaitingReAttach
+} HostUSBDeviceSubState;
+
+
+/**
+ * Object class used to hold Host USB Device properties.
+ */
+class ATL_NO_VTABLE HostUSBDevice :
+ public HostUSBDeviceWrap
+{
+public:
+ DECLARE_COMMON_CLASS_METHODS(HostUSBDevice)
+
+ HRESULT FinalConstruct();
+ void FinalRelease();
+
+ // public initializer/uninitializer for internal purposes only
+ HRESULT init(PUSBDEVICE aUsb, USBProxyBackend *aUSBProxyBackend);
+ void uninit();
+
+ // public methods only for internal purposes
+
+ /** @note Must be called from under the object read lock. */
+ const Guid& i_getId() const { return mId; }
+
+ /** @note Must be called from under the object read lock. */
+ HostUSBDeviceState i_getUnistate() const { return mUniState; }
+
+ /** @note Must be called from under the object read lock. */
+ const char *i_getStateName() { return i_stateName (mUniState, mPendingUniState, mUniSubState); }
+
+ /** @note Must be called from under the object read lock. */
+ bool i_isCapturableOrHeld()
+ {
+ return mUniState == kHostUSBDeviceState_Unused
+ || mUniState == kHostUSBDeviceState_Capturable
+ || mUniState == kHostUSBDeviceState_HeldByProxy;
+ }
+
+ /** @note Must be called from under the object read lock. */
+ ComObjPtr<SessionMachine> &i_getMachine() { return mMachine; }
+
+ /** @note Must be called from under the object read lock. */
+ PCUSBDEVICE i_getUsbData() const { return mUsb; }
+
+ USBProxyBackend *i_getUsbProxyBackend() const { return mUSBProxyBackend; }
+
+ com::Utf8Str i_getName();
+
+ HRESULT i_requestCaptureForVM(SessionMachine *aMachine, bool aSetError,
+ const com::Utf8Str &aCaptureFilename, ULONG aMaskedIfs = 0);
+ HRESULT i_onDetachFromVM(SessionMachine *aMachine, bool aDone, bool *aRunFilters, bool aAbnormal = false);
+ HRESULT i_requestReleaseToHost();
+ HRESULT i_requestHold();
+ bool i_wasActuallyDetached();
+ void i_onPhysicalDetached();
+
+ bool i_isMatch(const USBDeviceFilter::BackupableUSBDeviceFilterData &aData);
+ int i_compare(PCUSBDEVICE aDev2);
+ static int i_compare(PCUSBDEVICE aDev1, PCUSBDEVICE aDev2, bool aIsAwaitingReAttach = false);
+
+ bool i_updateState(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine);
+ bool i_updateStateFake(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine);
+
+ static const char *i_stateName(HostUSBDeviceState aState,
+ HostUSBDeviceState aPendingState = kHostUSBDeviceState_Invalid,
+ HostUSBDeviceSubState aSubState = kHostUSBDeviceSubState_Default);
+
+ void *i_getBackendUserData() { return m_pvBackendUser; }
+ void i_setBackendUserData(void *pvBackendUser) { m_pvBackendUser = pvBackendUser; }
+
+protected:
+
+ HRESULT i_attachToVM(SessionMachine *aMachine, const com::Utf8Str &aCaptureFilename, ULONG aMaskedIfs = 0);
+ void i_detachFromVM(HostUSBDeviceState aFinalState);
+ void i_onPhysicalDetachedInternal();
+ bool i_hasAsyncOperationTimedOut() const;
+
+ bool i_setState (HostUSBDeviceState aNewState, HostUSBDeviceState aNewPendingState = kHostUSBDeviceState_Invalid,
+ HostUSBDeviceSubState aNewSubState = kHostUSBDeviceSubState_Default);
+ bool i_startTransition (HostUSBDeviceState aNewState, HostUSBDeviceState aFinalState,
+ HostUSBDeviceSubState aNewSubState = kHostUSBDeviceSubState_Default);
+ bool i_advanceTransition(bool aSkipReAttach = false);
+ bool i_failTransition(HostUSBDeviceState a_enmStateHint);
+ USBDeviceState_T i_canonicalState() const;
+
+private:
+
+ // wrapped IUSBDevice properties
+ HRESULT getId(com::Guid &aId);
+ HRESULT getVendorId(USHORT *aVendorId);
+ HRESULT getProductId(USHORT *aProductId);
+ HRESULT getRevision(USHORT *aRevision);
+ HRESULT getManufacturer(com::Utf8Str &aManufacturer);
+ HRESULT getProduct(com::Utf8Str &aProduct);
+ HRESULT getSerialNumber(com::Utf8Str &aSerialNumber);
+ HRESULT getAddress(com::Utf8Str &aAddress);
+ HRESULT getPort(USHORT *aPort);
+ HRESULT getPortPath(com::Utf8Str &aPortPath);
+ HRESULT getVersion(USHORT *aVersion);
+ HRESULT getPortVersion(USHORT *aPortVersion);
+ HRESULT getSpeed(USBConnectionSpeed_T *aSpeed);
+ HRESULT getRemote(BOOL *aRemote);
+ HRESULT getState(USBDeviceState_T *aState);
+ HRESULT getBackend(com::Utf8Str &aBackend);
+ HRESULT getDeviceInfo(std::vector<com::Utf8Str> &aInfo);
+
+
+ const Guid mId;
+
+ /** @name The state machine variables
+ * Only setState(), init() and uninit() will modify these members!
+ * @{ */
+ /** The RTTimeNanoTS() corresponding to the last state change.
+ *
+ * Old state machine: RTTimeNanoTS() of when mIsStatePending was set or mDetaching changed
+ * from kNotDetaching. For operations that cannot be canceled it's 0. */
+ uint64_t mLastStateChangeTS;
+ /** Current state. */
+ HostUSBDeviceState mUniState;
+ /** Sub-state for tracking re-enumeration. */
+ HostUSBDeviceSubState mUniSubState;
+ /** The final state of an pending transition.
+ * This is mainly a measure to reduce the number of HostUSBDeviceState values. */
+ HostUSBDeviceState mPendingUniState;
+ /** Previous state.
+ * This is used for bailing out when a transition like capture fails. */
+ HostUSBDeviceState mPrevUniState;
+ /** Indicator set by onDetachedPhys and check when advancing a transitional state. */
+ bool mIsPhysicallyDetached;
+ /** @} */
+
+ /** The machine the usb device is (being) attached to. */
+ ComObjPtr<SessionMachine> mMachine;
+ /** Pointer to the USB Proxy Backend instance. */
+ USBProxyBackend *mUSBProxyBackend;
+ /** Pointer to the USB Device structure owned by this device.
+ * Only used for host devices. */
+ PUSBDEVICE mUsb;
+ /** The interface mask to be used in the pending capture.
+ * This is a filter property. */
+ ULONG mMaskedIfs;
+ /** The name of this device. */
+ Utf8Str mNameObj;
+ /** The name of this device (for logging purposes).
+ * This points to the string in mNameObj. */
+ const char *mName;
+ /** The filename to capture the USB traffic to. */
+ com::Utf8Str mCaptureFilename;
+ /** Optional opaque user data assigned by the USB proxy backend owning the device. */
+ void *m_pvBackendUser;
+};
+
+#endif /* !MAIN_INCLUDED_HostUSBDeviceImpl_h */
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */