VirtualBox

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

Last change on this file since 59154 was 59119, checked in by vboxsync, 9 years ago

Main: build fixes

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