VirtualBox

source: vbox/trunk/src/VBox/Main/include/HostUSBDeviceImpl.h@ 106297

Last change on this file since 106297 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/* $Id: HostUSBDeviceImpl.h 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VirtualBox IHostUSBDevice COM interface implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#ifndef MAIN_INCLUDED_HostUSBDeviceImpl_h
29#define MAIN_INCLUDED_HostUSBDeviceImpl_h
30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
33
34#include "VirtualBoxBase.h"
35#include "USBDeviceFilterImpl.h"
36#include <VBox/usb.h>
37#include "HostUSBDeviceWrap.h"
38
39class SessionMachine;
40class USBProxyBackend;
41
42/**
43 * The unified state machine of HostUSBDevice.
44 *
45 * This is a super set of USBDEVICESTATE / USBDeviceState_T that
46 * includes additional states for tracking state transitions.
47 *
48 * @remarks
49 * The CapturingForVM and CapturingForProxy states have been merged
50 * into Capturing with a destination state (AttachingToVM or HeldByProxy).
51 *
52 * The DetachingFromVM state is a merge of DetachingFromVMToProxy and
53 * DetachingFromVMToHost and uses the destination state (HeldByProxy
54 * or ReleasingToHost) like Capturing.
55 *
56 * The *AwaitingDetach and *AwaitingReattach substates (optionally used
57 * in Capturing, AttachingToVM, DetachingFromVM and ReleasingToHost) are
58 * implemented via a substate kHostUSBDeviceSubState.
59 */
60typedef enum
61{
62 /** The device is unsupported (HUB).
63 * Next Host: PhysDetached.
64 * Next VBox: No change permitted.
65 */
66 kHostUSBDeviceState_Unsupported = USBDEVICESTATE_UNSUPPORTED,
67 /** The device is used exclusivly by the host or is inaccessible for some other reason.
68 * Next Host: Capturable, Unused, PhysDetached.
69 * Run filters.
70 * Next VBox: No change permitted.
71 */
72 kHostUSBDeviceState_UsedByHost = USBDEVICESTATE_USED_BY_HOST,
73 /** The device is used by the host but can be captured.
74 * Next Host: Unsupported, UsedByHost, Unused, PhysDetached.
75 * Run filters if Unused (for wildcard filters).
76 * Next VBox: CapturingForVM, CapturingForProxy.
77 */
78 kHostUSBDeviceState_Capturable = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE,
79 /** The device is not used by the host and can be captured.
80 * Next Host: UsedByHost, Capturable, PhysDetached
81 * Don't run any filters (done on state entry).
82 * Next VBox: CapturingForVM, CapturingForProxy.
83 */
84 kHostUSBDeviceState_Unused = USBDEVICESTATE_UNUSED,
85 /** The device is held captive by the proxy.
86 * Next Host: PhysDetached
87 * Next VBox: ReleasingHeld, AttachingToVM
88 */
89 kHostUSBDeviceState_HeldByProxy = USBDEVICESTATE_HELD_BY_PROXY,
90 /** The device is in use by a VM.
91 * Next Host: PhysDetachingFromVM
92 * Next VBox: DetachingFromVM
93 */
94 kHostUSBDeviceState_UsedByVM = USBDEVICESTATE_USED_BY_GUEST,
95 /** The device has been detach from both the host and VMs.
96 * This is the final state. */
97 kHostUSBDeviceState_PhysDetached = 9,
98
99
100 /** The start of the transitional states. */
101 kHostUSBDeviceState_FirstTransitional,
102
103 /** The device is being seized from the host, either for HeldByProxy or for AttachToVM.
104 *
105 * On some hosts we will need to re-enumerate the in which case the sub-state
106 * is employed to track this progress. On others, this is synchronous or faked, and
107 * will will then leave the device in this state and poke the service thread to do
108 * the completion state change.
109 *
110 * Next Host: PhysDetached.
111 * Next VBox: HeldByProxy or AttachingToVM on success,
112 * previous state (Unused or Capturable) or UsedByHost on failure.
113 */
114 kHostUSBDeviceState_Capturing = kHostUSBDeviceState_FirstTransitional,
115
116 /** The device is being released back to the host, following VM or Proxy usage.
117 * Most hosts needs to re-enumerate the device and will therefore employ the
118 * sub-state as during capturing. On the others we'll just leave it to the usb
119 * service thread to advance the device state.
120 *
121 * Next Host: Unused, UsedByHost, Capturable.
122 * No filters.
123 * Next VBox: PhysDetached (timeout), HeldByProxy (failure).
124 */
125 kHostUSBDeviceState_ReleasingToHost,
126
127 /** The device is being attached to a VM.
128 *
129 * This requires IPC to the VM and we will not advance the state until
130 * that completes.
131 *
132 * Next Host: PhysDetachingFromVM.
133 * Next VBox: UsedByGuest, HeldByProxy (failure).
134 */
135 kHostUSBDeviceState_AttachingToVM,
136
137 /** The device is being detached from a VM and will be returned to the proxy or host.
138 *
139 * This involves IPC and may or may not also require re-enumeration of the
140 * device. Which means that it might transition directly into the ReleasingToHost state
141 * because the client (VM) will do the actual re-enumeration.
142 *
143 * Next Host: PhysDetachingFromVM (?) or just PhysDetached.
144 * Next VBox: ReleasingToHost, HeldByProxy.
145 */
146 kHostUSBDeviceState_DetachingFromVM,
147
148 /** The device has been physically removed while a VM used it.
149 *
150 * This is the device state while VBoxSVC is doing IPC to the client (VM) telling it
151 * to detach it.
152 *
153 * Next Host: None.
154 * Next VBox: PhysDetached
155 */
156 kHostUSBDeviceState_PhysDetachingFromVM,
157
158 /** Just an invalid state value for use as default for some methods. */
159 kHostUSBDeviceState_Invalid = 0x7fff
160} HostUSBDeviceState;
161
162
163/**
164 * Sub-state for dealing with device re-enumeration.
165 */
166typedef enum
167{
168 /** Not in any sub-state. */
169 kHostUSBDeviceSubState_Default = 0,
170 /** Awaiting a logical device detach following a device re-enumeration. */
171 kHostUSBDeviceSubState_AwaitingDetach,
172 /** Awaiting a logical device re-attach following a device re-enumeration. */
173 kHostUSBDeviceSubState_AwaitingReAttach
174} HostUSBDeviceSubState;
175
176
177/**
178 * Object class used to hold Host USB Device properties.
179 */
180class ATL_NO_VTABLE HostUSBDevice :
181 public HostUSBDeviceWrap
182{
183public:
184 DECLARE_COMMON_CLASS_METHODS(HostUSBDevice)
185
186 HRESULT FinalConstruct();
187 void FinalRelease();
188
189 // public initializer/uninitializer for internal purposes only
190 HRESULT init(PUSBDEVICE aUsb, USBProxyBackend *aUSBProxyBackend);
191 void uninit();
192
193 // public methods only for internal purposes
194
195 /** @note Must be called from under the object read lock. */
196 const Guid& i_getId() const { return mId; }
197
198 /** @note Must be called from under the object read lock. */
199 HostUSBDeviceState i_getUnistate() const { return mUniState; }
200
201 /** @note Must be called from under the object read lock. */
202 const char *i_getStateName() { return i_stateName (mUniState, mPendingUniState, mUniSubState); }
203
204 /** @note Must be called from under the object read lock. */
205 bool i_isCapturableOrHeld()
206 {
207 return mUniState == kHostUSBDeviceState_Unused
208 || mUniState == kHostUSBDeviceState_Capturable
209 || mUniState == kHostUSBDeviceState_HeldByProxy;
210 }
211
212 /** @note Must be called from under the object read lock. */
213 ComObjPtr<SessionMachine> &i_getMachine() { return mMachine; }
214
215 /** @note Must be called from under the object read lock. */
216 PCUSBDEVICE i_getUsbData() const { return mUsb; }
217
218 USBProxyBackend *i_getUsbProxyBackend() const { return mUSBProxyBackend; }
219
220 com::Utf8Str i_getName();
221
222 HRESULT i_requestCaptureForVM(SessionMachine *aMachine, bool aSetError,
223 const com::Utf8Str &aCaptureFilename, ULONG aMaskedIfs = 0);
224 HRESULT i_onDetachFromVM(SessionMachine *aMachine, bool aDone, bool *aRunFilters, bool aAbnormal = false);
225 HRESULT i_requestReleaseToHost();
226 HRESULT i_requestHold();
227 bool i_wasActuallyDetached();
228 void i_onPhysicalDetached();
229
230 bool i_isMatch(const USBDeviceFilter::BackupableUSBDeviceFilterData &aData);
231 int i_compare(PCUSBDEVICE aDev2);
232 static int i_compare(PCUSBDEVICE aDev1, PCUSBDEVICE aDev2, bool aIsAwaitingReAttach = false);
233
234 bool i_updateState(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine);
235 bool i_updateStateFake(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine);
236
237 static const char *i_stateName(HostUSBDeviceState aState,
238 HostUSBDeviceState aPendingState = kHostUSBDeviceState_Invalid,
239 HostUSBDeviceSubState aSubState = kHostUSBDeviceSubState_Default);
240
241 void *i_getBackendUserData() { return m_pvBackendUser; }
242 void i_setBackendUserData(void *pvBackendUser) { m_pvBackendUser = pvBackendUser; }
243
244protected:
245
246 HRESULT i_attachToVM(SessionMachine *aMachine, const com::Utf8Str &aCaptureFilename, ULONG aMaskedIfs = 0);
247 void i_detachFromVM(HostUSBDeviceState aFinalState);
248 void i_onPhysicalDetachedInternal();
249 bool i_hasAsyncOperationTimedOut() const;
250
251 bool i_setState (HostUSBDeviceState aNewState, HostUSBDeviceState aNewPendingState = kHostUSBDeviceState_Invalid,
252 HostUSBDeviceSubState aNewSubState = kHostUSBDeviceSubState_Default);
253 bool i_startTransition (HostUSBDeviceState aNewState, HostUSBDeviceState aFinalState,
254 HostUSBDeviceSubState aNewSubState = kHostUSBDeviceSubState_Default);
255 bool i_advanceTransition(bool aSkipReAttach = false);
256 bool i_failTransition(HostUSBDeviceState a_enmStateHint);
257 USBDeviceState_T i_canonicalState() const;
258
259private:
260
261 // wrapped IUSBDevice properties
262 HRESULT getId(com::Guid &aId);
263 HRESULT getVendorId(USHORT *aVendorId);
264 HRESULT getProductId(USHORT *aProductId);
265 HRESULT getRevision(USHORT *aRevision);
266 HRESULT getManufacturer(com::Utf8Str &aManufacturer);
267 HRESULT getProduct(com::Utf8Str &aProduct);
268 HRESULT getSerialNumber(com::Utf8Str &aSerialNumber);
269 HRESULT getAddress(com::Utf8Str &aAddress);
270 HRESULT getPort(USHORT *aPort);
271 HRESULT getPortPath(com::Utf8Str &aPortPath);
272 HRESULT getVersion(USHORT *aVersion);
273 HRESULT getPortVersion(USHORT *aPortVersion);
274 HRESULT getSpeed(USBConnectionSpeed_T *aSpeed);
275 HRESULT getRemote(BOOL *aRemote);
276 HRESULT getState(USBDeviceState_T *aState);
277 HRESULT getBackend(com::Utf8Str &aBackend);
278 HRESULT getDeviceInfo(std::vector<com::Utf8Str> &aInfo);
279
280
281 const Guid mId;
282
283 /** @name The state machine variables
284 * Only setState(), init() and uninit() will modify these members!
285 * @{ */
286 /** The RTTimeNanoTS() corresponding to the last state change.
287 *
288 * Old state machine: RTTimeNanoTS() of when mIsStatePending was set or mDetaching changed
289 * from kNotDetaching. For operations that cannot be canceled it's 0. */
290 uint64_t mLastStateChangeTS;
291 /** Current state. */
292 HostUSBDeviceState mUniState;
293 /** Sub-state for tracking re-enumeration. */
294 HostUSBDeviceSubState mUniSubState;
295 /** The final state of an pending transition.
296 * This is mainly a measure to reduce the number of HostUSBDeviceState values. */
297 HostUSBDeviceState mPendingUniState;
298 /** Previous state.
299 * This is used for bailing out when a transition like capture fails. */
300 HostUSBDeviceState mPrevUniState;
301 /** Indicator set by onDetachedPhys and check when advancing a transitional state. */
302 bool mIsPhysicallyDetached;
303 /** @} */
304
305 /** The machine the usb device is (being) attached to. */
306 ComObjPtr<SessionMachine> mMachine;
307 /** Pointer to the USB Proxy Backend instance. */
308 USBProxyBackend *mUSBProxyBackend;
309 /** Pointer to the USB Device structure owned by this device.
310 * Only used for host devices. */
311 PUSBDEVICE mUsb;
312 /** The interface mask to be used in the pending capture.
313 * This is a filter property. */
314 ULONG mMaskedIfs;
315 /** The name of this device. */
316 Utf8Str mNameObj;
317 /** The name of this device (for logging purposes).
318 * This points to the string in mNameObj. */
319 const char *mName;
320 /** The filename to capture the USB traffic to. */
321 com::Utf8Str mCaptureFilename;
322 /** Optional opaque user data assigned by the USB proxy backend owning the device. */
323 void *m_pvBackendUser;
324};
325
326#endif /* !MAIN_INCLUDED_HostUSBDeviceImpl_h */
327/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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