VirtualBox

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

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

Main/HostUSBdevice: added USB ID database, database generator, source files

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.0 KB
Line 
1/* $Id: HostUSBDeviceImpl.cpp 57034 2015-07-21 08:29:16Z 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 ). \
352 Please, report the idVendor and idProduct to vbox.org.\n", vendorName, productName));
353 }
354 }
355
356 return name;
357}
358
359/**
360 * Requests the USB proxy service capture the device (from the host)
361 * and attach it to a VM.
362 *
363 * As a convenience, this method will operate like attachToVM() if the device
364 * is already held by the proxy. Note that it will then perform IPC to the VM
365 * process, which means it will temporarily release all locks. (Is this a good idea?)
366 *
367 * @param aMachine Machine this device should be attach to.
368 * @param aSetError Whether to set full error message or not to bother.
369 * @param aCaptureFilename The filename to capture the USB traffic to.
370 * @param aMaskedIfs The interfaces to hide from the guest.
371 *
372 * @returns Status indicating whether it was successfully captured and/or attached.
373 * @retval S_OK on success.
374 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
375 * @retval E_* as appropriate.
376 */
377HRESULT HostUSBDevice::i_requestCaptureForVM(SessionMachine *aMachine, bool aSetError,
378 const com::Utf8Str &aCaptureFilename, ULONG aMaskedIfs /* = 0*/)
379{
380 /*
381 * Validate preconditions and input.
382 */
383 AssertReturn(aMachine, E_INVALIDARG);
384 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
385 AssertReturn(!aMachine->isWriteLockOnCurrentThread(), E_FAIL);
386
387 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
388 LogFlowThisFunc(("{%s} aMachine=%p aMaskedIfs=%#x\n", mName, aMachine, aMaskedIfs));
389
390 if (aSetError)
391 {
392 if (mUniState == kHostUSBDeviceState_Unsupported)
393 return setError(E_INVALIDARG,
394 tr("USB device '%s' with UUID {%RTuuid} cannot be accessed by guest computers"),
395 mName, mId.raw());
396 if (mUniState == kHostUSBDeviceState_UsedByHost)
397 return setError(E_INVALIDARG,
398 tr("USB device '%s' with UUID {%RTuuid} is being exclusively used by the host computer"),
399 mName, mId.raw());
400 if (mUniState == kHostUSBDeviceState_UsedByVM)
401 {
402 /* Machine::name() requires a read lock */
403 alock.release();
404 AutoReadLock machLock(mMachine COMMA_LOCKVAL_SRC_POS);
405 return setError(E_INVALIDARG,
406 tr("USB device '%s' with UUID {%RTuuid} is already captured by the virtual machine '%s'"),
407 mName, mId.raw(), mMachine->i_getName().c_str());
408 }
409 if (mUniState >= kHostUSBDeviceState_FirstTransitional)
410 return setError(E_INVALIDARG,
411 tr("USB device '%s' with UUID {%RTuuid} is busy with a previous request. Please try again later"),
412 mName, mId.raw());
413 if ( mUniState != kHostUSBDeviceState_Unused
414 && mUniState != kHostUSBDeviceState_HeldByProxy
415 && mUniState != kHostUSBDeviceState_Capturable)
416 return setError(E_INVALIDARG,
417 tr("USB device '%s' with UUID {%RTuuid} is not in the right state for capturing (%s)"),
418 mName, mId.raw(), i_getStateName());
419 }
420
421 AssertReturn( mUniState == kHostUSBDeviceState_HeldByProxy
422 || mUniState == kHostUSBDeviceState_Unused
423 || mUniState == kHostUSBDeviceState_Capturable,
424 E_UNEXPECTED);
425 Assert(mMachine.isNull());
426
427 /*
428 * If it's already held by the proxy, we'll simply call
429 * attachToVM synchronously.
430 */
431 if (mUniState == kHostUSBDeviceState_HeldByProxy)
432 {
433 alock.release();
434 HRESULT hrc = i_attachToVM(aMachine, aCaptureFilename, aMaskedIfs);
435 return SUCCEEDED(hrc);
436 }
437
438 /*
439 * Need to capture the device before it can be used.
440 *
441 * The device will be attached to the VM by the USB proxy service thread
442 * when the request succeeds (i.e. asynchronously).
443 */
444 LogFlowThisFunc(("{%s} capturing the device.\n", mName));
445#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
446 || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS)
447 i_setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM, kHostUSBDeviceSubState_AwaitingDetach);
448#else
449 i_setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM);
450#endif
451 mMachine = aMachine;
452 mMaskedIfs = aMaskedIfs;
453 mCaptureFilename = aCaptureFilename;
454 alock.release();
455 int rc = mUSBProxyService->captureDevice(this);
456 if (RT_FAILURE(rc))
457 {
458 alock.acquire();
459 i_failTransition();
460 mMachine.setNull();
461 if (rc == VERR_SHARING_VIOLATION)
462 return setError(E_FAIL,
463 tr("USB device '%s' with UUID {%RTuuid} is in use by someone else"),
464 mName, mId.raw());
465 return E_FAIL;
466 }
467
468 return S_OK;
469}
470
471/**
472 * Attempts to attach the USB device to a VM.
473 *
474 * The device must be in the HeldByProxy state or about to exit the
475 * Capturing state.
476 *
477 * This method will make an IPC to the VM process and do the actual
478 * attaching. While in the IPC locks will be abandond.
479 *
480 * @returns Status indicating whether it was successfully attached or not.
481 * @retval S_OK on success.
482 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
483 * @retval E_* as appropriate.
484 *
485 * @param aMachine Machine this device should be attach to.
486 * @param aMaskedIfs The interfaces to hide from the guest.
487 */
488HRESULT HostUSBDevice::i_attachToVM(SessionMachine *aMachine, const com::Utf8Str &aCaptureFilename,
489 ULONG aMaskedIfs /* = 0*/)
490{
491 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
492 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
493 /*
494 * Validate and update the state.
495 */
496 AssertReturn( mUniState == kHostUSBDeviceState_Capturing
497 || mUniState == kHostUSBDeviceState_HeldByProxy
498 || mUniState == kHostUSBDeviceState_AttachingToVM,
499 E_UNEXPECTED);
500 i_setState(kHostUSBDeviceState_AttachingToVM, kHostUSBDeviceState_UsedByVM);
501
502 /*
503 * The VM process will query the object, so grab a reference to ourselves and release the locks.
504 */
505 ComPtr<IUSBDevice> d = this;
506
507 /*
508 * Call the VM process (IPC) and request it to attach the device.
509 *
510 * There are many reasons for this to fail, so, as a consequence we don't
511 * assert the return code as it will crash the daemon and annoy the heck
512 * out of people.
513 */
514 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceAttach()...\n", mName));
515 alock.release();
516 HRESULT hrc = aMachine->i_onUSBDeviceAttach(d, NULL, aMaskedIfs, aCaptureFilename);
517 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceAttach()=%08X\n", mName, hrc));
518
519 /*
520 * As we re-acquire the lock, we'll have to check if the device was
521 * physically detached while we were busy.
522 */
523 alock.acquire();
524
525 if (SUCCEEDED(hrc))
526 {
527 mMachine = aMachine;
528 if (!mIsPhysicallyDetached)
529 i_setState(kHostUSBDeviceState_UsedByVM);
530 else
531 {
532 alock.release();
533 i_detachFromVM(kHostUSBDeviceState_PhysDetached);
534 hrc = E_UNEXPECTED;
535 }
536 }
537 else
538 {
539 mMachine.setNull();
540 if (!mIsPhysicallyDetached)
541 {
542 i_setState(kHostUSBDeviceState_HeldByProxy);
543 if (hrc == E_UNEXPECTED)
544 hrc = E_FAIL; /* No confusion. */
545 }
546 else
547 {
548 alock.release();
549 i_onPhysicalDetachedInternal();
550 hrc = E_UNEXPECTED;
551 }
552 }
553 return hrc;
554}
555
556
557/**
558 * Detaches the device from the VM.
559 *
560 * This is used for a special scenario in attachToVM() and from
561 * onPhysicalDetachedInternal().
562 *
563 * @param aFinalState The final state (PhysDetached).
564 */
565void HostUSBDevice::i_detachFromVM(HostUSBDeviceState aFinalState)
566{
567 NOREF(aFinalState);
568
569 /*
570 * Assert preconditions.
571 */
572 Assert(aFinalState == kHostUSBDeviceState_PhysDetached);
573 AssertReturnVoid(!isWriteLockOnCurrentThread());
574 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
575 Assert( mUniState == kHostUSBDeviceState_AttachingToVM
576 || mUniState == kHostUSBDeviceState_UsedByVM);
577 Assert(!mMachine.isNull());
578
579 /*
580 * Change the state and abandon the locks. The VM may query
581 * data and we don't want to deadlock - the state protects us,
582 * so, it's not a bit issue here.
583 */
584 i_setState(kHostUSBDeviceState_PhysDetachingFromVM, kHostUSBDeviceState_PhysDetached);
585
586 /*
587 * Call the VM process (IPC) and request it to detach the device.
588 *
589 * There are many reasons for this to fail, so, as a consequence we don't
590 * assert the return code as it will crash the daemon and annoy the heck
591 * out of people.
592 */
593 alock.release();
594 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceDetach()...\n", mName));
595 HRESULT hrc = mMachine->i_onUSBDeviceDetach(mId.toUtf16().raw(), NULL);
596 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceDetach()=%Rhrc\n", mName, hrc));
597 NOREF(hrc);
598
599 /*
600 * Re-acquire the locks and complete the transition.
601 */
602 alock.acquire();
603 i_advanceTransition();
604}
605
606/**
607 * Called when the VM process to inform us about the device being
608 * detached from it.
609 *
610 * This is NOT called when we detach the device via onUSBDeviceDetach.
611 *
612 *
613 * @param[in] aMachine The machine making the request.
614 * This must be the machine this device is currently attached to.
615 * @param[in] aDone When set to false, the VM just informs us that it's about
616 * to detach this device but hasn't done it just yet.
617 * When set to true, the VM informs us that it has completed
618 * the detaching of this device.
619 * @param[out] aRunFilters Whether to run filters.
620 * @param[in] aAbnormal Set if we're cleaning up after a crashed VM.
621 *
622 * @returns S_OK on success, and E_UNEXPECTED if the device isn't in the right state.
623 *
624 * @note Must be called from under the object write lock.
625 */
626HRESULT HostUSBDevice::i_onDetachFromVM(SessionMachine *aMachine, bool aDone, bool *aRunFilters, bool aAbnormal /*= true*/)
627{
628 LogFlowThisFunc(("{%s} state=%s aDone=%RTbool aAbnormal=%RTbool\n", mName, i_getStateName(), aDone, aAbnormal));
629
630 /*
631 * Validate preconditions.
632 */
633 AssertPtrReturn(aRunFilters, E_INVALIDARG);
634 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
635 if (!aDone)
636 {
637 if (mUniState != kHostUSBDeviceState_UsedByVM)
638 return setError(E_INVALIDARG,
639 tr("USB device '%s' with UUID {%RTuuid} is busy (state '%s'). Please try again later"),
640 mName, mId.raw(), i_getStateName());
641 }
642 else
643 AssertMsgReturn( mUniState == kHostUSBDeviceState_DetachingFromVM /** @todo capturing for VM
644 ends up here on termination. */
645 || (mUniState == kHostUSBDeviceState_UsedByVM && aAbnormal),
646 ("{%s} %s\n", mName, i_getStateName()), E_UNEXPECTED);
647 AssertMsgReturn((mMachine == aMachine), ("%p != %p\n", (void *)mMachine, aMachine), E_FAIL);
648
649 /*
650 * Change the state.
651 */
652 if (!aDone)
653 {
654 *aRunFilters = i_startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
655 /* PORTME: This might require host specific changes if you re-enumerate the device. */
656 }
657 else if (aAbnormal && mUniState == kHostUSBDeviceState_UsedByVM)
658 {
659 /* Fast forward thru the DetachingFromVM state and on to HeldByProxy. */
660 /** @todo need to update the state machine to handle crashed VMs. */
661 i_startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
662 *aRunFilters = i_advanceTransition();
663 mMachine.setNull();
664 /* PORTME: ditto / trouble if you depend on the VM process to do anything. */
665 }
666 else
667 {
668 /* normal completion. */
669 Assert(mUniSubState == kHostUSBDeviceSubState_Default); /* PORTME: ditto */
670 *aRunFilters = i_advanceTransition();
671 mMachine.setNull();
672 }
673
674 return S_OK;
675}
676
677/**
678 * Requests the USB proxy service to release the device back to the host.
679 *
680 * This method will ignore (not assert) calls for devices that already
681 * belong to the host because it simplifies the usage a bit.
682 *
683 * @returns COM status code.
684 * @retval S_OK on success.
685 * @retval E_UNEXPECTED on bad state.
686 * @retval E_* as appropriate.
687 *
688 * @note Must be called without holding the object lock.
689 */
690HRESULT HostUSBDevice::i_requestReleaseToHost()
691{
692 /*
693 * Validate preconditions.
694 */
695 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
696 Assert(mMachine.isNull());
697
698 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
699 LogFlowThisFunc(("{%s}\n", mName));
700 if ( mUniState == kHostUSBDeviceState_Unused
701 || mUniState == kHostUSBDeviceState_Capturable)
702 return S_OK;
703 AssertMsgReturn(mUniState == kHostUSBDeviceState_HeldByProxy, ("{%s} %s\n", mName, i_getStateName()), E_UNEXPECTED);
704
705 /*
706 * Try release it.
707 */
708#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
709 || defined(RT_OS_WINDOWS)
710 i_startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused, kHostUSBDeviceSubState_AwaitingDetach);
711#else
712 i_startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused);
713#endif
714 alock.release();
715 int rc = mUSBProxyService->releaseDevice(this);
716 if (RT_FAILURE(rc))
717 {
718 alock.acquire();
719 i_failTransition();
720 return E_FAIL;
721 }
722 return S_OK;
723}
724
725/**
726 * Requests the USB proxy service to capture and hold the device.
727 *
728 * The device must be owned by the host at the time of the call. But for
729 * the callers convenience, calling this method on a device that is already
730 * being held will success without any assertions.
731 *
732 * @returns COM status code.
733 * @retval S_OK on success.
734 * @retval E_UNEXPECTED on bad state.
735 * @retval E_* as appropriate.
736 *
737 * @note Must be called without holding the object lock.
738 */
739HRESULT HostUSBDevice::i_requestHold()
740{
741 /*
742 * Validate preconditions.
743 */
744 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
745 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
746 LogFlowThisFunc(("{%s}\n", mName));
747 AssertMsgReturn( mUniState == kHostUSBDeviceState_Unused
748 || mUniState == kHostUSBDeviceState_Capturable
749 || mUniState == kHostUSBDeviceState_HeldByProxy,
750 ("{%s} %s\n", mName, i_getStateName()),
751 E_UNEXPECTED);
752
753 Assert(mMachine.isNull());
754 mMachine.setNull();
755
756 if (mUniState == kHostUSBDeviceState_HeldByProxy)
757 return S_OK;
758
759 /*
760 * Do the job.
761 */
762#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
763 || defined(RT_OS_WINDOWS)
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();
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();
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!\n", mName));
1203 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1204 *aRunFilters = i_failTransition();
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!\n", mName));
1271 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1272 *aRunFilters = i_failTransition();
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!\n", mName));
1339 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1340 *aRunFilters = i_failTransition();
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",
1476 i_getStateName(), mId.raw(), mName));
1477 *aRunFilters = i_failTransition();
1478 fIsImportant = true;
1479 }
1480 else
1481 {
1482 LogFlowThisFunc(("%p {%s} %s - no change %d\n", this, mName, i_getStateName(), enmOldState));
1483 /** @todo might have to handle some stuff here too if we cannot make the release/capture
1484 * handling deal with that above ... */
1485 }
1486
1487 return fIsImportant;
1488}
1489
1490
1491/**
1492 * Updates the state of the device, checking for cases which we fake.
1493 *
1494 * See HostUSBDevice::updateState() for details.
1495 *
1496 * @param[in] aDev See HostUSBDevice::updateState().
1497 * @param[out] aRunFilters See HostUSBDevice::updateState()
1498 * @param[out] aIgnoreMachine See HostUSBDevice::updateState()
1499 *
1500 * @returns See HostUSBDevice::updateState()
1501 */
1502bool HostUSBDevice::i_updateStateFake(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1503{
1504 Assert(!isWriteLockOnCurrentThread());
1505 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1506 const HostUSBDeviceState enmState = mUniState;
1507 switch (enmState)
1508 {
1509 case kHostUSBDeviceState_Capturing:
1510 case kHostUSBDeviceState_ReleasingToHost:
1511 {
1512 *aIgnoreMachine = mUniState == kHostUSBDeviceState_ReleasingToHost ? mMachine : NULL;
1513 *aRunFilters = i_advanceTransition();
1514 LogThisFunc(("{%s} %s\n", mName, i_getStateName()));
1515
1516 if (mUsb != aDev)
1517 {
1518 aDev->pNext = mUsb->pNext;
1519 aDev->pPrev = mUsb->pPrev;
1520 USBProxyService::freeDevice(mUsb);
1521 mUsb = aDev;
1522 }
1523
1524 /* call the completion method */
1525 if (enmState == kHostUSBDeviceState_Capturing)
1526 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
1527 else
1528 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1529
1530 /* Take action if we're supposed to attach it to a VM. */
1531 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1532 {
1533 alock.release();
1534 i_attachToVM(mMachine, mCaptureFilename, mMaskedIfs);
1535 }
1536 return true;
1537 }
1538
1539 default:
1540 alock.release();
1541 return i_updateState(aDev, aRunFilters, aIgnoreMachine);
1542 }
1543}
1544
1545
1546/**
1547 * Checks if there is a pending asynchronous operation and whether
1548 * it has timed out or not.
1549 *
1550 * @returns true on timeout, false if not.
1551 *
1552 * @note Caller must have read or write locked the object before calling.
1553 */
1554bool HostUSBDevice::i_hasAsyncOperationTimedOut() const
1555{
1556 switch (mUniSubState)
1557 {
1558#ifndef RT_OS_WINDOWS /* no timeouts on windows yet since I don't have all the details here... */
1559 case kHostUSBDeviceSubState_AwaitingDetach:
1560 case kHostUSBDeviceSubState_AwaitingReAttach:
1561 {
1562 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
1563 return elapsedNanoseconds > UINT64_C(60000000000); /* 60 seconds */ /* PORTME */
1564 }
1565#endif
1566 default:
1567 return false;
1568 }
1569}
1570
1571
1572/**
1573 * Translate the state into
1574 *
1575 * @returns
1576 * @param aState
1577 * @param aSubState
1578 * @param aPendingState
1579 */
1580/*static*/ const char *HostUSBDevice::i_stateName(HostUSBDeviceState aState,
1581 HostUSBDeviceState aPendingState /*= kHostUSBDeviceState_Invalid*/,
1582 HostUSBDeviceSubState aSubState /*= kHostUSBDeviceSubState_Default*/)
1583{
1584 switch (aState)
1585 {
1586 case kHostUSBDeviceState_Unsupported:
1587 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unsupported{bad}");
1588 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unsupported[bad]");
1589 return "Unsupported";
1590
1591 case kHostUSBDeviceState_UsedByHost:
1592 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByHost{bad}");
1593 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByHost[bad]");
1594 return "UsedByHost";
1595
1596 case kHostUSBDeviceState_Capturable:
1597 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Capturable{bad}");
1598 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Capturable[bad]");
1599 return "Capturable";
1600
1601 case kHostUSBDeviceState_Unused:
1602 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "Unused{bad}");
1603 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "Unused[bad]");
1604 return "Unused";
1605
1606 case kHostUSBDeviceState_HeldByProxy:
1607 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "HeldByProxy{bad}");
1608 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "HeldByProxy[bad]");
1609 return "HeldByProxy";
1610
1611 case kHostUSBDeviceState_UsedByVM:
1612 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "UsedByVM{bad}");
1613 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "UsedByVM[bad]");
1614 return "UsedByVM";
1615
1616 case kHostUSBDeviceState_PhysDetached:
1617 AssertReturn(aPendingState == kHostUSBDeviceState_Invalid, "PhysDetached{bad}");
1618 AssertReturn(aSubState == kHostUSBDeviceSubState_Default, "PhysDetached[bad]");
1619 return "PhysDetached";
1620
1621 case kHostUSBDeviceState_Capturing:
1622 switch (aPendingState)
1623 {
1624 case kHostUSBDeviceState_UsedByVM:
1625 switch (aSubState)
1626 {
1627 case kHostUSBDeviceSubState_Default:
1628 return "CapturingForVM";
1629 case kHostUSBDeviceSubState_AwaitingDetach:
1630 return "CapturingForVM[Detach]";
1631 case kHostUSBDeviceSubState_AwaitingReAttach:
1632 return "CapturingForVM[Attach]";
1633 default:
1634 AssertFailedReturn("CapturingForVM[bad]");
1635 }
1636 break;
1637
1638 case kHostUSBDeviceState_HeldByProxy:
1639 switch (aSubState)
1640 {
1641 case kHostUSBDeviceSubState_Default:
1642 return "CapturingForProxy";
1643 case kHostUSBDeviceSubState_AwaitingDetach:
1644 return "CapturingForProxy[Detach]";
1645 case kHostUSBDeviceSubState_AwaitingReAttach:
1646 return "CapturingForProxy[Attach]";
1647 default:
1648 AssertFailedReturn("CapturingForProxy[bad]");
1649 }
1650 break;
1651
1652 default:
1653 AssertFailedReturn("Capturing{bad}");
1654 }
1655 break;
1656
1657 case kHostUSBDeviceState_ReleasingToHost:
1658 switch (aPendingState)
1659 {
1660 case kHostUSBDeviceState_Unused:
1661 switch (aSubState)
1662 {
1663 case kHostUSBDeviceSubState_Default:
1664 return "ReleasingToHost";
1665 case kHostUSBDeviceSubState_AwaitingDetach:
1666 return "ReleasingToHost[Detach]";
1667 case kHostUSBDeviceSubState_AwaitingReAttach:
1668 return "ReleasingToHost[Attach]";
1669 default:
1670 AssertFailedReturn("ReleasingToHost[bad]");
1671 }
1672 break;
1673 default:
1674 AssertFailedReturn("ReleasingToHost{bad}");
1675 }
1676 break;
1677
1678 case kHostUSBDeviceState_DetachingFromVM:
1679 switch (aPendingState)
1680 {
1681 case kHostUSBDeviceState_HeldByProxy:
1682 switch (aSubState)
1683 {
1684 case kHostUSBDeviceSubState_Default:
1685 return "DetatchingFromVM>Proxy";
1686 case kHostUSBDeviceSubState_AwaitingDetach:
1687 return "DetatchingFromVM>Proxy[Detach]";
1688 case kHostUSBDeviceSubState_AwaitingReAttach:
1689 return "DetatchingFromVM>Proxy[Attach]";
1690 default:
1691 AssertFailedReturn("DetatchingFromVM>Proxy[bad]");
1692 }
1693 break;
1694
1695 case kHostUSBDeviceState_Unused:
1696 switch (aSubState)
1697 {
1698 case kHostUSBDeviceSubState_Default:
1699 return "DetachingFromVM>Host";
1700 case kHostUSBDeviceSubState_AwaitingDetach:
1701 return "DetachingFromVM>Host[Detach]";
1702 case kHostUSBDeviceSubState_AwaitingReAttach:
1703 return "DetachingFromVM>Host[Attach]";
1704 default:
1705 AssertFailedReturn("DetachingFromVM>Host[bad]");
1706 }
1707 break;
1708
1709 default:
1710 AssertFailedReturn("DetachingFromVM{bad}");
1711 }
1712 break;
1713
1714 case kHostUSBDeviceState_AttachingToVM:
1715 switch (aPendingState)
1716 {
1717 case kHostUSBDeviceState_UsedByVM:
1718 switch (aSubState)
1719 {
1720 case kHostUSBDeviceSubState_Default:
1721 return "AttachingToVM";
1722 case kHostUSBDeviceSubState_AwaitingDetach:
1723 return "AttachingToVM[Detach]";
1724 case kHostUSBDeviceSubState_AwaitingReAttach:
1725 return "AttachingToVM[Attach]";
1726 default:
1727 AssertFailedReturn("AttachingToVM[bad]");
1728 }
1729 break;
1730
1731 default:
1732 AssertFailedReturn("AttachingToVM{bad}");
1733 }
1734 break;
1735
1736
1737 case kHostUSBDeviceState_PhysDetachingFromVM:
1738 switch (aPendingState)
1739 {
1740 case kHostUSBDeviceState_PhysDetached:
1741 switch (aSubState)
1742 {
1743 case kHostUSBDeviceSubState_Default:
1744 return "PhysDetachingFromVM";
1745 default:
1746 AssertFailedReturn("AttachingToVM[bad]");
1747 }
1748 break;
1749
1750 default:
1751 AssertFailedReturn("AttachingToVM{bad}");
1752 }
1753 break;
1754
1755 default:
1756 AssertFailedReturn("BadState");
1757
1758 }
1759
1760 AssertFailedReturn("shouldn't get here");
1761}
1762
1763/**
1764 * Set the device state.
1765 *
1766 * This method will verify that the state transition is a legal one
1767 * according to the statemachine. It will also take care of the
1768 * associated house keeping and determine if filters needs to be applied.
1769 *
1770 * @param aNewState The new state.
1771 * @param aNewPendingState The final state of a transition when applicable.
1772 * @param aNewSubState The new sub-state when applicable.
1773 *
1774 * @returns true if filters should be applied to the device, false if not.
1775 *
1776 * @note The caller must own the write lock for this object.
1777 */
1778bool HostUSBDevice::i_setState(HostUSBDeviceState aNewState,
1779 HostUSBDeviceState aNewPendingState /*= kHostUSBDeviceState_Invalid*/,
1780 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
1781{
1782 Assert(isWriteLockOnCurrentThread());
1783 Assert( aNewSubState == kHostUSBDeviceSubState_Default
1784 || aNewSubState == kHostUSBDeviceSubState_AwaitingDetach
1785 || aNewSubState == kHostUSBDeviceSubState_AwaitingReAttach);
1786
1787 /*
1788 * If the state is unchanged, then don't bother going
1789 * thru the validation and setting. This saves a bit of code.
1790 */
1791 if ( aNewState == mUniState
1792 && aNewPendingState == mPendingUniState
1793 && aNewSubState == mUniSubState)
1794 return false;
1795
1796 /*
1797 * Welcome to the switch orgies!
1798 * You're welcome to check out the ones in startTransition(),
1799 * advanceTransition(), failTransition() and i_getStateName() too. Enjoy!
1800 */
1801
1802 bool fFilters = false;
1803 HostUSBDeviceState NewPrevState = mUniState;
1804 switch (mUniState)
1805 {
1806 /*
1807 * Not much can be done with a device in this state.
1808 */
1809 case kHostUSBDeviceState_Unsupported:
1810 switch (aNewState)
1811 {
1812 case kHostUSBDeviceState_PhysDetached:
1813 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1814 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1815 break;
1816 default:
1817 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1818 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1819 }
1820 break;
1821
1822 /*
1823 * Only the host OS (or the user) can make changes
1824 * that'll make a device get out of this state.
1825 */
1826 case kHostUSBDeviceState_UsedByHost:
1827 switch (aNewState)
1828 {
1829 case kHostUSBDeviceState_Capturable:
1830 case kHostUSBDeviceState_Unused:
1831 fFilters = true;
1832 case kHostUSBDeviceState_PhysDetached:
1833 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1834 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1835 break;
1836 default:
1837 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1838 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1839 }
1840 break;
1841
1842 /*
1843 * Now it gets interesting.
1844 */
1845 case kHostUSBDeviceState_Capturable:
1846 switch (aNewState)
1847 {
1848 /* Host changes. */
1849 case kHostUSBDeviceState_Unused:
1850 fFilters = true; /* Wildcard only... */
1851 case kHostUSBDeviceState_UsedByHost:
1852 case kHostUSBDeviceState_PhysDetached:
1853 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1854 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1855 break;
1856
1857 /* VBox actions */
1858 case kHostUSBDeviceState_Capturing:
1859 switch (aNewPendingState)
1860 {
1861 case kHostUSBDeviceState_HeldByProxy:
1862 case kHostUSBDeviceState_UsedByVM:
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 default:
1870 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1871 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1872 }
1873 break;
1874
1875 case kHostUSBDeviceState_Unused:
1876 switch (aNewState)
1877 {
1878 /* Host changes. */
1879 case kHostUSBDeviceState_PhysDetached:
1880 case kHostUSBDeviceState_UsedByHost:
1881 case kHostUSBDeviceState_Capturable:
1882 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1883 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1884 break;
1885
1886 /* VBox actions */
1887 case kHostUSBDeviceState_Capturing:
1888 switch (aNewPendingState)
1889 {
1890 case kHostUSBDeviceState_HeldByProxy:
1891 case kHostUSBDeviceState_UsedByVM:
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 default:
1899 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1900 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1901 }
1902 break;
1903
1904 /*
1905 * VBox owns this device now, what's next...
1906 */
1907 case kHostUSBDeviceState_HeldByProxy:
1908 switch (aNewState)
1909 {
1910 /* Host changes. */
1911 case kHostUSBDeviceState_PhysDetached:
1912 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
1913 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1914 break;
1915
1916 /* VBox actions */
1917 case kHostUSBDeviceState_AttachingToVM:
1918 switch (aNewPendingState)
1919 {
1920 case kHostUSBDeviceState_UsedByVM:
1921 break;
1922 default:
1923 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1924 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1925 }
1926 break;
1927 case kHostUSBDeviceState_ReleasingToHost:
1928 switch (aNewPendingState)
1929 {
1930 case kHostUSBDeviceState_Unused: /* Only this! */
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 default:
1938 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1939 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1940 }
1941 break;
1942
1943
1944 case kHostUSBDeviceState_UsedByVM:
1945 switch (aNewState)
1946 {
1947 /* Host changes. */
1948 case kHostUSBDeviceState_PhysDetachingFromVM:
1949 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
1950 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
1951 break;
1952
1953 /* VBox actions */
1954 case kHostUSBDeviceState_DetachingFromVM:
1955 switch (aNewPendingState)
1956 {
1957 case kHostUSBDeviceState_HeldByProxy:
1958 case kHostUSBDeviceState_Unused: /* Only this! */
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 default:
1966 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1967 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1968 }
1969 break;
1970
1971 /*
1972 * The final state.
1973 */
1974 case kHostUSBDeviceState_PhysDetached:
1975 switch (mUniState)
1976 {
1977 case kHostUSBDeviceState_Unsupported:
1978 case kHostUSBDeviceState_UsedByHost:
1979 case kHostUSBDeviceState_Capturable:
1980 case kHostUSBDeviceState_Unused:
1981 case kHostUSBDeviceState_HeldByProxy:
1982 case kHostUSBDeviceState_PhysDetachingFromVM:
1983 case kHostUSBDeviceState_DetachingFromVM: // ??
1984 case kHostUSBDeviceState_Capturing:
1985 case kHostUSBDeviceState_ReleasingToHost:
1986 break;
1987
1988 case kHostUSBDeviceState_AttachingToVM: // ??
1989 case kHostUSBDeviceState_UsedByVM:
1990 default:
1991 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
1992 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
1993 }
1994 break;
1995
1996
1997 /*
1998 * The transitional states.
1999 */
2000 case kHostUSBDeviceState_Capturing:
2001 NewPrevState = mPrevUniState;
2002 switch (aNewState)
2003 {
2004 /* Sub state advance. */
2005 case kHostUSBDeviceState_Capturing:
2006 switch (aNewSubState)
2007 {
2008 case kHostUSBDeviceSubState_AwaitingReAttach:
2009 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
2010 Assert(aNewPendingState == mPendingUniState);
2011 break;
2012 default:
2013 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2014 }
2015 break;
2016
2017 /* Host/User/Failure. */
2018 case kHostUSBDeviceState_PhysDetached:
2019 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2020 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2021 break;
2022 case kHostUSBDeviceState_UsedByHost:
2023 case kHostUSBDeviceState_Capturable:
2024 case kHostUSBDeviceState_Unused:
2025 Assert(aNewState == mPrevUniState);
2026 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2027 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2028 break;
2029
2030 /* VBox */
2031 case kHostUSBDeviceState_HeldByProxy:
2032 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2033 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2034 Assert( mPendingUniState == kHostUSBDeviceState_HeldByProxy
2035 || mPendingUniState == kHostUSBDeviceState_UsedByVM /* <- failure */ );
2036 break;
2037 case kHostUSBDeviceState_AttachingToVM:
2038 Assert(aNewPendingState == kHostUSBDeviceState_UsedByVM);
2039 NewPrevState = kHostUSBDeviceState_HeldByProxy;
2040 break;
2041
2042 default:
2043 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2044 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2045 }
2046 break;
2047
2048 case kHostUSBDeviceState_ReleasingToHost:
2049 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2050 NewPrevState = mPrevUniState;
2051 switch (aNewState)
2052 {
2053 /* Sub state advance. */
2054 case kHostUSBDeviceState_ReleasingToHost:
2055 switch (aNewSubState)
2056 {
2057 case kHostUSBDeviceSubState_AwaitingReAttach:
2058 Assert(mUniSubState == kHostUSBDeviceSubState_AwaitingDetach);
2059 Assert(aNewPendingState == mPendingUniState);
2060 break;
2061 default:
2062 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2063 }
2064 break;
2065
2066 /* Host/Failure. */
2067 case kHostUSBDeviceState_PhysDetached:
2068 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2069 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2070 break;
2071 case kHostUSBDeviceState_HeldByProxy:
2072 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2073 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2074 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2075 break;
2076
2077 /* Success */
2078 case kHostUSBDeviceState_UsedByHost:
2079 case kHostUSBDeviceState_Capturable:
2080 case kHostUSBDeviceState_Unused:
2081 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2082 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2083 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2084 break;
2085
2086 default:
2087 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2088 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2089 }
2090 break;
2091
2092 case kHostUSBDeviceState_AttachingToVM:
2093 Assert(mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2094 NewPrevState = mPrevUniState;
2095 switch (aNewState)
2096 {
2097 /* Host/Failure. */
2098 case kHostUSBDeviceState_PhysDetachingFromVM:
2099 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2100 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2101 break;
2102 case kHostUSBDeviceState_HeldByProxy:
2103 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2104 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2105 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2106 break;
2107
2108 /* Success */
2109 case kHostUSBDeviceState_UsedByVM:
2110 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2111 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2112 Assert(mPendingUniState == kHostUSBDeviceState_UsedByVM);
2113 break;
2114
2115 default:
2116 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2117 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2118 }
2119 break;
2120
2121 case kHostUSBDeviceState_DetachingFromVM:
2122 Assert(mPrevUniState == kHostUSBDeviceState_UsedByVM);
2123 NewPrevState = mPrevUniState;
2124 switch (aNewState)
2125 {
2126 /* Host/Failure. */
2127 case kHostUSBDeviceState_PhysDetached: //??
2128 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2129 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2130 break;
2131 case kHostUSBDeviceState_PhysDetachingFromVM:
2132 Assert(aNewPendingState == kHostUSBDeviceState_PhysDetached);
2133 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2134 break;
2135
2136 /* Success */
2137 case kHostUSBDeviceState_HeldByProxy:
2138 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2139 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2140 Assert(mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2141 fFilters = true;
2142 break;
2143
2144 case kHostUSBDeviceState_ReleasingToHost:
2145 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2146 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2147 Assert(mPendingUniState == kHostUSBDeviceState_Unused);
2148 NewPrevState = kHostUSBDeviceState_HeldByProxy;
2149 break;
2150
2151 default:
2152 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2153 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2154 }
2155 break;
2156
2157 case kHostUSBDeviceState_PhysDetachingFromVM:
2158 Assert( mPrevUniState == kHostUSBDeviceState_DetachingFromVM
2159 || mPrevUniState == kHostUSBDeviceState_AttachingToVM
2160 || mPrevUniState == kHostUSBDeviceState_UsedByVM);
2161 NewPrevState = mPrevUniState; /* preserving it is more useful. */
2162 switch (aNewState)
2163 {
2164 case kHostUSBDeviceState_PhysDetached:
2165 Assert(aNewPendingState == kHostUSBDeviceState_Invalid);
2166 Assert(aNewSubState == kHostUSBDeviceSubState_Default);
2167 break;
2168 default:
2169 AssertLogRelMsgFailedReturn(("this=%p %s -X-> %s\n", this, i_getStateName(),
2170 i_stateName(aNewState, aNewPendingState, aNewSubState)), false);
2171 }
2172 break;
2173
2174 default:
2175 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2176 }
2177
2178 /*
2179 * Make the state change.
2180 */
2181 if (NewPrevState != mPrevUniState)
2182 LogFlowThisFunc(("%s -> %s (prev: %s -> %s) [%s]\n",
2183 i_getStateName(), i_stateName(aNewState, aNewPendingState, aNewSubState),
2184 i_stateName(mPrevUniState), i_stateName(NewPrevState), mName));
2185 else
2186 LogFlowThisFunc(("%s -> %s (prev: %s) [%s]\n",
2187 i_getStateName(), i_stateName(aNewState, aNewPendingState, aNewSubState),
2188 i_stateName(NewPrevState), mName));
2189 mPrevUniState = NewPrevState;
2190 mUniState = aNewState;
2191 mUniSubState = aNewSubState;
2192 mPendingUniState = aNewPendingState;
2193 mLastStateChangeTS = RTTimeNanoTS();
2194
2195 return fFilters;
2196}
2197
2198
2199/**
2200 * A convenience for entering a transitional state.
2201
2202 * @param aNewState The new state (transitional).
2203 * @param aFinalSubState The final state of the transition (non-transitional).
2204 * @param aNewSubState The new sub-state when applicable.
2205 *
2206 * @returns Always false because filters are never applied for the start of a transition.
2207 *
2208 * @note The caller must own the write lock for this object.
2209 */
2210bool HostUSBDevice::i_startTransition(HostUSBDeviceState aNewState, HostUSBDeviceState aFinalState,
2211 HostUSBDeviceSubState aNewSubState /*= kHostUSBDeviceSubState_Default*/)
2212{
2213 AssertReturn(isWriteLockOnCurrentThread(), false);
2214 /*
2215 * A quick prevalidation thing. Not really necessary since setState
2216 * verifies this too, but it's very easy here.
2217 */
2218 switch (mUniState)
2219 {
2220 case kHostUSBDeviceState_Unsupported:
2221 case kHostUSBDeviceState_UsedByHost:
2222 case kHostUSBDeviceState_Capturable:
2223 case kHostUSBDeviceState_Unused:
2224 case kHostUSBDeviceState_HeldByProxy:
2225 case kHostUSBDeviceState_UsedByVM:
2226 break;
2227
2228 case kHostUSBDeviceState_DetachingFromVM:
2229 case kHostUSBDeviceState_Capturing:
2230 case kHostUSBDeviceState_ReleasingToHost:
2231 case kHostUSBDeviceState_AttachingToVM:
2232 case kHostUSBDeviceState_PhysDetachingFromVM:
2233 AssertMsgFailedReturn(("this=%p %s is a transitional state.\n", this, i_getStateName()), false);
2234
2235 case kHostUSBDeviceState_PhysDetached:
2236 default:
2237 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2238 }
2239
2240 return i_setState(aNewState, aFinalState, aNewSubState);
2241}
2242
2243
2244/**
2245 * A convenience for advancing a transitional state forward.
2246 *
2247 * @param aSkipReAttach Fast forwards thru the re-attach substate if
2248 * applicable.
2249 *
2250 * @returns true if filters should be applied to the device, false if not.
2251 *
2252 * @note The caller must own the write lock for this object.
2253 */
2254bool HostUSBDevice::i_advanceTransition(bool aSkipReAttach /* = false */)
2255{
2256 AssertReturn(isWriteLockOnCurrentThread(), false);
2257 HostUSBDeviceState enmPending = mPendingUniState;
2258 HostUSBDeviceSubState enmSub = mUniSubState;
2259 HostUSBDeviceState enmState = mUniState;
2260 switch (enmState)
2261 {
2262 case kHostUSBDeviceState_Capturing:
2263 switch (enmSub)
2264 {
2265 case kHostUSBDeviceSubState_AwaitingDetach:
2266 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2267 break;
2268 case kHostUSBDeviceSubState_AwaitingReAttach:
2269 enmSub = kHostUSBDeviceSubState_Default;
2270 /* fall thru */
2271 case kHostUSBDeviceSubState_Default:
2272 switch (enmPending)
2273 {
2274 case kHostUSBDeviceState_UsedByVM:
2275 enmState = kHostUSBDeviceState_AttachingToVM;
2276 break;
2277 case kHostUSBDeviceState_HeldByProxy:
2278 enmState = enmPending;
2279 enmPending = kHostUSBDeviceState_Invalid;
2280 break;
2281 default:
2282 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2283 this, enmPending, i_getStateName()), false);
2284 }
2285 break;
2286 default:
2287 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2288 }
2289 break;
2290
2291 case kHostUSBDeviceState_ReleasingToHost:
2292 switch (enmSub)
2293 {
2294 case kHostUSBDeviceSubState_AwaitingDetach:
2295 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2296 break;
2297 case kHostUSBDeviceSubState_AwaitingReAttach:
2298 enmSub = kHostUSBDeviceSubState_Default;
2299 /* fall thru */
2300 case kHostUSBDeviceSubState_Default:
2301 switch (enmPending)
2302 {
2303 /* Use Unused here since it implies that filters has been applied
2304 and will make sure they aren't applied if the final state really
2305 is Capturable. */
2306 case kHostUSBDeviceState_Unused:
2307 enmState = enmPending;
2308 enmPending = kHostUSBDeviceState_Invalid;
2309 break;
2310 default:
2311 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2312 this, enmPending, i_getStateName()), false);
2313 }
2314 break;
2315 default:
2316 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2317 }
2318 break;
2319
2320 case kHostUSBDeviceState_AttachingToVM:
2321 switch (enmSub)
2322 {
2323 case kHostUSBDeviceSubState_AwaitingDetach:
2324 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2325 break;
2326 case kHostUSBDeviceSubState_AwaitingReAttach:
2327 enmSub = kHostUSBDeviceSubState_Default;
2328 /* fall thru */
2329 case kHostUSBDeviceSubState_Default:
2330 switch (enmPending)
2331 {
2332 case kHostUSBDeviceState_UsedByVM:
2333 enmState = enmPending;
2334 enmPending = kHostUSBDeviceState_Invalid;
2335 break;
2336 default:
2337 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2338 this, enmPending, i_getStateName()), false);
2339 }
2340 break;
2341 default:
2342 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2343 }
2344 break;
2345
2346 case kHostUSBDeviceState_DetachingFromVM:
2347 switch (enmSub)
2348 {
2349 case kHostUSBDeviceSubState_AwaitingDetach:
2350 enmSub = kHostUSBDeviceSubState_AwaitingReAttach;
2351 break;
2352 case kHostUSBDeviceSubState_AwaitingReAttach:
2353 enmSub = kHostUSBDeviceSubState_Default;
2354 /* fall thru */
2355 case kHostUSBDeviceSubState_Default:
2356 switch (enmPending)
2357 {
2358 case kHostUSBDeviceState_HeldByProxy:
2359 enmState = enmPending;
2360 enmPending = kHostUSBDeviceState_Invalid;
2361 break;
2362 case kHostUSBDeviceState_Unused:
2363 enmState = kHostUSBDeviceState_ReleasingToHost;
2364 break;
2365 default:
2366 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2367 this, enmPending, i_getStateName()), false);
2368 }
2369 break;
2370 default:
2371 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2372 }
2373 break;
2374
2375 case kHostUSBDeviceState_PhysDetachingFromVM:
2376 switch (enmSub)
2377 {
2378 case kHostUSBDeviceSubState_Default:
2379 switch (enmPending)
2380 {
2381 case kHostUSBDeviceState_PhysDetached:
2382 enmState = enmPending;
2383 enmPending = kHostUSBDeviceState_Invalid;
2384 break;
2385 default:
2386 AssertMsgFailedReturn(("this=%p invalid pending state %d: %s\n",
2387 this, enmPending, i_getStateName()), false);
2388 }
2389 break;
2390 default:
2391 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2392 }
2393 break;
2394
2395 case kHostUSBDeviceState_Unsupported:
2396 case kHostUSBDeviceState_UsedByHost:
2397 case kHostUSBDeviceState_Capturable:
2398 case kHostUSBDeviceState_Unused:
2399 case kHostUSBDeviceState_HeldByProxy:
2400 case kHostUSBDeviceState_UsedByVM:
2401 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, i_getStateName()), false);
2402 case kHostUSBDeviceState_PhysDetached:
2403 default:
2404 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, enmState), false);
2405
2406 }
2407
2408 bool fRc = i_setState(enmState, enmPending, enmSub);
2409 if (aSkipReAttach && mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
2410 fRc |= i_advanceTransition(false /* don't fast forward re-attach */);
2411 return fRc;
2412}
2413
2414/**
2415 * A convenience for failing a transitional state.
2416 *
2417 * @return true if filters should be applied to the device, false if not.
2418 *
2419 * @note The caller must own the write lock for this object.
2420 */
2421bool HostUSBDevice::i_failTransition()
2422{
2423 AssertReturn(isWriteLockOnCurrentThread(), false);
2424 HostUSBDeviceSubState enmSub = mUniSubState;
2425 HostUSBDeviceState enmState = mUniState;
2426 switch (enmState)
2427 {
2428 /*
2429 * There are just two cases, either we got back to the
2430 * previous state (assumes Capture+Attach-To-VM updates it)
2431 * or we assume the device has been unplugged (physically).
2432 */
2433 case kHostUSBDeviceState_DetachingFromVM:
2434 case kHostUSBDeviceState_Capturing:
2435 case kHostUSBDeviceState_ReleasingToHost:
2436 case kHostUSBDeviceState_AttachingToVM:
2437 switch (enmSub)
2438 {
2439 case kHostUSBDeviceSubState_AwaitingDetach:
2440 enmSub = kHostUSBDeviceSubState_Default;
2441 /* fall thru */
2442 case kHostUSBDeviceSubState_Default:
2443 enmState = mPrevUniState;
2444 break;
2445 case kHostUSBDeviceSubState_AwaitingReAttach:
2446 enmSub = kHostUSBDeviceSubState_Default;
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.

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