VirtualBox

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

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

USB,Main: Rework USBProxyService. Split it into a USBProxyService and USBProxyBackend class, USBProxyService can use multiple USBProxyBackend instances as sources for USB devices to attach to a VM which will be used for USB/IP support. Change the PDM USB API to contain a backend parameter instead of a remote flag to indicate the USB backend to use for the given device.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.8 KB
Line 
1/* $Id: HostUSBDeviceImpl.cpp 59117 2015-12-14 14:04:37Z 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 if (strcmp(aDev1->pszBackend, aDev2->pszBackend))
992 {
993 return 1;
994 }
995
996 /*
997 * Things that stays the same everywhere.
998 *
999 * The more uniquely these properties identifies a device the less the chance
1000 * that we mix similar devices during re-enumeration. Bus+port would help
1001 * provide ~99.8% accuracy if the host can provide those attributes.
1002 */
1003 int iDiff = aDev1->idVendor - aDev2->idVendor;
1004 if (iDiff)
1005 return iDiff;
1006
1007 iDiff = aDev1->idProduct - aDev2->idProduct;
1008 if (iDiff)
1009 return iDiff;
1010
1011 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
1012 if (iDiff)
1013 {
1014 //Log3(("compare: bcdDevice: %#x != %#x\n", aDev1->bcdDevice, aDev2->bcdDevice));
1015 return iDiff;
1016 }
1017
1018#ifdef RT_OS_WINDOWS /* the string query may fail on windows during replugging, ignore serial mismatch if this is the case. */
1019 if ( aDev1->u64SerialHash != aDev2->u64SerialHash
1020 && ( !aIsAwaitingReAttach
1021 || (aDev2->pszSerialNumber && *aDev2->pszSerialNumber)
1022 || (aDev2->pszManufacturer && *aDev2->pszManufacturer)
1023 || (aDev2->pszProduct && *aDev2->pszProduct))
1024 )
1025#else
1026 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
1027#endif
1028 {
1029 //Log3(("compare: u64SerialHash: %#llx != %#llx\n", aDev1->u64SerialHash, aDev2->u64SerialHash));
1030 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
1031 }
1032
1033 /* The hub/bus + port should help a lot in a re-attach situation. */
1034#ifdef RT_OS_WINDOWS
1035 iDiff = strcmp(aDev1->pszHubName, aDev2->pszHubName);
1036 if (iDiff)
1037 {
1038 //Log3(("compare: HubName: %s != %s\n", aDev1->pszHubName, aDev2->pszHubName));
1039 return iDiff;
1040 }
1041#else
1042 iDiff = aDev1->bBus - aDev2->bBus;
1043 if (iDiff)
1044 {
1045 //Log3(("compare: bBus: %#x != %#x\n", aDev1->bBus, aDev2->bBus));
1046 return iDiff;
1047 }
1048#endif
1049
1050 iDiff = aDev1->bPort - aDev2->bPort; /* shouldn't change anywhere and help pinpoint it very accurately. */
1051 if (iDiff)
1052 {
1053 //Log3(("compare: bPort: %#x != %#x\n", aDev1->bPort, aDev2->bPort));
1054 return iDiff;
1055 }
1056
1057 /*
1058 * Things that usually doesn't stay the same when re-enumerating
1059 * a device. The fewer things in the category the better chance
1060 * that we avoid messing up when more than one device of the same
1061 * kind is attached.
1062 */
1063 if (aIsAwaitingReAttach)
1064 {
1065 //Log3(("aDev1=%p == aDev2=%p\n", aDev1, aDev2));
1066 return 0;
1067 }
1068 /* device number always changes. */
1069 return strcmp(aDev1->pszAddress, aDev2->pszAddress);
1070}
1071
1072/**
1073 * Updates the state of the device.
1074 *
1075 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
1076 * called to process the state change (complete the state change request,
1077 * inform the VM process etc.).
1078 *
1079 * If this method returns @c false, it is assumed that the given state change
1080 * is "minor": it doesn't require any further action other than update the
1081 * mState field with the actual state value.
1082 *
1083 * Regardless of the return value, this method always takes ownership of the
1084 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
1085 * it using the values of the old structure.
1086 *
1087 * @param[in] aDev The current device state as seen by the proxy backend.
1088 * @param[out] aRunFilters Whether the state change should be accompanied by
1089 * running filters on the device.
1090 * @param[out] aIgnoreMachine Machine to ignore when running filters.
1091 *
1092 * @returns Whether the Host object should be bothered with this state change.
1093 *
1094 * @todo Just do everything here, that is, call filter runners and everything that
1095 * works by state change. Using 3 return codes/parameters is just plain ugly.
1096 */
1097bool HostUSBDevice::i_updateState(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1098{
1099 *aRunFilters = false;
1100 *aIgnoreMachine = NULL;
1101
1102 /*
1103 * Locking.
1104 */
1105 AssertReturn(!isWriteLockOnCurrentThread(), false);
1106 AutoCaller autoCaller(this);
1107 AssertComRCReturn(autoCaller.rc(), false);
1108 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1109
1110 /*
1111 * Replace the existing structure by the new one.
1112 */
1113 const USBDEVICESTATE enmOldState = mUsb->enmState; NOREF(enmOldState);
1114 if (mUsb != aDev)
1115 {
1116#ifdef RT_OS_WINDOWS
1117 /* we used this logic of string comparison in HostUSBDevice::compare
1118 * now we need to preserve strings from the old device if the new device has zero strings
1119 * this ensures the device is correctly matched later on
1120 * otherwise we may end up with a phantom misconfigured device instance */
1121 if ((mUniSubState == kHostUSBDeviceSubState_AwaitingDetach /* (In case we don't get the detach notice.) */
1122 || mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
1123 && (!aDev->pszSerialNumber || !*aDev->pszSerialNumber)
1124 && (!aDev->pszManufacturer || !*aDev->pszManufacturer)
1125 && (!aDev->pszProduct || !*aDev->pszProduct))
1126 {
1127 aDev->u64SerialHash = mUsb->u64SerialHash;
1128
1129 if (mUsb->pszSerialNumber && *mUsb->pszSerialNumber)
1130 {
1131 if (aDev->pszSerialNumber)
1132 RTStrFree((char *)aDev->pszSerialNumber);
1133
1134 /* since we're going to free old device later on,
1135 * we can just assign the string from it to the new device
1136 * and zero up the string filed for the old device */
1137 aDev->pszSerialNumber = mUsb->pszSerialNumber;
1138 mUsb->pszSerialNumber = NULL;
1139 }
1140
1141 if (mUsb->pszManufacturer && *mUsb->pszManufacturer)
1142 {
1143 if (aDev->pszManufacturer)
1144 RTStrFree((char *)aDev->pszManufacturer);
1145
1146 /* since we're going to free old device later on,
1147 * we can just assign the string from it to the new device
1148 * and zero up the string filed for the old device */
1149 aDev->pszManufacturer = mUsb->pszManufacturer;
1150 mUsb->pszManufacturer = NULL;
1151 }
1152
1153 if (mUsb->pszProduct && *mUsb->pszProduct)
1154 {
1155 if (aDev->pszProduct)
1156 RTStrFree((char *)aDev->pszProduct);
1157
1158 /* since we're going to free old device later on,
1159 * we can just assign the string from it to the new device
1160 * and zero up the string filed for the old device */
1161 aDev->pszProduct = mUsb->pszProduct;
1162 mUsb->pszProduct = NULL;
1163 }
1164 }
1165#endif
1166 aDev->pNext = mUsb->pNext;
1167 aDev->pPrev = mUsb->pPrev;
1168 USBProxyBackend::freeDevice(mUsb);
1169 mUsb = aDev;
1170 }
1171
1172/** @def HOSTUSBDEVICE_FUZZY_STATE
1173 * Defined on hosts where we have a driver that keeps proper device states.
1174 */
1175# if defined(RT_OS_LINUX) || defined(DOXYGEN_RUNNING)
1176# define HOSTUSBDEVICE_FUZZY_STATE 1
1177# else
1178# undef HOSTUSBDEVICE_FUZZY_STATE
1179# endif
1180 /*
1181 * For some hosts we'll have to be pretty careful here because
1182 * they don't always have a clue what is going on. This is
1183 * particularly true on linux and solaris, while windows and
1184 * darwin generally knows a bit more.
1185 */
1186 bool fIsImportant = false;
1187 if (enmOldState != mUsb->enmState)
1188 {
1189 LogFlowThisFunc(("%p {%s} %s\n", this, mName, i_getStateName()));
1190 switch (mUsb->enmState)
1191 {
1192 /*
1193 * Little fuzziness here, except where we fake capture.
1194 */
1195 case USBDEVICESTATE_USED_BY_HOST:
1196 switch (mUniState)
1197 {
1198 /* Host drivers installed, that's fine. */
1199 case kHostUSBDeviceState_Capturable:
1200 case kHostUSBDeviceState_Unused:
1201 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1202 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1203 break;
1204 case kHostUSBDeviceState_UsedByHost:
1205 break;
1206
1207 /* Can only mean that we've failed capturing it. */
1208 case kHostUSBDeviceState_Capturing:
1209 LogThisFunc(("{%s} capture failed! (#1)\n", mName));
1210 mUSBProxyBackend->captureDeviceCompleted(this, false /* aSuccess */);
1211 *aRunFilters = i_failTransition(kHostUSBDeviceState_UsedByHost);
1212 mMachine.setNull();
1213 break;
1214
1215 /* Guess we've successfully released it. */
1216 case kHostUSBDeviceState_ReleasingToHost:
1217 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1218 mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
1219 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1220 break;
1221
1222 /* These are IPC states and should be left alone. */
1223 case kHostUSBDeviceState_AttachingToVM:
1224 case kHostUSBDeviceState_DetachingFromVM:
1225 case kHostUSBDeviceState_PhysDetachingFromVM:
1226 LogThisFunc(("{%s} %s - changed to USED_BY_HOST...\n", mName, i_getStateName()));
1227 break;
1228
1229#ifdef HOSTUSBDEVICE_FUZZY_STATE
1230 /* Fake: We can't prevent anyone from grabbing it. */
1231 case kHostUSBDeviceState_HeldByProxy:
1232 LogThisFunc(("{%s} %s -> %s!\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1233 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1234 break;
1235 //case kHostUSBDeviceState_UsedByVM:
1236 // /** @todo needs to be detached from the VM. */
1237 // break;
1238#endif
1239 /* Not supposed to happen... */
1240#ifndef HOSTUSBDEVICE_FUZZY_STATE
1241 case kHostUSBDeviceState_HeldByProxy:
1242#endif
1243 case kHostUSBDeviceState_UsedByVM:
1244 case kHostUSBDeviceState_PhysDetached:
1245 case kHostUSBDeviceState_Unsupported:
1246 default:
1247 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1248 break;
1249 }
1250 break;
1251
1252 /*
1253 * It changed to capturable. Fuzzy hosts might easily
1254 * confuse UsedByVM with this one.
1255 */
1256 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1257 switch (mUniState)
1258 {
1259 /* No change. */
1260#ifdef HOSTUSBDEVICE_FUZZY_STATE
1261 case kHostUSBDeviceState_HeldByProxy:
1262 case kHostUSBDeviceState_UsedByVM:
1263#endif
1264 case kHostUSBDeviceState_Capturable:
1265 break;
1266
1267 /* Changed! */
1268 case kHostUSBDeviceState_UsedByHost:
1269 fIsImportant = true;
1270 case kHostUSBDeviceState_Unused:
1271 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
1272 *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
1273 break;
1274
1275 /* Can only mean that we've failed capturing it. */
1276 case kHostUSBDeviceState_Capturing:
1277 LogThisFunc(("{%s} capture failed! (#2)\n", mName));
1278 mUSBProxyBackend->captureDeviceCompleted(this, false /* aSuccess */);
1279 *aRunFilters = i_failTransition(kHostUSBDeviceState_Capturable);
1280 mMachine.setNull();
1281 break;
1282
1283 /* Guess we've successfully released it. */
1284 case kHostUSBDeviceState_ReleasingToHost:
1285 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
1286 mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
1287 *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
1288 break;
1289
1290 /* These are IPC states and should be left alone. */
1291 case kHostUSBDeviceState_AttachingToVM:
1292 case kHostUSBDeviceState_DetachingFromVM:
1293 case kHostUSBDeviceState_PhysDetachingFromVM:
1294 LogThisFunc(("{%s} %s - changed to USED_BY_HOST_CAPTURABLE...\n", mName, i_getStateName()));
1295 break;
1296
1297 /* Not supposed to happen*/
1298#ifndef HOSTUSBDEVICE_FUZZY_STATE
1299 case kHostUSBDeviceState_HeldByProxy:
1300 case kHostUSBDeviceState_UsedByVM:
1301#endif
1302 case kHostUSBDeviceState_Unsupported:
1303 case kHostUSBDeviceState_PhysDetached:
1304 default:
1305 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1306 break;
1307 }
1308 break;
1309
1310
1311 /*
1312 * It changed to capturable. Fuzzy hosts might easily
1313 * confuse UsedByVM and HeldByProxy with this one.
1314 */
1315 case USBDEVICESTATE_UNUSED:
1316 switch (mUniState)
1317 {
1318 /* No change. */
1319#ifdef HOSTUSBDEVICE_FUZZY_STATE
1320 case kHostUSBDeviceState_HeldByProxy:
1321 case kHostUSBDeviceState_UsedByVM:
1322#endif
1323 case kHostUSBDeviceState_Unused:
1324 break;
1325
1326 /* Changed! */
1327 case kHostUSBDeviceState_UsedByHost:
1328 case kHostUSBDeviceState_Capturable:
1329 fIsImportant = true;
1330 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
1331 *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
1332 break;
1333
1334 /* Can mean that we've failed capturing it, but on windows it is the detach signal. */
1335 case kHostUSBDeviceState_Capturing:
1336#if defined(RT_OS_WINDOWS)
1337 if (mUniSubState == kHostUSBDeviceSubState_AwaitingDetach)
1338 {
1339 LogThisFunc(("{%s} capture advancing thru UNUSED...\n", mName));
1340 *aRunFilters = i_advanceTransition();
1341 }
1342 else
1343#endif
1344 {
1345 LogThisFunc(("{%s} capture failed! (#3)\n", mName));
1346 mUSBProxyBackend->captureDeviceCompleted(this, false /* aSuccess */);
1347 *aRunFilters = i_failTransition(kHostUSBDeviceState_Unused);
1348 mMachine.setNull();
1349 }
1350 break;
1351
1352 /* Guess we've successfully released it. */
1353 case kHostUSBDeviceState_ReleasingToHost:
1354 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
1355 mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
1356 *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
1357 break;
1358
1359 /* These are IPC states and should be left alone. */
1360 case kHostUSBDeviceState_AttachingToVM:
1361 case kHostUSBDeviceState_DetachingFromVM:
1362 case kHostUSBDeviceState_PhysDetachingFromVM:
1363 LogThisFunc(("{%s} %s - changed to UNUSED...\n", mName, i_getStateName()));
1364 break;
1365
1366 /* Not supposed to happen*/
1367#ifndef HOSTUSBDEVICE_FUZZY_STATE
1368 case kHostUSBDeviceState_HeldByProxy:
1369 case kHostUSBDeviceState_UsedByVM:
1370#endif
1371 case kHostUSBDeviceState_Unsupported:
1372 case kHostUSBDeviceState_PhysDetached:
1373 default:
1374 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1375 break;
1376 }
1377 break;
1378
1379 /*
1380 * This is pretty straight forward, except that everyone
1381 * might sometimes confuse this and the UsedByVM state.
1382 */
1383 case USBDEVICESTATE_HELD_BY_PROXY:
1384 switch (mUniState)
1385 {
1386 /* No change. */
1387 case kHostUSBDeviceState_HeldByProxy:
1388 break;
1389 case kHostUSBDeviceState_UsedByVM:
1390 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, i_getStateName()));
1391 break;
1392
1393 /* Guess we've successfully captured it. */
1394 case kHostUSBDeviceState_Capturing:
1395 LogThisFunc(("{%s} capture succeeded!\n", mName));
1396 mUSBProxyBackend->captureDeviceCompleted(this, true /* aSuccess */);
1397 *aRunFilters = i_advanceTransition(true /* fast forward thru re-attach */);
1398
1399 /* Take action if we're supposed to attach it to a VM. */
1400 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1401 {
1402 alock.release();
1403 i_attachToVM(mMachine, mCaptureFilename, mMaskedIfs);
1404 alock.acquire();
1405 }
1406 break;
1407
1408 /* Can only mean that we've failed capturing it. */
1409 case kHostUSBDeviceState_ReleasingToHost:
1410 LogThisFunc(("{%s} %s failed!\n", mName, i_getStateName()));
1411 mUSBProxyBackend->releaseDeviceCompleted(this, false /* aSuccess */);
1412 *aRunFilters = i_setState(kHostUSBDeviceState_HeldByProxy);
1413 break;
1414
1415 /* These are IPC states and should be left alone. */
1416 case kHostUSBDeviceState_AttachingToVM:
1417 case kHostUSBDeviceState_DetachingFromVM:
1418 case kHostUSBDeviceState_PhysDetachingFromVM:
1419 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, i_getStateName()));
1420 break;
1421
1422 /* Not supposed to happen. */
1423 case kHostUSBDeviceState_Unsupported:
1424 case kHostUSBDeviceState_UsedByHost:
1425 case kHostUSBDeviceState_Capturable:
1426 case kHostUSBDeviceState_Unused:
1427 case kHostUSBDeviceState_PhysDetached:
1428 default:
1429 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1430 break;
1431 }
1432 break;
1433
1434 /*
1435 * This is very straight forward and only Darwin implements it.
1436 */
1437 case USBDEVICESTATE_USED_BY_GUEST:
1438 switch (mUniState)
1439 {
1440 /* No change. */
1441 case kHostUSBDeviceState_HeldByProxy:
1442 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, i_getStateName()));
1443 break;
1444 case kHostUSBDeviceState_UsedByVM:
1445 break;
1446
1447 /* These are IPC states and should be left alone. */
1448 case kHostUSBDeviceState_AttachingToVM:
1449 case kHostUSBDeviceState_DetachingFromVM:
1450 case kHostUSBDeviceState_PhysDetachingFromVM:
1451 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, i_getStateName()));
1452 break;
1453
1454 /* Not supposed to happen. */
1455 case kHostUSBDeviceState_Unsupported:
1456 case kHostUSBDeviceState_Capturable:
1457 case kHostUSBDeviceState_Unused:
1458 case kHostUSBDeviceState_UsedByHost:
1459 case kHostUSBDeviceState_PhysDetached:
1460 case kHostUSBDeviceState_ReleasingToHost:
1461 case kHostUSBDeviceState_Capturing:
1462 default:
1463 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1464 break;
1465 }
1466 break;
1467
1468 /*
1469 * This is not supposed to happen and indicates a bug in the backend!
1470 */
1471 case USBDEVICESTATE_UNSUPPORTED:
1472 AssertMsgFailed(("enmOldState=%d {%s} %s\n", enmOldState, mName, i_getStateName()));
1473 break;
1474 default:
1475 AssertMsgFailed(("enmState=%d {%s} %s\n", mUsb->enmState, mName, i_getStateName()));
1476 break;
1477 }
1478 }
1479 else if ( mUniSubState == kHostUSBDeviceSubState_AwaitingDetach
1480 && i_hasAsyncOperationTimedOut())
1481 {
1482 LogRel(("USB: timeout in %s for {%RTuuid} / {%s}\n", i_getStateName(), mId.raw(), mName));
1483 *aRunFilters = i_failTransition(kHostUSBDeviceState_Invalid);
1484 fIsImportant = true;
1485 }
1486 else
1487 {
1488 LogFlowThisFunc(("%p {%s} %s - no change %d\n", this, mName, i_getStateName(), enmOldState));
1489 /** @todo might have to handle some stuff here too if we cannot make the release/capture
1490 * handling deal with that above ... */
1491 }
1492
1493 return fIsImportant;
1494}
1495
1496
1497/**
1498 * Updates the state of the device, checking for cases which we fake.
1499 *
1500 * See HostUSBDevice::updateState() for details.
1501 *
1502 * @param[in] aDev See HostUSBDevice::updateState().
1503 * @param[out] aRunFilters See HostUSBDevice::updateState()
1504 * @param[out] aIgnoreMachine See HostUSBDevice::updateState()
1505 *
1506 * @returns See HostUSBDevice::updateState()
1507 */
1508bool HostUSBDevice::i_updateStateFake(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1509{
1510 Assert(!isWriteLockOnCurrentThread());
1511 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1512 const HostUSBDeviceState enmState = mUniState;
1513 switch (enmState)
1514 {
1515 case kHostUSBDeviceState_Capturing:
1516 case kHostUSBDeviceState_ReleasingToHost:
1517 {
1518 *aIgnoreMachine = mUniState == kHostUSBDeviceState_ReleasingToHost ? mMachine : NULL;
1519 *aRunFilters = i_advanceTransition();
1520 LogThisFunc(("{%s} %s\n", mName, i_getStateName()));
1521
1522 if (mUsb != aDev)
1523 {
1524 aDev->pNext = mUsb->pNext;
1525 aDev->pPrev = mUsb->pPrev;
1526 USBProxyBackend::freeDevice(mUsb);
1527 mUsb = aDev;
1528 }
1529
1530 /* call the completion method */
1531 if (enmState == kHostUSBDeviceState_Capturing)
1532 mUSBProxyBackend->captureDeviceCompleted(this, true /* aSuccess */);
1533 else
1534 mUSBProxyBackend->releaseDeviceCompleted(this, true /* aSuccess */);
1535
1536 /* Take action if we're supposed to attach it to a VM. */
1537 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1538 {
1539 alock.release();
1540 i_attachToVM(mMachine, mCaptureFilename, mMaskedIfs);
1541 }
1542 return true;
1543 }
1544
1545 default:
1546 alock.release();
1547 return i_updateState(aDev, aRunFilters, aIgnoreMachine);
1548 }
1549}
1550
1551
1552/**
1553 * Checks if there is a pending asynchronous operation and whether
1554 * it has timed out or not.
1555 *
1556 * @returns true on timeout, false if not.
1557 *
1558 * @note Caller must have read or write locked the object before calling.
1559 */
1560bool HostUSBDevice::i_hasAsyncOperationTimedOut() const
1561{
1562 switch (mUniSubState)
1563 {
1564#ifndef RT_OS_WINDOWS /* no timeouts on windows yet since I don't have all the details here... */
1565 case kHostUSBDeviceSubState_AwaitingDetach:
1566 case kHostUSBDeviceSubState_AwaitingReAttach:
1567 {
1568 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
1569 return elapsedNanoseconds > UINT64_C(60000000000); /* 60 seconds */ /* PORTME */
1570 }
1571#endif
1572 default:
1573 return false;
1574 }
1575}
1576
1577
1578/**
1579 * Translate the state into
1580 *
1581 * @returns
1582 * @param aState
1583 * @param aSubState
1584 * @param aPendingState
1585 */
1586/*static*/ const char *HostUSBDevice::i_stateName(HostUSBDeviceState aState,
1587 HostUSBDeviceState aPendingState /*= kHostUSBDeviceState_Invalid*/,
1588 HostUSBDeviceSubState aSubState /*= kHostUSBDeviceSubState_Default*/)
1589{
1590 switch (aState)
1591 {
1592 case kHostUSBDeviceState_Unsupported:
1593 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unsupported{bad}");
1594 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unsupported[bad]");
1595 return "Unsupported";
1596
1597 case kHostUSBDeviceState_UsedByHost:
1598 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByHost{bad}");
1599 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByHost[bad]");
1600 return "UsedByHost";
1601
1602 case kHostUSBDeviceState_Capturable:
1603 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Capturable{bad}");
1604 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Capturable[bad]");
1605 return "Capturable";
1606
1607 case kHostUSBDeviceState_Unused:
1608 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unused{bad}");
1609 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unused[bad]");
1610 return "Unused";
1611
1612 case kHostUSBDeviceState_HeldByProxy:
1613 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "HeldByProxy{bad}");
1614 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "HeldByProxy[bad]");
1615 return "HeldByProxy";
1616
1617 case kHostUSBDeviceState_UsedByVM:
1618 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByVM{bad}");
1619 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByVM[bad]");
1620 return "UsedByVM";
1621
1622 case kHostUSBDeviceState_PhysDetached:
1623 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "PhysDetached{bad}");
1624 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "PhysDetached[bad]");
1625 return "PhysDetached";
1626
1627 case kHostUSBDeviceState_Capturing:
1628 switch (aPendingState)
1629 {
1630 case kHostUSBDeviceState_UsedByVM:
1631 switch (aSubState)
1632 {
1633 case kHostUSBDeviceSubState_Default:
1634 return "CapturingForVM";
1635 case kHostUSBDeviceSubState_AwaitingDetach:
1636 return "CapturingForVM[Detach]";
1637 case kHostUSBDeviceSubState_AwaitingReAttach:
1638 return "CapturingForVM[Attach]";
1639 default:
1640 AssertFailedReturn("CapturingForVM[bad]");
1641 }
1642 break;
1643
1644 case kHostUSBDeviceState_HeldByProxy:
1645 switch (aSubState)
1646 {
1647 case kHostUSBDeviceSubState_Default:
1648 return "CapturingForProxy";
1649 case kHostUSBDeviceSubState_AwaitingDetach:
1650 return "CapturingForProxy[Detach]";
1651 case kHostUSBDeviceSubState_AwaitingReAttach:
1652 return "CapturingForProxy[Attach]";
1653 default:
1654 AssertFailedReturn("CapturingForProxy[bad]");
1655 }
1656 break;
1657
1658 default:
1659 AssertFailedReturn("Capturing{bad}");
1660 }
1661 break;
1662
1663 case kHostUSBDeviceState_ReleasingToHost:
1664 switch (aPendingState)
1665 {
1666 case kHostUSBDeviceState_Unused:
1667 switch (aSubState)
1668 {
1669 case kHostUSBDeviceSubState_Default:
1670 return "ReleasingToHost";
1671 case kHostUSBDeviceSubState_AwaitingDetach:
1672 return "ReleasingToHost[Detach]";
1673 case kHostUSBDeviceSubState_AwaitingReAttach:
1674 return "ReleasingToHost[Attach]";
1675 default:
1676 AssertFailedReturn("ReleasingToHost[bad]");
1677 }
1678 break;
1679 default:
1680 AssertFailedReturn("ReleasingToHost{bad}");
1681 }
1682 break;
1683
1684 case kHostUSBDeviceState_DetachingFromVM:
1685 switch (aPendingState)
1686 {
1687 case kHostUSBDeviceState_HeldByProxy:
1688 switch (aSubState)
1689 {
1690 case kHostUSBDeviceSubState_Default:
1691 return "DetatchingFromVM>Proxy";
1692 case kHostUSBDeviceSubState_AwaitingDetach:
1693 return "DetatchingFromVM>Proxy[Detach]";
1694 case kHostUSBDeviceSubState_AwaitingReAttach:
1695 return "DetatchingFromVM>Proxy[Attach]";
1696 default:
1697 AssertFailedReturn("DetatchingFromVM>Proxy[bad]");
1698 }
1699 break;
1700
1701 case kHostUSBDeviceState_Unused:
1702 switch (aSubState)
1703 {
1704 case kHostUSBDeviceSubState_Default:
1705 return "DetachingFromVM>Host";
1706 case kHostUSBDeviceSubState_AwaitingDetach:
1707 return "DetachingFromVM>Host[Detach]";
1708 case kHostUSBDeviceSubState_AwaitingReAttach:
1709 return "DetachingFromVM>Host[Attach]";
1710 default:
1711 AssertFailedReturn("DetachingFromVM>Host[bad]");
1712 }
1713 break;
1714
1715 default:
1716 AssertFailedReturn("DetachingFromVM{bad}");
1717 }
1718 break;
1719
1720 case kHostUSBDeviceState_AttachingToVM:
1721 switch (aPendingState)
1722 {
1723 case kHostUSBDeviceState_UsedByVM:
1724 switch (aSubState)
1725 {
1726 case kHostUSBDeviceSubState_Default:
1727 return "AttachingToVM";
1728 case kHostUSBDeviceSubState_AwaitingDetach:
1729 return "AttachingToVM[Detach]";
1730 case kHostUSBDeviceSubState_AwaitingReAttach:
1731 return "AttachingToVM[Attach]";
1732 default:
1733 AssertFailedReturn("AttachingToVM[bad]");
1734 }
1735 break;
1736
1737 default:
1738 AssertFailedReturn("AttachingToVM{bad}");
1739 }
1740 break;
1741
1742
1743 case kHostUSBDeviceState_PhysDetachingFromVM:
1744 switch (aPendingState)
1745 {
1746 case kHostUSBDeviceState_PhysDetached:
1747 switch (aSubState)
1748 {
1749 case kHostUSBDeviceSubState_Default:
1750 return "PhysDetachingFromVM";
1751 default:
1752 AssertFailedReturn("AttachingToVM[bad]");
1753 }
1754 break;
1755
1756 default:
1757 AssertFailedReturn("AttachingToVM{bad}");
1758 }
1759 break;
1760
1761 default:
1762 AssertFailedReturn("BadState");
1763
1764 }
1765
1766 AssertFailedReturn("shouldn't get here");
1767}
1768
1769/**
1770 * Set the device state.
1771 *
1772 * This method will verify that the state transition is a legal one
1773 * according to the statemachine. It will also take care of the
1774 * associated house keeping and determine if filters needs to be applied.
1775 *
1776 * @param aNewState The new state.
1777 * @param aNewPendingState The final state of a transition when applicable.
1778 * @param aNewSubState The new sub-state when applicable.
1779 *
1780 * @returns true if filters should be applied to the device, false if not.
1781 *
1782 * @note The caller must own the write lock for this object.
1783 */
1784bool HostUSBDevice::i_setState(HostUSBDeviceState aNewState,
1785 HostUSBDeviceState aNewPendingState /*= kHostUSBDeviceState_Invalid*/,
1786 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
1787{
1788 Assert(isWriteLockOnCurrentThread());
1789 Assert( aNewSubState == kHostUSBDeviceSubState_Default
1790 || aNewSubState == kHostUSBDeviceSubState_AwaitingDetach
1791 || aNewSubState == kHostUSBDeviceSubState_AwaitingReAttach);
1792
1793 /*
1794 * If the state is unchanged, then don't bother going
1795 * thru the validation and setting. This saves a bit of code.
1796 */
1797 if ( aNewState == mUniState
1798 && aNewPendingState == mPendingUniState
1799 && aNewSubState == mUniSubState)
1800 return false;
1801
1802 /*
1803 * Welcome to the switch orgies!
1804 * You're welcome to check out the ones in startTransition(),
1805 * advanceTransition(), failTransition() and i_getStateName() too. Enjoy!
1806 */
1807
1808 bool fFilters = false;
1809 HostUSBDeviceState NewPrevState = mUniState;
1810 switch (mUniState)
1811 {
1812 /*
1813 * Not much can be done with a device in this state.
1814 */
1815 case kHostUSBDeviceState_Unsupported:
1816 switch (aNewState)
1817 {
1818 case kHostUSBDeviceState_PhysDetached:
1819 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1820 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1821 break;
1822 default:
1823 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1824 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1825 }
1826 break;
1827
1828 /*
1829 * Only the host OS (or the user) can make changes
1830 * that'll make a device get out of this state.
1831 */
1832 case kHostUSBDeviceState_UsedByHost:
1833 switch (aNewState)
1834 {
1835 case kHostUSBDeviceState_Capturable:
1836 case kHostUSBDeviceState_Unused:
1837 fFilters = true;
1838 case kHostUSBDeviceState_PhysDetached:
1839 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1840 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1841 break;
1842 default:
1843 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1844 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1845 }
1846 break;
1847
1848 /*
1849 * Now it gets interesting.
1850 */
1851 case kHostUSBDeviceState_Capturable:
1852 switch (aNewState)
1853 {
1854 /* Host changes. */
1855 case kHostUSBDeviceState_Unused:
1856 fFilters = true; /* Wildcard only... */
1857 case kHostUSBDeviceState_UsedByHost:
1858 case kHostUSBDeviceState_PhysDetached:
1859 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1860 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1861 break;
1862
1863 /* VBox actions */
1864 case kHostUSBDeviceState_Capturing:
1865 switch (aNewPendingState)
1866 {
1867 case kHostUSBDeviceState_HeldByProxy:
1868 case kHostUSBDeviceState_UsedByVM:
1869 break;
1870 default:
1871 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1872 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1873 }
1874 break;
1875 default:
1876 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1877 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1878 }
1879 break;
1880
1881 case kHostUSBDeviceState_Unused:
1882 switch (aNewState)
1883 {
1884 /* Host changes. */
1885 case kHostUSBDeviceState_PhysDetached:
1886 case kHostUSBDeviceState_UsedByHost:
1887 case kHostUSBDeviceState_Capturable:
1888 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1889 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1890 break;
1891
1892 /* VBox actions */
1893 case kHostUSBDeviceState_Capturing:
1894 switch (aNewPendingState)
1895 {
1896 case kHostUSBDeviceState_HeldByProxy:
1897 case kHostUSBDeviceState_UsedByVM:
1898 break;
1899 default:
1900 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1901 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1902 }
1903 break;
1904 default:
1905 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1906 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1907 }
1908 break;
1909
1910 /*
1911 * VBox owns this device now, what's next...
1912 */
1913 case kHostUSBDeviceState_HeldByProxy:
1914 switch (aNewState)
1915 {
1916 /* Host changes. */
1917 case kHostUSBDeviceState_PhysDetached:
1918 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1919 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1920 break;
1921
1922 /* VBox actions */
1923 case kHostUSBDeviceState_AttachingToVM:
1924 switch (aNewPendingState)
1925 {
1926 case kHostUSBDeviceState_UsedByVM:
1927 break;
1928 default:
1929 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1930 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1931 }
1932 break;
1933 case kHostUSBDeviceState_ReleasingToHost:
1934 switch (aNewPendingState)
1935 {
1936 case kHostUSBDeviceState_Unused: /* Only this! */
1937 break;
1938 default:
1939 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1940 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1941 }
1942 break;
1943 default:
1944 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1945 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1946 }
1947 break;
1948
1949
1950 case kHostUSBDeviceState_UsedByVM:
1951 switch (aNewState)
1952 {
1953 /* Host changes. */
1954 case kHostUSBDeviceState_PhysDetachingFromVM:
1955 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1956 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
1957 break;
1958
1959 /* VBox actions */
1960 case kHostUSBDeviceState_DetachingFromVM:
1961 switch (aNewPendingState)
1962 {
1963 case kHostUSBDeviceState_HeldByProxy:
1964 case kHostUSBDeviceState_Unused: /* Only this! */
1965 break;
1966 default:
1967 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1968 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1969 }
1970 break;
1971 default:
1972 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1973 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1974 }
1975 break;
1976
1977 /*
1978 * The final state.
1979 */
1980 case kHostUSBDeviceState_PhysDetached:
1981 switch (mUniState)
1982 {
1983 case kHostUSBDeviceState_Unsupported:
1984 case kHostUSBDeviceState_UsedByHost:
1985 case kHostUSBDeviceState_Capturable:
1986 case kHostUSBDeviceState_Unused:
1987 case kHostUSBDeviceState_HeldByProxy:
1988 case kHostUSBDeviceState_PhysDetachingFromVM:
1989 case kHostUSBDeviceState_DetachingFromVM: // ??
1990 case kHostUSBDeviceState_Capturing:
1991 case kHostUSBDeviceState_ReleasingToHost:
1992 break;
1993
1994 case kHostUSBDeviceState_AttachingToVM: // ??
1995 case kHostUSBDeviceState_UsedByVM:
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 /*
2004 * The transitional states.
2005 */
2006 case kHostUSBDeviceState_Capturing:
2007 NewPrevState = mPrevUniState;
2008 switch (aNewState)
2009 {
2010 /* Sub state advance. */
2011 case kHostUSBDeviceState_Capturing:
2012 switch (aNewSubState)
2013 {
2014 case kHostUSBDeviceSubState_AwaitingReAttach:
2015 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
2016 Assert(aNewPendingState == mPendingUniState);
2017 break;
2018 default:
2019 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2020 }
2021 break;
2022
2023 /* Host/User/Failure. */
2024 case kHostUSBDeviceState_PhysDetached:
2025 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2026 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2027 break;
2028 case kHostUSBDeviceState_UsedByHost:
2029 case kHostUSBDeviceState_Capturable:
2030 case kHostUSBDeviceState_Unused:
2031 Assert(aNewState == mPrevUniState); /** @todo This is kind of wrong, see i_failTransition. */
2032 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2033 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2034 break;
2035
2036 /* VBox */
2037 case kHostUSBDeviceState_HeldByProxy:
2038 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2039 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2040 Assert( mPendingUniState == kHostUSBDeviceState_HeldByProxy
2041 || mPendingUniState == kHostUSBDeviceState_UsedByVM /* <- failure */ );
2042 break;
2043 case kHostUSBDeviceState_AttachingToVM:
2044 Assert(aNewPendingState == kHostUSBDeviceState_UsedByVM);
2045 NewPrevState = kHostUSBDeviceState_HeldByProxy;
2046 break;
2047
2048 default:
2049 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2050 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2051 }
2052 break;
2053
2054 case kHostUSBDeviceState_ReleasingToHost:
2055 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2056 NewPrevState = mPrevUniState;
2057 switch (aNewState)
2058 {
2059 /* Sub state advance. */
2060 case kHostUSBDeviceState_ReleasingToHost:
2061 switch (aNewSubState)
2062 {
2063 case kHostUSBDeviceSubState_AwaitingReAttach:
2064 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
2065 Assert(aNewPendingState == mPendingUniState);
2066 break;
2067 default:
2068 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2069 }
2070 break;
2071
2072 /* Host/Failure. */
2073 case kHostUSBDeviceState_PhysDetached:
2074 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2075 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2076 break;
2077 case kHostUSBDeviceState_HeldByProxy:
2078 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2079 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2080 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2081 break;
2082
2083 /* Success */
2084 case kHostUSBDeviceState_UsedByHost:
2085 case kHostUSBDeviceState_Capturable:
2086 case kHostUSBDeviceState_Unused:
2087 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2088 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2089 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2090 break;
2091
2092 default:
2093 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2094 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2095 }
2096 break;
2097
2098 case kHostUSBDeviceState_AttachingToVM:
2099 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2100 NewPrevState = mPrevUniState;
2101 switch (aNewState)
2102 {
2103 /* Host/Failure. */
2104 case kHostUSBDeviceState_PhysDetachingFromVM:
2105 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2106 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2107 break;
2108 case kHostUSBDeviceState_HeldByProxy:
2109 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2110 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2111 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2112 break;
2113
2114 /* Success */
2115 case kHostUSBDeviceState_UsedByVM:
2116 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2117 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2118 Assert(mPendingUniState == kHostUSBDeviceState_UsedByVM);
2119 break;
2120
2121 default:
2122 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2123 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2124 }
2125 break;
2126
2127 case kHostUSBDeviceState_DetachingFromVM:
2128 Assert(mPrevUniState == kHostUSBDeviceState_UsedByVM);
2129 NewPrevState = mPrevUniState;
2130 switch (aNewState)
2131 {
2132 /* Host/Failure. */
2133 case kHostUSBDeviceState_PhysDetached: //??
2134 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2135 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2136 break;
2137 case kHostUSBDeviceState_PhysDetachingFromVM:
2138 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2139 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2140 break;
2141
2142 /* Success */
2143 case kHostUSBDeviceState_HeldByProxy:
2144 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2145 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2146 Assert(mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2147 fFilters = true;
2148 break;
2149
2150 case kHostUSBDeviceState_ReleasingToHost:
2151 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2152 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2153 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2154 NewPrevState = kHostUSBDeviceState_HeldByProxy;
2155 break;
2156
2157 default:
2158 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2159 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2160 }
2161 break;
2162
2163 case kHostUSBDeviceState_PhysDetachingFromVM:
2164 Assert( mPrevUniState == kHostUSBDeviceState_DetachingFromVM
2165 || mPrevUniState == kHostUSBDeviceState_AttachingToVM
2166 || mPrevUniState == kHostUSBDeviceState_UsedByVM);
2167 NewPrevState = mPrevUniState; /* preserving it is more useful. */
2168 switch (aNewState)
2169 {
2170 case kHostUSBDeviceState_PhysDetached:
2171 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2172 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2173 break;
2174 default:
2175 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2176 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2177 }
2178 break;
2179
2180 default:
2181 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2182 }
2183
2184 /*
2185 * Make the state change.
2186 */
2187 if (NewPrevState != mPrevUniState)
2188 LogFlowThisFunc(("%s -> %s (prev: %s -> %s) [%s]\n",
2189 i_getStateName(), i_stateName(aNewState, aNewPendingState, aNewSubState),
2190 i_stateName(mPrevUniState), i_stateName(NewPrevState), mName));
2191 else
2192 LogFlowThisFunc(("%s -> %s (prev: %s) [%s]\n",
2193 i_getStateName(), i_stateName(aNewState, aNewPendingState, aNewSubState),
2194 i_stateName(NewPrevState), mName));
2195 mPrevUniState = NewPrevState;
2196 mUniState = aNewState;
2197 mUniSubState = aNewSubState;
2198 mPendingUniState = aNewPendingState;
2199 mLastStateChangeTS = RTTimeNanoTS();
2200
2201 return fFilters;
2202}
2203
2204
2205/**
2206 * A convenience for entering a transitional state.
2207
2208 * @param aNewState The new state (transitional).
2209 * @param aFinalSubState The final state of the transition (non-transitional).
2210 * @param aNewSubState The new sub-state when applicable.
2211 *
2212 * @returns Always false because filters are never applied for the start of a transition.
2213 *
2214 * @note The caller must own the write lock for this object.
2215 */
2216bool HostUSBDevice::i_startTransition(HostUSBDeviceState aNewState, HostUSBDeviceState aFinalState,
2217 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
2218{
2219 AssertReturn(isWriteLockOnCurrentThread(), false);
2220 /*
2221 * A quick prevalidation thing. Not really necessary since setState
2222 * verifies this too, but it's very easy here.
2223 */
2224 switch (mUniState)
2225 {
2226 case kHostUSBDeviceState_Unsupported:
2227 case kHostUSBDeviceState_UsedByHost:
2228 case kHostUSBDeviceState_Capturable:
2229 case kHostUSBDeviceState_Unused:
2230 case kHostUSBDeviceState_HeldByProxy:
2231 case kHostUSBDeviceState_UsedByVM:
2232 break;
2233
2234 case kHostUSBDeviceState_DetachingFromVM:
2235 case kHostUSBDeviceState_Capturing:
2236 case kHostUSBDeviceState_ReleasingToHost:
2237 case kHostUSBDeviceState_AttachingToVM:
2238 case kHostUSBDeviceState_PhysDetachingFromVM:
2239 AssertMsgFailedReturn(("this=%p %s is a transitional state.\n", this, i_getStateName()), false);
2240
2241 case kHostUSBDeviceState_PhysDetached:
2242 default:
2243 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2244 }
2245
2246 return i_setState(aNewState, aFinalState, aNewSubState);
2247}
2248
2249
2250/**
2251 * A convenience for advancing a transitional state forward.
2252 *
2253 * @param aSkipReAttach Fast forwards thru the re-attach substate if
2254 * applicable.
2255 *
2256 * @returns true if filters should be applied to the device, false if not.
2257 *
2258 * @note The caller must own the write lock for this object.
2259 */
2260bool HostUSBDevice::i_advanceTransition(bool aSkipReAttach /* = false */)
2261{
2262 AssertReturn(isWriteLockOnCurrentThread(), false);
2263 HostUSBDeviceState enmPending = mPendingUniState;
2264 HostUSBDeviceSubState enmSub = mUniSubState;
2265 HostUSBDeviceState enmState = mUniState;
2266 switch (enmState)
2267 {
2268 case kHostUSBDeviceState_Capturing:
2269 switch (enmSub)
2270 {
2271 case kHostUSBDeviceSubState_AwaitingDetach:
2272 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2273 break;
2274 case kHostUSBDeviceSubState_AwaitingReAttach:
2275 enmSub = kHostUSBDeviceSubState_Default;
2276 /* fall thru */
2277 case kHostUSBDeviceSubState_Default:
2278 switch (enmPending)
2279 {
2280 case kHostUSBDeviceState_UsedByVM:
2281 enmState = kHostUSBDeviceState_AttachingToVM;
2282 break;
2283 case kHostUSBDeviceState_HeldByProxy:
2284 enmState = enmPending;
2285 enmPending = kHostUSBDeviceState_Invalid;
2286 break;
2287 default:
2288 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2289 this, enmPending, i_getStateName()), false);
2290 }
2291 break;
2292 default:
2293 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2294 }
2295 break;
2296
2297 case kHostUSBDeviceState_ReleasingToHost:
2298 switch (enmSub)
2299 {
2300 case kHostUSBDeviceSubState_AwaitingDetach:
2301 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2302 break;
2303 case kHostUSBDeviceSubState_AwaitingReAttach:
2304 enmSub = kHostUSBDeviceSubState_Default;
2305 /* fall thru */
2306 case kHostUSBDeviceSubState_Default:
2307 switch (enmPending)
2308 {
2309 /* Use Unused here since it implies that filters has been applied
2310 and will make sure they aren't applied if the final state really
2311 is Capturable. */
2312 case kHostUSBDeviceState_Unused:
2313 enmState = enmPending;
2314 enmPending = kHostUSBDeviceState_Invalid;
2315 break;
2316 default:
2317 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2318 this, enmPending, i_getStateName()), false);
2319 }
2320 break;
2321 default:
2322 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2323 }
2324 break;
2325
2326 case kHostUSBDeviceState_AttachingToVM:
2327 switch (enmSub)
2328 {
2329 case kHostUSBDeviceSubState_AwaitingDetach:
2330 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2331 break;
2332 case kHostUSBDeviceSubState_AwaitingReAttach:
2333 enmSub = kHostUSBDeviceSubState_Default;
2334 /* fall thru */
2335 case kHostUSBDeviceSubState_Default:
2336 switch (enmPending)
2337 {
2338 case kHostUSBDeviceState_UsedByVM:
2339 enmState = enmPending;
2340 enmPending = kHostUSBDeviceState_Invalid;
2341 break;
2342 default:
2343 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2344 this, enmPending, i_getStateName()), false);
2345 }
2346 break;
2347 default:
2348 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2349 }
2350 break;
2351
2352 case kHostUSBDeviceState_DetachingFromVM:
2353 switch (enmSub)
2354 {
2355 case kHostUSBDeviceSubState_AwaitingDetach:
2356 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2357 break;
2358 case kHostUSBDeviceSubState_AwaitingReAttach:
2359 enmSub = kHostUSBDeviceSubState_Default;
2360 /* fall thru */
2361 case kHostUSBDeviceSubState_Default:
2362 switch (enmPending)
2363 {
2364 case kHostUSBDeviceState_HeldByProxy:
2365 enmState = enmPending;
2366 enmPending = kHostUSBDeviceState_Invalid;
2367 break;
2368 case kHostUSBDeviceState_Unused:
2369 enmState = kHostUSBDeviceState_ReleasingToHost;
2370 break;
2371 default:
2372 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2373 this, enmPending, i_getStateName()), false);
2374 }
2375 break;
2376 default:
2377 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2378 }
2379 break;
2380
2381 case kHostUSBDeviceState_PhysDetachingFromVM:
2382 switch (enmSub)
2383 {
2384 case kHostUSBDeviceSubState_Default:
2385 switch (enmPending)
2386 {
2387 case kHostUSBDeviceState_PhysDetached:
2388 enmState = enmPending;
2389 enmPending = kHostUSBDeviceState_Invalid;
2390 break;
2391 default:
2392 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2393 this, enmPending, i_getStateName()), false);
2394 }
2395 break;
2396 default:
2397 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2398 }
2399 break;
2400
2401 case kHostUSBDeviceState_Unsupported:
2402 case kHostUSBDeviceState_UsedByHost:
2403 case kHostUSBDeviceState_Capturable:
2404 case kHostUSBDeviceState_Unused:
2405 case kHostUSBDeviceState_HeldByProxy:
2406 case kHostUSBDeviceState_UsedByVM:
2407 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, i_getStateName()), false);
2408 case kHostUSBDeviceState_PhysDetached:
2409 default:
2410 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, enmState), false);
2411
2412 }
2413
2414 bool fRc = i_setState(enmState, enmPending, enmSub);
2415 if (aSkipReAttach && mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
2416 fRc |= i_advanceTransition(false /* don't fast forward re-attach */);
2417 return fRc;
2418}
2419
2420/**
2421 * A convenience for failing a transitional state.
2422 *
2423 * @return true if filters should be applied to the device, false if not.
2424 * @param a_enmStateHint USB device state hint. kHostUSBDeviceState_Invalid
2425 * if the caller doesn't have a clue to give.
2426 *
2427 * @note The caller must own the write lock for this object.
2428 */
2429bool HostUSBDevice::i_failTransition(HostUSBDeviceState a_enmStateHint)
2430{
2431 AssertReturn(isWriteLockOnCurrentThread(), false);
2432 HostUSBDeviceSubState enmSub = mUniSubState;
2433 HostUSBDeviceState enmState = mUniState;
2434 switch (enmState)
2435 {
2436 /*
2437 * There are just two cases, either we got back to the
2438 * previous state (assumes Capture+Attach-To-VM updates it)
2439 * or we assume the device has been unplugged (physically).
2440 */
2441 case kHostUSBDeviceState_DetachingFromVM:
2442 case kHostUSBDeviceState_Capturing:
2443 case kHostUSBDeviceState_ReleasingToHost:
2444 case kHostUSBDeviceState_AttachingToVM:
2445 switch (enmSub)
2446 {
2447 case kHostUSBDeviceSubState_AwaitingDetach:
2448 enmSub = kHostUSBDeviceSubState_Default;
2449 /* fall thru */
2450 case kHostUSBDeviceSubState_Default:
2451 enmState = mPrevUniState;
2452 break;
2453 case kHostUSBDeviceSubState_AwaitingReAttach:
2454 enmSub = kHostUSBDeviceSubState_Default;
2455 if (a_enmStateHint != kHostUSBDeviceState_Invalid)
2456 enmState = mPrevUniState; /** @todo enmState = a_enmStateHint is more correct, but i_setState doesn't like it. It will usually correct itself shortly. */
2457 else
2458 enmState = kHostUSBDeviceState_PhysDetached;
2459 break;
2460 default:
2461 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2462 }
2463 break;
2464
2465 case kHostUSBDeviceState_PhysDetachingFromVM:
2466 AssertMsgFailedReturn(("this=%p %s shall not fail\n", this, i_getStateName()), false);
2467
2468 case kHostUSBDeviceState_Unsupported:
2469 case kHostUSBDeviceState_UsedByHost:
2470 case kHostUSBDeviceState_Capturable:
2471 case kHostUSBDeviceState_Unused:
2472 case kHostUSBDeviceState_HeldByProxy:
2473 case kHostUSBDeviceState_UsedByVM:
2474 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, i_getStateName()), false);
2475 case kHostUSBDeviceState_PhysDetached:
2476 default:
2477 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2478
2479 }
2480
2481 return i_setState(enmState, kHostUSBDeviceState_Invalid, enmSub);
2482}
2483
2484
2485/**
2486 * Determines the canonical state of the device.
2487 *
2488 * @returns canonical state.
2489 *
2490 * @note The caller must own the read (or write) lock for this object.
2491 */
2492USBDeviceState_T HostUSBDevice::i_canonicalState() const
2493{
2494 switch (mUniState)
2495 {
2496 /*
2497 * Straight forward.
2498 */
2499 case kHostUSBDeviceState_Unsupported:
2500 return USBDeviceState_NotSupported;
2501
2502 case kHostUSBDeviceState_UsedByHost:
2503 return USBDeviceState_Unavailable;
2504
2505 case kHostUSBDeviceState_Capturable:
2506 return USBDeviceState_Busy;
2507
2508 case kHostUSBDeviceState_Unused:
2509 return USBDeviceState_Available;
2510
2511 case kHostUSBDeviceState_HeldByProxy:
2512 return USBDeviceState_Held;
2513
2514 case kHostUSBDeviceState_UsedByVM:
2515 return USBDeviceState_Captured;
2516
2517 /*
2518 * Pretend we've reached the final state.
2519 */
2520 case kHostUSBDeviceState_Capturing:
2521 Assert( mPendingUniState == kHostUSBDeviceState_UsedByVM
2522 || mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2523 return mPendingUniState == kHostUSBDeviceState_UsedByVM
2524 ? (USBDeviceState_T)USBDeviceState_Captured
2525 : (USBDeviceState_T)USBDeviceState_Held;
2526 /* The cast ^^^^ is because xidl is using different enums for
2527 each of the values. *Very* nice idea... :-) */
2528
2529 case kHostUSBDeviceState_AttachingToVM:
2530 return USBDeviceState_Captured;
2531
2532 /*
2533 * Return the previous state.
2534 */
2535 case kHostUSBDeviceState_ReleasingToHost:
2536 Assert( mPrevUniState == kHostUSBDeviceState_UsedByVM
2537 || mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2538 return mPrevUniState == kHostUSBDeviceState_UsedByVM
2539 ? (USBDeviceState_T)USBDeviceState_Captured
2540 : (USBDeviceState_T)USBDeviceState_Held;
2541 /* The cast ^^^^ is because xidl is using different enums for
2542 each of the values. *Very* nice idea... :-) */
2543
2544 case kHostUSBDeviceState_DetachingFromVM:
2545 return USBDeviceState_Captured;
2546 case kHostUSBDeviceState_PhysDetachingFromVM:
2547 return USBDeviceState_Captured;
2548
2549 case kHostUSBDeviceState_PhysDetached:
2550 default:
2551 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), USBDeviceState_NotSupported);
2552 }
2553 /* won't ever get here. */
2554}
2555/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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