VirtualBox

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

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

warning

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

© 2023 Oracle
ContactPrivacy policyTerms of Use