VirtualBox

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

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

USBIdDatabase*: Corrected file header, fixed LogRel statement (was given NULL string pointers instead of vendor + device IDs), some style fixes.

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