VirtualBox

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

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

Main/USB: Fix darwin assertion on Macbooks with USB 3.0 (Superspeed) ports and devices, introduce new device speed enum value for USB 3.0 devices

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