VirtualBox

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

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

HostUSBDeviceImpl: Fixed wrong state transition in i_failTransition when the device reappers but is not actually captured as we expect.

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