VirtualBox

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

Last change on this file since 73768 was 73003, checked in by vboxsync, 6 years ago

Main: Use setErrorBoth when we've got a VBox status code handy. (The COM status codes aren't too specfic and this may help us decode error messages and provide an alternative to strstr for API clients. setErrorBoth isn't new, btw.)

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

© 2023 Oracle
ContactPrivacy policyTerms of Use