VirtualBox

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

Last change on this file since 40685 was 40257, checked in by vboxsync, 13 years ago

Main/Medium: rework locking scheme to solve lock order violations and long GUI start up time caused by too much locking
Main/all: Remove the enter and leave methods from write locks, they cause hard to find locking problems. Better solve them explicitly.

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