VirtualBox

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

Last change on this file since 52497 was 51498, checked in by vboxsync, 11 years ago

6813 - MachineImpl use of server side wrappers + misc mods on other classes

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette