VirtualBox

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

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

Main/HostUSBdevice: added USB device aliases dictionary and script to update the dictionary

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