VirtualBox

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

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

Removed the 'temporary' VBOX_WITH_NEW_USB_CODE_ON_DARWIN define (r29740, 7 years ago).

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