VirtualBox

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

Last change on this file since 79812 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

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