VirtualBox

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

Last change on this file was 98288, checked in by vboxsync, 16 months ago

Main/src-server: rc -> hrc/vrc (partial). bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use