VirtualBox

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

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

Main/src-server/HostUSBDeviceImpl.cpp: quick fix for release log message

  • 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 57475 2015-08-20 13:05:20Z vboxsync $ */
2/** @file
3 * VirtualBox IHostUSBDevice COM interface implementation.
4 */
5
6/*
7 * Copyright (C) 2005-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19#include <iprt/types.h> /* for UINT64_C */
20
21#include "HostUSBDeviceImpl.h"
22#include "MachineImpl.h"
23#include "HostImpl.h"
24#include "VirtualBoxErrorInfoImpl.h"
25#include "USBProxyService.h"
26#include "USBIdDatabase.h"
27
28#include "AutoCaller.h"
29#include "Logging.h"
30
31#include <VBox/err.h>
32#include <iprt/cpp/utils.h>
33
34// constructor / destructor
35/////////////////////////////////////////////////////////////////////////////
36
37DEFINE_EMPTY_CTOR_DTOR(HostUSBDevice)
38
39HRESULT HostUSBDevice::FinalConstruct()
40{
41 mUSBProxyService = NULL;
42 mUsb = NULL;
43
44 return BaseFinalConstruct();
45}
46
47void HostUSBDevice::FinalRelease()
48{
49 uninit();
50 BaseFinalRelease();
51}
52
53// public initializer/uninitializer for internal purposes only
54/////////////////////////////////////////////////////////////////////////////
55
56/**
57 * Initializes the USB device object.
58 *
59 * @returns COM result indicator
60 * @param aUsb Pointer to the usb device structure for which the object is to be a wrapper.
61 * This structure is now fully owned by the HostUSBDevice object and will be
62 * freed when it is destructed.
63 * @param aUSBProxyService Pointer to the USB Proxy Service object.
64 */
65HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
66{
67 ComAssertRet(aUsb, E_INVALIDARG);
68
69 /* Enclose the state transition NotReady->InInit->Ready */
70 AutoInitSpan autoInitSpan(this);
71 AssertReturn(autoInitSpan.isOk(), E_FAIL);
72
73 /*
74 * We need a unique ID for this VBoxSVC session.
75 * The UUID isn't stored anywhere.
76 */
77 unconst(mId).create();
78
79 /*
80 * Set the initial device state.
81 */
82 AssertMsgReturn( aUsb->enmState >= USBDEVICESTATE_UNSUPPORTED
83 && aUsb->enmState < USBDEVICESTATE_USED_BY_GUEST, /* used-by-guest is not a legal initial state. */
84 ("%d\n", aUsb->enmState), E_FAIL);
85 mUniState = (HostUSBDeviceState)aUsb->enmState;
86 mUniSubState = kHostUSBDeviceSubState_Default;
87 mPendingUniState = kHostUSBDeviceState_Invalid;
88 mPrevUniState = mUniState;
89 mIsPhysicallyDetached = false;
90
91 /* Other data members */
92 mUSBProxyService = aUSBProxyService;
93 mUsb = aUsb;
94
95 /* Set the name. */
96 mNameObj = i_getName();
97 mName = mNameObj.c_str();
98
99 /* Confirm the successful initialization */
100 autoInitSpan.setSucceeded();
101
102 return S_OK;
103}
104
105/**
106 * Uninitializes the instance and sets the ready flag to FALSE.
107 * Called either from FinalRelease() or by the parent when it gets destroyed.
108 */
109void HostUSBDevice::uninit()
110{
111 /* Enclose the state transition Ready->InUninit->NotReady */
112 AutoUninitSpan autoUninitSpan(this);
113 if (autoUninitSpan.uninitDone())
114 return;
115
116 if (mUsb != NULL)
117 {
118 USBProxyService::freeDevice(mUsb);
119 mUsb = NULL;
120 }
121
122 mUSBProxyService = NULL;
123 mUniState = kHostUSBDeviceState_Invalid;
124}
125
126// Wrapped IUSBDevice properties
127/////////////////////////////////////////////////////////////////////////////
128HRESULT HostUSBDevice::getId(com::Guid &aId)
129{
130 /* mId is constant during life time, no need to lock */
131 aId = mId;
132
133 return S_OK;
134}
135
136
137HRESULT HostUSBDevice::getVendorId(USHORT *aVendorId)
138{
139 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
140
141 *aVendorId = mUsb->idVendor;
142
143 return S_OK;
144}
145
146HRESULT HostUSBDevice::getProductId(USHORT *aProductId)
147{
148 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
149
150 *aProductId = mUsb->idProduct;
151
152 return S_OK;
153}
154
155
156HRESULT HostUSBDevice::getRevision(USHORT *aRevision)
157{
158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
159
160 *aRevision = mUsb->bcdDevice;
161
162 return S_OK;
163}
164
165HRESULT HostUSBDevice::getManufacturer(com::Utf8Str &aManufacturer)
166{
167 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
168
169 aManufacturer = mUsb->pszManufacturer;
170 if (mUsb->pszManufacturer == NULL || mUsb->pszManufacturer[0] == 0)
171 {
172 const char* vendorName = AliasDictionary::findVendor(mUsb->idVendor);
173 if (vendorName)
174 aManufacturer = vendorName;
175 }
176 return S_OK;
177}
178
179
180HRESULT HostUSBDevice::getProduct(com::Utf8Str &aProduct)
181{
182 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
183
184 aProduct = mUsb->pszProduct;
185 if (mUsb->pszProduct == NULL || mUsb->pszProduct[0] == 0)
186 {
187 const char* productName = AliasDictionary::findProduct(mUsb->idVendor, mUsb->idProduct);
188 if (productName)
189 aProduct = productName;
190 }
191 return S_OK;
192}
193
194
195HRESULT HostUSBDevice::getSerialNumber(com::Utf8Str &aSerialNumber)
196{
197 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
198
199 aSerialNumber = mUsb->pszSerialNumber;
200
201 return S_OK;
202}
203
204HRESULT HostUSBDevice::getAddress(com::Utf8Str &aAddress)
205{
206 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
207 aAddress = mUsb->pszAddress;
208 return S_OK;
209}
210
211
212HRESULT HostUSBDevice::getPort(USHORT *aPort)
213{
214 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
215
216#if !defined(RT_OS_WINDOWS) /// @todo check up the bPort value on Windows before enabling this.
217 *aPort = mUsb->bPort;
218#else
219 *aPort = 0;
220#endif
221
222 return S_OK;
223}
224
225
226HRESULT HostUSBDevice::getVersion(USHORT *aVersion)
227{
228 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
229
230 *aVersion = mUsb->bcdUSB >> 8;
231
232 return S_OK;
233}
234
235
236HRESULT HostUSBDevice::getSpeed(USBConnectionSpeed_T *aSpeed)
237{
238 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
239
240 /* If the speed is unknown (which it shouldn't be), make a guess
241 * which will be correct for USB 1 and 3 devices, but may be wrong
242 * for USB 2.0 devices
243 */
244 switch (mUsb->enmSpeed)
245 {
246 case USBDEVICESPEED_LOW: *aSpeed = USBConnectionSpeed_Low; break;
247 case USBDEVICESPEED_FULL: *aSpeed = USBConnectionSpeed_Full; break;
248 case USBDEVICESPEED_HIGH: *aSpeed = USBConnectionSpeed_High; break;
249 case USBDEVICESPEED_SUPER: *aSpeed = USBConnectionSpeed_Super; break;
250// case USBDEVICESPEED_SUPERPLUS: *aSpeed = USBConnectionSpeed_SuperPlus; break;
251 default:
252 switch (mUsb->bcdUSB >> 8)
253 {
254 case 3: *aSpeed = USBConnectionSpeed_Super; break;
255 case 2: *aSpeed = USBConnectionSpeed_High; break;
256 default: *aSpeed = USBConnectionSpeed_Full;
257 }
258 }
259
260 return S_OK;
261}
262
263
264HRESULT HostUSBDevice::getPortVersion(USHORT *aPortVersion)
265{
266 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
267 /* Port version is 2 (EHCI) if and only if the device runs at high speed;
268 * if speed is unknown, fall back to the old and inaccurate method.
269 */
270 if (mUsb->enmSpeed == USBDEVICESPEED_UNKNOWN)
271 *aPortVersion = mUsb->bcdUSB >> 8;
272 else
273 {
274 switch (mUsb->enmSpeed)
275 {
276 case USBDEVICESPEED_SUPER:
277 *aPortVersion = 3;
278 break;
279 case USBDEVICESPEED_HIGH:
280 *aPortVersion = 2;
281 break;
282 case USBDEVICESPEED_FULL:
283 case USBDEVICESPEED_LOW:
284 case USBDEVICESPEED_VARIABLE:
285 *aPortVersion = 1;
286 break;
287 default:
288 AssertMsgFailed(("Invalid USB speed: %d\n", mUsb->enmSpeed));
289 *aPortVersion = 1;
290 }
291 }
292
293 return S_OK;
294}
295
296
297HRESULT HostUSBDevice::getRemote(BOOL *aRemote)
298{
299 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
300
301 *aRemote = FALSE;
302
303 return S_OK;
304}
305
306
307HRESULT HostUSBDevice::getState(USBDeviceState_T *aState)
308{
309 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
310
311 *aState = i_canonicalState();
312
313 return S_OK;
314}
315
316
317// public methods only for internal purposes
318////////////////////////////////////////////////////////////////////////////////
319
320/**
321 * @note Locks this object for reading.
322 */
323com::Utf8Str HostUSBDevice::i_getName()
324{
325 Utf8Str name;
326
327 AutoCaller autoCaller(this);
328 AssertComRCReturn(autoCaller.rc(), name);
329
330 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
331
332 bool haveManufacturer = mUsb->pszManufacturer && *mUsb->pszManufacturer;
333 bool haveProduct = mUsb->pszProduct && *mUsb->pszProduct;
334 if (haveManufacturer && haveProduct)
335 name = Utf8StrFmt("%s %s", mUsb->pszManufacturer, mUsb->pszProduct);
336 else if (haveManufacturer)
337 name = Utf8StrFmt("%s", mUsb->pszManufacturer);
338 else if (haveProduct)
339 name = Utf8StrFmt("%s", mUsb->pszProduct);
340 else
341 {
342 const char* vendorName = AliasDictionary::findVendor(mUsb->idVendor);
343 const char* productName = AliasDictionary::findProduct(mUsb->idVendor, mUsb->idProduct);
344 if (vendorName && productName)
345 {
346 name = Utf8StrFmt("%s %s", vendorName, productName);
347 }
348 else
349 {
350 name = "<unknown>";
351 LogRel(("USB: Unknown USB device detected (idVendor: 0x%04x, idProduct: 0x%04x). Please, report the idVendor and idProduct to virtualbox.org.\n", vendorName, productName));
352 }
353 }
354
355 return name;
356}
357
358/**
359 * Requests the USB proxy service capture the device (from the host)
360 * and attach it to a VM.
361 *
362 * As a convenience, this method will operate like attachToVM() if the device
363 * is already held by the proxy. Note that it will then perform IPC to the VM
364 * process, which means it will temporarily release all locks. (Is this a good idea?)
365 *
366 * @param aMachine Machine this device should be attach to.
367 * @param aSetError Whether to set full error message or not to bother.
368 * @param aCaptureFilename The filename to capture the USB traffic to.
369 * @param aMaskedIfs The interfaces to hide from the guest.
370 *
371 * @returns Status indicating whether it was successfully captured and/or attached.
372 * @retval S_OK on success.
373 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
374 * @retval E_* as appropriate.
375 */
376HRESULT HostUSBDevice::i_requestCaptureForVM(SessionMachine *aMachine, bool aSetError,
377 const com::Utf8Str &aCaptureFilename, ULONG aMaskedIfs /* = 0*/)
378{
379 /*
380 * Validate preconditions and input.
381 */
382 AssertReturn(aMachine, E_INVALIDARG);
383 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
384 AssertReturn(!aMachine->isWriteLockOnCurrentThread(), E_FAIL);
385
386 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
387 LogFlowThisFunc(("{%s} aMachine=%p aMaskedIfs=%#x\n", mName, aMachine, aMaskedIfs));
388
389 if (aSetError)
390 {
391 if (mUniState == kHostUSBDeviceState_Unsupported)
392 return setError(E_INVALIDARG,
393 tr("USB device '%s' with UUID {%RTuuid} cannot be accessed by guest computers"),
394 mName, mId.raw());
395 if (mUniState == kHostUSBDeviceState_UsedByHost)
396 return setError(E_INVALIDARG,
397 tr("USB device '%s' with UUID {%RTuuid} is being exclusively used by the host computer"),
398 mName, mId.raw());
399 if (mUniState == kHostUSBDeviceState_UsedByVM)
400 {
401 /* Machine::name() requires a read lock */
402 alock.release();
403 AutoReadLock machLock(mMachine COMMA_LOCKVAL_SRC_POS);
404 return setError(E_INVALIDARG,
405 tr("USB device '%s' with UUID {%RTuuid} is already captured by the virtual machine '%s'"),
406 mName, mId.raw(), mMachine->i_getName().c_str());
407 }
408 if (mUniState >= kHostUSBDeviceState_FirstTransitional)
409 return setError(E_INVALIDARG,
410 tr("USB device '%s' with UUID {%RTuuid} is busy with a previous request. Please try again later"),
411 mName, mId.raw());
412 if ( mUniState != kHostUSBDeviceState_Unused
413 && mUniState != kHostUSBDeviceState_HeldByProxy
414 && mUniState != kHostUSBDeviceState_Capturable)
415 return setError(E_INVALIDARG,
416 tr("USB device '%s' with UUID {%RTuuid} is not in the right state for capturing (%s)"),
417 mName, mId.raw(), i_getStateName());
418 }
419
420 AssertReturn( mUniState == kHostUSBDeviceState_HeldByProxy
421 || mUniState == kHostUSBDeviceState_Unused
422 || mUniState == kHostUSBDeviceState_Capturable,
423 E_UNEXPECTED);
424 Assert(mMachine.isNull());
425
426 /*
427 * If it's already held by the proxy, we'll simply call
428 * attachToVM synchronously.
429 */
430 if (mUniState == kHostUSBDeviceState_HeldByProxy)
431 {
432 alock.release();
433 HRESULT hrc = i_attachToVM(aMachine, aCaptureFilename, aMaskedIfs);
434 return SUCCEEDED(hrc);
435 }
436
437 /*
438 * Need to capture the device before it can be used.
439 *
440 * The device will be attached to the VM by the USB proxy service thread
441 * when the request succeeds (i.e. asynchronously).
442 */
443 LogFlowThisFunc(("{%s} capturing the device.\n", mName));
444#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
445 || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS)
446 i_setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM, kHostUSBDeviceSubState_AwaitingDetach);
447#else
448 i_setState(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_UsedByVM);
449#endif
450 mMachine = aMachine;
451 mMaskedIfs = aMaskedIfs;
452 mCaptureFilename = aCaptureFilename;
453 alock.release();
454 int rc = mUSBProxyService->captureDevice(this);
455 if (RT_FAILURE(rc))
456 {
457 alock.acquire();
458 i_failTransition();
459 mMachine.setNull();
460 if (rc == VERR_SHARING_VIOLATION)
461 return setError(E_FAIL,
462 tr("USB device '%s' with UUID {%RTuuid} is in use by someone else"),
463 mName, mId.raw());
464 return E_FAIL;
465 }
466
467 return S_OK;
468}
469
470/**
471 * Attempts to attach the USB device to a VM.
472 *
473 * The device must be in the HeldByProxy state or about to exit the
474 * Capturing state.
475 *
476 * This method will make an IPC to the VM process and do the actual
477 * attaching. While in the IPC locks will be abandond.
478 *
479 * @returns Status indicating whether it was successfully attached or not.
480 * @retval S_OK on success.
481 * @retval E_UNEXPECTED if the device state doesn't permit for any attaching.
482 * @retval E_* as appropriate.
483 *
484 * @param aMachine Machine this device should be attach to.
485 * @param aMaskedIfs The interfaces to hide from the guest.
486 */
487HRESULT HostUSBDevice::i_attachToVM(SessionMachine *aMachine, const com::Utf8Str &aCaptureFilename,
488 ULONG aMaskedIfs /* = 0*/)
489{
490 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
491 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
492 /*
493 * Validate and update the state.
494 */
495 AssertReturn( mUniState == kHostUSBDeviceState_Capturing
496 || mUniState == kHostUSBDeviceState_HeldByProxy
497 || mUniState == kHostUSBDeviceState_AttachingToVM,
498 E_UNEXPECTED);
499 i_setState(kHostUSBDeviceState_AttachingToVM, kHostUSBDeviceState_UsedByVM);
500
501 /*
502 * The VM process will query the object, so grab a reference to ourselves and release the locks.
503 */
504 ComPtr<IUSBDevice> d = this;
505
506 /*
507 * Call the VM process (IPC) and request it to attach the device.
508 *
509 * There are many reasons for this to fail, so, as a consequence we don't
510 * assert the return code as it will crash the daemon and annoy the heck
511 * out of people.
512 */
513 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceAttach()...\n", mName));
514 alock.release();
515 HRESULT hrc = aMachine->i_onUSBDeviceAttach(d, NULL, aMaskedIfs, aCaptureFilename);
516 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceAttach()=%08X\n", mName, hrc));
517
518 /*
519 * As we re-acquire the lock, we'll have to check if the device was
520 * physically detached while we were busy.
521 */
522 alock.acquire();
523
524 if (SUCCEEDED(hrc))
525 {
526 mMachine = aMachine;
527 if (!mIsPhysicallyDetached)
528 i_setState(kHostUSBDeviceState_UsedByVM);
529 else
530 {
531 alock.release();
532 i_detachFromVM(kHostUSBDeviceState_PhysDetached);
533 hrc = E_UNEXPECTED;
534 }
535 }
536 else
537 {
538 mMachine.setNull();
539 if (!mIsPhysicallyDetached)
540 {
541 i_setState(kHostUSBDeviceState_HeldByProxy);
542 if (hrc == E_UNEXPECTED)
543 hrc = E_FAIL; /* No confusion. */
544 }
545 else
546 {
547 alock.release();
548 i_onPhysicalDetachedInternal();
549 hrc = E_UNEXPECTED;
550 }
551 }
552 return hrc;
553}
554
555
556/**
557 * Detaches the device from the VM.
558 *
559 * This is used for a special scenario in attachToVM() and from
560 * onPhysicalDetachedInternal().
561 *
562 * @param aFinalState The final state (PhysDetached).
563 */
564void HostUSBDevice::i_detachFromVM(HostUSBDeviceState aFinalState)
565{
566 NOREF(aFinalState);
567
568 /*
569 * Assert preconditions.
570 */
571 Assert(aFinalState == kHostUSBDeviceState_PhysDetached);
572 AssertReturnVoid(!isWriteLockOnCurrentThread());
573 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
574 Assert( mUniState == kHostUSBDeviceState_AttachingToVM
575 || mUniState == kHostUSBDeviceState_UsedByVM);
576 Assert(!mMachine.isNull());
577
578 /*
579 * Change the state and abandon the locks. The VM may query
580 * data and we don't want to deadlock - the state protects us,
581 * so, it's not a bit issue here.
582 */
583 i_setState(kHostUSBDeviceState_PhysDetachingFromVM, kHostUSBDeviceState_PhysDetached);
584
585 /*
586 * Call the VM process (IPC) and request it to detach the device.
587 *
588 * There are many reasons for this to fail, so, as a consequence we don't
589 * assert the return code as it will crash the daemon and annoy the heck
590 * out of people.
591 */
592 alock.release();
593 LogFlowThisFunc(("{%s} Calling machine->onUSBDeviceDetach()...\n", mName));
594 HRESULT hrc = mMachine->i_onUSBDeviceDetach(mId.toUtf16().raw(), NULL);
595 LogFlowThisFunc(("{%s} Done machine->onUSBDeviceDetach()=%Rhrc\n", mName, hrc));
596 NOREF(hrc);
597
598 /*
599 * Re-acquire the locks and complete the transition.
600 */
601 alock.acquire();
602 i_advanceTransition();
603}
604
605/**
606 * Called when the VM process to inform us about the device being
607 * detached from it.
608 *
609 * This is NOT called when we detach the device via onUSBDeviceDetach.
610 *
611 *
612 * @param[in] aMachine The machine making the request.
613 * This must be the machine this device is currently attached to.
614 * @param[in] aDone When set to false, the VM just informs us that it's about
615 * to detach this device but hasn't done it just yet.
616 * When set to true, the VM informs us that it has completed
617 * the detaching of this device.
618 * @param[out] aRunFilters Whether to run filters.
619 * @param[in] aAbnormal Set if we're cleaning up after a crashed VM.
620 *
621 * @returns S_OK on success, and E_UNEXPECTED if the device isn't in the right state.
622 *
623 * @note Must be called from under the object write lock.
624 */
625HRESULT HostUSBDevice::i_onDetachFromVM(SessionMachine *aMachine, bool aDone, bool *aRunFilters, bool aAbnormal /*= true*/)
626{
627 LogFlowThisFunc(("{%s} state=%s aDone=%RTbool aAbnormal=%RTbool\n", mName, i_getStateName(), aDone, aAbnormal));
628
629 /*
630 * Validate preconditions.
631 */
632 AssertPtrReturn(aRunFilters, E_INVALIDARG);
633 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
634 if (!aDone)
635 {
636 if (mUniState != kHostUSBDeviceState_UsedByVM)
637 return setError(E_INVALIDARG,
638 tr("USB device '%s' with UUID {%RTuuid} is busy (state '%s'). Please try again later"),
639 mName, mId.raw(), i_getStateName());
640 }
641 else
642 AssertMsgReturn( mUniState == kHostUSBDeviceState_DetachingFromVM /** @todo capturing for VM
643 ends up here on termination. */
644 || (mUniState == kHostUSBDeviceState_UsedByVM && aAbnormal),
645 ("{%s} %s\n", mName, i_getStateName()), E_UNEXPECTED);
646 AssertMsgReturn((mMachine == aMachine), ("%p != %p\n", (void *)mMachine, aMachine), E_FAIL);
647
648 /*
649 * Change the state.
650 */
651 if (!aDone)
652 {
653 *aRunFilters = i_startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
654 /* PORTME: This might require host specific changes if you re-enumerate the device. */
655 }
656 else if (aAbnormal && mUniState == kHostUSBDeviceState_UsedByVM)
657 {
658 /* Fast forward thru the DetachingFromVM state and on to HeldByProxy. */
659 /** @todo need to update the state machine to handle crashed VMs. */
660 i_startTransition(kHostUSBDeviceState_DetachingFromVM, kHostUSBDeviceState_HeldByProxy);
661 *aRunFilters = i_advanceTransition();
662 mMachine.setNull();
663 /* PORTME: ditto / trouble if you depend on the VM process to do anything. */
664 }
665 else
666 {
667 /* normal completion. */
668 Assert(mUniSubState == kHostUSBDeviceSubState_Default); /* PORTME: ditto */
669 *aRunFilters = i_advanceTransition();
670 mMachine.setNull();
671 }
672
673 return S_OK;
674}
675
676/**
677 * Requests the USB proxy service to release the device back to the host.
678 *
679 * This method will ignore (not assert) calls for devices that already
680 * belong to the host because it simplifies the usage a bit.
681 *
682 * @returns COM status code.
683 * @retval S_OK on success.
684 * @retval E_UNEXPECTED on bad state.
685 * @retval E_* as appropriate.
686 *
687 * @note Must be called without holding the object lock.
688 */
689HRESULT HostUSBDevice::i_requestReleaseToHost()
690{
691 /*
692 * Validate preconditions.
693 */
694 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
695 Assert(mMachine.isNull());
696
697 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
698 LogFlowThisFunc(("{%s}\n", mName));
699 if ( mUniState == kHostUSBDeviceState_Unused
700 || mUniState == kHostUSBDeviceState_Capturable)
701 return S_OK;
702 AssertMsgReturn(mUniState == kHostUSBDeviceState_HeldByProxy, ("{%s} %s\n", mName, i_getStateName()), E_UNEXPECTED);
703
704 /*
705 * Try release it.
706 */
707#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
708 || defined(RT_OS_WINDOWS)
709 i_startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused, kHostUSBDeviceSubState_AwaitingDetach);
710#else
711 i_startTransition(kHostUSBDeviceState_ReleasingToHost, kHostUSBDeviceState_Unused);
712#endif
713 alock.release();
714 int rc = mUSBProxyService->releaseDevice(this);
715 if (RT_FAILURE(rc))
716 {
717 alock.acquire();
718 i_failTransition();
719 return E_FAIL;
720 }
721 return S_OK;
722}
723
724/**
725 * Requests the USB proxy service to capture and hold the device.
726 *
727 * The device must be owned by the host at the time of the call. But for
728 * the callers convenience, calling this method on a device that is already
729 * being held will success without any assertions.
730 *
731 * @returns COM status code.
732 * @retval S_OK on success.
733 * @retval E_UNEXPECTED on bad state.
734 * @retval E_* as appropriate.
735 *
736 * @note Must be called without holding the object lock.
737 */
738HRESULT HostUSBDevice::i_requestHold()
739{
740 /*
741 * Validate preconditions.
742 */
743 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
744 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
745 LogFlowThisFunc(("{%s}\n", mName));
746 AssertMsgReturn( mUniState == kHostUSBDeviceState_Unused
747 || mUniState == kHostUSBDeviceState_Capturable
748 || mUniState == kHostUSBDeviceState_HeldByProxy,
749 ("{%s} %s\n", mName, i_getStateName()),
750 E_UNEXPECTED);
751
752 Assert(mMachine.isNull());
753 mMachine.setNull();
754
755 if (mUniState == kHostUSBDeviceState_HeldByProxy)
756 return S_OK;
757
758 /*
759 * Do the job.
760 */
761#if (defined(RT_OS_DARWIN) && defined(VBOX_WITH_NEW_USB_CODE_ON_DARWIN)) /* PORTME */ \
762 || defined(RT_OS_WINDOWS)
763 i_startTransition(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_HeldByProxy, kHostUSBDeviceSubState_AwaitingDetach);
764#else
765 i_startTransition(kHostUSBDeviceState_Capturing, kHostUSBDeviceState_HeldByProxy);
766#endif
767 alock.release();
768 int rc = mUSBProxyService->captureDevice(this);
769 if (RT_FAILURE(rc))
770 {
771 alock.acquire();
772 i_failTransition();
773 return E_FAIL;
774 }
775 return S_OK;
776}
777
778
779/**
780 * Check a detach detected by the USB Proxy Service to see if
781 * it's a real one or just a logical following a re-enumeration.
782 *
783 * This will work the internal sub state of the device and do time
784 * outs, so it does more than just querying data!
785 *
786 * @returns true if it was actually detached, false if it's just a re-enumeration.
787 */
788bool HostUSBDevice::i_wasActuallyDetached()
789{
790 /*
791 * This only applies to the detach and re-attach states.
792 */
793 switch (mUniState)
794 {
795 case kHostUSBDeviceState_Capturing:
796 case kHostUSBDeviceState_ReleasingToHost:
797 case kHostUSBDeviceState_AttachingToVM:
798 case kHostUSBDeviceState_DetachingFromVM:
799 switch (mUniSubState)
800 {
801 /*
802 * If we're awaiting a detach, the this has now occurred
803 * and the state should be advanced.
804 */
805 case kHostUSBDeviceSubState_AwaitingDetach:
806 i_advanceTransition();
807 return false; /* not physically detached. */
808
809 /*
810 * Check for timeouts.
811 */
812 case kHostUSBDeviceSubState_AwaitingReAttach:
813 {
814#ifndef RT_OS_WINDOWS /* check the implementation details here. */
815 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mLastStateChangeTS;
816 if (elapsedNanoseconds > UINT64_C(60000000000)) /* 60 seconds */
817 {
818 LogRel(("USB: Async operation timed out for device %s (state: %s)\n", mName, i_getStateName()));
819 i_failTransition();
820 }
821#endif
822 return false; /* not physically detached. */
823 }
824
825 /* not applicable.*/
826 case kHostUSBDeviceSubState_Default:
827 break;
828 }
829 break;
830
831 /* not applicable. */
832 case kHostUSBDeviceState_Unsupported:
833 case kHostUSBDeviceState_UsedByHost:
834 case kHostUSBDeviceState_Capturable:
835 case kHostUSBDeviceState_Unused:
836 case kHostUSBDeviceState_HeldByProxy:
837 case kHostUSBDeviceState_UsedByVM:
838 case kHostUSBDeviceState_PhysDetachingFromVM:
839 case kHostUSBDeviceState_PhysDetached:
840 break;
841
842 default:
843 AssertLogRelMsgFailed(("this=%p %s\n", this, i_getStateName()));
844 break;
845 }
846
847 /* It was detached. */
848 return true;
849}
850
851/**
852 * Notification from the USB Proxy that the device was physically detached.
853 *
854 * If a transition is pending, mIsPhysicallyDetached will be set and
855 * handled when the transition advances forward.
856 *
857 * Otherwise the device will be detached from any VM currently using it - this
858 * involves IPC and will temporarily abandon locks - and all the device data
859 * reset.
860 */
861void HostUSBDevice::i_onPhysicalDetached()
862{
863 AssertReturnVoid(!isWriteLockOnCurrentThread());
864 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
865 LogFlowThisFunc(("{%s}\n", mName));
866
867 mIsPhysicallyDetached = true;
868 if (mUniState < kHostUSBDeviceState_FirstTransitional)
869 {
870 alock.release();
871 i_onPhysicalDetachedInternal();
872 }
873}
874
875
876/**
877 * Do the physical detach work for a device in a stable state or
878 * at a transition state change.
879 *
880 * See onPhysicalDetach() for details.
881 */
882void HostUSBDevice::i_onPhysicalDetachedInternal()
883{
884 AssertReturnVoid(!isWriteLockOnCurrentThread());
885 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
886 LogFlowThisFunc(("{%s}\n", mName));
887 Assert(mIsPhysicallyDetached);
888
889 /*
890 * Do we need to detach it from the VM first?
891 */
892 if ( !mMachine.isNull()
893 && ( mUniState == kHostUSBDeviceState_UsedByVM
894 || mUniState == kHostUSBDeviceState_AttachingToVM))
895 {
896 alock.release();
897 i_detachFromVM(kHostUSBDeviceState_PhysDetached);
898 alock.acquire();
899 }
900 else
901 AssertMsg(mMachine.isNull(), ("%s\n", i_getStateName()));
902
903 /*
904 * Reset the data and enter the final state.
905 */
906 mMachine.setNull();
907 i_setState(kHostUSBDeviceState_PhysDetached);
908}
909
910
911/**
912 * Returns true if this device matches the given filter data.
913 *
914 * @note It is assumed, that the filter data owner is appropriately
915 * locked before calling this method.
916 *
917 * @note
918 * This method MUST correlate with
919 * USBController::hasMatchingFilter (IUSBDevice *)
920 * in the sense of the device matching logic.
921 *
922 * @note Locks this object for reading.
923 */
924bool HostUSBDevice::i_isMatch(const USBDeviceFilter::Data &aData)
925{
926 AutoCaller autoCaller(this);
927 AssertComRCReturn(autoCaller.rc(), false);
928
929 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
930
931 if (!aData.mActive)
932 return false;
933
934 if (!aData.mRemote.isMatch(FALSE))
935 return false;
936
937 if (!USBFilterMatchDevice(&aData.mUSBFilter, mUsb))
938 return false;
939
940 /* Don't match busy devices with a 100% wildcard filter - this will
941 later become a filter prop (ring-3 only). */
942 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
943 && !USBFilterHasAnySubstatialCriteria(&aData.mUSBFilter))
944 return false;
945
946 LogFlowThisFunc(("returns true\n"));
947 return true;
948}
949
950/**
951 * Compares this device with a USBDEVICE and decides if the match or which comes first.
952 *
953 * This will take into account device re-attaching and omit the bits
954 * that may change during a device re-enumeration.
955 *
956 * @param aDev2 Device 2.
957 *
958 * @returns < 0 if this should come before aDev2.
959 * @returns 0 if this and aDev2 are equal.
960 * @returns > 0 if this should come after aDev2.
961 *
962 * @note Must be called from under the object write lock.
963 */
964int HostUSBDevice::i_compare(PCUSBDEVICE aDev2)
965{
966 AssertReturn(isWriteLockOnCurrentThread(), -1);
967 //Log3(("%Rfn: %p {%s}\n", __PRETTY_FUNCTION__, this, mName));
968 return i_compare(mUsb, aDev2,
969 mUniSubState == kHostUSBDeviceSubState_AwaitingDetach /* (In case we don't get the detach notice.) */
970 || mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach);
971}
972
973/**
974 * Compares two USBDEVICE structures and decides if the match or which comes first.
975 *
976 * @param aDev1 Device 1.
977 * @param aDev2 Device 2.
978 * @param aIsAwaitingReAttach Whether to omit bits that will change in a device
979 * re-enumeration (true) or not (false).
980 *
981 * @returns < 0 if aDev1 should come before aDev2.
982 * @returns 0 if aDev1 and aDev2 are equal.
983 * @returns > 0 if aDev1 should come after aDev2.
984 */
985/*static*/
986int HostUSBDevice::i_compare(PCUSBDEVICE aDev1, PCUSBDEVICE aDev2, bool aIsAwaitingReAttach /*= false */)
987{
988 /*
989 * Things that stays the same everywhere.
990 *
991 * The more uniquely these properties identifies a device the less the chance
992 * that we mix similar devices during re-enumeration. Bus+port would help
993 * provide ~99.8% accuracy if the host can provide those attributes.
994 */
995 int iDiff = aDev1->idVendor - aDev2->idVendor;
996 if (iDiff)
997 return iDiff;
998
999 iDiff = aDev1->idProduct - aDev2->idProduct;
1000 if (iDiff)
1001 return iDiff;
1002
1003 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
1004 if (iDiff)
1005 {
1006 //Log3(("compare: bcdDevice: %#x != %#x\n", aDev1->bcdDevice, aDev2->bcdDevice));
1007 return iDiff;
1008 }
1009
1010#ifdef RT_OS_WINDOWS /* the string query may fail on windows during replugging, ignore serial mismatch if this is the case. */
1011 if ( aDev1->u64SerialHash != aDev2->u64SerialHash
1012 && ( !aIsAwaitingReAttach
1013 || (aDev2->pszSerialNumber && *aDev2->pszSerialNumber)
1014 || (aDev2->pszManufacturer && *aDev2->pszManufacturer)
1015 || (aDev2->pszProduct && *aDev2->pszProduct))
1016 )
1017#else
1018 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
1019#endif
1020 {
1021 //Log3(("compare: u64SerialHash: %#llx != %#llx\n", aDev1->u64SerialHash, aDev2->u64SerialHash));
1022 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
1023 }
1024
1025 /* The hub/bus + port should help a lot in a re-attach situation. */
1026#ifdef RT_OS_WINDOWS
1027 iDiff = strcmp(aDev1->pszHubName, aDev2->pszHubName);
1028 if (iDiff)
1029 {
1030 //Log3(("compare: HubName: %s != %s\n", aDev1->pszHubName, aDev2->pszHubName));
1031 return iDiff;
1032 }
1033#else
1034 iDiff = aDev1->bBus - aDev2->bBus;
1035 if (iDiff)
1036 {
1037 //Log3(("compare: bBus: %#x != %#x\n", aDev1->bBus, aDev2->bBus));
1038 return iDiff;
1039 }
1040#endif
1041
1042 iDiff = aDev1->bPort - aDev2->bPort; /* shouldn't change anywhere and help pinpoint it very accurately. */
1043 if (iDiff)
1044 {
1045 //Log3(("compare: bPort: %#x != %#x\n", aDev1->bPort, aDev2->bPort));
1046 return iDiff;
1047 }
1048
1049 /*
1050 * Things that usually doesn't stay the same when re-enumerating
1051 * a device. The fewer things in the category the better chance
1052 * that we avoid messing up when more than one device of the same
1053 * kind is attached.
1054 */
1055 if (aIsAwaitingReAttach)
1056 {
1057 //Log3(("aDev1=%p == aDev2=%p\n", aDev1, aDev2));
1058 return 0;
1059 }
1060 /* device number always changes. */
1061 return strcmp(aDev1->pszAddress, aDev2->pszAddress);
1062}
1063
1064/**
1065 * Updates the state of the device.
1066 *
1067 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
1068 * called to process the state change (complete the state change request,
1069 * inform the VM process etc.).
1070 *
1071 * If this method returns @c false, it is assumed that the given state change
1072 * is "minor": it doesn't require any further action other than update the
1073 * mState field with the actual state value.
1074 *
1075 * Regardless of the return value, this method always takes ownership of the
1076 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
1077 * it using the values of the old structure.
1078 *
1079 * @param[in] aDev The current device state as seen by the proxy backend.
1080 * @param[out] aRunFilters Whether the state change should be accompanied by
1081 * running filters on the device.
1082 * @param[out] aIgnoreMachine Machine to ignore when running filters.
1083 *
1084 * @returns Whether the Host object should be bothered with this state change.
1085 *
1086 * @todo Just do everything here, that is, call filter runners and everything that
1087 * works by state change. Using 3 return codes/parameters is just plain ugly.
1088 */
1089bool HostUSBDevice::i_updateState(PCUSBDEVICE aDev, bool *aRunFilters, SessionMachine **aIgnoreMachine)
1090{
1091 *aRunFilters = false;
1092 *aIgnoreMachine = NULL;
1093
1094 /*
1095 * Locking.
1096 */
1097 AssertReturn(!isWriteLockOnCurrentThread(), false);
1098 AutoCaller autoCaller(this);
1099 AssertComRCReturn(autoCaller.rc(), false);
1100 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1101
1102 /*
1103 * Replace the existing structure by the new one.
1104 */
1105 const USBDEVICESTATE enmOldState = mUsb->enmState; NOREF(enmOldState);
1106 if (mUsb != aDev)
1107 {
1108#ifdef RT_OS_WINDOWS
1109 /* we used this logic of string comparison in HostUSBDevice::compare
1110 * now we need to preserve strings from the old device if the new device has zero strings
1111 * this ensures the device is correctly matched later on
1112 * otherwise we may end up with a phantom misconfigured device instance */
1113 if ((mUniSubState == kHostUSBDeviceSubState_AwaitingDetach /* (In case we don't get the detach notice.) */
1114 || mUniSubState == kHostUSBDeviceSubState_AwaitingReAttach)
1115 && (!aDev->pszSerialNumber || !*aDev->pszSerialNumber)
1116 && (!aDev->pszManufacturer || !*aDev->pszManufacturer)
1117 && (!aDev->pszProduct || !*aDev->pszProduct))
1118 {
1119 aDev->u64SerialHash = mUsb->u64SerialHash;
1120
1121 if (mUsb->pszSerialNumber && *mUsb->pszSerialNumber)
1122 {
1123 if (aDev->pszSerialNumber)
1124 RTStrFree((char *)aDev->pszSerialNumber);
1125
1126 /* since we're going to free old device later on,
1127 * we can just assign the string from it to the new device
1128 * and zero up the string filed for the old device */
1129 aDev->pszSerialNumber = mUsb->pszSerialNumber;
1130 mUsb->pszSerialNumber = NULL;
1131 }
1132
1133 if (mUsb->pszManufacturer && *mUsb->pszManufacturer)
1134 {
1135 if (aDev->pszManufacturer)
1136 RTStrFree((char *)aDev->pszManufacturer);
1137
1138 /* since we're going to free old device later on,
1139 * we can just assign the string from it to the new device
1140 * and zero up the string filed for the old device */
1141 aDev->pszManufacturer = mUsb->pszManufacturer;
1142 mUsb->pszManufacturer = NULL;
1143 }
1144
1145 if (mUsb->pszProduct && *mUsb->pszProduct)
1146 {
1147 if (aDev->pszProduct)
1148 RTStrFree((char *)aDev->pszProduct);
1149
1150 /* since we're going to free old device later on,
1151 * we can just assign the string from it to the new device
1152 * and zero up the string filed for the old device */
1153 aDev->pszProduct = mUsb->pszProduct;
1154 mUsb->pszProduct = NULL;
1155 }
1156 }
1157#endif
1158 aDev->pNext = mUsb->pNext;
1159 aDev->pPrev = mUsb->pPrev;
1160 USBProxyService::freeDevice(mUsb);
1161 mUsb = aDev;
1162 }
1163
1164/** @def HOSTUSBDEVICE_FUZZY_STATE
1165 * Defined on hosts where we have a driver that keeps proper device states.
1166 */
1167# if defined(RT_OS_LINUX) || defined(DOXYGEN_RUNNING)
1168# define HOSTUSBDEVICE_FUZZY_STATE 1
1169# else
1170# undef HOSTUSBDEVICE_FUZZY_STATE
1171# endif
1172 /*
1173 * For some hosts we'll have to be pretty careful here because
1174 * they don't always have a clue what is going on. This is
1175 * particularly true on linux and solaris, while windows and
1176 * darwin generally knows a bit more.
1177 */
1178 bool fIsImportant = false;
1179 if (enmOldState != mUsb->enmState)
1180 {
1181 LogFlowThisFunc(("%p {%s} %s\n", this, mName, i_getStateName()));
1182 switch (mUsb->enmState)
1183 {
1184 /*
1185 * Little fuzziness here, except where we fake capture.
1186 */
1187 case USBDEVICESTATE_USED_BY_HOST:
1188 switch (mUniState)
1189 {
1190 /* Host drivers installed, that's fine. */
1191 case kHostUSBDeviceState_Capturable:
1192 case kHostUSBDeviceState_Unused:
1193 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1194 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1195 break;
1196 case kHostUSBDeviceState_UsedByHost:
1197 break;
1198
1199 /* Can only mean that we've failed capturing it. */
1200 case kHostUSBDeviceState_Capturing:
1201 LogThisFunc(("{%s} capture failed!\n", mName));
1202 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1203 *aRunFilters = i_failTransition();
1204 mMachine.setNull();
1205 break;
1206
1207 /* Guess we've successfully released it. */
1208 case kHostUSBDeviceState_ReleasingToHost:
1209 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1210 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1211 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1212 break;
1213
1214 /* These are IPC states and should be left alone. */
1215 case kHostUSBDeviceState_AttachingToVM:
1216 case kHostUSBDeviceState_DetachingFromVM:
1217 case kHostUSBDeviceState_PhysDetachingFromVM:
1218 LogThisFunc(("{%s} %s - changed to USED_BY_HOST...\n", mName, i_getStateName()));
1219 break;
1220
1221#ifdef HOSTUSBDEVICE_FUZZY_STATE
1222 /* Fake: We can't prevent anyone from grabbing it. */
1223 case kHostUSBDeviceState_HeldByProxy:
1224 LogThisFunc(("{%s} %s -> %s!\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_UsedByHost)));
1225 *aRunFilters = i_setState(kHostUSBDeviceState_UsedByHost);
1226 break;
1227 //case kHostUSBDeviceState_UsedByVM:
1228 // /** @todo needs to be detached from the VM. */
1229 // break;
1230#endif
1231 /* Not supposed to happen... */
1232#ifndef HOSTUSBDEVICE_FUZZY_STATE
1233 case kHostUSBDeviceState_HeldByProxy:
1234#endif
1235 case kHostUSBDeviceState_UsedByVM:
1236 case kHostUSBDeviceState_PhysDetached:
1237 case kHostUSBDeviceState_Unsupported:
1238 default:
1239 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1240 break;
1241 }
1242 break;
1243
1244 /*
1245 * It changed to capturable. Fuzzy hosts might easily
1246 * confuse UsedByVM with this one.
1247 */
1248 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1249 switch (mUniState)
1250 {
1251 /* No change. */
1252#ifdef HOSTUSBDEVICE_FUZZY_STATE
1253 case kHostUSBDeviceState_HeldByProxy:
1254 case kHostUSBDeviceState_UsedByVM:
1255#endif
1256 case kHostUSBDeviceState_Capturable:
1257 break;
1258
1259 /* Changed! */
1260 case kHostUSBDeviceState_UsedByHost:
1261 fIsImportant = true;
1262 case kHostUSBDeviceState_Unused:
1263 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
1264 *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
1265 break;
1266
1267 /* Can only mean that we've failed capturing it. */
1268 case kHostUSBDeviceState_Capturing:
1269 LogThisFunc(("{%s} capture failed!\n", mName));
1270 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1271 *aRunFilters = i_failTransition();
1272 mMachine.setNull();
1273 break;
1274
1275 /* Guess we've successfully released it. */
1276 case kHostUSBDeviceState_ReleasingToHost:
1277 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Capturable)));
1278 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1279 *aRunFilters = i_setState(kHostUSBDeviceState_Capturable);
1280 break;
1281
1282 /* These are IPC states and should be left alone. */
1283 case kHostUSBDeviceState_AttachingToVM:
1284 case kHostUSBDeviceState_DetachingFromVM:
1285 case kHostUSBDeviceState_PhysDetachingFromVM:
1286 LogThisFunc(("{%s} %s - changed to USED_BY_HOST_CAPTURABLE...\n", mName, i_getStateName()));
1287 break;
1288
1289 /* Not supposed to happen*/
1290#ifndef HOSTUSBDEVICE_FUZZY_STATE
1291 case kHostUSBDeviceState_HeldByProxy:
1292 case kHostUSBDeviceState_UsedByVM:
1293#endif
1294 case kHostUSBDeviceState_Unsupported:
1295 case kHostUSBDeviceState_PhysDetached:
1296 default:
1297 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1298 break;
1299 }
1300 break;
1301
1302
1303 /*
1304 * It changed to capturable. Fuzzy hosts might easily
1305 * confuse UsedByVM and HeldByProxy with this one.
1306 */
1307 case USBDEVICESTATE_UNUSED:
1308 switch (mUniState)
1309 {
1310 /* No change. */
1311#ifdef HOSTUSBDEVICE_FUZZY_STATE
1312 case kHostUSBDeviceState_HeldByProxy:
1313 case kHostUSBDeviceState_UsedByVM:
1314#endif
1315 case kHostUSBDeviceState_Unused:
1316 break;
1317
1318 /* Changed! */
1319 case kHostUSBDeviceState_UsedByHost:
1320 case kHostUSBDeviceState_Capturable:
1321 fIsImportant = true;
1322 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
1323 *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
1324 break;
1325
1326 /* Can mean that we've failed capturing it, but on windows it is the detach signal. */
1327 case kHostUSBDeviceState_Capturing:
1328#if defined(RT_OS_WINDOWS)
1329 if (mUniSubState == kHostUSBDeviceSubState_AwaitingDetach)
1330 {
1331 LogThisFunc(("{%s} capture advancing thru UNUSED...\n", mName));
1332 *aRunFilters = i_advanceTransition();
1333 }
1334 else
1335#endif
1336 {
1337 LogThisFunc(("{%s} capture failed!\n", mName));
1338 mUSBProxyService->captureDeviceCompleted(this, false /* aSuccess */);
1339 *aRunFilters = i_failTransition();
1340 mMachine.setNull();
1341 }
1342 break;
1343
1344 /* Guess we've successfully released it. */
1345 case kHostUSBDeviceState_ReleasingToHost:
1346 LogThisFunc(("{%s} %s -> %s\n", mName, i_getStateName(), i_stateName(kHostUSBDeviceState_Unused)));
1347 mUSBProxyService->releaseDeviceCompleted(this, true /* aSuccess */);
1348 *aRunFilters = i_setState(kHostUSBDeviceState_Unused);
1349 break;
1350
1351 /* These are IPC states and should be left alone. */
1352 case kHostUSBDeviceState_AttachingToVM:
1353 case kHostUSBDeviceState_DetachingFromVM:
1354 case kHostUSBDeviceState_PhysDetachingFromVM:
1355 LogThisFunc(("{%s} %s - changed to UNUSED...\n", mName, i_getStateName()));
1356 break;
1357
1358 /* Not supposed to happen*/
1359#ifndef HOSTUSBDEVICE_FUZZY_STATE
1360 case kHostUSBDeviceState_HeldByProxy:
1361 case kHostUSBDeviceState_UsedByVM:
1362#endif
1363 case kHostUSBDeviceState_Unsupported:
1364 case kHostUSBDeviceState_PhysDetached:
1365 default:
1366 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1367 break;
1368 }
1369 break;
1370
1371 /*
1372 * This is pretty straight forward, except that everyone
1373 * might sometimes confuse this and the UsedByVM state.
1374 */
1375 case USBDEVICESTATE_HELD_BY_PROXY:
1376 switch (mUniState)
1377 {
1378 /* No change. */
1379 case kHostUSBDeviceState_HeldByProxy:
1380 break;
1381 case kHostUSBDeviceState_UsedByVM:
1382 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, i_getStateName()));
1383 break;
1384
1385 /* Guess we've successfully captured it. */
1386 case kHostUSBDeviceState_Capturing:
1387 LogThisFunc(("{%s} capture succeeded!\n", mName));
1388 mUSBProxyService->captureDeviceCompleted(this, true /* aSuccess */);
1389 *aRunFilters = i_advanceTransition(true /* fast forward thru re-attach */);
1390
1391 /* Take action if we're supposed to attach it to a VM. */
1392 if (mUniState == kHostUSBDeviceState_AttachingToVM)
1393 {
1394 alock.release();
1395 i_attachToVM(mMachine, mCaptureFilename, mMaskedIfs);
1396 alock.acquire();
1397 }
1398 break;
1399
1400 /* Can only mean that we've failed capturing it. */
1401 case kHostUSBDeviceState_ReleasingToHost:
1402 LogThisFunc(("{%s} %s failed!\n", mName, i_getStateName()));
1403 mUSBProxyService->releaseDeviceCompleted(this, false /* aSuccess */);
1404 *aRunFilters = i_setState(kHostUSBDeviceState_HeldByProxy);
1405 break;
1406
1407 /* These are IPC states and should be left alone. */
1408 case kHostUSBDeviceState_AttachingToVM:
1409 case kHostUSBDeviceState_DetachingFromVM:
1410 case kHostUSBDeviceState_PhysDetachingFromVM:
1411 LogThisFunc(("{%s} %s - changed to HELD_BY_PROXY...\n", mName, i_getStateName()));
1412 break;
1413
1414 /* Not supposed to happen. */
1415 case kHostUSBDeviceState_Unsupported:
1416 case kHostUSBDeviceState_UsedByHost:
1417 case kHostUSBDeviceState_Capturable:
1418 case kHostUSBDeviceState_Unused:
1419 case kHostUSBDeviceState_PhysDetached:
1420 default:
1421 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1422 break;
1423 }
1424 break;
1425
1426 /*
1427 * This is very straight forward and only Darwin implements it.
1428 */
1429 case USBDEVICESTATE_USED_BY_GUEST:
1430 switch (mUniState)
1431 {
1432 /* No change. */
1433 case kHostUSBDeviceState_HeldByProxy:
1434 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, i_getStateName()));
1435 break;
1436 case kHostUSBDeviceState_UsedByVM:
1437 break;
1438
1439 /* These are IPC states and should be left alone. */
1440 case kHostUSBDeviceState_AttachingToVM:
1441 case kHostUSBDeviceState_DetachingFromVM:
1442 case kHostUSBDeviceState_PhysDetachingFromVM:
1443 LogThisFunc(("{%s} %s - changed to USED_BY_GUEST...\n", mName, i_getStateName()));
1444 break;
1445
1446 /* Not supposed to happen. */
1447 case kHostUSBDeviceState_Unsupported:
1448 case kHostUSBDeviceState_Capturable:
1449 case kHostUSBDeviceState_Unused:
1450 case kHostUSBDeviceState_UsedByHost:
1451 case kHostUSBDeviceState_PhysDetached:
1452 case kHostUSBDeviceState_ReleasingToHost:
1453 case kHostUSBDeviceState_Capturing:
1454 default:
1455 AssertMsgFailed(("{%s} %s\n", mName, i_getStateName()));
1456 break;
1457 }
1458 break;
1459
1460 /*
1461 * This is not supposed to happen and indicates a bug in the backend!
1462 */
1463 case USBDEVICESTATE_UNSUPPORTED:
1464 AssertMsgFailed(("enmOldState=%d {%s} %s\n", enmOldState, mName, i_getStateName()));
1465 break;
1466 default:
1467 AssertMsgFailed(("enmState=%d {%s} %s\n", mUsb->enmState, mName, i_getStateName()));
1468 break;
1469 }
1470 }
1471 else if ( mUniSubState == kHostUSBDeviceSubState_AwaitingDetach
1472 && i_hasAsyncOperationTimedOut())
1473 {
1474 LogRel(("USB: timeout in %s for {%RTuuid} / {%s}\n",
1475 i_getStateName(), mId.raw(), mName));
1476 *aRunFilters = i_failTransition();
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);
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 *
2418 * @note The caller must own the write lock for this object.
2419 */
2420bool HostUSBDevice::i_failTransition()
2421{
2422 AssertReturn(isWriteLockOnCurrentThread(), false);
2423 HostUSBDeviceSubState enmSub = mUniSubState;
2424 HostUSBDeviceState enmState = mUniState;
2425 switch (enmState)
2426 {
2427 /*
2428 * There are just two cases, either we got back to the
2429 * previous state (assumes Capture+Attach-To-VM updates it)
2430 * or we assume the device has been unplugged (physically).
2431 */
2432 case kHostUSBDeviceState_DetachingFromVM:
2433 case kHostUSBDeviceState_Capturing:
2434 case kHostUSBDeviceState_ReleasingToHost:
2435 case kHostUSBDeviceState_AttachingToVM:
2436 switch (enmSub)
2437 {
2438 case kHostUSBDeviceSubState_AwaitingDetach:
2439 enmSub = kHostUSBDeviceSubState_Default;
2440 /* fall thru */
2441 case kHostUSBDeviceSubState_Default:
2442 enmState = mPrevUniState;
2443 break;
2444 case kHostUSBDeviceSubState_AwaitingReAttach:
2445 enmSub = kHostUSBDeviceSubState_Default;
2446 enmState = kHostUSBDeviceState_PhysDetached;
2447 break;
2448 default:
2449 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2450 }
2451 break;
2452
2453 case kHostUSBDeviceState_PhysDetachingFromVM:
2454 AssertMsgFailedReturn(("this=%p %s shall not fail\n", this, i_getStateName()), false);
2455
2456 case kHostUSBDeviceState_Unsupported:
2457 case kHostUSBDeviceState_UsedByHost:
2458 case kHostUSBDeviceState_Capturable:
2459 case kHostUSBDeviceState_Unused:
2460 case kHostUSBDeviceState_HeldByProxy:
2461 case kHostUSBDeviceState_UsedByVM:
2462 AssertMsgFailedReturn(("this=%p %s is not transitional\n", this, i_getStateName()), false);
2463 case kHostUSBDeviceState_PhysDetached:
2464 default:
2465 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), false);
2466
2467 }
2468
2469 return i_setState(enmState, kHostUSBDeviceState_Invalid, enmSub);
2470}
2471
2472
2473/**
2474 * Determines the canonical state of the device.
2475 *
2476 * @returns canonical state.
2477 *
2478 * @note The caller must own the read (or write) lock for this object.
2479 */
2480USBDeviceState_T HostUSBDevice::i_canonicalState() const
2481{
2482 switch (mUniState)
2483 {
2484 /*
2485 * Straight forward.
2486 */
2487 case kHostUSBDeviceState_Unsupported:
2488 return USBDeviceState_NotSupported;
2489
2490 case kHostUSBDeviceState_UsedByHost:
2491 return USBDeviceState_Unavailable;
2492
2493 case kHostUSBDeviceState_Capturable:
2494 return USBDeviceState_Busy;
2495
2496 case kHostUSBDeviceState_Unused:
2497 return USBDeviceState_Available;
2498
2499 case kHostUSBDeviceState_HeldByProxy:
2500 return USBDeviceState_Held;
2501
2502 case kHostUSBDeviceState_UsedByVM:
2503 return USBDeviceState_Captured;
2504
2505 /*
2506 * Pretend we've reached the final state.
2507 */
2508 case kHostUSBDeviceState_Capturing:
2509 Assert( mPendingUniState == kHostUSBDeviceState_UsedByVM
2510 || mPendingUniState == kHostUSBDeviceState_HeldByProxy);
2511 return mPendingUniState == kHostUSBDeviceState_UsedByVM
2512 ? (USBDeviceState_T)USBDeviceState_Captured
2513 : (USBDeviceState_T)USBDeviceState_Held;
2514 /* The cast ^^^^ is because xidl is using different enums for
2515 each of the values. *Very* nice idea... :-) */
2516
2517 case kHostUSBDeviceState_AttachingToVM:
2518 return USBDeviceState_Captured;
2519
2520 /*
2521 * Return the previous state.
2522 */
2523 case kHostUSBDeviceState_ReleasingToHost:
2524 Assert( mPrevUniState == kHostUSBDeviceState_UsedByVM
2525 || mPrevUniState == kHostUSBDeviceState_HeldByProxy);
2526 return mPrevUniState == kHostUSBDeviceState_UsedByVM
2527 ? (USBDeviceState_T)USBDeviceState_Captured
2528 : (USBDeviceState_T)USBDeviceState_Held;
2529 /* The cast ^^^^ is because xidl is using different enums for
2530 each of the values. *Very* nice idea... :-) */
2531
2532 case kHostUSBDeviceState_DetachingFromVM:
2533 return USBDeviceState_Captured;
2534 case kHostUSBDeviceState_PhysDetachingFromVM:
2535 return USBDeviceState_Captured;
2536
2537 case kHostUSBDeviceState_PhysDetached:
2538 default:
2539 AssertReleaseMsgFailedReturn(("this=%p mUniState=%d\n", this, mUniState), USBDeviceState_NotSupported);
2540 }
2541 /* won't ever get here. */
2542}
2543/* 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