VirtualBox

source: vbox/trunk/src/VBox/Main/HostUSBDeviceImpl.cpp@ 7936

Last change on this file since 7936 was 7852, checked in by vboxsync, 17 years ago

manual-cpp -DVBOX_WITH_USBFILTER. One worry, not sure why the Action setter call was omitted from the init. Hopefully just a left over.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.2 KB
Line 
1/** @file
2 *
3 * VirtualBox IHostUSBDevice COM interface implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 "VirtualBoxErrorInfoImpl.h"
23#include "USBProxyService.h"
24
25#include "Logging.h"
26
27#include <VBox/err.h>
28#include <iprt/cpputils.h>
29
30// constructor / destructor
31/////////////////////////////////////////////////////////////////////////////
32
33DEFINE_EMPTY_CTOR_DTOR (HostUSBDevice)
34
35HRESULT HostUSBDevice::FinalConstruct()
36{
37 mUSBProxyService = NULL;
38 mUsb = NULL;
39
40 return S_OK;
41}
42
43void HostUSBDevice::FinalRelease()
44{
45 uninit();
46}
47
48// public initializer/uninitializer for internal purposes only
49/////////////////////////////////////////////////////////////////////////////
50
51/**
52 * Initializes the USB device object.
53 *
54 * @returns COM result indicator
55 * @param aUsb Pointer to the usb device structure for which the object is to be a wrapper.
56 * This structure is now fully owned by the HostUSBDevice object and will be
57 * freed when it is destructed.
58 * @param aUSBProxyService Pointer to the USB Proxy Service object.
59 */
60HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
61{
62 ComAssertRet (aUsb, E_INVALIDARG);
63
64 /* Enclose the state transition NotReady->InInit->Ready */
65 AutoInitSpan autoInitSpan (this);
66 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
67
68 /*
69 * We need a unique ID for this VBoxSVC session.
70 * The UUID isn't stored anywhere.
71 */
72 unconst (mId).create();
73
74 /*
75 * Convert from USBDEVICESTATE to USBDeviceState.
76 *
77 * Note that not all proxy backend can detect the HELD_BY_PROXY
78 * and USED_BY_GUEST states. But that shouldn't matter much.
79 */
80 switch (aUsb->enmState)
81 {
82 default:
83 AssertMsgFailed(("aUsb->enmState=%d\n", aUsb->enmState));
84 case USBDEVICESTATE_UNSUPPORTED:
85 mState = USBDeviceState_NotSupported;
86 break;
87 case USBDEVICESTATE_USED_BY_HOST:
88 mState = USBDeviceState_Unavailable;
89 break;
90 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
91 mState = USBDeviceState_Busy;
92 break;
93 case USBDEVICESTATE_UNUSED:
94 mState = USBDeviceState_Available;
95 break;
96 case USBDEVICESTATE_HELD_BY_PROXY:
97 mState = USBDeviceState_Held;
98 break;
99 case USBDEVICESTATE_USED_BY_GUEST:
100 /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
101 * anywhere in the proxy code; it's quite logical because the
102 * proxy doesn't know anything about guest VMs. */
103 AssertFailedReturn (E_FAIL);
104 break;
105 }
106
107 mPendingState = mState;
108 mPendingStateEx = kNothingPending;
109
110 /* Other data members */
111 mIsStatePending = false;
112 mUSBProxyService = aUSBProxyService;
113 mUsb = aUsb;
114
115 /* Confirm the successful initialization */
116 autoInitSpan.setSucceeded();
117
118 return S_OK;
119}
120
121/**
122 * Uninitializes the instance and sets the ready flag to FALSE.
123 * Called either from FinalRelease() or by the parent when it gets destroyed.
124 */
125void HostUSBDevice::uninit()
126{
127 /* Enclose the state transition Ready->InUninit->NotReady */
128 AutoUninitSpan autoUninitSpan (this);
129 if (autoUninitSpan.uninitDone())
130 return;
131
132 if (mUsb != NULL)
133 {
134 USBProxyService::freeDevice (mUsb);
135 mUsb = NULL;
136 }
137
138 mUSBProxyService = NULL;
139}
140
141// IUSBDevice properties
142/////////////////////////////////////////////////////////////////////////////
143
144STDMETHODIMP HostUSBDevice::COMGETTER(Id)(GUIDPARAMOUT aId)
145{
146 if (!aId)
147 return E_INVALIDARG;
148
149 AutoCaller autoCaller (this);
150 CheckComRCReturnRC (autoCaller.rc());
151
152 /* mId is constant during life time, no need to lock */
153 mId.cloneTo (aId);
154
155 return S_OK;
156}
157
158STDMETHODIMP HostUSBDevice::COMGETTER(VendorId)(USHORT *aVendorId)
159{
160 if (!aVendorId)
161 return E_INVALIDARG;
162
163 AutoCaller autoCaller (this);
164 CheckComRCReturnRC (autoCaller.rc());
165
166 AutoReaderLock alock (this);
167
168 *aVendorId = mUsb->idVendor;
169
170 return S_OK;
171}
172
173STDMETHODIMP HostUSBDevice::COMGETTER(ProductId)(USHORT *aProductId)
174{
175 if (!aProductId)
176 return E_INVALIDARG;
177
178 AutoCaller autoCaller (this);
179 CheckComRCReturnRC (autoCaller.rc());
180
181 AutoReaderLock alock (this);
182
183 *aProductId = mUsb->idProduct;
184
185 return S_OK;
186}
187
188STDMETHODIMP HostUSBDevice::COMGETTER(Revision)(USHORT *aRevision)
189{
190 if (!aRevision)
191 return E_INVALIDARG;
192
193 AutoCaller autoCaller (this);
194 CheckComRCReturnRC (autoCaller.rc());
195
196 AutoReaderLock alock (this);
197
198 *aRevision = mUsb->bcdDevice;
199
200 return S_OK;
201}
202
203STDMETHODIMP HostUSBDevice::COMGETTER(Manufacturer)(BSTR *aManufacturer)
204{
205 if (!aManufacturer)
206 return E_INVALIDARG;
207
208 AutoCaller autoCaller (this);
209 CheckComRCReturnRC (autoCaller.rc());
210
211 AutoReaderLock alock (this);
212
213 Bstr (mUsb->pszManufacturer).cloneTo (aManufacturer);
214
215 return S_OK;
216}
217
218STDMETHODIMP HostUSBDevice::COMGETTER(Product)(BSTR *aProduct)
219{
220 if (!aProduct)
221 return E_INVALIDARG;
222
223 AutoCaller autoCaller (this);
224 CheckComRCReturnRC (autoCaller.rc());
225
226 AutoReaderLock alock (this);
227
228 Bstr (mUsb->pszProduct).cloneTo (aProduct);
229
230 return S_OK;
231}
232
233STDMETHODIMP HostUSBDevice::COMGETTER(SerialNumber)(BSTR *aSerialNumber)
234{
235 if (!aSerialNumber)
236 return E_INVALIDARG;
237
238 AutoCaller autoCaller (this);
239 CheckComRCReturnRC (autoCaller.rc());
240
241 AutoReaderLock alock (this);
242
243 Bstr (mUsb->pszSerialNumber).cloneTo (aSerialNumber);
244
245 return S_OK;
246}
247
248STDMETHODIMP HostUSBDevice::COMGETTER(Address)(BSTR *aAddress)
249{
250 if (!aAddress)
251 return E_INVALIDARG;
252
253 AutoCaller autoCaller (this);
254 CheckComRCReturnRC (autoCaller.rc());
255
256 AutoReaderLock alock (this);
257
258 Bstr (mUsb->pszAddress).cloneTo (aAddress);
259
260 return S_OK;
261}
262
263STDMETHODIMP HostUSBDevice::COMGETTER(Port)(USHORT *aPort)
264{
265 if (!aPort)
266 return E_INVALIDARG;
267
268 AutoCaller autoCaller (this);
269 CheckComRCReturnRC (autoCaller.rc());
270
271 AutoReaderLock alock (this);
272
273 ///@todo implement
274 aPort = 0;
275
276 return S_OK;
277}
278
279STDMETHODIMP HostUSBDevice::COMGETTER(Version)(USHORT *aVersion)
280{
281 if (!aVersion)
282 return E_INVALIDARG;
283
284 AutoCaller autoCaller (this);
285 CheckComRCReturnRC (autoCaller.rc());
286
287 AutoReaderLock alock (this);
288
289 *aVersion = mUsb->bcdUSB >> 8;
290
291 return S_OK;
292}
293
294STDMETHODIMP HostUSBDevice::COMGETTER(PortVersion)(USHORT *aPortVersion)
295{
296 if (!aPortVersion)
297 return E_INVALIDARG;
298
299 AutoCaller autoCaller (this);
300 CheckComRCReturnRC (autoCaller.rc());
301
302 AutoReaderLock alock (this);
303
304 /* Port version is 2 (EHCI) if and only if the device runs at high speed;
305 * if speed is unknown, fall back to the old and innacurate method.
306 */
307 if (mUsb->enmSpeed == USBDEVICESPEED_UNKNOWN)
308 *aPortVersion = mUsb->bcdUSB >> 8;
309 else
310 *aPortVersion = (mUsb->enmSpeed == USBDEVICESPEED_HIGH) ? 2 : 1;
311
312 return S_OK;
313}
314
315STDMETHODIMP HostUSBDevice::COMGETTER(Remote)(BOOL *aRemote)
316{
317 if (!aRemote)
318 return E_INVALIDARG;
319
320 AutoCaller autoCaller (this);
321 CheckComRCReturnRC (autoCaller.rc());
322
323 AutoReaderLock alock (this);
324
325 *aRemote = FALSE;
326
327 return S_OK;
328}
329
330// IHostUSBDevice properties
331/////////////////////////////////////////////////////////////////////////////
332
333STDMETHODIMP HostUSBDevice::COMGETTER(State) (USBDeviceState_T *aState)
334{
335 if (!aState)
336 return E_POINTER;
337
338 AutoCaller autoCaller (this);
339 CheckComRCReturnRC (autoCaller.rc());
340
341 AutoReaderLock alock (this);
342
343 *aState = mState;
344
345 return S_OK;
346}
347
348
349// public methods only for internal purposes
350////////////////////////////////////////////////////////////////////////////////
351
352/**
353 * @note Locks this object for reading.
354 */
355Utf8Str HostUSBDevice::name()
356{
357 Utf8Str name;
358
359 AutoCaller autoCaller (this);
360 AssertComRCReturn (autoCaller.rc(), name);
361
362 AutoReaderLock alock (this);
363
364 bool haveManufacturer = mUsb->pszManufacturer && *mUsb->pszManufacturer;
365 bool haveProduct = mUsb->pszProduct && *mUsb->pszProduct;
366 if (haveManufacturer && haveProduct)
367 name = Utf8StrFmt ("%s %s", mUsb->pszManufacturer,
368 mUsb->pszProduct);
369 else if (haveManufacturer)
370 name = Utf8StrFmt ("%s", mUsb->pszManufacturer);
371 else if (haveProduct)
372 name = Utf8StrFmt ("%s", mUsb->pszProduct);
373 else
374 name = "<unknown>";
375
376 return name;
377}
378
379/**
380 * Requests the USB proxy service to capture the device and sets the pending
381 * state to Captured.
382 *
383 * If the state change may be performed immediately (for example, Hold ->
384 * Captured), then the machine is informed before this method returns.
385 *
386 * @param aMachine Machine that will capture this device on success.
387 * @param aMaskedIfs The interfaces to hide from the guest.
388 * @return @c false if the device could be immediately captured
389 * but the VM process refused to grab it;
390 * @c true otherwise.
391 *
392 * @note Must be called from under the object write lock.
393 *
394 * @note May lock the given machine object for reading.
395 */
396bool HostUSBDevice::requestCapture (SessionMachine *aMachine, ULONG aMaskedIfs /* = 0*/)
397{
398 LogFlowThisFunc (("\n"));
399
400 AssertReturn (aMachine, false);
401
402 AssertReturn (isLockedOnCurrentThread(), false);
403
404 AssertReturn (mIsStatePending == false, false);
405
406 AssertReturn (
407 mState == USBDeviceState_Busy ||
408 mState == USBDeviceState_Available ||
409 mState == USBDeviceState_Held,
410 false);
411
412 if (mState == USBDeviceState_Held)
413 {
414 /* can perform immediate capture, inform the VM process */
415
416 ComPtr <IUSBDevice> d = this;
417
418 mIsStatePending = true;
419 mPendingSince = 0;
420
421 /* the VM process will query the object, so leave the lock */
422 AutoLock alock (this);
423 alock.leave();
424
425 LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
426
427 HRESULT rc = aMachine->onUSBDeviceAttach (d, NULL, aMaskedIfs);
428
429 /* The VM process has a legal reason to fail (for example, incorrect
430 * usbfs permissions or out of virtual USB ports). More over, the VM
431 * process might have been accidentially crashed and not accessible
432 * any more (so that calling an uninitialized SessionMachine returns a
433 * failure). So don't assert. */
434
435 LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
436
437 alock.enter();
438
439 mIsStatePending = false;
440 mPendingStateEx = kNothingPending;
441
442 if (SUCCEEDED (rc))
443 {
444 mState = mPendingState = USBDeviceState_Captured;
445 mMachine = aMachine;
446 return true;
447 }
448
449 return false;
450 }
451
452 mIsStatePending = true;
453 mPendingState = USBDeviceState_Captured;
454 mPendingStateEx = kNothingPending;
455 mPendingSince = RTTimeNanoTS();
456 mMachine = aMachine;
457 mMaskedIfs = aMaskedIfs;
458
459 mUSBProxyService->captureDevice (this);
460
461 return true;
462}
463
464/**
465 * Requests the USB proxy service to release the device and sets the pending
466 * state to Available.
467 *
468 * If the state change may be performed immediately (for example, the current
469 * state is Busy), this method does nothing.
470 *
471 * @note Must be called from under the object write lock.
472 */
473void HostUSBDevice::requestRelease()
474{
475 LogFlowThisFunc (("\n"));
476
477 AssertReturnVoid (isLockedOnCurrentThread());
478
479 AssertReturnVoid (mIsStatePending == false);
480
481 AssertReturnVoid (
482 mState == USBDeviceState_Busy ||
483 mState == USBDeviceState_Available ||
484 mState == USBDeviceState_Held);
485
486 if (mState != USBDeviceState_Held)
487 return;
488
489 mIsStatePending = true;
490 mPendingState = USBDeviceState_Available;
491 mPendingStateEx = kNothingPending;
492 mPendingSince = RTTimeNanoTS();
493
494 mUSBProxyService->releaseDevice (this);
495}
496
497/**
498 * Requests the USB proxy service to release the device, sets the pending
499 * state to Held and removes the machine association if any.
500 *
501 * If the state change may be performed immediately (for example, the current
502 * state is already Held), this method does nothing but removes the machine
503 * association.
504 *
505 * @note Must be called from under the object write lock.
506 */
507void HostUSBDevice::requestHold()
508{
509 LogFlowThisFunc (("\n"));
510
511 AssertReturnVoid (isLockedOnCurrentThread());
512
513 AssertReturnVoid (mIsStatePending == false);
514
515 AssertReturnVoid (
516 mState == USBDeviceState_Busy ||
517 mState == USBDeviceState_Available ||
518 mState == USBDeviceState_Held);
519
520 mMachine.setNull();
521
522 if (mState == USBDeviceState_Held)
523 return;
524
525 mIsStatePending = true;
526 mPendingState = USBDeviceState_Held;
527 mPendingStateEx = kNothingPending;
528 mPendingSince = RTTimeNanoTS();
529
530 mUSBProxyService->captureDevice (this);
531}
532
533/**
534 * Sets the device state from Captured to Held and resets the machine
535 * association (if any). Usually called before applying filters.
536 *
537 * @note Must be called from under the object write lock.
538 */
539void HostUSBDevice::setHeld()
540{
541 LogFlowThisFunc (("\n"));
542
543 AssertReturnVoid (isLockedOnCurrentThread());
544
545 AssertReturnVoid (mState == USBDeviceState_Captured);
546 AssertReturnVoid (mPendingState == USBDeviceState_Captured);
547 AssertReturnVoid (mIsStatePending == false);
548
549 mState = USBDeviceState_Held;
550 mMachine.setNull();
551}
552
553/**
554 * Resets all device data and informs the machine (if any) about the
555 * detachment. Must be called when this device is physically detached from
556 * the host.
557 *
558 * @note Must be called from under the object write lock.
559 */
560void HostUSBDevice::onDetachedPhys()
561{
562 LogFlowThisFunc (("\n"));
563
564 AssertReturnVoid (isLockedOnCurrentThread());
565
566 if (!mMachine.isNull() && mState == USBDeviceState_Captured)
567 {
568 /* the device is captured by a machine, instruct it to release */
569
570 mIsStatePending = true;
571 mPendingSince = 0;
572
573 /* the VM process will query the object, so leave the lock */
574 AutoLock alock (this);
575 alock.leave();
576
577 LogFlowThisFunc (("Calling machine->onUSBDeviceDetach()...\n"));
578
579 HRESULT rc = mMachine->onUSBDeviceDetach (mId, NULL);
580 NOREF(rc);
581
582 /* This call may expectedly fail with rc = NS_ERROR_FAILURE (on XPCOM)
583 * if the VM process requests device release right before termination
584 * and then terminates before onUSBDeviceDetach() reached
585 * it. Therefore, we don't assert here. On MS COM, there should be
586 * something similar (with the different error code). More over, the
587 * VM process might have been accidentially crashed and not accessible
588 * any more (so that calling an uninitialized SessionMachine returns a
589 * failure). So don't assert. */
590
591 LogFlowThisFunc (("Done machine->onUSBDeviceDetach()=%08X\n", rc));
592
593 alock.enter();
594
595 /* Reset all fields. The object should have been
596 * uninitialized after this method returns, so it doesn't really
597 * matter what state we put it in. */
598 mIsStatePending = false;
599 mState = mPendingState = USBDeviceState_NotSupported;
600 mPendingStateEx = kNothingPending;
601 mMachine.setNull();
602 }
603}
604
605/**
606 * Handles the finished pending state change and informs the VM process if
607 * necessary.
608 *
609 * @note Must be called from under the object write lock.
610 */
611void HostUSBDevice::handlePendingStateChange()
612{
613 LogFlowThisFunc (("\n"));
614
615 AssertReturnVoid (isLockedOnCurrentThread());
616
617 AssertReturnVoid (mIsStatePending == true);
618 AssertReturnVoid (mState != USBDeviceState_Captured || mPendingStateEx != kNothingPending);
619
620 bool wasCapture = false;
621
622 HRESULT requestRC = S_OK;
623 Bstr errorText;
624
625 switch (mPendingStateEx)
626 {
627 case kNothingPending:
628 switch (mPendingState)
629 {
630 case USBDeviceState_Captured:
631 {
632 if (mState == USBDeviceState_Held)
633 {
634 if (!mMachine.isNull())
635 wasCapture = true;
636 else
637 {
638 /* it is a canceled capture request. Give the device back
639 * to the host. */
640 mPendingState = USBDeviceState_Available;
641 mUSBProxyService->releaseDevice (this);
642 }
643 }
644 else
645 {
646 /* couldn't capture the device, will report an error */
647 wasCapture = true;
648
649 Assert (!mMachine.isNull());
650
651 /// @todo more detailed error message depending on the state?
652 // probably need some error code/string from the USB proxy itself
653
654 requestRC = E_FAIL;
655 errorText = Utf8StrFmt (
656 tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the host "
657 "computer and cannot be attached to the virtual machine."
658 "Please try later"),
659 name().raw(), id().raw());
660 }
661 break;
662 }
663 case USBDeviceState_Available:
664 {
665 Assert (mMachine.isNull());
666
667 if (mState == USBDeviceState_Held)
668 {
669 /* couldn't release the device (give it back to the host).
670 * there is nobody to report an error to (the machine has
671 * already been deassociated because VMM has already detached
672 * the device before requesting a release). */
673 }
674 else
675 {
676 /* it is a canceled release request. Leave at the host */
677 /// @todo we may want to re-run all filters in this case
678 }
679 break;
680 }
681 case USBDeviceState_Held:
682 {
683 if (mState == USBDeviceState_Held)
684 {
685 /* All right, the device is now held (due to some global
686 * filter). */
687 break;
688 }
689 else
690 {
691 /* couldn't capture the device requested by the global
692 * filter, there is nobody to report an error to. */
693 }
694 break;
695 }
696 default:
697 AssertFailed();
698 }
699 break;
700
701 /*
702 * The device has reappeared, the caller (Host) will (maybe) reapply filters,
703 * since we don't quite know we set the machine to NULL.
704 */
705 case kDetachingPendingAttachFilters:
706 mMachine.setNull();
707 break;
708
709 /*
710 * The device has reappeared while the detach operation is still in
711 * progress, just clear the pending operation and leave the machine as is.
712 */
713 case kDetachingPendingAttach:
714 break;
715
716 case kDetachingPendingDetach:
717 case kDetachingPendingDetachFilters:
718 default:
719 AssertMsgFailed(("%d\n", mPendingStateEx));
720 return;
721 }
722
723 ComObjPtr <VirtualBoxErrorInfo> error;
724 if (FAILED (requestRC))
725 {
726 LogFlowThisFunc (("Request failed, requestRC=%08X, text='%ls'\n",
727 requestRC, errorText.raw()));
728
729 error.createObject();
730 error->init (requestRC, COM_IIDOF (IHostUSBDevice),
731 Bstr (HostUSBDevice::getComponentName()),
732 errorText.raw());
733 }
734
735 if (wasCapture)
736 {
737 /* inform the VM process */
738
739 ComPtr <IUSBDevice> d = this;
740
741 /* the VM process will query the object, so leave the lock */
742 AutoLock alock (this);
743 alock.leave();
744
745 LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
746
747 HRESULT rc = mMachine->onUSBDeviceAttach (d, error, mMaskedIfs);
748
749 /* The VM process has a legal reason to fail (for example, incorrect
750 * usbfs permissions or out of virtual USB ports). More over, the VM
751 * process might have been accidentially crashed and not accessible
752 * any more (so that calling an uninitialized SessionMachine returns a
753 * failure). So don't assert. */
754
755 /// @todo we will probably want to re-run all filters on failure
756
757 LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
758
759 alock.enter();
760
761 if (SUCCEEDED (requestRC) && SUCCEEDED (rc))
762 {
763 mIsStatePending = false;
764 mState = mPendingState = USBDeviceState_Captured;
765 mPendingStateEx = kNothingPending;
766 return;
767 }
768
769 /* on failure, either from the proxy or from the VM process,
770 * deassociate from the machine */
771 mMachine.setNull();
772 }
773
774 mIsStatePending = false;
775 mPendingState = mState;
776 mPendingStateEx = kNothingPending;
777}
778
779/**
780 * Cancels pending state change due to machine termination or timeout.
781 *
782 * @note Must be called from under the object write lock.
783 * @param aTimeout Whether this is a timeout or not.
784 */
785void HostUSBDevice::cancelPendingState(bool aTimeout /*= false*/)
786{
787 LogFlowThisFunc (("\n"));
788
789 AssertReturnVoid (isLockedOnCurrentThread());
790
791 AssertReturnVoid (mIsStatePending == true);
792 AssertReturnVoid (aTimeout || !mMachine.isNull());
793
794 switch (mPendingStateEx)
795 {
796 case kNothingPending:
797 switch (mPendingState)
798 {
799 case USBDeviceState_Captured:
800 /* reset mMachine to deassociate it from the filter and tell
801 * handlePendingStateChange() what to do */
802 mMachine.setNull();
803 if (!aTimeout)
804 break;
805 case USBDeviceState_Available:
806 case USBDeviceState_Held:
807 if (aTimeout)
808 {
809 mPendingStateEx = kNothingPending;
810 mIsStatePending = false;
811 break;
812 }
813 /* fall thru */
814 default:
815 AssertFailed();
816 }
817 break;
818
819 case kDetachingPendingDetach:
820 case kDetachingPendingDetachFilters:
821 case kDetachingPendingAttach:
822 case kDetachingPendingAttachFilters:
823 LogFlowThisFunc (("cancelling reattach in state %d\n", mPendingStateEx));
824 mMachine.setNull();
825 mPendingStateEx = kNothingPending;
826 mIsStatePending = false;
827 break;
828
829 default:
830 AssertMsgFailed(("%d\n", mPendingStateEx));
831 break;
832 }
833}
834
835/**
836 * Returns true if this device matches the given filter data.
837 *
838 * @note It is assumed, that the filter data owner is appropriately
839 * locked before calling this method.
840 *
841 * @note
842 * This method MUST correlate with
843 * USBController::hasMatchingFilter (IUSBDevice *)
844 * in the sense of the device matching logic.
845 *
846 * @note Locks this object for reading.
847 */
848bool HostUSBDevice::isMatch (const USBDeviceFilter::Data &aData)
849{
850 AutoCaller autoCaller (this);
851 AssertComRCReturn (autoCaller.rc(), false);
852
853 AutoReaderLock alock (this);
854
855 if (!aData.mActive)
856 return false;
857
858 if (!USBFilterMatchDevice (&aData.mUSBFilter, mUsb))
859 return false;
860
861 /* Don't match busy devices with a 100% wildcard filter - this will
862 later become a filter prop (ring-3 only). */
863 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
864 && !USBFilterHasAnySubstatialCriteria (&aData.mUSBFilter))
865 return false;
866
867 LogFlowThisFunc (("returns true\n"));
868 return true;
869}
870
871
872/**
873 * Compares this device with a USBDEVICE and decides which comes first.
874 *
875 * If the device has a pending state request, a non-strict comparison is made
876 * (to properly detect a re-attached device). Otherwise, a strict comparison
877 * is performed.
878 *
879 * @param aDev2 Device 2.
880 *
881 * @return < 0 if this should come before aDev2.
882 * @return 0 if this and aDev2 are equal.
883 * @return > 0 if this should come after aDev2.
884 *
885 * @note Must be called from under the object write lock.
886 */
887int HostUSBDevice::compare (PCUSBDEVICE aDev2)
888{
889 AssertReturn (isLockedOnCurrentThread(), -1);
890
891 return compare (mUsb, aDev2, !isStatePending());
892}
893
894/**
895 * Compares two USB devices and decides which comes first.
896 *
897 * If @a aIsStrict is @c true then the comparison will indicate a difference
898 * even if the same physical device (represented by @a aDev1) has been just
899 * re-attached to the host computer (represented by @a aDev2) and got a
900 * different address from the host OS, etc.
901 *
902 * If @a aIsStrict is @c false, then such a re-attached device will be
903 * considered equal to the previous device definition and this function will
904 * retrun 0.
905 *
906 * @param aDev1 Device 1.
907 * @param aDev2 Device 2.
908 * @param aIsStrict @c true to do a strict check and @c false otherwise.
909
910 * @return < 0 if aDev1 should come before aDev2.
911 * @return 0 if aDev1 and aDev2 are equal.
912 * @return > 0 if aDev1 should come after aDev2.
913 */
914/*static*/
915int HostUSBDevice::compare (PCUSBDEVICE aDev1, PCUSBDEVICE aDev2,
916 bool aIsStrict /* = true */)
917{
918 /* The non-strict checks tries as best as it can to distiguish between
919 different physical devices of the same product. Unfortunately this
920 isn't always possible and we might end up a bit confused in rare cases... */
921
922 int iDiff = aDev1->idVendor - aDev2->idVendor;
923 if (iDiff)
924 return iDiff;
925
926 iDiff = aDev1->idProduct - aDev2->idProduct;
927 if (iDiff)
928 return iDiff;
929
930 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
931 if (iDiff)
932 return iDiff;
933
934 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
935 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
936
937 if (!aIsStrict)
938 return 0;
939
940 /* The rest is considered as a strict check since it includes bits that
941 may vary on logical reconnects (or whatever you wish to call it). */
942 return strcmp (aDev1->pszAddress, aDev2->pszAddress);
943}
944
945/**
946 * Updates the state of the device.
947 *
948 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
949 * called to process the state change (complete the state change request,
950 * inform the VM process etc.).
951 *
952 * If this method returns @c false, it is assumed that the given state change
953 * is "minor": it doesn't require any further action other than update the
954 * mState field with the actual state value.
955 *
956 * Regardless of the return value, this method always takes ownership of the
957 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
958 * it using the values of the old structure.
959 *
960 * @param aDev The current device state as seen by the proxy backend.
961 *
962 * @return Whether the Host object should be bothered with this state change.
963 *
964 * @note Locks this object for writing.
965 */
966bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
967{
968 LogFlowThisFunc (("\n"));
969
970 AssertReturn (isLockedOnCurrentThread(), false);
971
972 AutoCaller autoCaller (this);
973 AssertComRCReturn (autoCaller.rc(), false);
974
975 AutoLock alock (this);
976
977 /* Replace the existing structure by the new one */
978 if (mUsb != aDev)
979 {
980 aDev->pNext = mUsb->pNext;
981 aDev->pPrev = mUsb->pPrev;
982 USBProxyService::freeDevice (mUsb);
983 mUsb = aDev;
984 }
985
986 bool isImportant = false;
987
988 /*
989 * We have to be pretty conservative here because the proxy backend
990 * doesn't necessarily know everything that's going on. So, rather
991 * be overly careful than changing the state once when we shouldn't!
992 *
993 * In particular, we treat changing between three states Unavailable, Busy
994 * and Available as non-important (because they all mean that the device
995 * is owned by the host) and return false in this case. We may want to
996 * change it later and, e.g. re-run all USB filters when the device goes from
997 * from Busy to Available).
998 *
999 * 2007-07-04: State transitions from Unavailable to Busy or Available
1000 * are now considered important and will cause filters to
1001 * be rerun on the device. (See #2030 and #1870.)
1002 */
1003
1004 LogFlowThisFunc (("aDev->enmState=%d mState=%d mPendingState=%d mPendingStateEx=%d\n",
1005 aDev->enmState, mState, mPendingState, mPendingStateEx));
1006
1007 switch (aDev->enmState)
1008 {
1009 default:
1010 AssertMsgFailed (("aDev->enmState=%d\n", aDev->enmState));
1011 case USBDEVICESTATE_UNSUPPORTED:
1012 Assert (mState == USBDeviceState_NotSupported);
1013 switch (mState)
1014 {
1015 case USBDeviceState_Captured:
1016 isImportant = mIsStatePending;
1017 break;
1018 }
1019 return isImportant;
1020
1021 case USBDEVICESTATE_USED_BY_HOST:
1022 switch (mState)
1023 {
1024 case USBDeviceState_Unavailable:
1025 return false;
1026 /* the following state changes don't require any action for now */
1027 case USBDeviceState_Busy:
1028 case USBDeviceState_Available:
1029 isImportant = false;
1030 break;
1031#ifndef RT_OS_WINDOWS /* Only windows really knows whether the device is unavailable or captured. */
1032 case USBDeviceState_Captured:
1033 if (!mIsStatePending)
1034 return false;
1035 /* fall thru */
1036#endif
1037 default:
1038 isImportant = true;
1039 }
1040 LogFlowThisFunc (("%d -> %d\n",
1041 mState, USBDeviceState_Unavailable));
1042 mState = USBDeviceState_Unavailable;
1043 return isImportant;
1044
1045 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1046 switch (mState)
1047 {
1048 case USBDeviceState_Busy:
1049 return false;
1050 case USBDeviceState_Available:
1051 isImportant = false;
1052 break;
1053 case USBDeviceState_Captured:
1054#ifndef RT_OS_WINDOWS /* Only Windows really knows whether the device is busy or captured. */
1055 if (!mIsStatePending)
1056 return false;
1057#endif
1058 /* Remain in the captured state if it's an async detach. */
1059 if (mPendingStateEx != kNothingPending)
1060 {
1061 LogFlowThisFunc (("USBDeviceCaptured - async detach completed (%d)\n", mPendingStateEx));
1062 return true;
1063 }
1064 /* fall thru */
1065 default:
1066 /* USBDeviceState_Unavailable: The device has become capturable, re-run filters. */
1067 /* USBDeviceState_Held: Pending request. */
1068 /* USBDeviceState_Captured: Pending request. */
1069 /* USBDeviceState_NotSupported: Something is broken. */
1070 isImportant = true;
1071 }
1072 LogFlowThisFunc (("%d -> %d\n",
1073 mState, USBDeviceState_Busy));
1074 mState = USBDeviceState_Busy;
1075 return isImportant;
1076
1077 case USBDEVICESTATE_UNUSED:
1078 switch (mState)
1079 {
1080 case USBDeviceState_Available:
1081 return false;
1082#if defined(RT_OS_LINUX) /* Hack for /proc/bus/usb/devices not necessarily putting up a driver. */ \
1083 || defined(RT_OS_DARWIN) /* We're a bit clueless as to the exact device state, just like linux. */
1084 case USBDeviceState_Captured:
1085 if ( !mIsStatePending
1086 || mPendingStateEx != kNothingPending)
1087 return false;
1088 isImportant = true;
1089 break;
1090#endif
1091 /* the following state changes don't require any action for now */
1092 case USBDeviceState_Busy:
1093 isImportant = false;
1094 break;
1095 default:
1096 /* USBDeviceState_Unavailable: The device has become available, re-run filters. */
1097 /* USBDeviceState_Held: Pending request. */
1098 /* USBDeviceState_NotSupported: Something is broken. */
1099 isImportant = true;
1100 }
1101 LogFlowThisFunc (("%d -> %d\n",
1102 mState, USBDeviceState_Available));
1103 mState = USBDeviceState_Available;
1104 return isImportant;
1105
1106 case USBDEVICESTATE_HELD_BY_PROXY:
1107 switch (mState)
1108 {
1109 case USBDeviceState_Held:
1110 return false;
1111 case USBDeviceState_Captured:
1112 if (!mIsStatePending)
1113 return false;
1114 /* no break */
1115 default:
1116 LogFlowThisFunc (("%d -> %d\n",
1117 mState, USBDeviceState_Held));
1118 mState = USBDeviceState_Held;
1119 return true;
1120 }
1121 break;
1122
1123 case USBDEVICESTATE_USED_BY_GUEST:
1124 /** @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
1125 * anywhere in the proxy code; it's quite logical because the
1126 * proxy doesn't know anything about guest VMs. */
1127 AssertFailed();
1128#if 0
1129 switch (mState)
1130 {
1131 case USBDeviceState_Captured:
1132 /* the proxy may confuse following state(s) with captured */
1133 case USBDeviceState_Held:
1134 case USBDeviceState_Available:
1135 case USBDeviceState_Busy:
1136 return false;
1137 default:
1138 LogFlowThisFunc (("%d -> %d\n",
1139 mState, USBDeviceState_Held));
1140 mState = USBDeviceState_Held;
1141 return true;
1142 }
1143#endif
1144 break;
1145 }
1146
1147 return false;
1148}
1149
1150/**
1151 * Checks for timeout of any pending async operation.
1152 *
1153 * The caller must write lock the object prior to calling
1154 * this method.
1155 */
1156void HostUSBDevice::checkForAsyncTimeout()
1157{
1158 AssertReturnVoid (isLockedOnCurrentThread());
1159
1160#ifndef RT_OS_WINDOWS /* no timeouts on windows yet since I don't have all the details here... */
1161 if (isStatePending() && mPendingSince)
1162 {
1163 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mPendingSince;
1164 if (elapsedNanoseconds > UINT64_C (60000000000) ) /* 60 seconds */
1165 {
1166 LogRel (("USB: Async operation timed out; mPendingState=%d mPendingStateEx=%d idVendor=%04x (%s) idProduct=%04x (%s) bcdDevice=%04x\n",
1167 mPendingState, mPendingStateEx, mUsb->idVendor, mUsb->pszManufacturer, mUsb->idProduct, mUsb->pszProduct, mUsb->bcdDevice));
1168
1169 cancelPendingState (true);
1170 }
1171 }
1172#endif
1173}
1174
1175/**
1176 * This method is called by the USB proxy and Host to work the
1177 * logical reconnection operation.
1178 *
1179 * @param aStage kDeatchingPendingDetach, kDeatchingPendingDetachFilters,
1180 * kDetachingPendingAttach or kDetachingPendingAttachFilters.
1181 *
1182 * @returns Success indicator.
1183 */
1184bool HostUSBDevice::setLogicalReconnect (InternalState aStage)
1185{
1186 AssertReturn (isLockedOnCurrentThread(), false);
1187
1188 switch (aStage)
1189 {
1190 case kDetachingPendingDetach:
1191 AssertReturn (!mIsStatePending, false);
1192 mPendingState = mState;
1193 mIsStatePending = true;
1194 mPendingSince = RTTimeNanoTS();
1195 LogFlowThisFunc (("pending detach\n"));
1196 break;
1197
1198 case kDetachingPendingDetachFilters:
1199 AssertReturn (mIsStatePending, false);
1200 AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
1201 LogFlowThisFunc (("pending detach+filters\n"));
1202 break;
1203
1204 case kDetachingPendingAttach:
1205 AssertReturn (mIsStatePending, false);
1206 AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
1207 LogFlowThisFunc (("pending attach\n"));
1208 break;
1209
1210 case kDetachingPendingAttachFilters:
1211 AssertReturn (mIsStatePending, false);
1212 AssertReturn ( mPendingStateEx == kDetachingPendingAttach
1213 || mPendingStateEx == kDetachingPendingDetachFilters, false);
1214 LogFlowThisFunc (("pending attach+filters\n"));
1215 break;
1216
1217 default:
1218 AssertFailedReturn (false);
1219 }
1220 mPendingStateEx = aStage;
1221 return true;
1222}
1223
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