VirtualBox

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

Last change on this file since 53517 was 53297, checked in by vboxsync, 10 years ago

Main: Added API to report actual USB device speed.

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

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