VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostUSBDeviceImpl.cpp@ 51092

Last change on this file since 51092 was 51092, checked in by vboxsync, 11 years ago

6813 src-client/MachineDebuggerImpl.cpp + various formatting changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 93.0 KB
Line 
1/* $Id: HostUSBDeviceImpl.cpp 51092 2014-04-16 17:57:25Z vboxsync $ */
2/** @file
3 * VirtualBox IHostUSBDevice COM interface implementation.
4 */
5
6/*
7 * Copyright (C) 2005-2013 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#include <iprt/types.h> /* for UINT64_C */
20
21#include "HostUSBDeviceImpl.h"
22#include "MachineImpl.h"
23#include "HostImpl.h"
24#include "VirtualBoxErrorInfoImpl.h"
25#include "USBProxyService.h"
26
27#include "AutoCaller.h"
28#include "Logging.h"
29
30#include <VBox/err.h>
31#include <iprt/cpp/utils.h>
32
33// constructor / destructor
34/////////////////////////////////////////////////////////////////////////////
35
36DEFINE_EMPTY_CTOR_DTOR(HostUSBDevice)
37
38HRESULT HostUSBDevice::FinalConstruct()
39{
40 mUSBProxyService = NULL;
41 mUsb = NULL;
42
43 return BaseFinalConstruct();
44}
45
46void HostUSBDevice::FinalRelease()
47{
48 uninit();
49 BaseFinalRelease();
50}
51
52// public initializer/uninitializer for internal purposes only
53/////////////////////////////////////////////////////////////////////////////
54
55/**
56 * Initializes the USB device object.
57 *
58 * @returns COM result indicator
59 * @param aUsb Pointer to the usb device structure for which the object is to be a wrapper.
60 * This structure is now fully owned by the HostUSBDevice object and will be
61 * freed when it is destructed.
62 * @param aUSBProxyService Pointer to the USB Proxy Service object.
63 */
64HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
65{
66 ComAssertRet(aUsb, E_INVALIDARG);
67
68 /* Enclose the state transition NotReady->InInit->Ready */
69 AutoInitSpan autoInitSpan(this);
70 AssertReturn(autoInitSpan.isOk(), E_FAIL);
71
72 /*
73 * We need a unique ID for this VBoxSVC session.
74 * The UUID isn't stored anywhere.
75 */
76 unconst(mId).create();
77
78 /*
79 * Set the initial device state.
80 */
81 AssertMsgReturn( aUsb->enmState >= USBDEVICESTATE_UNSUPPORTED
82 && aUsb->enmState < USBDEVICESTATE_USED_BY_GUEST, /* used-by-guest is not a legal initial state. */
83 ("%d\n", aUsb->enmState), E_FAIL);
84 mUniState = (HostUSBDeviceState)aUsb->enmState;
85 mUniSubState = kHostUSBDeviceSubState_Default;
86 mPendingUniState = kHostUSBDeviceState_Invalid;
87 mPrevUniState = mUniState;
88 mIsPhysicallyDetached = false;
89
90 /* Other data members */
91 mUSBProxyService = aUSBProxyService;
92 mUsb = aUsb;
93
94 /* Set the name. */
95 mNameObj = i_getName();
96 mName = mNameObj.c_str();
97
98 /* Confirm the successful initialization */
99 autoInitSpan.setSucceeded();
100
101 return S_OK;
102}
103
104/**
105 * Uninitializes the instance and sets the ready flag to FALSE.
106 * Called either from FinalRelease() or by the parent when it gets destroyed.
107 */
108void HostUSBDevice::uninit()
109{
110 /* Enclose the state transition Ready->InUninit->NotReady */
111 AutoUninitSpan autoUninitSpan(this);
112 if (autoUninitSpan.uninitDone())
113 return;
114
115 if (mUsb != NULL)
116 {
117 USBProxyService::freeDevice(mUsb);
118 mUsb = NULL;
119 }
120
121 mUSBProxyService = NULL;
122 mUniState = kHostUSBDeviceState_Invalid;
123}
124
125// Wrapped IUSBDevice properties
126/////////////////////////////////////////////////////////////////////////////
127HRESULT HostUSBDevice::getId(com::Guid &aId)
128{
129 /* mId is constant during life time, no need to lock */
130 aId = mId;
131
132 return S_OK;
133}
134
135
136HRESULT HostUSBDevice::getVendorId(USHORT *aVendorId)
137{
138 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
139
140 *aVendorId = mUsb->idVendor;
141
142 return S_OK;
143}
144
145HRESULT HostUSBDevice::getProductId(USHORT *aProductId)
146{
147 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
148
149 *aProductId = mUsb->idProduct;
150
151 return S_OK;
152}
153
154
155HRESULT HostUSBDevice::getRevision(USHORT *aRevision)
156{
157 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
158
159 *aRevision = mUsb->bcdDevice;
160
161 return S_OK;
162}
163
164HRESULT HostUSBDevice::getManufacturer(com::Utf8Str &aManufacturer)
165{
166 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
167
168 aManufacturer = mUsb->pszManufacturer;
169
170 return S_OK;
171}
172
173
174HRESULT HostUSBDevice::getProduct(com::Utf8Str &aProduct)
175{
176 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
177
178 aProduct = mUsb->pszProduct;
179
180 return S_OK;
181}
182
183
184HRESULT HostUSBDevice::getSerialNumber(com::Utf8Str &aSerialNumber)
185{
186 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
187
188 aSerialNumber = mUsb->pszSerialNumber;
189
190 return S_OK;
191}
192
193HRESULT HostUSBDevice::getAddress(com::Utf8Str &aAddress)
194{
195 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
196 aAddress = mUsb->pszAddress;
197 return S_OK;
198}
199
200
201HRESULT HostUSBDevice::getPort(USHORT *aPort)
202{
203 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
204
205#if !defined(RT_OS_WINDOWS) /// @todo check up the bPort value on Windows before enabling this.
206 *aPort = mUsb->bPort;
207#else
208 *aPort = 0;
209#endif
210
211 return S_OK;
212}
213
214
215HRESULT HostUSBDevice::getVersion(USHORT *aVersion)
216{
217 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
218
219 *aVersion = mUsb->bcdUSB >> 8;
220
221 return S_OK;
222}
223
224HRESULT HostUSBDevice::getPortVersion(USHORT *aPortVersion)
225{
226 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
227 /* Port version is 2 (EHCI) if and only if the device runs at high speed;
228 * if speed is unknown, fall back to the old and inaccurate method.
229 */
230 if (mUsb->enmSpeed == USBDEVICESPEED_UNKNOWN)
231 *aPortVersion = mUsb->bcdUSB >> 8;
232 else
233 *aPortVersion = (mUsb->enmSpeed == USBDEVICESPEED_HIGH) ? 2 : 1;
234
235 return S_OK;
236}
237
238
239HRESULT HostUSBDevice::getRemote(BOOL *aRemote)
240{
241 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
242
243 *aRemote = FALSE;
244
245 return S_OK;
246}
247
248
249HRESULT HostUSBDevice::getState(USBDeviceState_T *aState)
250{
251 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
252
253 *aState = i_canonicalState();
254
255 return S_OK;
256}
257
258
259// public methods only for internal purposes
260////////////////////////////////////////////////////////////////////////////////
261
262/**
263 * @note Locks this object for reading.
264 */
265com::Utf8Str HostUSBDevice::i_getName()
266{
267 Utf8Str name;
268
269 AutoCaller autoCaller(this);
270 AssertComRCReturn(autoCaller.rc(), name);
271
272 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
273
274 bool haveManufacturer = mUsb->pszManufacturer && *mUsb->pszManufacturer;
275 bool haveProduct = mUsb->pszProduct && *mUsb->pszProduct;
276 if (haveManufacturer && haveProduct)
277 name = Utf8StrFmt("%s %s", mUsb->pszManufacturer, mUsb->pszProduct);
278 else if (haveManufacturer)
279 name = Utf8StrFmt("%s", mUsb->pszManufacturer);
280 else if (haveProduct)
281 name = Utf8StrFmt("%s", mUsb->pszProduct);
282 else
283 name = "<unknown>";
284
285 return name;
286}
287
288/**
289 * Requests the USB proxy service capture the device (from the host)
290 * and attach it to a VM.
291 *
292 * As a convenience, this method will operate like attachToVM() if the device
293 * is already held by the proxy. Note that it will then perform IPC to the VM
294 * process, which means it will temporarily release all locks. (Is this a good idea?)
295 *
296 * @param aMachine Machine this device should be attach to.
297 * @param aSetError Whether to set full error message or not to bother.
298 * @param aMaskedIfs The interfaces to hide from the guest.
299 *
300 * @returns Status indicating whether it was successfully captured and/or attached.
301 * @retval S_OK on success.
302 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
303 * @retval E_* as appropriate.
304 */
305HRESULT HostUSBDevice::i_requestCaptureForVM(SessionMachine *aMachine, bool aSetError, ULONG aMaskedIfs /* = 0*/)
306{
307 /*
308 * Validate preconditions and input.
309 */
310 AssertReturn(aMachine, E_INVALIDARG);
311 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
312 AssertReturn(!aMachine->isWriteLockOnCurrentThread(), E_FAIL);
313
314 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
315 LogFlowThisFunc(("{%s} aMachine=%p aMaskedIfs=%#x\n", mName, aMachine, aMaskedIfs));
316
317 if (aSetError)
318 {
319 if (mUniState == kHostUSBDeviceState_Unsupported)
320 return setError(E_INVALIDARG,
321 tr("USB device '%s' with UUID {%RTuuid} cannot be accessed by guest computers"),
322 mName, mId.raw());
323 if (mUniState == kHostUSBDeviceState_UsedByHost)
324 return setError(E_INVALIDARG,
325 tr("USB device '%s' with UUID {%RTuuid} is being exclusively used by the host computer"),
326 mName, mId.raw());
327 if (mUniState == kHostUSBDeviceState_UsedByVM)
328 {
329 /* Machine::name() requires a read lock */
330 alock.release();
331 AutoReadLock machLock(mMachine COMMA_LOCKVAL_SRC_POS);
332 return setError(E_INVALIDARG,
333 tr("USB device '%s' with UUID {%RTuuid} is already captured by the virtual machine '%s'"),
334 mName, mId.raw(), mMachine->getName().c_str());
335 }
336 if (mUniState >= kHostUSBDeviceState_FirstTransitional)
337 return setError(E_INVALIDARG,
338 tr("USB device '%s' with UUID {%RTuuid} is busy with a previous request. Please try again later"),
339 mName, mId.raw());
340 if ( mUniState != kHostUSBDeviceState_Unused
341 && mUniState != kHostUSBDeviceState_HeldByProxy
342 && mUniState != kHostUSBDeviceState_Capturable)
343 return setError(E_INVALIDARG,
344 tr("USB device '%s' with UUID {%RTuuid} is not in the right state for capturing (%s)"),
345 mName, mId.raw(), i_getStateName());
346 }
347
348 AssertReturn( mUniState == kHostUSBDeviceState_HeldByProxy
349 || mUniState == kHostUSBDeviceState_Unused
350 || mUniState == kHostUSBDeviceState_Capturable,
351 E_UNEXPECTED);
352 Assert(mMachine.isNull());
353
354 /*
355 * If it's already held by the proxy, we'll simply call
356 * attachToVM synchronously.
357 */
358 if (mUniState == kHostUSBDeviceState_HeldByProxy)
359 {
360 alock.release();
361 HRESULT hrc = i_attachToVM(aMachine, aMaskedIfs);
362 return SUCCEEDED(hrc);
363 }
364
365 /*
366 * Need to capture the device before it can be used.
367 *
368 * The device will be attached to the VM by the USB proxy service thread
369 * when the request succeeds (i.e. asynchronously).
370 */
371 LogFlowThisFunc(("{%s} capturing the device.\n", mName));
372#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
373 || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS)
374 i_setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM, kHostUSBDeviceSubState_AwaitingDetach);
375#else
376 i_setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM);
377#endif
378 mMachine = aMachine;
379 mMaskedIfs = aMaskedIfs;
380 alock.release();
381 int rc = mUSBProxyService->captureDevice(this);
382 if (RT_FAILURE(rc))
383 {
384 alock.acquire();
385 i_failTransition();
386 mMachine.setNull();
387 if (rc == VERR_SHARING_VIOLATION)
388 return setError(E_FAIL,
389 tr("USB device '%s' with UUID {%RTuuid} is in use by someone else"),
390 mName, mId.raw());
391 return E_FAIL;
392 }
393
394 return S_OK;
395}
396
397/**
398 * Attempts to attach the USB device to a VM.
399 *
400 * The device must be in the HeldByProxy state or about to exit the
401 * Capturing state.
402 *
403 * This method will make an IPC to the VM process and do the actual
404 * attaching. While in the IPC locks will be abandond.
405 *
406 * @returns Status indicating whether it was successfully attached or not.
407 * @retval S_OK on success.
408 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
409 * @retval E_* as appropriate.
410 *
411 * @param aMachine Machine this device should be attach to.
412 * @param aMaskedIfs The interfaces to hide from the guest.
413 */
414HRESULT HostUSBDevice::i_attachToVM(SessionMachine *aMachine, ULONG aMaskedIfs /* = 0*/)
415{
416 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
417 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
418 /*
419 * Validate and update the state.
420 */
421 AssertReturn( mUniState == kHostUSBDeviceState_Capturing
422 || mUniState == kHostUSBDeviceState_HeldByProxy
423 || mUniState == kHostUSBDeviceState_AttachingToVM,
424 E_UNEXPECTED);
425 i_setState(kHostUSBDeviceState_AttachingToVM, kHostUSBDeviceState_UsedByVM);
426
427 /*
428 * The VM process will query the object, so grab a reference to ourselves and release the locks.
429 */
430 ComPtr<IUSBDevice> d = this;
431
432 /*
433 * Call the VM process (IPC) and request it to attach the device.
434 *
435 * There are many reasons for this to fail, so, as a consequence we don't
436 * assert the return code as it will crash the daemon and annoy the heck
437 * out of people.
438 */
439 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceAttach()...\n", mName));
440 alock.release();
441 HRESULT hrc = aMachine->onUSBDeviceAttach(d, NULL, aMaskedIfs);
442 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceAttach()=%08X\n", mName, hrc));
443
444 /*
445 * As we re-acquire the lock, we'll have to check if the device was
446 * physically detached while we were busy.
447 */
448 alock.acquire();
449
450 if (SUCCEEDED(hrc))
451 {
452 mMachine = aMachine;
453 if (!mIsPhysicallyDetached)
454 i_setState(kHostUSBDeviceState_UsedByVM);
455 else
456 {
457 alock.release();
458 i_detachFromVM(kHostUSBDeviceState_PhysDetached);
459 hrc = E_UNEXPECTED;
460 }
461 }
462 else
463 {
464 mMachine.setNull();
465 if (!mIsPhysicallyDetached)
466 {
467 i_setState(kHostUSBDeviceState_HeldByProxy);
468 if (hrc == E_UNEXPECTED)
469 hrc = E_FAIL; /* No confusion. */
470 }
471 else
472 {
473 alock.release();
474 i_onPhysicalDetachedInternal();
475 hrc = E_UNEXPECTED;
476 }
477 }
478 return hrc;
479}
480
481
482/**
483 * Detaches the device from the VM.
484 *
485 * This is used for a special scenario in attachToVM() and from
486 * onPhysicalDetachedInternal().
487 *
488 * @param aFinalState The final state (PhysDetached).
489 */
490void HostUSBDevice::i_detachFromVM(HostUSBDeviceState aFinalState)
491{
492 NOREF(aFinalState);
493
494 /*
495 * Assert preconditions.
496 */
497 Assert(aFinalState == kHostUSBDeviceState_PhysDetached);
498 AssertReturnVoid(!isWriteLockOnCurrentThread());
499 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
500 Assert( mUniState == kHostUSBDeviceState_AttachingToVM
501 || mUniState == kHostUSBDeviceState_UsedByVM);
502 Assert(!mMachine.isNull());
503
504 /*
505 * Change the state and abandon the locks. The VM may query
506 * data and we don't want to deadlock - the state protects us,
507 * so, it's not a bit issue here.
508 */
509 i_setState(kHostUSBDeviceState_PhysDetachingFromVM, kHostUSBDeviceState_PhysDetached);
510
511 /*
512 * Call the VM process (IPC) and request it to detach the device.
513 *
514 * There are many reasons for this to fail, so, as a consequence we don't
515 * assert the return code as it will crash the daemon and annoy the heck
516 * out of people.
517 */
518 alock.release();
519 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceDetach()...\n", mName));
520 HRESULT hrc = mMachine->onUSBDeviceDetach(mId.toUtf16().raw(), NULL);
521 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceDetach()=%Rhrc\n", mName, hrc));
522 NOREF(hrc);
523
524 /*
525 * Re-acquire the locks and complete the transition.
526 */
527 alock.acquire();
528 i_advanceTransition();
529}
530
531/**
532 * Called when the VM process to inform us about the device being
533 * detached from it.
534 *
535 * This is NOT called when we detach the device via onUSBDeviceDetach.
536 *
537 *
538 * @param[in] aMachine The machine making the request.
539 * This must be the machine this device is currently attached to.
540 * @param[in] aDone When set to false, the VM just informs us that it's about
541 * to detach this device but hasn't done it just yet.
542 * When set to true, the VM informs us that it has completed
543 * the detaching of this device.
544 * @param[out] aRunFilters Whether to run filters.
545 * @param[in] aAbnormal Set if we're cleaning up after a crashed VM.
546 *
547 * @returns S_OK on success, and E_UNEXPECTED if the device isn't in the right state.
548 *
549 * @note Must be called from under the object write lock.
550 */
551HRESULT HostUSBDevice::i_onDetachFromVM(SessionMachine *aMachine, bool aDone, bool *aRunFilters, bool aAbnormal /*= true*/)
552{
553 LogFlowThisFunc(("{%s} state=%s aDone=%RTbool aAbnormal=%RTbool\n", mName, i_getStateName(), aDone, aAbnormal));
554
555 /*
556 * Validate preconditions.
557 */
558 AssertPtrReturn(aRunFilters, E_INVALIDARG);
559 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
560 if (!aDone)
561 {
562 if (mUniState != kHostUSBDeviceState_UsedByVM)
563 return setError(E_INVALIDARG,
564 tr("USB device '%s' with UUID {%RTuuid} is busy (state '%s'). Please try again later"),
565 mName, mId.raw(), i_getStateName());
566 }
567 else
568 AssertMsgReturn( mUniState == kHostUSBDeviceState_DetachingFromVM /** @todo capturing for VM
569 ends up here on termination. */
570 || (mUniState == kHostUSBDeviceState_UsedByVM && aAbnormal),
571 ("{%s} %s\n", mName, i_getStateName()), E_UNEXPECTED);
572 AssertMsgReturn((mMachine == aMachine), ("%p != %p\n", (void *)mMachine, aMachine), E_FAIL);
573
574 /*
575 * Change the state.
576 */
577 if (!aDone)
578 {
579 *aRunFilters = i_startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
580 /* PORTME: This might require host specific changes if you re-enumerate the device. */
581 }
582 else if (aAbnormal && mUniState == kHostUSBDeviceState_UsedByVM)
583 {
584 /* Fast forward thru the DetachingFromVM state and on to HeldByProxy. */
585 /** @todo need to update the state machine to handle crashed VMs. */
586 i_startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
587 *aRunFilters = i_advanceTransition();
588 mMachine.setNull();
589 /* PORTME: ditto / trouble if you depend on the VM process to do anything. */
590 }
591 else
592 {
593 /* normal completion. */
594 Assert(mUniSubState == kHostUSBDeviceSubState_Default); /* PORTME: ditto */
595 *aRunFilters = i_advanceTransition();
596 mMachine.setNull();
597 }
598
599 return S_OK;
600}
601
602/**
603 * Requests the USB proxy service to release the device back to the host.
604 *
605 * This method will ignore (not assert) calls for devices that already
606 * belong to the host because it simplifies the usage a bit.
607 *
608 * @returns COM status code.
609 * @retval S_OK on success.
610 * @retval E_UNEXPECTED on bad state.
611 * @retval E_* as appropriate.
612 *
613 * @note Must be called without holding the object lock.
614 */
615HRESULT HostUSBDevice::i_requestReleaseToHost()
616{
617 /*
618 * Validate preconditions.
619 */
620 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
621 Assert(mMachine.isNull());
622
623 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
624 LogFlowThisFunc(("{%s}\n", mName));
625 if ( mUniState == kHostUSBDeviceState_Unused
626 || mUniState == kHostUSBDeviceState_Capturable)
627 return S_OK;
628 AssertMsgReturn(mUniState == kHostUSBDeviceState_HeldByProxy, ("{%s} %s\n", mName, i_getStateName()), E_UNEXPECTED);
629
630 /*
631 * Try release it.
632 */
633#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
634 || defined(RT_OS_WINDOWS)
635 i_startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused, kHostUSBDeviceSubState_AwaitingDetach);
636#else
637 i_startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused);
638#endif
639 alock.release();
640 int rc = mUSBProxyService->releaseDevice(this);
641 if (RT_FAILURE(rc))
642 {
643 alock.acquire();
644 i_failTransition();
645 return E_FAIL;
646 }
647 return S_OK;
648}
649
650/**
651 * Requests the USB proxy service to capture and hold the device.
652 *
653 * The device must be owned by the host at the time of the call. But for
654 * the callers convenience, calling this method on a device that is already
655 * being held will success without any assertions.
656 *
657 * @returns COM status code.
658 * @retval S_OK on success.
659 * @retval E_UNEXPECTED on bad state.
660 * @retval E_* as appropriate.
661 *
662 * @note Must be called without holding the object lock.
663 */
664HRESULT HostUSBDevice::i_requestHold()
665{
666 /*
667 * Validate preconditions.
668 */
669 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
670 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
671 LogFlowThisFunc(("{%s}\n", mName));
672 AssertMsgReturn( mUniState == kHostUSBDeviceState_Unused
673 || mUniState == kHostUSBDeviceState_Capturable
674 || mUniState == kHostUSBDeviceState_HeldByProxy,
675 ("{%s} %s\n", mName, i_getStateName()),
676 E_UNEXPECTED);
677
678 Assert(mMachine.isNull());
679 mMachine.setNull();
680
681 if (mUniState == kHostUSBDeviceState_HeldByProxy)
682 return S_OK;
683
684 /*
685 * Do the job.
686 */
687#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
688 || defined(RT_OS_WINDOWS)
689 i_startTransition(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_HeldByProxy, kHostUSBDeviceSubState_AwaitingDetach);
690#else
691 i_startTransition(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_HeldByProxy);
692#endif
693 alock.release();
694 int rc = mUSBProxyService->captureDevice(this);
695 if (RT_FAILURE(rc))
696 {
697 alock.acquire();
698 i_failTransition();
699 return E_FAIL;
700 }
701 return S_OK;
702}
703
704
705/**
706 * Check a detach detected by the USB Proxy Service to see if
707 * it's a real one or just a logical following a re-enumeration.
708 *
709 * This will work the internal sub state of the device and do time
710 * outs, so it does more than just querying data!
711 *
712 * @returns true if it was actually detached, false if it's just a re-enumeration.
713 */
714bool HostUSBDevice::i_wasActuallyDetached()
715{
716 /*
717 * This only applies to the detach and re-attach states.
718 */
719 switch (mUniState)
720 {
721 case kHostUSBDeviceState_Capturing:
722 case kHostUSBDeviceState_ReleasingToHost:
723 case kHostUSBDeviceState_AttachingToVM:
724 case kHostUSBDeviceState_DetachingFromVM:
725 switch (mUniSubState)
726 {
727 /*
728 * If we're awaiting a detach, the this has now occurred
729 * and the state should be advanced.
730 */
731 case kHostUSBDeviceSubState_AwaitingDetach:
732 i_advanceTransition();
733 return false; /* not physically detached. */
734
735 /*
736 * Check for timeouts.
737 */
738 case kHostUSBDeviceSubState_AwaitingReAttach:
739 {
740#ifndef RT_OS_WINDOWS /* check the implementation details here. */
741 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
742 if (elapsedNanoseconds > UINT64_C(60000000000)) /* 60 seconds */
743 {
744 LogRel(("USB: Async operation timed out for device %s (state: %s)\n", mName, i_getStateName()));
745 i_failTransition();
746 }
747#endif
748 return false; /* not physically detached. */
749 }
750
751 /* not applicable.*/
752 case kHostUSBDeviceSubState_Default:
753 break;
754 }
755 break;
756
757 /* not applicable. */
758 case kHostUSBDeviceState_Unsupported:
759 case kHostUSBDeviceState_UsedByHost:
760 case kHostUSBDeviceState_Capturable:
761 case kHostUSBDeviceState_Unused:
762 case kHostUSBDeviceState_HeldByProxy:
763 case kHostUSBDeviceState_UsedByVM:
764 case kHostUSBDeviceState_PhysDetachingFromVM:
765 case kHostUSBDeviceState_PhysDetached:
766 break;
767
768 default:
769 AssertLogRelMsgFailed(("this=%p %s\n", this, i_getStateName()));
770 break;
771 }
772
773 /* It was detached. */
774 return true;
775}
776
777/**
778 * Notification from the USB Proxy that the device was physically detached.
779 *
780 * If a transition is pending, mIsPhysicallyDetached will be set and
781 * handled when the transition advances forward.
782 *
783 * Otherwise the device will be detached from any VM currently using it - this
784 * involves IPC and will temporarily abandon locks - and all the device data
785 * reset.
786 */
787void HostUSBDevice::i_onPhysicalDetached()
788{
789 AssertReturnVoid(!isWriteLockOnCurrentThread());
790 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
791 LogFlowThisFunc(("{%s}\n", mName));
792
793 mIsPhysicallyDetached = true;
794 if (mUniState < kHostUSBDeviceState_FirstTransitional)
795 {
796 alock.release();
797 i_onPhysicalDetachedInternal();
798 }
799}
800
801
802/**
803 * Do the physical detach work for a device in a stable state or
804 * at a transition state change.
805 *
806 * See onPhysicalDetach() for details.
807 */
808void HostUSBDevice::i_onPhysicalDetachedInternal()
809{
810 AssertReturnVoid(!isWriteLockOnCurrentThread());
811 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
812 LogFlowThisFunc(("{%s}\n", mName));
813 Assert(mIsPhysicallyDetached);
814
815 /*
816 * Do we need to detach it from the VM first?
817 */
818 if ( !mMachine.isNull()
819 && ( mUniState == kHostUSBDeviceState_UsedByVM
820 || mUniState == kHostUSBDeviceState_AttachingToVM))
821 {
822 alock.release();
823 i_detachFromVM(kHostUSBDeviceState_PhysDetached);
824 alock.acquire();
825 }
826 else
827 AssertMsg(mMachine.isNull(), ("%s\n", i_getStateName()));
828
829 /*
830 * Reset the data and enter the final state.
831 */
832 mMachine.setNull();
833 i_setState(kHostUSBDeviceState_PhysDetached);
834}
835
836
837/**
838 * Returns true if this device matches the given filter data.
839 *
840 * @note It is assumed, that the filter data owner is appropriately
841 * locked before calling this method.
842 *
843 * @note
844 * This method MUST correlate with
845 * USBController::hasMatchingFilter (IUSBDevice *)
846 * in the sense of the device matching logic.
847 *
848 * @note Locks this object for reading.
849 */
850bool HostUSBDevice::i_isMatch(const USBDeviceFilter::Data &aData)
851{
852 AutoCaller autoCaller(this);
853 AssertComRCReturn(autoCaller.rc(), false);
854
855 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
856
857 if (!aData.mActive)
858 return false;
859
860 if (!aData.mRemote.isMatch(FALSE))
861 return false;
862
863 if (!USBFilterMatchDevice(&aData.mUSBFilter, mUsb))
864 return false;
865
866 /* Don't match busy devices with a 100% wildcard filter - this will
867 later become a filter prop (ring-3 only). */
868 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
869 && !USBFilterHasAnySubstatialCriteria(&aData.mUSBFilter))
870 return false;
871
872 LogFlowThisFunc(("returns true\n"));
873 return true;
874}
875
876/**
877 * Compares this device with a USBDEVICE and decides if the match or which comes first.
878 *
879 * This will take into account device re-attaching and omit the bits
880 * that may change during a device re-enumeration.
881 *
882 * @param aDev2 Device 2.
883 *
884 * @returns < 0 if this should come before aDev2.
885 * @returns 0 if this and aDev2 are equal.
886 * @returns > 0 if this should come after aDev2.
887 *
888 * @note Must be called from under the object write lock.
889 */
890int HostUSBDevice::i_compare(PCUSBDEVICE aDev2)
891{
892 AssertReturn(isWriteLockOnCurrentThread(), -1);
893 //Log3(("%Rfn: %p {%s}\n", __PRETTY_FUNCTION__, this, mName));
894 return i_compare(mUsb, aDev2,
895 mUniSubState == kHostUSBDeviceSubState_AwaitingDetach /* (In case we don't get the detach notice.) */
896 || mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach);
897}
898
899/**
900 * Compares two USBDEVICE structures and decides if the match or which comes first.
901 *
902 * @param aDev1 Device 1.
903 * @param aDev2 Device 2.
904 * @param aIsAwaitingReAttach Whether to omit bits that will change in a device
905 * re-enumeration (true) or not (false).
906 *
907 * @returns < 0 if aDev1 should come before aDev2.
908 * @returns 0 if aDev1 and aDev2 are equal.
909 * @returns > 0 if aDev1 should come after aDev2.
910 */
911/*static*/
912int HostUSBDevice::i_compare(PCUSBDEVICE aDev1, PCUSBDEVICE aDev2, bool aIsAwaitingReAttach /*= false */)
913{
914 /*
915 * Things that stays the same everywhere.
916 *
917 * The more uniquely these properties identifies a device the less the chance
918 * that we mix similar devices during re-enumeration. Bus+port would help
919 * provide ~99.8% accuracy if the host can provide those attributes.
920 */
921 int iDiff = aDev1->idVendor - aDev2->idVendor;
922 if (iDiff)
923 return iDiff;
924
925 iDiff = aDev1->idProduct - aDev2->idProduct;
926 if (iDiff)
927 return iDiff;
928
929 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
930 if (iDiff)
931 {
932 //Log3(("compare: bcdDevice: %#x != %#x\n", aDev1->bcdDevice, aDev2->bcdDevice));
933 return iDiff;
934 }
935
936#ifdef RT_OS_WINDOWS /* the string query may fail on windows during replugging, ignore serial mismatch if this is the case. */
937 if ( aDev1->u64SerialHash != aDev2->u64SerialHash
938 && ( !aIsAwaitingReAttach
939 || (aDev2->pszSerialNumber && *aDev2->pszSerialNumber)
940 || (aDev2->pszManufacturer && *aDev2->pszManufacturer)
941 || (aDev2->pszProduct && *aDev2->pszProduct))
942 )
943#else
944 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
945#endif
946 {
947 //Log3(("compare: u64SerialHash: %#llx != %#llx\n", aDev1->u64SerialHash, aDev2->u64SerialHash));
948 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
949 }
950
951 /* The hub/bus + port should help a lot in a re-attach situation. */
952#ifdef RT_OS_WINDOWS
953 iDiff = strcmp(aDev1->pszHubName, aDev2->pszHubName);
954 if (iDiff)
955 {
956 //Log3(("compare: HubName: %s != %s\n", aDev1->pszHubName, aDev2->pszHubName));
957 return iDiff;
958 }
959#else
960 iDiff = aDev1->bBus - aDev2->bBus;
961 if (iDiff)
962 {
963 //Log3(("compare: bBus: %#x != %#x\n", aDev1->bBus, aDev2->bBus));
964 return iDiff;
965 }
966#endif
967
968 iDiff = aDev1->bPort - aDev2->bPort; /* shouldn't change anywhere and help pinpoint it very accurately. */
969 if (iDiff)
970 {
971 //Log3(("compare: bPort: %#x != %#x\n", aDev1->bPort, aDev2->bPort));
972 return iDiff;
973 }
974
975 /*
976 * Things that usually doesn't stay the same when re-enumerating
977 * a device. The fewer things in the category the better chance
978 * that we avoid messing up when more than one device of the same
979 * kind is attached.
980 */
981 if (aIsAwaitingReAttach)
982 {
983 //Log3(("aDev1=%p == aDev2=%p\n", aDev1, aDev2));
984 return 0;
985 }
986 /* device number always changes. */
987 return strcmp(aDev1->pszAddress, aDev2->pszAddress);
988}
989
990/**
991 * Updates the state of the device.
992 *
993 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
994 * called to process the state change (complete the state change request,
995 * inform the VM process etc.).
996 *
997 * If this method returns @c false, it is assumed that the given state change
998 * is "minor": it doesn't require any further action other than update the
999 * mState field with the actual state value.
1000 *
1001 * Regardless of the return value, this method always takes ownership of the
1002 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
1003 * it using the values of the old structure.
1004 *
1005 * @param[in] aDev The current device state as seen by the proxy backend.
1006 * @param[out] aRunFilters Whether the state change should be accompanied by
1007 * running filters on the device.
1008 * @param[out] aIgnoreMachine Machine to ignore when running filters.
1009 *
1010 * @returns Whether the Host object should be bothered with this state change.
1011 *
1012 * @todo Just do everything here, that is, call filter runners and everything that
1013 * works by state change. Using 3 return codes/parameters is just plain ugly.
1014 */
1015bool HostUSBDevice::i_updateState(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1016{
1017 *aRunFilters = false;
1018 *aIgnoreMachine = NULL;
1019
1020 /*
1021 * Locking.
1022 */
1023 AssertReturn(!isWriteLockOnCurrentThread(), false);
1024 AutoCaller autoCaller(this);
1025 AssertComRCReturn(autoCaller.rc(), false);
1026 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1027
1028 /*
1029 * Replace the existing structure by the new one.
1030 */
1031 const USBDEVICESTATE enmOldState = mUsb->enmState; NOREF(enmOldState);
1032 if (mUsb != aDev)
1033 {
1034#ifdef RT_OS_WINDOWS
1035 /* we used this logic of string comparison in HostUSBDevice::compare
1036 * now we need to preserve strings from the old device if the new device has zero strings
1037 * this ensures the device is correctly matched later on
1038 * otherwise we may end up with a phantom misconfigured device instance */
1039 if ((mUniSubState == kHostUSBDeviceSubState_AwaitingDetach /* (In case we don't get the detach notice.) */
1040 || mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
1041 && (!aDev->pszSerialNumber || !*aDev->pszSerialNumber)
1042 && (!aDev->pszManufacturer || !*aDev->pszManufacturer)
1043 && (!aDev->pszProduct || !*aDev->pszProduct))
1044 {
1045 aDev->u64SerialHash = mUsb->u64SerialHash;
1046
1047 if (mUsb->pszSerialNumber && *mUsb->pszSerialNumber)
1048 {
1049 if (aDev->pszSerialNumber)
1050 RTStrFree((char *)aDev->pszSerialNumber);
1051
1052 /* since we're going to free old device later on,
1053 * we can just assign the string from it to the new device
1054 * and zero up the string filed for the old device */
1055 aDev->pszSerialNumber = mUsb->pszSerialNumber;
1056 mUsb->pszSerialNumber = NULL;
1057 }
1058
1059 if (mUsb->pszManufacturer && *mUsb->pszManufacturer)
1060 {
1061 if (aDev->pszManufacturer)
1062 RTStrFree((char *)aDev->pszManufacturer);
1063
1064 /* since we're going to free old device later on,
1065 * we can just assign the string from it to the new device
1066 * and zero up the string filed for the old device */
1067 aDev->pszManufacturer = mUsb->pszManufacturer;
1068 mUsb->pszManufacturer = NULL;
1069 }
1070
1071 if (mUsb->pszProduct && *mUsb->pszProduct)
1072 {
1073 if (aDev->pszProduct)
1074 RTStrFree((char *)aDev->pszProduct);
1075
1076 /* since we're going to free old device later on,
1077 * we can just assign the string from it to the new device
1078 * and zero up the string filed for the old device */
1079 aDev->pszProduct = mUsb->pszProduct;
1080 mUsb->pszProduct = NULL;
1081 }
1082 }
1083#endif
1084 aDev->pNext = mUsb->pNext;
1085 aDev->pPrev = mUsb->pPrev;
1086 USBProxyService::freeDevice(mUsb);
1087 mUsb = aDev;
1088 }
1089
1090/** @def HOSTUSBDEVICE_FUZZY_STATE
1091 * Defined on hosts where we have a driver that keeps proper device states.
1092 */
1093# if defined(RT_OS_LINUX) || defined(DOXYGEN_RUNNING)
1094# define HOSTUSBDEVICE_FUZZY_STATE 1
1095# else
1096# undef HOSTUSBDEVICE_FUZZY_STATE
1097# endif
1098 /*
1099 * For some hosts we'll have to be pretty careful here because
1100 * they don't always have a clue what is going on. This is
1101 * particularly true on linux and solaris, while windows and
1102 * darwin generally knows a bit more.
1103 */
1104 bool fIsImportant = false;
1105 if (enmOldState != mUsb->enmState)
1106 {
1107 LogFlowThisFunc(("%p {%s} %s\n", this, mName, i_getStateName()));
1108 switch (mUsb->enmState)
1109 {
1110 /*
1111 * Little fuzziness here, except where we fake capture.
1112 */
1113 case USBDEVICESTATE_USED_BY_HOST:
1114 switch (mUniState)
1115 {
1116 /* Host drivers installed, that's fine. */
1117 case kHostUSBDeviceState_Capturable:
1118 case kHostUSBDeviceState_Unused:
1119 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1120 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1121 break;
1122 case kHostUSBDeviceState_UsedByHost:
1123 break;
1124
1125 /* Can only mean that we've failed capturing it. */
1126 case kHostUSBDeviceState_Capturing:
1127 LogThisFunc(("{%s} capture failed!\n", mName));
1128 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1129 *aRunFilters = i_failTransition();
1130 mMachine.setNull();
1131 break;
1132
1133 /* Guess we've successfully released it. */
1134 case kHostUSBDeviceState_ReleasingToHost:
1135 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1136 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1137 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1138 break;
1139
1140 /* These are IPC states and should be left alone. */
1141 case kHostUSBDeviceState_AttachingToVM:
1142 case kHostUSBDeviceState_DetachingFromVM:
1143 case kHostUSBDeviceState_PhysDetachingFromVM:
1144 LogThisFunc(("{%s} %s - changed to USED_BY_HOST...\n", mName, i_getStateName()));
1145 break;
1146
1147#ifdef HOSTUSBDEVICE_FUZZY_STATE
1148 /* Fake: We can't prevent anyone from grabbing it. */
1149 case kHostUSBDeviceState_HeldByProxy:
1150 LogThisFunc(("{%s} %s -> %s!\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1151 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1152 break;
1153 //case kHostUSBDeviceState_UsedByVM:
1154 // /** @todo needs to be detached from the VM. */
1155 // break;
1156#endif
1157 /* Not supposed to happen... */
1158#ifndef HOSTUSBDEVICE_FUZZY_STATE
1159 case kHostUSBDeviceState_HeldByProxy:
1160#endif
1161 case kHostUSBDeviceState_UsedByVM:
1162 case kHostUSBDeviceState_PhysDetached:
1163 case kHostUSBDeviceState_Unsupported:
1164 default:
1165 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1166 break;
1167 }
1168 break;
1169
1170 /*
1171 * It changed to capturable. Fuzzy hosts might easily
1172 * confuse UsedByVM with this one.
1173 */
1174 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1175 switch (mUniState)
1176 {
1177 /* No change. */
1178#ifdef HOSTUSBDEVICE_FUZZY_STATE
1179 case kHostUSBDeviceState_HeldByProxy:
1180 case kHostUSBDeviceState_UsedByVM:
1181#endif
1182 case kHostUSBDeviceState_Capturable:
1183 break;
1184
1185 /* Changed! */
1186 case kHostUSBDeviceState_UsedByHost:
1187 fIsImportant = true;
1188 case kHostUSBDeviceState_Unused:
1189 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
1190 *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
1191 break;
1192
1193 /* Can only mean that we've failed capturing it. */
1194 case kHostUSBDeviceState_Capturing:
1195 LogThisFunc(("{%s} capture failed!\n", mName));
1196 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1197 *aRunFilters = i_failTransition();
1198 mMachine.setNull();
1199 break;
1200
1201 /* Guess we've successfully released it. */
1202 case kHostUSBDeviceState_ReleasingToHost:
1203 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
1204 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1205 *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
1206 break;
1207
1208 /* These are IPC states and should be left alone. */
1209 case kHostUSBDeviceState_AttachingToVM:
1210 case kHostUSBDeviceState_DetachingFromVM:
1211 case kHostUSBDeviceState_PhysDetachingFromVM:
1212 LogThisFunc(("{%s} %s - changed to USED_BY_HOST_CAPTURABLE...\n", mName, i_getStateName()));
1213 break;
1214
1215 /* Not supposed to happen*/
1216#ifndef HOSTUSBDEVICE_FUZZY_STATE
1217 case kHostUSBDeviceState_HeldByProxy:
1218 case kHostUSBDeviceState_UsedByVM:
1219#endif
1220 case kHostUSBDeviceState_Unsupported:
1221 case kHostUSBDeviceState_PhysDetached:
1222 default:
1223 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1224 break;
1225 }
1226 break;
1227
1228
1229 /*
1230 * It changed to capturable. Fuzzy hosts might easily
1231 * confuse UsedByVM and HeldByProxy with this one.
1232 */
1233 case USBDEVICESTATE_UNUSED:
1234 switch (mUniState)
1235 {
1236 /* No change. */
1237#ifdef HOSTUSBDEVICE_FUZZY_STATE
1238 case kHostUSBDeviceState_HeldByProxy:
1239 case kHostUSBDeviceState_UsedByVM:
1240#endif
1241 case kHostUSBDeviceState_Unused:
1242 break;
1243
1244 /* Changed! */
1245 case kHostUSBDeviceState_UsedByHost:
1246 case kHostUSBDeviceState_Capturable:
1247 fIsImportant = true;
1248 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
1249 *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
1250 break;
1251
1252 /* Can mean that we've failed capturing it, but on windows it is the detach signal. */
1253 case kHostUSBDeviceState_Capturing:
1254#if defined(RT_OS_WINDOWS)
1255 if (mUniSubState == kHostUSBDeviceSubState_AwaitingDetach)
1256 {
1257 LogThisFunc(("{%s} capture advancing thru UNUSED...\n", mName));
1258 *aRunFilters = i_advanceTransition();
1259 }
1260 else
1261#endif
1262 {
1263 LogThisFunc(("{%s} capture failed!\n", mName));
1264 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1265 *aRunFilters = i_failTransition();
1266 mMachine.setNull();
1267 }
1268 break;
1269
1270 /* Guess we've successfully released it. */
1271 case kHostUSBDeviceState_ReleasingToHost:
1272 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
1273 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1274 *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
1275 break;
1276
1277 /* These are IPC states and should be left alone. */
1278 case kHostUSBDeviceState_AttachingToVM:
1279 case kHostUSBDeviceState_DetachingFromVM:
1280 case kHostUSBDeviceState_PhysDetachingFromVM:
1281 LogThisFunc(("{%s} %s - changed to UNUSED...\n", mName, i_getStateName()));
1282 break;
1283
1284 /* Not supposed to happen*/
1285#ifndef HOSTUSBDEVICE_FUZZY_STATE
1286 case kHostUSBDeviceState_HeldByProxy:
1287 case kHostUSBDeviceState_UsedByVM:
1288#endif
1289 case kHostUSBDeviceState_Unsupported:
1290 case kHostUSBDeviceState_PhysDetached:
1291 default:
1292 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1293 break;
1294 }
1295 break;
1296
1297 /*
1298 * This is pretty straight forward, except that everyone
1299 * might sometimes confuse this and the UsedByVM state.
1300 */
1301 case USBDEVICESTATE_HELD_BY_PROXY:
1302 switch (mUniState)
1303 {
1304 /* No change. */
1305 case kHostUSBDeviceState_HeldByProxy:
1306 break;
1307 case kHostUSBDeviceState_UsedByVM:
1308 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, i_getStateName()));
1309 break;
1310
1311 /* Guess we've successfully captured it. */
1312 case kHostUSBDeviceState_Capturing:
1313 LogThisFunc(("{%s} capture succeeded!\n", mName));
1314 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
1315 *aRunFilters = i_advanceTransition(true /* fast forward thru re-attach */);
1316
1317 /* Take action if we're supposed to attach it to a VM. */
1318 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1319 {
1320 alock.release();
1321 i_attachToVM(mMachine, mMaskedIfs);
1322 alock.acquire();
1323 }
1324 break;
1325
1326 /* Can only mean that we've failed capturing it. */
1327 case kHostUSBDeviceState_ReleasingToHost:
1328 LogThisFunc(("{%s} %s failed!\n", mName, i_getStateName()));
1329 mUSBProxyService->releaseDeviceCompleted(this, false /* aSuccess */);
1330 *aRunFilters = i_setState(kHostUSBDeviceState_HeldByProxy);
1331 break;
1332
1333 /* These are IPC states and should be left alone. */
1334 case kHostUSBDeviceState_AttachingToVM:
1335 case kHostUSBDeviceState_DetachingFromVM:
1336 case kHostUSBDeviceState_PhysDetachingFromVM:
1337 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, i_getStateName()));
1338 break;
1339
1340 /* Not supposed to happen. */
1341 case kHostUSBDeviceState_Unsupported:
1342 case kHostUSBDeviceState_UsedByHost:
1343 case kHostUSBDeviceState_Capturable:
1344 case kHostUSBDeviceState_Unused:
1345 case kHostUSBDeviceState_PhysDetached:
1346 default:
1347 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1348 break;
1349 }
1350 break;
1351
1352 /*
1353 * This is very straight forward and only Darwin implements it.
1354 */
1355 case USBDEVICESTATE_USED_BY_GUEST:
1356 switch (mUniState)
1357 {
1358 /* No change. */
1359 case kHostUSBDeviceState_HeldByProxy:
1360 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, i_getStateName()));
1361 break;
1362 case kHostUSBDeviceState_UsedByVM:
1363 break;
1364
1365 /* These are IPC states and should be left alone. */
1366 case kHostUSBDeviceState_AttachingToVM:
1367 case kHostUSBDeviceState_DetachingFromVM:
1368 case kHostUSBDeviceState_PhysDetachingFromVM:
1369 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, i_getStateName()));
1370 break;
1371
1372 /* Not supposed to happen. */
1373 case kHostUSBDeviceState_Unsupported:
1374 case kHostUSBDeviceState_Capturable:
1375 case kHostUSBDeviceState_Unused:
1376 case kHostUSBDeviceState_UsedByHost:
1377 case kHostUSBDeviceState_PhysDetached:
1378 case kHostUSBDeviceState_ReleasingToHost:
1379 case kHostUSBDeviceState_Capturing:
1380 default:
1381 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1382 break;
1383 }
1384 break;
1385
1386 /*
1387 * This is not supposed to happen and indicates a bug in the backend!
1388 */
1389 case USBDEVICESTATE_UNSUPPORTED:
1390 AssertMsgFailed(("enmOldState=%d {%s} %s\n", enmOldState, mName, i_getStateName()));
1391 break;
1392 default:
1393 AssertMsgFailed(("enmState=%d {%s} %s\n", mUsb->enmState, mName, i_getStateName()));
1394 break;
1395 }
1396 }
1397 else if ( mUniSubState == kHostUSBDeviceSubState_AwaitingDetach
1398 && i_hasAsyncOperationTimedOut())
1399 {
1400 LogRel(("USB: timeout in %s for {%RTuuid} / {%s}\n",
1401 i_getStateName(), mId.raw(), mName));
1402 *aRunFilters = i_failTransition();
1403 fIsImportant = true;
1404 }
1405 else
1406 {
1407 LogFlowThisFunc(("%p {%s} %s - no change %d\n", this, mName, i_getStateName(), enmOldState));
1408 /** @todo might have to handle some stuff here too if we cannot make the release/capture
1409 * handling deal with that above ... */
1410 }
1411
1412 return fIsImportant;
1413}
1414
1415
1416/**
1417 * Updates the state of the device, checking for cases which we fake.
1418 *
1419 * See HostUSBDevice::updateState() for details.
1420 *
1421 * @param[in] aDev See HostUSBDevice::updateState().
1422 * @param[out] aRunFilters See HostUSBDevice::updateState()
1423 * @param[out] aIgnoreMachine See HostUSBDevice::updateState()
1424 *
1425 * @returns See HostUSBDevice::updateState()
1426 */
1427bool HostUSBDevice::i_updateStateFake(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1428{
1429 Assert(!isWriteLockOnCurrentThread());
1430 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1431 const HostUSBDeviceState enmState = mUniState;
1432 switch (enmState)
1433 {
1434 case kHostUSBDeviceState_Capturing:
1435 case kHostUSBDeviceState_ReleasingToHost:
1436 {
1437 *aIgnoreMachine = mUniState == kHostUSBDeviceState_ReleasingToHost ? mMachine : NULL;
1438 *aRunFilters = i_advanceTransition();
1439 LogThisFunc(("{%s} %s\n", mName, i_getStateName()));
1440
1441 if (mUsb != aDev)
1442 {
1443 aDev->pNext = mUsb->pNext;
1444 aDev->pPrev = mUsb->pPrev;
1445 USBProxyService::freeDevice(mUsb);
1446 mUsb = aDev;
1447 }
1448
1449 /* call the completion method */
1450 if (enmState == kHostUSBDeviceState_Capturing)
1451 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
1452 else
1453 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1454
1455 /* Take action if we're supposed to attach it to a VM. */
1456 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1457 {
1458 alock.release();
1459 i_attachToVM(mMachine, mMaskedIfs);
1460 }
1461 return true;
1462 }
1463
1464 default:
1465 alock.release();
1466 return i_updateState(aDev, aRunFilters, aIgnoreMachine);
1467 }
1468}
1469
1470
1471/**
1472 * Checks if there is a pending asynchronous operation and whether
1473 * it has timed out or not.
1474 *
1475 * @returns true on timeout, false if not.
1476 *
1477 * @note Caller must have read or write locked the object before calling.
1478 */
1479bool HostUSBDevice::i_hasAsyncOperationTimedOut() const
1480{
1481 switch (mUniSubState)
1482 {
1483#ifndef RT_OS_WINDOWS /* no timeouts on windows yet since I don't have all the details here... */
1484 case kHostUSBDeviceSubState_AwaitingDetach:
1485 case kHostUSBDeviceSubState_AwaitingReAttach:
1486 {
1487 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
1488 return elapsedNanoseconds > UINT64_C(60000000000); /* 60 seconds */ /* PORTME */
1489 }
1490#endif
1491 default:
1492 return false;
1493 }
1494}
1495
1496
1497/**
1498 * Translate the state into
1499 *
1500 * @returns
1501 * @param aState
1502 * @param aSubState
1503 * @param aPendingState
1504 */
1505/*static*/ const char *HostUSBDevice::i_stateName(HostUSBDeviceState aState,
1506 HostUSBDeviceState aPendingState /*= kHostUSBDeviceState_Invalid*/,
1507 HostUSBDeviceSubState aSubState /*= kHostUSBDeviceSubState_Default*/)
1508{
1509 switch (aState)
1510 {
1511 case kHostUSBDeviceState_Unsupported:
1512 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unsupported{bad}");
1513 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unsupported[bad]");
1514 return "Unsupported";
1515
1516 case kHostUSBDeviceState_UsedByHost:
1517 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByHost{bad}");
1518 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByHost[bad]");
1519 return "UsedByHost";
1520
1521 case kHostUSBDeviceState_Capturable:
1522 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Capturable{bad}");
1523 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Capturable[bad]");
1524 return "Capturable";
1525
1526 case kHostUSBDeviceState_Unused:
1527 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unused{bad}");
1528 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unused[bad]");
1529 return "Unused";
1530
1531 case kHostUSBDeviceState_HeldByProxy:
1532 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "HeldByProxy{bad}");
1533 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "HeldByProxy[bad]");
1534 return "HeldByProxy";
1535
1536 case kHostUSBDeviceState_UsedByVM:
1537 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByVM{bad}");
1538 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByVM[bad]");
1539 return "UsedByVM";
1540
1541 case kHostUSBDeviceState_PhysDetached:
1542 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "PhysDetached{bad}");
1543 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "PhysDetached[bad]");
1544 return "PhysDetached";
1545
1546 case kHostUSBDeviceState_Capturing:
1547 switch (aPendingState)
1548 {
1549 case kHostUSBDeviceState_UsedByVM:
1550 switch (aSubState)
1551 {
1552 case kHostUSBDeviceSubState_Default:
1553 return "CapturingForVM";
1554 case kHostUSBDeviceSubState_AwaitingDetach:
1555 return "CapturingForVM[Detach]";
1556 case kHostUSBDeviceSubState_AwaitingReAttach:
1557 return "CapturingForVM[Attach]";
1558 default:
1559 AssertFailedReturn("CapturingForVM[bad]");
1560 }
1561 break;
1562
1563 case kHostUSBDeviceState_HeldByProxy:
1564 switch (aSubState)
1565 {
1566 case kHostUSBDeviceSubState_Default:
1567 return "CapturingForProxy";
1568 case kHostUSBDeviceSubState_AwaitingDetach:
1569 return "CapturingForProxy[Detach]";
1570 case kHostUSBDeviceSubState_AwaitingReAttach:
1571 return "CapturingForProxy[Attach]";
1572 default:
1573 AssertFailedReturn("CapturingForProxy[bad]");
1574 }
1575 break;
1576
1577 default:
1578 AssertFailedReturn("Capturing{bad}");
1579 }
1580 break;
1581
1582 case kHostUSBDeviceState_ReleasingToHost:
1583 switch (aPendingState)
1584 {
1585 case kHostUSBDeviceState_Unused:
1586 switch (aSubState)
1587 {
1588 case kHostUSBDeviceSubState_Default:
1589 return "ReleasingToHost";
1590 case kHostUSBDeviceSubState_AwaitingDetach:
1591 return "ReleasingToHost[Detach]";
1592 case kHostUSBDeviceSubState_AwaitingReAttach:
1593 return "ReleasingToHost[Attach]";
1594 default:
1595 AssertFailedReturn("ReleasingToHost[bad]");
1596 }
1597 break;
1598 default:
1599 AssertFailedReturn("ReleasingToHost{bad}");
1600 }
1601 break;
1602
1603 case kHostUSBDeviceState_DetachingFromVM:
1604 switch (aPendingState)
1605 {
1606 case kHostUSBDeviceState_HeldByProxy:
1607 switch (aSubState)
1608 {
1609 case kHostUSBDeviceSubState_Default:
1610 return "DetatchingFromVM>Proxy";
1611 case kHostUSBDeviceSubState_AwaitingDetach:
1612 return "DetatchingFromVM>Proxy[Detach]";
1613 case kHostUSBDeviceSubState_AwaitingReAttach:
1614 return "DetatchingFromVM>Proxy[Attach]";
1615 default:
1616 AssertFailedReturn("DetatchingFromVM>Proxy[bad]");
1617 }
1618 break;
1619
1620 case kHostUSBDeviceState_Unused:
1621 switch (aSubState)
1622 {
1623 case kHostUSBDeviceSubState_Default:
1624 return "DetachingFromVM>Host";
1625 case kHostUSBDeviceSubState_AwaitingDetach:
1626 return "DetachingFromVM>Host[Detach]";
1627 case kHostUSBDeviceSubState_AwaitingReAttach:
1628 return "DetachingFromVM>Host[Attach]";
1629 default:
1630 AssertFailedReturn("DetachingFromVM>Host[bad]");
1631 }
1632 break;
1633
1634 default:
1635 AssertFailedReturn("DetachingFromVM{bad}");
1636 }
1637 break;
1638
1639 case kHostUSBDeviceState_AttachingToVM:
1640 switch (aPendingState)
1641 {
1642 case kHostUSBDeviceState_UsedByVM:
1643 switch (aSubState)
1644 {
1645 case kHostUSBDeviceSubState_Default:
1646 return "AttachingToVM";
1647 case kHostUSBDeviceSubState_AwaitingDetach:
1648 return "AttachingToVM[Detach]";
1649 case kHostUSBDeviceSubState_AwaitingReAttach:
1650 return "AttachingToVM[Attach]";
1651 default:
1652 AssertFailedReturn("AttachingToVM[bad]");
1653 }
1654 break;
1655
1656 default:
1657 AssertFailedReturn("AttachingToVM{bad}");
1658 }
1659 break;
1660
1661
1662 case kHostUSBDeviceState_PhysDetachingFromVM:
1663 switch (aPendingState)
1664 {
1665 case kHostUSBDeviceState_PhysDetached:
1666 switch (aSubState)
1667 {
1668 case kHostUSBDeviceSubState_Default:
1669 return "PhysDetachingFromVM";
1670 default:
1671 AssertFailedReturn("AttachingToVM[bad]");
1672 }
1673 break;
1674
1675 default:
1676 AssertFailedReturn("AttachingToVM{bad}");
1677 }
1678 break;
1679
1680 default:
1681 AssertFailedReturn("BadState");
1682
1683 }
1684
1685 AssertFailedReturn("shouldn't get here");
1686}
1687
1688/**
1689 * Set the device state.
1690 *
1691 * This method will verify that the state transition is a legal one
1692 * according to the statemachine. It will also take care of the
1693 * associated house keeping and determine if filters needs to be applied.
1694 *
1695 * @param aNewState The new state.
1696 * @param aNewPendingState The final state of a transition when applicable.
1697 * @param aNewSubState The new sub-state when applicable.
1698 *
1699 * @returns true if filters should be applied to the device, false if not.
1700 *
1701 * @note The caller must own the write lock for this object.
1702 */
1703bool HostUSBDevice::i_setState(HostUSBDeviceState aNewState, HostUSBDeviceState aNewPendingState /*= kHostUSBDeviceState_Invalid*/,
1704 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
1705{
1706 Assert(isWriteLockOnCurrentThread());
1707 Assert( aNewSubState == kHostUSBDeviceSubState_Default
1708 || aNewSubState == kHostUSBDeviceSubState_AwaitingDetach
1709 || aNewSubState == kHostUSBDeviceSubState_AwaitingReAttach);
1710
1711 /*
1712 * If the state is unchanged, then don't bother going
1713 * thru the validation and setting. This saves a bit of code.
1714 */
1715 if ( aNewState == mUniState
1716 && aNewPendingState == mPendingUniState
1717 && aNewSubState == mUniSubState)
1718 return false;
1719
1720 /*
1721 * Welcome to the switch orgies!
1722 * You're welcome to check out the ones in startTransition(),
1723 * advanceTransition(), failTransition() and i_getStateName() too. Enjoy!
1724 */
1725
1726 bool fFilters = false;
1727 HostUSBDeviceState NewPrevState = mUniState;
1728 switch (mUniState)
1729 {
1730 /*
1731 * Not much can be done with a device in this state.
1732 */
1733 case kHostUSBDeviceState_Unsupported:
1734 switch (aNewState)
1735 {
1736 case kHostUSBDeviceState_PhysDetached:
1737 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1738 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1739 break;
1740 default:
1741 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1742 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1743 }
1744 break;
1745
1746 /*
1747 * Only the host OS (or the user) can make changes
1748 * that'll make a device get out of this state.
1749 */
1750 case kHostUSBDeviceState_UsedByHost:
1751 switch (aNewState)
1752 {
1753 case kHostUSBDeviceState_Capturable:
1754 case kHostUSBDeviceState_Unused:
1755 fFilters = true;
1756 case kHostUSBDeviceState_PhysDetached:
1757 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1758 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1759 break;
1760 default:
1761 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1762 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1763 }
1764 break;
1765
1766 /*
1767 * Now it gets interesting.
1768 */
1769 case kHostUSBDeviceState_Capturable:
1770 switch (aNewState)
1771 {
1772 /* Host changes. */
1773 case kHostUSBDeviceState_Unused:
1774 fFilters = true; /* Wildcard only... */
1775 case kHostUSBDeviceState_UsedByHost:
1776 case kHostUSBDeviceState_PhysDetached:
1777 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1778 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1779 break;
1780
1781 /* VBox actions */
1782 case kHostUSBDeviceState_Capturing:
1783 switch (aNewPendingState)
1784 {
1785 case kHostUSBDeviceState_HeldByProxy:
1786 case kHostUSBDeviceState_UsedByVM:
1787 break;
1788 default:
1789 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1790 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1791 }
1792 break;
1793 default:
1794 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1795 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1796 }
1797 break;
1798
1799 case kHostUSBDeviceState_Unused:
1800 switch (aNewState)
1801 {
1802 /* Host changes. */
1803 case kHostUSBDeviceState_PhysDetached:
1804 case kHostUSBDeviceState_UsedByHost:
1805 case kHostUSBDeviceState_Capturable:
1806 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1807 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1808 break;
1809
1810 /* VBox actions */
1811 case kHostUSBDeviceState_Capturing:
1812 switch (aNewPendingState)
1813 {
1814 case kHostUSBDeviceState_HeldByProxy:
1815 case kHostUSBDeviceState_UsedByVM:
1816 break;
1817 default:
1818 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1819 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1820 }
1821 break;
1822 default:
1823 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1824 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1825 }
1826 break;
1827
1828 /*
1829 * VBox owns this device now, what's next...
1830 */
1831 case kHostUSBDeviceState_HeldByProxy:
1832 switch (aNewState)
1833 {
1834 /* Host changes. */
1835 case kHostUSBDeviceState_PhysDetached:
1836 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1837 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1838 break;
1839
1840 /* VBox actions */
1841 case kHostUSBDeviceState_AttachingToVM:
1842 switch (aNewPendingState)
1843 {
1844 case kHostUSBDeviceState_UsedByVM:
1845 break;
1846 default:
1847 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1848 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1849 }
1850 break;
1851 case kHostUSBDeviceState_ReleasingToHost:
1852 switch (aNewPendingState)
1853 {
1854 case kHostUSBDeviceState_Unused: /* Only this! */
1855 break;
1856 default:
1857 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1858 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1859 }
1860 break;
1861 default:
1862 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1863 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1864 }
1865 break;
1866
1867
1868 case kHostUSBDeviceState_UsedByVM:
1869 switch (aNewState)
1870 {
1871 /* Host changes. */
1872 case kHostUSBDeviceState_PhysDetachingFromVM:
1873 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1874 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
1875 break;
1876
1877 /* VBox actions */
1878 case kHostUSBDeviceState_DetachingFromVM:
1879 switch (aNewPendingState)
1880 {
1881 case kHostUSBDeviceState_HeldByProxy:
1882 case kHostUSBDeviceState_Unused: /* Only this! */
1883 break;
1884 default:
1885 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1886 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1887 }
1888 break;
1889 default:
1890 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1891 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1892 }
1893 break;
1894
1895 /*
1896 * The final state.
1897 */
1898 case kHostUSBDeviceState_PhysDetached:
1899 switch (mUniState)
1900 {
1901 case kHostUSBDeviceState_Unsupported:
1902 case kHostUSBDeviceState_UsedByHost:
1903 case kHostUSBDeviceState_Capturable:
1904 case kHostUSBDeviceState_Unused:
1905 case kHostUSBDeviceState_HeldByProxy:
1906 case kHostUSBDeviceState_PhysDetachingFromVM:
1907 case kHostUSBDeviceState_DetachingFromVM: // ??
1908 case kHostUSBDeviceState_Capturing:
1909 case kHostUSBDeviceState_ReleasingToHost:
1910 break;
1911
1912 case kHostUSBDeviceState_AttachingToVM: // ??
1913 case kHostUSBDeviceState_UsedByVM:
1914 default:
1915 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1916 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1917 }
1918 break;
1919
1920
1921 /*
1922 * The transitional states.
1923 */
1924 case kHostUSBDeviceState_Capturing:
1925 NewPrevState = mPrevUniState;
1926 switch (aNewState)
1927 {
1928 /* Sub state advance. */
1929 case kHostUSBDeviceState_Capturing:
1930 switch (aNewSubState)
1931 {
1932 case kHostUSBDeviceSubState_AwaitingReAttach:
1933 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
1934 Assert(aNewPendingState == mPendingUniState);
1935 break;
1936 default:
1937 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
1938 }
1939 break;
1940
1941 /* Host/User/Failure. */
1942 case kHostUSBDeviceState_PhysDetached:
1943 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1944 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1945 break;
1946 case kHostUSBDeviceState_UsedByHost:
1947 case kHostUSBDeviceState_Capturable:
1948 case kHostUSBDeviceState_Unused:
1949 Assert(aNewState == mPrevUniState);
1950 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1951 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1952 break;
1953
1954 /* VBox */
1955 case kHostUSBDeviceState_HeldByProxy:
1956 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1957 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1958 Assert( mPendingUniState == kHostUSBDeviceState_HeldByProxy
1959 || mPendingUniState == kHostUSBDeviceState_UsedByVM /* <- failure */ );
1960 break;
1961 case kHostUSBDeviceState_AttachingToVM:
1962 Assert(aNewPendingState == kHostUSBDeviceState_UsedByVM);
1963 NewPrevState = kHostUSBDeviceState_HeldByProxy;
1964 break;
1965
1966 default:
1967 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1968 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1969 }
1970 break;
1971
1972 case kHostUSBDeviceState_ReleasingToHost:
1973 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
1974 NewPrevState = mPrevUniState;
1975 switch (aNewState)
1976 {
1977 /* Sub state advance. */
1978 case kHostUSBDeviceState_ReleasingToHost:
1979 switch (aNewSubState)
1980 {
1981 case kHostUSBDeviceSubState_AwaitingReAttach:
1982 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
1983 Assert(aNewPendingState == mPendingUniState);
1984 break;
1985 default:
1986 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
1987 }
1988 break;
1989
1990 /* Host/Failure. */
1991 case kHostUSBDeviceState_PhysDetached:
1992 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1993 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1994 break;
1995 case kHostUSBDeviceState_HeldByProxy:
1996 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1997 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1998 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
1999 break;
2000
2001 /* Success */
2002 case kHostUSBDeviceState_UsedByHost:
2003 case kHostUSBDeviceState_Capturable:
2004 case kHostUSBDeviceState_Unused:
2005 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2006 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2007 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2008 break;
2009
2010 default:
2011 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2012 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2013 }
2014 break;
2015
2016 case kHostUSBDeviceState_AttachingToVM:
2017 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2018 NewPrevState = mPrevUniState;
2019 switch (aNewState)
2020 {
2021 /* Host/Failure. */
2022 case kHostUSBDeviceState_PhysDetachingFromVM:
2023 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2024 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2025 break;
2026 case kHostUSBDeviceState_HeldByProxy:
2027 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2028 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2029 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2030 break;
2031
2032 /* Success */
2033 case kHostUSBDeviceState_UsedByVM:
2034 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2035 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2036 Assert(mPendingUniState == kHostUSBDeviceState_UsedByVM);
2037 break;
2038
2039 default:
2040 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2041 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2042 }
2043 break;
2044
2045 case kHostUSBDeviceState_DetachingFromVM:
2046 Assert(mPrevUniState == kHostUSBDeviceState_UsedByVM);
2047 NewPrevState = mPrevUniState;
2048 switch (aNewState)
2049 {
2050 /* Host/Failure. */
2051 case kHostUSBDeviceState_PhysDetached: //??
2052 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2053 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2054 break;
2055 case kHostUSBDeviceState_PhysDetachingFromVM:
2056 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2057 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2058 break;
2059
2060 /* Success */
2061 case kHostUSBDeviceState_HeldByProxy:
2062 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2063 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2064 Assert(mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2065 fFilters = true;
2066 break;
2067
2068 case kHostUSBDeviceState_ReleasingToHost:
2069 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2070 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2071 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2072 NewPrevState = kHostUSBDeviceState_HeldByProxy;
2073 break;
2074
2075 default:
2076 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2077 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2078 }
2079 break;
2080
2081 case kHostUSBDeviceState_PhysDetachingFromVM:
2082 Assert( mPrevUniState == kHostUSBDeviceState_DetachingFromVM
2083 || mPrevUniState == kHostUSBDeviceState_AttachingToVM
2084 || mPrevUniState == kHostUSBDeviceState_UsedByVM);
2085 NewPrevState = mPrevUniState; /* preserving it is more useful. */
2086 switch (aNewState)
2087 {
2088 case kHostUSBDeviceState_PhysDetached:
2089 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2090 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2091 break;
2092 default:
2093 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2094 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2095 }
2096 break;
2097
2098 default:
2099 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2100 }
2101
2102 /*
2103 * Make the state change.
2104 */
2105 if (NewPrevState != mPrevUniState)
2106 LogFlowThisFunc(("%s -> %s (prev: %s -> %s) [%s]\n",
2107 i_getStateName(), i_stateName(aNewState, aNewPendingState, aNewSubState),
2108 i_stateName(mPrevUniState), i_stateName(NewPrevState), mName));
2109 else
2110 LogFlowThisFunc(("%s -> %s (prev: %s) [%s]\n",
2111 i_getStateName(), i_stateName(aNewState, aNewPendingState, aNewSubState),
2112 i_stateName(NewPrevState), mName));
2113 mPrevUniState = NewPrevState;
2114 mUniState = aNewState;
2115 mUniSubState = aNewSubState;
2116 mPendingUniState = aNewPendingState;
2117 mLastStateChangeTS = RTTimeNanoTS();
2118
2119 return fFilters;
2120}
2121
2122
2123/**
2124 * A convenience for entering a transitional state.
2125
2126 * @param aNewState The new state (transitional).
2127 * @param aFinalSubState The final state of the transition (non-transitional).
2128 * @param aNewSubState The new sub-state when applicable.
2129 *
2130 * @returns Always false because filters are never applied for the start of a transition.
2131 *
2132 * @note The caller must own the write lock for this object.
2133 */
2134bool HostUSBDevice::i_startTransition(HostUSBDeviceState aNewState, HostUSBDeviceState aFinalState,
2135 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
2136{
2137 AssertReturn(isWriteLockOnCurrentThread(), false);
2138 /*
2139 * A quick prevalidation thing. Not really necessary since setState
2140 * verifies this too, but it's very easy here.
2141 */
2142 switch (mUniState)
2143 {
2144 case kHostUSBDeviceState_Unsupported:
2145 case kHostUSBDeviceState_UsedByHost:
2146 case kHostUSBDeviceState_Capturable:
2147 case kHostUSBDeviceState_Unused:
2148 case kHostUSBDeviceState_HeldByProxy:
2149 case kHostUSBDeviceState_UsedByVM:
2150 break;
2151
2152 case kHostUSBDeviceState_DetachingFromVM:
2153 case kHostUSBDeviceState_Capturing:
2154 case kHostUSBDeviceState_ReleasingToHost:
2155 case kHostUSBDeviceState_AttachingToVM:
2156 case kHostUSBDeviceState_PhysDetachingFromVM:
2157 AssertMsgFailedReturn(("this=%p %s is a transitional state.\n", this, i_getStateName()), false);
2158
2159 case kHostUSBDeviceState_PhysDetached:
2160 default:
2161 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2162 }
2163
2164 return i_setState(aNewState, aFinalState, aNewSubState);
2165}
2166
2167
2168/**
2169 * A convenience for advancing a transitional state forward.
2170 *
2171 * @param aSkipReAttach Fast forwards thru the re-attach substate if
2172 * applicable.
2173 *
2174 * @returns true if filters should be applied to the device, false if not.
2175 *
2176 * @note The caller must own the write lock for this object.
2177 */
2178bool HostUSBDevice::i_advanceTransition(bool aSkipReAttach /* = false */)
2179{
2180 AssertReturn(isWriteLockOnCurrentThread(), false);
2181 HostUSBDeviceState enmPending = mPendingUniState;
2182 HostUSBDeviceSubState enmSub = mUniSubState;
2183 HostUSBDeviceState enmState = mUniState;
2184 switch (enmState)
2185 {
2186 case kHostUSBDeviceState_Capturing:
2187 switch (enmSub)
2188 {
2189 case kHostUSBDeviceSubState_AwaitingDetach:
2190 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2191 break;
2192 case kHostUSBDeviceSubState_AwaitingReAttach:
2193 enmSub = kHostUSBDeviceSubState_Default;
2194 /* fall thru */
2195 case kHostUSBDeviceSubState_Default:
2196 switch (enmPending)
2197 {
2198 case kHostUSBDeviceState_UsedByVM:
2199 enmState = kHostUSBDeviceState_AttachingToVM;
2200 break;
2201 case kHostUSBDeviceState_HeldByProxy:
2202 enmState = enmPending;
2203 enmPending = kHostUSBDeviceState_Invalid;
2204 break;
2205 default:
2206 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2207 this, enmPending, i_getStateName()), false);
2208 }
2209 break;
2210 default:
2211 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2212 }
2213 break;
2214
2215 case kHostUSBDeviceState_ReleasingToHost:
2216 switch (enmSub)
2217 {
2218 case kHostUSBDeviceSubState_AwaitingDetach:
2219 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2220 break;
2221 case kHostUSBDeviceSubState_AwaitingReAttach:
2222 enmSub = kHostUSBDeviceSubState_Default;
2223 /* fall thru */
2224 case kHostUSBDeviceSubState_Default:
2225 switch (enmPending)
2226 {
2227 /* Use Unused here since it implies that filters has been applied
2228 and will make sure they aren't applied if the final state really
2229 is Capturable. */
2230 case kHostUSBDeviceState_Unused:
2231 enmState = enmPending;
2232 enmPending = kHostUSBDeviceState_Invalid;
2233 break;
2234 default:
2235 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2236 this, enmPending, i_getStateName()), false);
2237 }
2238 break;
2239 default:
2240 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2241 }
2242 break;
2243
2244 case kHostUSBDeviceState_AttachingToVM:
2245 switch (enmSub)
2246 {
2247 case kHostUSBDeviceSubState_AwaitingDetach:
2248 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2249 break;
2250 case kHostUSBDeviceSubState_AwaitingReAttach:
2251 enmSub = kHostUSBDeviceSubState_Default;
2252 /* fall thru */
2253 case kHostUSBDeviceSubState_Default:
2254 switch (enmPending)
2255 {
2256 case kHostUSBDeviceState_UsedByVM:
2257 enmState = enmPending;
2258 enmPending = kHostUSBDeviceState_Invalid;
2259 break;
2260 default:
2261 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2262 this, enmPending, i_getStateName()), false);
2263 }
2264 break;
2265 default:
2266 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2267 }
2268 break;
2269
2270 case kHostUSBDeviceState_DetachingFromVM:
2271 switch (enmSub)
2272 {
2273 case kHostUSBDeviceSubState_AwaitingDetach:
2274 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2275 break;
2276 case kHostUSBDeviceSubState_AwaitingReAttach:
2277 enmSub = kHostUSBDeviceSubState_Default;
2278 /* fall thru */
2279 case kHostUSBDeviceSubState_Default:
2280 switch (enmPending)
2281 {
2282 case kHostUSBDeviceState_HeldByProxy:
2283 enmState = enmPending;
2284 enmPending = kHostUSBDeviceState_Invalid;
2285 break;
2286 case kHostUSBDeviceState_Unused:
2287 enmState = kHostUSBDeviceState_ReleasingToHost;
2288 break;
2289 default:
2290 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2291 this, enmPending, i_getStateName()), false);
2292 }
2293 break;
2294 default:
2295 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2296 }
2297 break;
2298
2299 case kHostUSBDeviceState_PhysDetachingFromVM:
2300 switch (enmSub)
2301 {
2302 case kHostUSBDeviceSubState_Default:
2303 switch (enmPending)
2304 {
2305 case kHostUSBDeviceState_PhysDetached:
2306 enmState = enmPending;
2307 enmPending = kHostUSBDeviceState_Invalid;
2308 break;
2309 default:
2310 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2311 this, enmPending, i_getStateName()), false);
2312 }
2313 break;
2314 default:
2315 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2316 }
2317 break;
2318
2319 case kHostUSBDeviceState_Unsupported:
2320 case kHostUSBDeviceState_UsedByHost:
2321 case kHostUSBDeviceState_Capturable:
2322 case kHostUSBDeviceState_Unused:
2323 case kHostUSBDeviceState_HeldByProxy:
2324 case kHostUSBDeviceState_UsedByVM:
2325 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, i_getStateName()), false);
2326 case kHostUSBDeviceState_PhysDetached:
2327 default:
2328 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, enmState), false);
2329
2330 }
2331
2332 bool fRc = i_setState(enmState, enmPending, enmSub);
2333 if (aSkipReAttach && mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
2334 fRc |= i_advanceTransition(false /* don't fast forward re-attach */);
2335 return fRc;
2336}
2337
2338/**
2339 * A convenience for failing a transitional state.
2340 *
2341 * @return true if filters should be applied to the device, false if not.
2342 *
2343 * @note The caller must own the write lock for this object.
2344 */
2345bool HostUSBDevice::i_failTransition()
2346{
2347 AssertReturn(isWriteLockOnCurrentThread(), false);
2348 HostUSBDeviceSubState enmSub = mUniSubState;
2349 HostUSBDeviceState enmState = mUniState;
2350 switch (enmState)
2351 {
2352 /*
2353 * There are just two cases, either we got back to the
2354 * previous state (assumes Capture+Attach-To-VM updates it)
2355 * or we assume the device has been unplugged (physically).
2356 */
2357 case kHostUSBDeviceState_DetachingFromVM:
2358 case kHostUSBDeviceState_Capturing:
2359 case kHostUSBDeviceState_ReleasingToHost:
2360 case kHostUSBDeviceState_AttachingToVM:
2361 switch (enmSub)
2362 {
2363 case kHostUSBDeviceSubState_AwaitingDetach:
2364 enmSub = kHostUSBDeviceSubState_Default;
2365 /* fall thru */
2366 case kHostUSBDeviceSubState_Default:
2367 enmState = mPrevUniState;
2368 break;
2369 case kHostUSBDeviceSubState_AwaitingReAttach:
2370 enmSub = kHostUSBDeviceSubState_Default;
2371 enmState = kHostUSBDeviceState_PhysDetached;
2372 break;
2373 default:
2374 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2375 }
2376 break;
2377
2378 case kHostUSBDeviceState_PhysDetachingFromVM:
2379 AssertMsgFailedReturn(("this=%p %s shall not fail\n", this, i_getStateName()), false);
2380
2381 case kHostUSBDeviceState_Unsupported:
2382 case kHostUSBDeviceState_UsedByHost:
2383 case kHostUSBDeviceState_Capturable:
2384 case kHostUSBDeviceState_Unused:
2385 case kHostUSBDeviceState_HeldByProxy:
2386 case kHostUSBDeviceState_UsedByVM:
2387 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, i_getStateName()), false);
2388 case kHostUSBDeviceState_PhysDetached:
2389 default:
2390 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2391
2392 }
2393
2394 return i_setState(enmState, kHostUSBDeviceState_Invalid, enmSub);
2395}
2396
2397
2398/**
2399 * Determines the canonical state of the device.
2400 *
2401 * @returns canonical state.
2402 *
2403 * @note The caller must own the read (or write) lock for this object.
2404 */
2405USBDeviceState_T HostUSBDevice::i_canonicalState() const
2406{
2407 switch (mUniState)
2408 {
2409 /*
2410 * Straight forward.
2411 */
2412 case kHostUSBDeviceState_Unsupported:
2413 return USBDeviceState_NotSupported;
2414
2415 case kHostUSBDeviceState_UsedByHost:
2416 return USBDeviceState_Unavailable;
2417
2418 case kHostUSBDeviceState_Capturable:
2419 return USBDeviceState_Busy;
2420
2421 case kHostUSBDeviceState_Unused:
2422 return USBDeviceState_Available;
2423
2424 case kHostUSBDeviceState_HeldByProxy:
2425 return USBDeviceState_Held;
2426
2427 case kHostUSBDeviceState_UsedByVM:
2428 return USBDeviceState_Captured;
2429
2430 /*
2431 * Pretend we've reached the final state.
2432 */
2433 case kHostUSBDeviceState_Capturing:
2434 Assert( mPendingUniState == kHostUSBDeviceState_UsedByVM
2435 || mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2436 return mPendingUniState == kHostUSBDeviceState_UsedByVM
2437 ? (USBDeviceState_T)USBDeviceState_Captured
2438 : (USBDeviceState_T)USBDeviceState_Held;
2439 /* The cast ^^^^ is because xidl is using different enums for
2440 each of the values. *Very* nice idea... :-) */
2441
2442 case kHostUSBDeviceState_AttachingToVM:
2443 return USBDeviceState_Captured;
2444
2445 /*
2446 * Return the previous state.
2447 */
2448 case kHostUSBDeviceState_ReleasingToHost:
2449 Assert( mPrevUniState == kHostUSBDeviceState_UsedByVM
2450 || mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2451 return mPrevUniState == kHostUSBDeviceState_UsedByVM
2452 ? (USBDeviceState_T)USBDeviceState_Captured
2453 : (USBDeviceState_T)USBDeviceState_Held;
2454 /* The cast ^^^^ is because xidl is using different enums for
2455 each of the values. *Very* nice idea... :-) */
2456
2457 case kHostUSBDeviceState_DetachingFromVM:
2458 return USBDeviceState_Captured;
2459 case kHostUSBDeviceState_PhysDetachingFromVM:
2460 return USBDeviceState_Captured;
2461
2462 case kHostUSBDeviceState_PhysDetached:
2463 default:
2464 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), USBDeviceState_NotSupported);
2465 }
2466 /* won't ever get here. */
2467}
2468/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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