VirtualBox

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

Last change on this file since 90330 was 87376, checked in by vboxsync, 4 years ago

USB/Darwin: Capture USB devices directly through IOUSBLib, no longer use VBoxUSB.kext (see bugref:9808).

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