VirtualBox

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

Last change on this file since 65314 was 65120, checked in by vboxsync, 8 years ago

Main: doxygen fixes

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