VirtualBox

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

Last change on this file since 3001 was 3001, checked in by vboxsync, 18 years ago

Main/Frontends: Next step to support asynchronous USB device flow.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.0 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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "HostUSBDeviceImpl.h"
23#include "MachineImpl.h"
24#include "VirtualBoxErrorInfoImpl.h"
25#include "USBProxyService.h"
26
27#include "Logging.h"
28
29#include <VBox/err.h>
30
31// constructor / destructor
32/////////////////////////////////////////////////////////////////////////////
33
34DEFINE_EMPTY_CTOR_DTOR (HostUSBDevice)
35
36HRESULT HostUSBDevice::FinalConstruct()
37{
38 mUSBProxyService = NULL;
39 mUsb = NULL;
40
41 return S_OK;
42}
43
44void HostUSBDevice::FinalRelease()
45{
46 uninit();
47}
48
49// public initializer/uninitializer for internal purposes only
50/////////////////////////////////////////////////////////////////////////////
51
52/**
53 * Initializes the USB device object.
54 *
55 * @returns COM result indicator
56 * @param aUsb Pointer to the usb device structure for which the object is to be a wrapper.
57 * This structure is now fully owned by the HostUSBDevice object and will be
58 * freed when it is destructed.
59 * @param aUSBProxyService Pointer to the USB Proxy Service object.
60 */
61HRESULT HostUSBDevice::init(PUSBDEVICE aUsb, USBProxyService *aUSBProxyService)
62{
63 ComAssertRet (aUsb, E_INVALIDARG);
64
65 /* Enclose the state transition NotReady->InInit->Ready */
66 AutoInitSpan autoInitSpan (this);
67 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
68
69 /*
70 * We need a unique ID for this VBoxSVC session.
71 * The UUID isn't stored anywhere.
72 */
73 unconst (mId).create();
74
75 /*
76 * Convert from USBDEVICESTATE to USBDeviceState.
77 *
78 * Note that not all proxy backend can detect the HELD_BY_PROXY
79 * and USED_BY_GUEST states. But that shouldn't matter much.
80 */
81 switch (aUsb->enmState)
82 {
83 default:
84 AssertMsgFailed(("aUsb->enmState=%d\n", aUsb->enmState));
85 case USBDEVICESTATE_UNSUPPORTED:
86 mState = USBDeviceState_USBDeviceNotSupported;
87 break;
88 case USBDEVICESTATE_USED_BY_HOST:
89 mState = USBDeviceState_USBDeviceUnavailable;
90 break;
91 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
92 mState = USBDeviceState_USBDeviceBusy;
93 break;
94 case USBDEVICESTATE_UNUSED:
95 mState = USBDeviceState_USBDeviceAvailable;
96 break;
97 case USBDEVICESTATE_HELD_BY_PROXY:
98 mState = USBDeviceState_USBDeviceHeld;
99 break;
100 case USBDEVICESTATE_USED_BY_GUEST:
101 /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
102 * anywhere in the proxy code; it's quite logical because the
103 * proxy doesn't know anything about guest VMs. */
104 AssertFailedReturn (E_FAIL);
105 break;
106 }
107
108 mPendingState = mState;
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(Remote)(BOOL *aRemote)
280{
281 if (!aRemote)
282 return E_INVALIDARG;
283
284 AutoCaller autoCaller (this);
285 CheckComRCReturnRC (autoCaller.rc());
286
287 AutoReaderLock alock (this);
288
289 *aRemote = FALSE;
290
291 return S_OK;
292}
293
294// IHostUSBDevice properties
295/////////////////////////////////////////////////////////////////////////////
296
297STDMETHODIMP HostUSBDevice::COMGETTER(State) (USBDeviceState_T *aState)
298{
299 if (!aState)
300 return E_POINTER;
301
302 AutoCaller autoCaller (this);
303 CheckComRCReturnRC (autoCaller.rc());
304
305 AutoReaderLock alock (this);
306
307 *aState = mState;
308
309 return S_OK;
310}
311
312
313// public methods only for internal purposes
314////////////////////////////////////////////////////////////////////////////////
315
316/**
317 * @note Locks this object for reading.
318 */
319Utf8Str HostUSBDevice::name()
320{
321 Utf8Str name;
322
323 AutoCaller autoCaller (this);
324 AssertComRCReturn (autoCaller.rc(), name);
325
326 AutoReaderLock alock (this);
327
328 bool haveManufacturer = mUsb->pszManufacturer && *mUsb->pszManufacturer;
329 bool haveProduct = mUsb->pszProduct && *mUsb->pszProduct;
330 if (haveManufacturer && haveProduct)
331 name = Utf8StrFmt ("%s %s", mUsb->pszManufacturer,
332 mUsb->pszProduct);
333 else if(haveManufacturer)
334 name = Utf8StrFmt ("%s", mUsb->pszManufacturer);
335 else if(haveProduct)
336 name = Utf8StrFmt ("%s", mUsb->pszManufacturer);
337 else
338 name = "<unknown>";
339
340 return name;
341}
342
343/**
344 * Requests the USB proxy service to capture the device and sets the pending
345 * state to Captured.
346 *
347 * If the state change may be performed immediately (for example, Hold ->
348 * Captured), then the machine is informed before this method returns.
349 *
350 * @param aMachine Machine that will capture this device on success.
351 * @return @c false if the device could be immediately captured
352 * but the VM process refused to grab it;
353 * @c true otherwise.
354 *
355 * @note Must be called from under the object write lock.
356 *
357 * @note May lock the given machine object for reading.
358 */
359bool HostUSBDevice::requestCapture (SessionMachine *aMachine)
360{
361 LogFlowThisFunc (("\n"));
362
363 AssertReturn (aMachine, false);
364
365 AssertReturn (isLockedOnCurrentThread(), false);
366
367 AssertReturn (mIsStatePending == false, false);
368
369 AssertReturn (
370 mState == USBDeviceState_USBDeviceBusy ||
371 mState == USBDeviceState_USBDeviceAvailable ||
372 mState == USBDeviceState_USBDeviceHeld,
373 false);
374
375 if (mState == USBDeviceState_USBDeviceHeld)
376 {
377 /* can perform immediate capture, inform the VM process */
378
379 ComPtr <IUSBDevice> d = this;
380
381 mIsStatePending = true;
382
383 /* the VM process will query the object, so leave the lock */
384 AutoLock alock (this);
385 alock.leave();
386
387 LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
388
389 HRESULT rc = aMachine->onUSBDeviceAttach (d, NULL);
390
391 LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
392
393 alock.enter();
394
395 mIsStatePending = false;
396
397 if (SUCCEEDED (rc))
398 {
399 mState = mPendingState = USBDeviceState_USBDeviceCaptured;
400 mMachine = aMachine;
401 return true;
402 }
403
404 return false;
405 }
406
407 mIsStatePending = true;
408 mPendingState = USBDeviceState_USBDeviceCaptured;
409 mMachine = aMachine;
410
411 mUSBProxyService->captureDevice (this);
412
413 return true;
414}
415
416/**
417 * Requests the USB proxy service to release the device and sets the pending
418 * state to Available.
419 *
420 * If the state change may be performed immediately (for example, the current
421 * state is Busy), this method does nothing.
422 *
423 * @note Must be called from under the object write lock.
424 */
425void HostUSBDevice::requestRelease()
426{
427 LogFlowThisFunc (("\n"));
428
429 AssertReturnVoid (isLockedOnCurrentThread());
430
431 AssertReturnVoid (mIsStatePending == false);
432
433 AssertReturnVoid (
434 mState == USBDeviceState_USBDeviceBusy ||
435 mState == USBDeviceState_USBDeviceAvailable ||
436 mState == USBDeviceState_USBDeviceHeld);
437
438 if (mState != USBDeviceState_USBDeviceHeld)
439 return;
440
441 mIsStatePending = true;
442 mPendingState = USBDeviceState_USBDeviceAvailable;
443
444 mUSBProxyService->releaseDevice (this);
445}
446
447/**
448 * Requests the USB proxy service to release the device, sets the pending
449 * state to Held and removes the machine association if any.
450 *
451 * If the state change may be performed immediately (for example, the current
452 * state is already Held), this method does nothing but removes the machine
453 * association.
454 *
455 * @note Must be called from under the object write lock.
456 */
457void HostUSBDevice::requestHold()
458{
459 LogFlowThisFunc (("\n"));
460
461 AssertReturnVoid (isLockedOnCurrentThread());
462
463 AssertReturnVoid (mIsStatePending == false);
464
465 AssertReturnVoid (
466 mState == USBDeviceState_USBDeviceBusy ||
467 mState == USBDeviceState_USBDeviceAvailable ||
468 mState == USBDeviceState_USBDeviceHeld);
469
470 mMachine.setNull();
471
472 if (mState == USBDeviceState_USBDeviceHeld)
473 return;
474
475 mIsStatePending = true;
476 mPendingState = USBDeviceState_USBDeviceHeld;
477
478 mUSBProxyService->captureDevice (this);
479}
480
481/**
482 * Sets the device state from Captured to Held and preserves the machine
483 * association (if any). Usually called before applying filters.
484 *
485 * @note Must be called from under the object write lock.
486 */
487void HostUSBDevice::setHeld()
488{
489 LogFlowThisFunc (("\n"));
490
491 AssertReturnVoid (isLockedOnCurrentThread());
492
493 AssertReturnVoid (mState == USBDeviceState_USBDeviceCaptured);
494 AssertReturnVoid (mPendingState == USBDeviceState_USBDeviceCaptured);
495 AssertReturnVoid (mIsStatePending == false);
496
497 mState = USBDeviceState_USBDeviceHeld;
498}
499
500/**
501 * Resets all device data and informs the machine (if any) about the
502 * detachment. Must be called when this device is physically detached from
503 * the host.
504 *
505 * @note Must be called from under the object write lock.
506 */
507void HostUSBDevice::reset()
508{
509 LogFlowThisFunc (("\n"));
510
511 AssertReturnVoid (isLockedOnCurrentThread());
512
513 if (!mMachine.isNull() && mState == USBDeviceState_USBDeviceCaptured)
514 {
515 /* the device is captured by a machine, instruct it to release */
516
517 mIsStatePending = true;
518
519 /* the VM process will query the object, so leave the lock */
520 AutoLock alock (this);
521 alock.leave();
522
523 LogFlowThisFunc (("Calling machine->onUSBDeviceDetach()...\n"));
524
525 HRESULT rc = mMachine->onUSBDeviceDetach (mId, NULL);
526 AssertComRC (rc);
527
528 LogFlowThisFunc (("Done machine->onUSBDeviceDetach()=%08X\n", rc));
529
530 alock.enter();
531
532 mIsStatePending = false;
533 mState = mPendingState = USBDeviceState_USBDeviceNotSupported;
534 }
535}
536
537/**
538 * Handles the finished pending state change and informs the VM process if
539 * necessary.
540 *
541 * @note Must be called from under the object write lock.
542 */
543void HostUSBDevice::handlePendingStateChange()
544{
545 LogFlowThisFunc (("\n"));
546
547 AssertReturnVoid (isLockedOnCurrentThread());
548
549 AssertReturnVoid (mIsStatePending == true);
550 AssertReturnVoid (mState != USBDeviceState_USBDeviceCaptured);
551
552 bool wasCapture = false;
553 bool wasRelease = false;
554
555 HRESULT requestRC = S_OK;
556 Bstr errorText;
557
558 switch (mPendingState)
559 {
560 case USBDeviceState_USBDeviceCaptured:
561 {
562 if (mState == USBDeviceState_USBDeviceHeld)
563 {
564 if (!mMachine.isNull())
565 wasCapture = true;
566 else
567 {
568 /* it is a canceled capture request. Give the device back
569 * to the host. */
570 mPendingState = USBDeviceState_USBDeviceAvailable;
571 mUSBProxyService->releaseDevice (this);
572 }
573 }
574 else
575 {
576 /* couldn't capture the device, will report an error */
577 wasCapture = true;
578
579 Assert (!mMachine.isNull());
580
581 /// @todo more detailed error message depending on the state?
582 // probably need some error code/string from the USB proxy itself
583
584 requestRC = E_FAIL;
585 errorText = Utf8StrFmt (
586 tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the host "
587 "computer and cannot be attached to the virtual machine."
588 "Please try later"),
589 name().raw(), id().raw());
590 }
591 break;
592 }
593 case USBDeviceState_USBDeviceAvailable:
594 {
595 if (mState == USBDeviceState_USBDeviceHeld)
596 {
597 /* couldn't release the device */
598 wasRelease = true;
599
600 Assert (!mMachine.isNull());
601
602 /* return the captured state back */
603 mState = USBDeviceState_USBDeviceCaptured;
604
605 /// @todo more detailed error message depending on the state?
606 // probably need some error code/string from the USB proxy itself
607
608 requestRC = E_FAIL;
609 errorText = Utf8StrFmt (
610 tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the guest "
611 "computer and cannot be attached from the virtual machine."
612 "Please try later"),
613 name().raw(), id().raw());
614 }
615 else
616 {
617 if (!mMachine.isNull())
618 wasRelease = true;
619 else
620 {
621 /* it is a canceled release request. Leave at the host */
622 /// @todo we may want to re-run all filters in this case
623 }
624 }
625 break;
626 }
627 case USBDeviceState_USBDeviceHeld:
628 {
629 if (mState == USBDeviceState_USBDeviceHeld)
630 {
631 break;
632 }
633 else
634 {
635 /* couldn't capture the device requested by the global
636 * filter, there is nobody to report an error to. */
637 }
638 break;
639 }
640 default:
641 AssertFailed();
642 }
643
644 ComObjPtr <VirtualBoxErrorInfo> error;
645 if (FAILED (requestRC))
646 {
647 LogFlowThisFunc (("Request failed, requestRC=%08X, text='%ls'\n",
648 requestRC, errorText.raw()));
649
650 error.createObject();
651 error->init (requestRC, COM_IIDOF (IHostUSBDevice),
652 Bstr (HostUSBDevice::getComponentName()),
653 errorText.raw());
654 }
655
656 if (wasCapture)
657 {
658 /* inform the VM process */
659
660 ComPtr <IUSBDevice> d = this;
661
662 /* the VM process will query the object, so leave the lock */
663 AutoLock alock (this);
664 alock.leave();
665
666 LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
667
668 HRESULT rc = mMachine->onUSBDeviceAttach (d, error);
669 /// @todo we will probably want to re-run all filters on failure
670 // instead of asserting
671 AssertComRC (rc);
672
673 LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
674
675 alock.enter();
676
677 if (SUCCEEDED (requestRC) && SUCCEEDED (rc))
678 {
679 mIsStatePending = false;
680 mState = mPendingState = USBDeviceState_USBDeviceCaptured;
681 return;
682 }
683 }
684 else if (wasRelease)
685 {
686 /* inform the VM process */
687
688 /* the VM process will query the object, so leave the lock */
689 AutoLock alock (this);
690 alock.leave();
691
692 LogFlowThisFunc (("Calling machine->onUSBDeviceDetach()...\n"));
693
694 HRESULT rc = mMachine->onUSBDeviceDetach (mId, error);
695
696 /* This call may expectedly fail with rc = NS_ERROR_FAILURE (on XPCOM)
697 * if the VM process requests device release right before termination
698 * and then terminates before onUSBDeviceDetach() is reached
699 * it. Therefore, we don't assert here. On MS COM, there should be
700 * something similar (with the different error code). */
701
702 LogFlowThisFunc (("Done machine->onUSBDeviceDetach()=%08X\n", rc));
703
704 alock.enter();
705
706 if (SUCCEEDED (requestRC))
707 {
708 /* deassociate from the machine */
709 mMachine.setNull();
710 }
711 }
712
713 mIsStatePending = false;
714 mPendingState = mState;
715}
716
717/**
718 * Cancels pending state change due to machine termination.
719 *
720 * @note Must be called from under the object write lock.
721 */
722void HostUSBDevice::cancelPendingState()
723{
724 LogFlowThisFunc (("\n"));
725
726 AssertReturnVoid (isLockedOnCurrentThread());
727
728 AssertReturnVoid (mIsStatePending == true);
729 AssertReturnVoid (!mMachine.isNull());
730
731 switch (mPendingState)
732 {
733 case USBDeviceState_USBDeviceCaptured:
734 {
735 /* reset mMachine to deassociate it from the filter and tell
736 * handlePendingStateChange() what to do */
737 mMachine.setNull();
738 break;
739 }
740 case USBDeviceState_USBDeviceAvailable:
741 {
742 /* reset mMachine to deassociate it from the filter and tell
743 * handlePendingStateChange() what to do */
744 mMachine.setNull();
745 break;
746 }
747 default:
748 AssertFailed();
749 }
750}
751
752/**
753 * Returns true if this device matches the given filter data.
754 *
755 * @note It is assumed, that the filter data owner is appropriately
756 * locked before calling this method.
757 *
758 * @note
759 * This method MUST correlate with
760 * USBController::hasMatchingFilter (IUSBDevice *)
761 * in the sense of the device matching logic.
762 *
763 * @note Locks this object for reading.
764 */
765bool HostUSBDevice::isMatch (const USBDeviceFilter::Data &aData)
766{
767 AutoCaller autoCaller (this);
768 AssertComRCReturn (autoCaller.rc(), false);
769
770 AutoReaderLock alock (this);
771
772 if (!aData.mActive)
773 return false;
774
775 if (!aData.mVendorId.isMatch (mUsb->idVendor))
776 {
777 LogFlowThisFunc (("vendor not match %04X\n",
778 mUsb->idVendor));
779 return false;
780 }
781 if (!aData.mProductId.isMatch (mUsb->idProduct))
782 {
783 LogFlowThisFunc (("product id not match %04X\n",
784 mUsb->idProduct));
785 return false;
786 }
787 if (!aData.mRevision.isMatch (mUsb->bcdDevice))
788 {
789 LogFlowThisFunc (("rev not match %04X\n",
790 mUsb->bcdDevice));
791 return false;
792 }
793
794#if !defined (__WIN__)
795 // these filters are temporarily ignored on Win32
796 if (!aData.mManufacturer.isMatch (Bstr (mUsb->pszManufacturer)))
797 return false;
798 if (!aData.mProduct.isMatch (Bstr (mUsb->pszProduct)))
799 return false;
800 if (!aData.mSerialNumber.isMatch (Bstr (mUsb->pszSerialNumber)))
801 return false;
802 /// @todo (dmik) pusPort is yet absent
803// if (!aData.mPort.isMatch (Bstr (mUsb->pusPort)))
804// return false;
805#endif
806
807 // Host USB devices are local, so remote is always FALSE
808 if (!aData.mRemote.isMatch (FALSE))
809 {
810 LogFlowMember (("Host::HostUSBDevice: remote not match FALSE\n"));
811 return false;
812 }
813
814 /// @todo (dmik): bird, I assumed isMatch() is called only for devices
815 // that are suitable for holding/capturing (also assuming that when the device
816 // is just attached it first goes to our filter driver, and only after applying
817 // filters goes back to the system when appropriate). So the below
818 // doesn't look too correct; moreover, currently there is no determinable
819 // "any match" state for intervalic filters, and it will be not so easy
820 // to determine this state for an arbitrary regexp expression...
821 // For now, I just check that the string filter is empty (which doesn't
822 // actually reflect all possible "any match" filters).
823 //
824 // bird: This method was called for any device some weeks back, and it most certainly
825 // should be called for 'busy' devices still. However, we do *not* want 'busy' devices
826 // to match empty filters (because that will for instance capture all USB keyboards & mice).
827 // You assumption about a filter driver is not correct on linux. We're racing with
828 // everyone else in the system there - see your problem with usbfs access.
829 //
830 // The customer *requires* a way of matching all devices which the host isn't using,
831 // if that is now difficult or the below method opens holes in the matching, this *must*
832 // be addresses immediately.
833
834 /*
835 * If all the criteria is empty, devices which are used by the host will not match.
836 */
837 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
838 && aData.mVendorId.string().isEmpty()
839 && aData.mProductId.string().isEmpty()
840 && aData.mRevision.string().isEmpty()
841 && aData.mManufacturer.string().isEmpty()
842 && aData.mProduct.string().isEmpty()
843 && aData.mSerialNumber.string().isEmpty())
844 return false;
845
846 LogFlowThisFunc (("returns true\n"));
847 return true;
848}
849
850
851/**
852 * Compares this device with a USBDEVICE and decides which comes first.
853 *
854 * @return < 0 if this should come before pDev2.
855 * @return 0 if this and pDev2 are equal.
856 * @return > 0 if this should come after pDev2.
857 *
858 * @param pDev2 Device 2.
859 *
860 * @note Must be called from under the object write lock.
861 */
862int HostUSBDevice::compare (PCUSBDEVICE pDev2)
863{
864 AssertReturn (isLockedOnCurrentThread(), -1);
865
866 return compare (mUsb, pDev2);
867}
868
869
870/**
871 * Compares two USB devices and decides which comes first.
872 *
873 * @return < 0 if pDev1 should come before pDev2.
874 * @return 0 if pDev1 and pDev2 are equal.
875 * @return > 0 if pDev1 should come after pDev2.
876 *
877 * @param pDev1 Device 1.
878 * @param pDev2 Device 2.
879 */
880/*static*/ int HostUSBDevice::compare (PCUSBDEVICE pDev1, PCUSBDEVICE pDev2)
881{
882 int iDiff = pDev1->idVendor - pDev2->idVendor;
883 if (iDiff)
884 return iDiff;
885
886 iDiff = pDev1->idProduct - pDev2->idProduct;
887 if (iDiff)
888 return iDiff;
889
890 /** @todo Sander, will this work on windows as well? Linux won't reuse an address for quite a while. */
891 return strcmp(pDev1->pszAddress, pDev2->pszAddress);
892}
893
894/**
895 * Updates the state of the device.
896 *
897 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
898 * called to process the state change (complete the state change request,
899 * inform the VM process etc.).
900 *
901 * If this method returns @c false, it is assumed that the given state change
902 * is "minor": it doesn't require any further action other than update the
903 * mState field with the actual state value.
904 *
905 * @param aDev The current device state as seen by the proxy backend.
906 *
907 * @note Locks this object for writing.
908 */
909bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
910{
911 LogFlowThisFunc (("\n"));
912
913 AssertReturn (isLockedOnCurrentThread(), false);
914
915 AutoCaller autoCaller (this);
916 AssertComRCReturn (autoCaller.rc(), false);
917
918 AutoLock alock (this);
919
920 bool isImportant = false;
921
922 /*
923 * We have to be pretty conservative here because the proxy backend
924 * doesn't necessarily know everything that's going on. So, rather
925 * be overly careful than changing the state once when we shouldn't!
926 *
927 * In particular, we treat changing between three states Unavailable, Busy
928 * and Available as non-important (because they all mean that the device
929 * is owned by the host) and return false in this case. We may want to
930 * change it later and, e.g. re-run all USB filters when the device goes from
931 * from Busy to Available).
932 */
933
934 switch (aDev->enmState)
935 {
936 default:
937 AssertMsgFailed (("aDev->enmState=%d\n", aDev->enmState));
938 case USBDEVICESTATE_UNSUPPORTED:
939 Assert (mState == USBDeviceState_USBDeviceNotSupported);
940 return false;
941
942 case USBDEVICESTATE_USED_BY_HOST:
943 switch (mState)
944 {
945 case USBDeviceState_USBDeviceUnavailable:
946 return false;
947 /* the following state changes don't require any action for now */
948 case USBDeviceState_USBDeviceBusy:
949 case USBDeviceState_USBDeviceAvailable:
950 isImportant = false;
951 default:
952 isImportant = true;
953 }
954 LogFlowThisFunc (("%d -> %d\n",
955 mState, USBDeviceState_USBDeviceUnavailable));
956 mState = USBDeviceState_USBDeviceUnavailable;
957 return isImportant;
958
959 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
960 switch (mState)
961 {
962 case USBDeviceState_USBDeviceBusy:
963 return false;
964 /* the following state changes don't require any action for now */
965 case USBDeviceState_USBDeviceUnavailable:
966 case USBDeviceState_USBDeviceAvailable:
967 isImportant = false;
968 default:
969 isImportant = true;
970 }
971 LogFlowThisFunc (("%d -> %d\n",
972 mState, USBDeviceState_USBDeviceBusy));
973 mState = USBDeviceState_USBDeviceBusy;
974 return isImportant;
975
976 case USBDEVICESTATE_UNUSED:
977 switch (mState)
978 {
979 case USBDeviceState_USBDeviceAvailable:
980 return false;
981 /* the following state changes don't require any action for now */
982 case USBDeviceState_USBDeviceUnavailable:
983 case USBDeviceState_USBDeviceBusy:
984 isImportant = false;
985 default:
986 isImportant = true;
987 }
988 LogFlowThisFunc (("%d -> %d\n",
989 mState, USBDeviceState_USBDeviceAvailable));
990 mState = USBDeviceState_USBDeviceAvailable;
991 return isImportant;
992
993 case USBDEVICESTATE_HELD_BY_PROXY:
994 switch (mState)
995 {
996 case USBDeviceState_USBDeviceHeld:
997 return false;
998 default:
999 LogFlowThisFunc (("%d -> %d\n",
1000 mState, USBDeviceState_USBDeviceHeld));
1001 mState = USBDeviceState_USBDeviceHeld;
1002 return true;
1003 }
1004 break;
1005
1006 case USBDEVICESTATE_USED_BY_GUEST:
1007 /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
1008 * anywhere in the proxy code; it's quite logical because the
1009 * proxy doesn't know anything about guest VMs. */
1010 AssertFailed();
1011#if 0
1012 switch (mState)
1013 {
1014 case USBDeviceState_USBDeviceCaptured:
1015 /* the proxy may confuse following state(s) with captured */
1016 case USBDeviceState_USBDeviceHeld:
1017 case USBDeviceState_USBDeviceAvailable:
1018 case USBDeviceState_USBDeviceBusy:
1019 return false;
1020 default:
1021 LogFlowThisFunc (("%d -> %d\n",
1022 mState, USBDeviceState_USBDeviceHeld));
1023 mState = USBDeviceState_USBDeviceHeld;
1024 return true;
1025 }
1026#endif
1027 break;
1028 }
1029
1030 return false;
1031}
1032
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