VirtualBox

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

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

Fixed bug in a VBOX_WITH_USBFILTER case.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.3 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#ifndef VBOX_WITH_USBFILTER
859 if (!aData.mVendorId.isMatch (mUsb->idVendor))
860 {
861 LogFlowThisFunc (("vendor not match %04X\n",
862 mUsb->idVendor));
863 return false;
864 }
865 if (!aData.mProductId.isMatch (mUsb->idProduct))
866 {
867 LogFlowThisFunc (("product id not match %04X\n",
868 mUsb->idProduct));
869 return false;
870 }
871 if (!aData.mRevision.isMatch (mUsb->bcdDevice))
872 {
873 LogFlowThisFunc (("rev not match %04X\n",
874 mUsb->bcdDevice));
875 return false;
876 }
877
878#if !defined (RT_OS_WINDOWS)
879 // these filters are temporarily ignored on Win32
880 if (!aData.mManufacturer.isMatch (Bstr (mUsb->pszManufacturer)))
881 return false;
882 if (!aData.mProduct.isMatch (Bstr (mUsb->pszProduct)))
883 return false;
884 if (!aData.mSerialNumber.isMatch (Bstr (mUsb->pszSerialNumber)))
885 return false;
886 /// @todo (dmik) pusPort is yet absent
887// if (!aData.mPort.isMatch (Bstr (mUsb->pusPort)))
888// return false;
889#endif
890
891 // Host USB devices are local, so remote is always FALSE
892 if (!aData.mRemote.isMatch (FALSE))
893 {
894 LogFlowMember (("Host::HostUSBDevice: remote not match FALSE\n"));
895 return false;
896 }
897
898 /// @todo (dmik): bird, I assumed isMatch() is called only for devices
899 // that are suitable for holding/capturing (also assuming that when the device
900 // is just attached it first goes to our filter driver, and only after applying
901 // filters goes back to the system when appropriate). So the below
902 // doesn't look too correct; moreover, currently there is no determinable
903 // "any match" state for intervalic filters, and it will be not so easy
904 // to determine this state for an arbitrary regexp expression...
905 // For now, I just check that the string filter is empty (which doesn't
906 // actually reflect all possible "any match" filters).
907 //
908 // bird: This method was called for any device some weeks back, and it most certainly
909 // should be called for 'busy' devices still. However, we do *not* want 'busy' devices
910 // to match empty filters (because that will for instance capture all USB keyboards & mice).
911 // You assumption about a filter driver is not correct on linux. We're racing with
912 // everyone else in the system there - see your problem with usbfs access.
913 //
914 // The customer *requires* a way of matching all devices which the host isn't using,
915 // if that is now difficult or the below method opens holes in the matching, this *must*
916 // be addresses immediately.
917
918 /*
919 * If all the criteria is empty, devices which are used by the host will not match.
920 */
921 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
922 && aData.mVendorId.string().isEmpty()
923 && aData.mProductId.string().isEmpty()
924 && aData.mRevision.string().isEmpty()
925 && aData.mManufacturer.string().isEmpty()
926 && aData.mProduct.string().isEmpty()
927 && aData.mSerialNumber.string().isEmpty())
928 return false;
929
930#else /* VBOX_WITH_USBFILTER */
931 if (!USBFilterMatchDevice (&aData.mUSBFilter, mUsb))
932 return false;
933
934 /* Don't match busy devices with a 100% wildcard filter - this will
935 later become a filter prop (ring-3 only). */
936 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
937 && !USBFilterHasAnySubstatialCriteria (&aData.mUSBFilter))
938 return false;
939#endif /* VBOX_WITH_USBFILTER */
940
941 LogFlowThisFunc (("returns true\n"));
942 return true;
943}
944
945
946/**
947 * Compares this device with a USBDEVICE and decides which comes first.
948 *
949 * If the device has a pending state request, a non-strict comparison is made
950 * (to properly detect a re-attached device). Otherwise, a strict comparison
951 * is performed.
952 *
953 * @param aDev2 Device 2.
954 *
955 * @return < 0 if this should come before aDev2.
956 * @return 0 if this and aDev2 are equal.
957 * @return > 0 if this should come after aDev2.
958 *
959 * @note Must be called from under the object write lock.
960 */
961int HostUSBDevice::compare (PCUSBDEVICE aDev2)
962{
963 AssertReturn (isLockedOnCurrentThread(), -1);
964
965 return compare (mUsb, aDev2, !isStatePending());
966}
967
968/**
969 * Compares two USB devices and decides which comes first.
970 *
971 * If @a aIsStrict is @c true then the comparison will indicate a difference
972 * even if the same physical device (represented by @a aDev1) has been just
973 * re-attached to the host computer (represented by @a aDev2) and got a
974 * different address from the host OS, etc.
975 *
976 * If @a aIsStrict is @c false, then such a re-attached device will be
977 * considered equal to the previous device definition and this function will
978 * retrun 0.
979 *
980 * @param aDev1 Device 1.
981 * @param aDev2 Device 2.
982 * @param aIsStrict @c true to do a strict check and @c false otherwise.
983
984 * @return < 0 if aDev1 should come before aDev2.
985 * @return 0 if aDev1 and aDev2 are equal.
986 * @return > 0 if aDev1 should come after aDev2.
987 */
988/*static*/
989int HostUSBDevice::compare (PCUSBDEVICE aDev1, PCUSBDEVICE aDev2,
990 bool aIsStrict /* = true */)
991{
992 /* The non-strict checks tries as best as it can to distiguish between
993 different physical devices of the same product. Unfortunately this
994 isn't always possible and we might end up a bit confused in rare cases... */
995
996 int iDiff = aDev1->idVendor - aDev2->idVendor;
997 if (iDiff)
998 return iDiff;
999
1000 iDiff = aDev1->idProduct - aDev2->idProduct;
1001 if (iDiff)
1002 return iDiff;
1003
1004 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
1005 if (iDiff)
1006 return iDiff;
1007
1008 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
1009 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
1010
1011 if (!aIsStrict)
1012 return 0;
1013
1014 /* The rest is considered as a strict check since it includes bits that
1015 may vary on logical reconnects (or whatever you wish to call it). */
1016 return strcmp (aDev1->pszAddress, aDev2->pszAddress);
1017}
1018
1019/**
1020 * Updates the state of the device.
1021 *
1022 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
1023 * called to process the state change (complete the state change request,
1024 * inform the VM process etc.).
1025 *
1026 * If this method returns @c false, it is assumed that the given state change
1027 * is "minor": it doesn't require any further action other than update the
1028 * mState field with the actual state value.
1029 *
1030 * Regardless of the return value, this method always takes ownership of the
1031 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
1032 * it using the values of the old structure.
1033 *
1034 * @param aDev The current device state as seen by the proxy backend.
1035 *
1036 * @return Whether the Host object should be bothered with this state change.
1037 *
1038 * @note Locks this object for writing.
1039 */
1040bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
1041{
1042 LogFlowThisFunc (("\n"));
1043
1044 AssertReturn (isLockedOnCurrentThread(), false);
1045
1046 AutoCaller autoCaller (this);
1047 AssertComRCReturn (autoCaller.rc(), false);
1048
1049 AutoLock alock (this);
1050
1051 /* Replace the existing structure by the new one */
1052 if (mUsb != aDev)
1053 {
1054 aDev->pNext = mUsb->pNext;
1055 aDev->pPrev = mUsb->pPrev;
1056 USBProxyService::freeDevice (mUsb);
1057 mUsb = aDev;
1058 }
1059
1060 bool isImportant = false;
1061
1062 /*
1063 * We have to be pretty conservative here because the proxy backend
1064 * doesn't necessarily know everything that's going on. So, rather
1065 * be overly careful than changing the state once when we shouldn't!
1066 *
1067 * In particular, we treat changing between three states Unavailable, Busy
1068 * and Available as non-important (because they all mean that the device
1069 * is owned by the host) and return false in this case. We may want to
1070 * change it later and, e.g. re-run all USB filters when the device goes from
1071 * from Busy to Available).
1072 *
1073 * 2007-07-04: State transitions from Unavailable to Busy or Available
1074 * are now considered important and will cause filters to
1075 * be rerun on the device. (See #2030 and #1870.)
1076 */
1077
1078 LogFlowThisFunc (("aDev->enmState=%d mState=%d mPendingState=%d mPendingStateEx=%d\n",
1079 aDev->enmState, mState, mPendingState, mPendingStateEx));
1080
1081 switch (aDev->enmState)
1082 {
1083 default:
1084 AssertMsgFailed (("aDev->enmState=%d\n", aDev->enmState));
1085 case USBDEVICESTATE_UNSUPPORTED:
1086 Assert (mState == USBDeviceState_NotSupported);
1087 switch (mState)
1088 {
1089 case USBDeviceState_Captured:
1090 isImportant = mIsStatePending;
1091 break;
1092 }
1093 return isImportant;
1094
1095 case USBDEVICESTATE_USED_BY_HOST:
1096 switch (mState)
1097 {
1098 case USBDeviceState_Unavailable:
1099 return false;
1100 /* the following state changes don't require any action for now */
1101 case USBDeviceState_Busy:
1102 case USBDeviceState_Available:
1103 isImportant = false;
1104 break;
1105#ifndef RT_OS_WINDOWS /* Only windows really knows whether the device is unavailable or captured. */
1106 case USBDeviceState_Captured:
1107 if (!mIsStatePending)
1108 return false;
1109 /* fall thru */
1110#endif
1111 default:
1112 isImportant = true;
1113 }
1114 LogFlowThisFunc (("%d -> %d\n",
1115 mState, USBDeviceState_Unavailable));
1116 mState = USBDeviceState_Unavailable;
1117 return isImportant;
1118
1119 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1120 switch (mState)
1121 {
1122 case USBDeviceState_Busy:
1123 return false;
1124 case USBDeviceState_Available:
1125 isImportant = false;
1126 break;
1127 case USBDeviceState_Captured:
1128#ifndef RT_OS_WINDOWS /* Only Windows really knows whether the device is busy or captured. */
1129 if (!mIsStatePending)
1130 return false;
1131#endif
1132 /* Remain in the captured state if it's an async detach. */
1133 if (mPendingStateEx != kNothingPending)
1134 {
1135 LogFlowThisFunc (("USBDeviceCaptured - async detach completed (%d)\n", mPendingStateEx));
1136 return true;
1137 }
1138 /* fall thru */
1139 default:
1140 /* USBDeviceState_Unavailable: The device has become capturable, re-run filters. */
1141 /* USBDeviceState_Held: Pending request. */
1142 /* USBDeviceState_Captured: Pending request. */
1143 /* USBDeviceState_NotSupported: Something is broken. */
1144 isImportant = true;
1145 }
1146 LogFlowThisFunc (("%d -> %d\n",
1147 mState, USBDeviceState_Busy));
1148 mState = USBDeviceState_Busy;
1149 return isImportant;
1150
1151 case USBDEVICESTATE_UNUSED:
1152 switch (mState)
1153 {
1154 case USBDeviceState_Available:
1155 return false;
1156#if defined(RT_OS_LINUX) /* Hack for /proc/bus/usb/devices not necessarily putting up a driver. */ \
1157 || defined(RT_OS_DARWIN) /* We're a bit clueless as to the exact device state, just like linux. */
1158 case USBDeviceState_Captured:
1159 if ( !mIsStatePending
1160 || mPendingStateEx != kNothingPending)
1161 return false;
1162 isImportant = true;
1163 break;
1164#endif
1165 /* the following state changes don't require any action for now */
1166 case USBDeviceState_Busy:
1167 isImportant = false;
1168 break;
1169 default:
1170 /* USBDeviceState_Unavailable: The device has become available, re-run filters. */
1171 /* USBDeviceState_Held: Pending request. */
1172 /* USBDeviceState_NotSupported: Something is broken. */
1173 isImportant = true;
1174 }
1175 LogFlowThisFunc (("%d -> %d\n",
1176 mState, USBDeviceState_Available));
1177 mState = USBDeviceState_Available;
1178 return isImportant;
1179
1180 case USBDEVICESTATE_HELD_BY_PROXY:
1181 switch (mState)
1182 {
1183 case USBDeviceState_Held:
1184 return false;
1185 case USBDeviceState_Captured:
1186 if (!mIsStatePending)
1187 return false;
1188 /* no break */
1189 default:
1190 LogFlowThisFunc (("%d -> %d\n",
1191 mState, USBDeviceState_Held));
1192 mState = USBDeviceState_Held;
1193 return true;
1194 }
1195 break;
1196
1197 case USBDEVICESTATE_USED_BY_GUEST:
1198 /** @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
1199 * anywhere in the proxy code; it's quite logical because the
1200 * proxy doesn't know anything about guest VMs. */
1201 AssertFailed();
1202#if 0
1203 switch (mState)
1204 {
1205 case USBDeviceState_Captured:
1206 /* the proxy may confuse following state(s) with captured */
1207 case USBDeviceState_Held:
1208 case USBDeviceState_Available:
1209 case USBDeviceState_Busy:
1210 return false;
1211 default:
1212 LogFlowThisFunc (("%d -> %d\n",
1213 mState, USBDeviceState_Held));
1214 mState = USBDeviceState_Held;
1215 return true;
1216 }
1217#endif
1218 break;
1219 }
1220
1221 return false;
1222}
1223
1224/**
1225 * Checks for timeout of any pending async operation.
1226 *
1227 * The caller must write lock the object prior to calling
1228 * this method.
1229 */
1230void HostUSBDevice::checkForAsyncTimeout()
1231{
1232 AssertReturnVoid (isLockedOnCurrentThread());
1233
1234#ifndef RT_OS_WINDOWS /* no timeouts on windows yet since I don't have all the details here... */
1235 if (isStatePending() && mPendingSince)
1236 {
1237 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mPendingSince;
1238 if (elapsedNanoseconds > UINT64_C (60000000000) ) /* 60 seconds */
1239 {
1240 LogRel (("USB: Async operation timed out; mPendingState=%d mPendingStateEx=%d idVendor=%04x (%s) idProduct=%04x (%s) bcdDevice=%04x\n",
1241 mPendingState, mPendingStateEx, mUsb->idVendor, mUsb->pszManufacturer, mUsb->idProduct, mUsb->pszProduct, mUsb->bcdDevice));
1242
1243 cancelPendingState (true);
1244 }
1245 }
1246#endif
1247}
1248
1249/**
1250 * This method is called by the USB proxy and Host to work the
1251 * logical reconnection operation.
1252 *
1253 * @param aStage kDeatchingPendingDetach, kDeatchingPendingDetachFilters,
1254 * kDetachingPendingAttach or kDetachingPendingAttachFilters.
1255 *
1256 * @returns Success indicator.
1257 */
1258bool HostUSBDevice::setLogicalReconnect (InternalState aStage)
1259{
1260 AssertReturn (isLockedOnCurrentThread(), false);
1261
1262 switch (aStage)
1263 {
1264 case kDetachingPendingDetach:
1265 AssertReturn (!mIsStatePending, false);
1266 mPendingState = mState;
1267 mIsStatePending = true;
1268 mPendingSince = RTTimeNanoTS();
1269 LogFlowThisFunc (("pending detach\n"));
1270 break;
1271
1272 case kDetachingPendingDetachFilters:
1273 AssertReturn (mIsStatePending, false);
1274 AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
1275 LogFlowThisFunc (("pending detach+filters\n"));
1276 break;
1277
1278 case kDetachingPendingAttach:
1279 AssertReturn (mIsStatePending, false);
1280 AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
1281 LogFlowThisFunc (("pending attach\n"));
1282 break;
1283
1284 case kDetachingPendingAttachFilters:
1285 AssertReturn (mIsStatePending, false);
1286 AssertReturn ( mPendingStateEx == kDetachingPendingAttach
1287 || mPendingStateEx == kDetachingPendingDetachFilters, false);
1288 LogFlowThisFunc (("pending attach+filters\n"));
1289 break;
1290
1291 default:
1292 AssertFailedReturn (false);
1293 }
1294 mPendingStateEx = aStage;
1295 return true;
1296}
1297
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