VirtualBox

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

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

bugfix for multiple attached devices in windows

  • 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
535 /* This call may expectedly fail with rc = NS_ERROR_FAILURE (on XPCOM)
536 * if the VM process requests device release right before termination
537 * and then terminates before onUSBDeviceDetach() reached
538 * it. Therefore, we don't assert here. On MS COM, there should be
539 * something similar (with the different error code). More over, the
540 * VM process might have been accidentially crashed and not accessible
541 * any more (so that calling an uninitialized SessionMachine returns a
542 * failure). So don't assert. */
543
544 LogFlowThisFunc (("Done machine->onUSBDeviceDetach()=%08X\n", rc));
545
546 alock.enter();
547
548 /* Reset all fields. Tthe object should have been
549 * uninitialized after this method returns, so it doesn't really
550 * matter what state we put it in. */
551 mIsStatePending = false;
552 mState = mPendingState = USBDeviceState_USBDeviceNotSupported;
553 mMachine.setNull();
554 }
555}
556
557/**
558 * Handles the finished pending state change and informs the VM process if
559 * necessary.
560 *
561 * @note Must be called from under the object write lock.
562 */
563void HostUSBDevice::handlePendingStateChange()
564{
565 LogFlowThisFunc (("\n"));
566
567 AssertReturnVoid (isLockedOnCurrentThread());
568
569 AssertReturnVoid (mIsStatePending == true);
570 AssertReturnVoid (mState != USBDeviceState_USBDeviceCaptured);
571
572 bool wasCapture = false;
573
574 HRESULT requestRC = S_OK;
575 Bstr errorText;
576
577 switch (mPendingState)
578 {
579 case USBDeviceState_USBDeviceCaptured:
580 {
581 if (mState == USBDeviceState_USBDeviceHeld)
582 {
583 if (!mMachine.isNull())
584 wasCapture = true;
585 else
586 {
587 /* it is a canceled capture request. Give the device back
588 * to the host. */
589 mPendingState = USBDeviceState_USBDeviceAvailable;
590 mUSBProxyService->releaseDevice (this);
591 }
592 }
593 else
594 {
595 /* couldn't capture the device, will report an error */
596 wasCapture = true;
597
598 Assert (!mMachine.isNull());
599
600 /// @todo more detailed error message depending on the state?
601 // probably need some error code/string from the USB proxy itself
602
603 requestRC = E_FAIL;
604 errorText = Utf8StrFmt (
605 tr ("USB device '%s' with UUID {%Vuuid} is being accessed by the host "
606 "computer and cannot be attached to the virtual machine."
607 "Please try later"),
608 name().raw(), id().raw());
609 }
610 break;
611 }
612 case USBDeviceState_USBDeviceAvailable:
613 {
614 Assert (mMachine.isNull());
615
616 if (mState == USBDeviceState_USBDeviceHeld)
617 {
618 /* couldn't release the device (give it back to the host).
619 * there is nobody to report an error to (the machine has
620 * already been deassociated because VMM has already detached
621 * the device before requesting a release). */
622 }
623 else
624 {
625 /* it is a canceled release request. Leave at the host */
626 /// @todo we may want to re-run all filters in this case
627 }
628 break;
629 }
630 case USBDeviceState_USBDeviceHeld:
631 {
632 if (mState == USBDeviceState_USBDeviceHeld)
633 {
634 /* All right, the device is now held (due to some global
635 * filter). */
636 break;
637 }
638 else
639 {
640 /* couldn't capture the device requested by the global
641 * filter, there is nobody to report an error to. */
642 }
643 break;
644 }
645 default:
646 AssertFailed();
647 }
648
649 ComObjPtr <VirtualBoxErrorInfo> error;
650 if (FAILED (requestRC))
651 {
652 LogFlowThisFunc (("Request failed, requestRC=%08X, text='%ls'\n",
653 requestRC, errorText.raw()));
654
655 error.createObject();
656 error->init (requestRC, COM_IIDOF (IHostUSBDevice),
657 Bstr (HostUSBDevice::getComponentName()),
658 errorText.raw());
659 }
660
661 if (wasCapture)
662 {
663 /* inform the VM process */
664
665 ComPtr <IUSBDevice> d = this;
666
667 /* the VM process will query the object, so leave the lock */
668 AutoLock alock (this);
669 alock.leave();
670
671 LogFlowThisFunc (("Calling machine->onUSBDeviceAttach()...\n"));
672
673 HRESULT rc = mMachine->onUSBDeviceAttach (d, error);
674
675 /* The VM process has a legal reason to fail (for example, incorrect
676 * usbfs permissions or out of virtual USB ports). More over, the VM
677 * process might have been accidentially crashed and not accessible
678 * any more (so that calling an uninitialized SessionMachine returns a
679 * failure). So don't assert. */
680
681 /// @todo we will probably want to re-run all filters on failure
682
683 LogFlowThisFunc (("Done machine->onUSBDeviceAttach()=%08X\n", rc));
684
685 alock.enter();
686
687 if (SUCCEEDED (requestRC) && SUCCEEDED (rc))
688 {
689 mIsStatePending = false;
690 mState = mPendingState = USBDeviceState_USBDeviceCaptured;
691 return;
692 }
693
694 /* on failure, either from the proxy or from the VM process,
695 * deassociate from the machine */
696 mMachine.setNull();
697 }
698
699 mIsStatePending = false;
700 mPendingState = mState;
701}
702
703/**
704 * Cancels pending state change due to machine termination.
705 *
706 * @note Must be called from under the object write lock.
707 */
708void HostUSBDevice::cancelPendingState()
709{
710 LogFlowThisFunc (("\n"));
711
712 AssertReturnVoid (isLockedOnCurrentThread());
713
714 AssertReturnVoid (mIsStatePending == true);
715 AssertReturnVoid (!mMachine.isNull());
716
717 switch (mPendingState)
718 {
719 case USBDeviceState_USBDeviceCaptured:
720 {
721 /* reset mMachine to deassociate it from the filter and tell
722 * handlePendingStateChange() what to do */
723 mMachine.setNull();
724 break;
725 }
726 default:
727 AssertFailed();
728 }
729}
730
731/**
732 * Returns true if this device matches the given filter data.
733 *
734 * @note It is assumed, that the filter data owner is appropriately
735 * locked before calling this method.
736 *
737 * @note
738 * This method MUST correlate with
739 * USBController::hasMatchingFilter (IUSBDevice *)
740 * in the sense of the device matching logic.
741 *
742 * @note Locks this object for reading.
743 */
744bool HostUSBDevice::isMatch (const USBDeviceFilter::Data &aData)
745{
746 AutoCaller autoCaller (this);
747 AssertComRCReturn (autoCaller.rc(), false);
748
749 AutoReaderLock alock (this);
750
751 if (!aData.mActive)
752 return false;
753
754 if (!aData.mVendorId.isMatch (mUsb->idVendor))
755 {
756 LogFlowThisFunc (("vendor not match %04X\n",
757 mUsb->idVendor));
758 return false;
759 }
760 if (!aData.mProductId.isMatch (mUsb->idProduct))
761 {
762 LogFlowThisFunc (("product id not match %04X\n",
763 mUsb->idProduct));
764 return false;
765 }
766 if (!aData.mRevision.isMatch (mUsb->bcdDevice))
767 {
768 LogFlowThisFunc (("rev not match %04X\n",
769 mUsb->bcdDevice));
770 return false;
771 }
772
773#if !defined (__WIN__)
774 // these filters are temporarily ignored on Win32
775 if (!aData.mManufacturer.isMatch (Bstr (mUsb->pszManufacturer)))
776 return false;
777 if (!aData.mProduct.isMatch (Bstr (mUsb->pszProduct)))
778 return false;
779 if (!aData.mSerialNumber.isMatch (Bstr (mUsb->pszSerialNumber)))
780 return false;
781 /// @todo (dmik) pusPort is yet absent
782// if (!aData.mPort.isMatch (Bstr (mUsb->pusPort)))
783// return false;
784#endif
785
786 // Host USB devices are local, so remote is always FALSE
787 if (!aData.mRemote.isMatch (FALSE))
788 {
789 LogFlowMember (("Host::HostUSBDevice: remote not match FALSE\n"));
790 return false;
791 }
792
793 /// @todo (dmik): bird, I assumed isMatch() is called only for devices
794 // that are suitable for holding/capturing (also assuming that when the device
795 // is just attached it first goes to our filter driver, and only after applying
796 // filters goes back to the system when appropriate). So the below
797 // doesn't look too correct; moreover, currently there is no determinable
798 // "any match" state for intervalic filters, and it will be not so easy
799 // to determine this state for an arbitrary regexp expression...
800 // For now, I just check that the string filter is empty (which doesn't
801 // actually reflect all possible "any match" filters).
802 //
803 // bird: This method was called for any device some weeks back, and it most certainly
804 // should be called for 'busy' devices still. However, we do *not* want 'busy' devices
805 // to match empty filters (because that will for instance capture all USB keyboards & mice).
806 // You assumption about a filter driver is not correct on linux. We're racing with
807 // everyone else in the system there - see your problem with usbfs access.
808 //
809 // The customer *requires* a way of matching all devices which the host isn't using,
810 // if that is now difficult or the below method opens holes in the matching, this *must*
811 // be addresses immediately.
812
813 /*
814 * If all the criteria is empty, devices which are used by the host will not match.
815 */
816 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
817 && aData.mVendorId.string().isEmpty()
818 && aData.mProductId.string().isEmpty()
819 && aData.mRevision.string().isEmpty()
820 && aData.mManufacturer.string().isEmpty()
821 && aData.mProduct.string().isEmpty()
822 && aData.mSerialNumber.string().isEmpty())
823 return false;
824
825 LogFlowThisFunc (("returns true\n"));
826 return true;
827}
828
829
830/**
831 * Compares this device with a USBDEVICE and decides which comes first.
832 *
833 * If the device has a pending state request, a non-strict comparison is made
834 * (to properly detect a re-attached device). Otherwise, a strict comparison
835 * is performed.
836 *
837 * @param aDev2 Device 2.
838 *
839 * @return < 0 if this should come before aDev2.
840 * @return 0 if this and aDev2 are equal.
841 * @return > 0 if this should come after aDev2.
842 *
843 * @note Must be called from under the object write lock.
844 */
845int HostUSBDevice::compare (PCUSBDEVICE aDev2)
846{
847 AssertReturn (isLockedOnCurrentThread(), -1);
848
849#ifdef __WIN__
850 return compare (mUsb, aDev2, !isStatePending());
851#else
852 /* Since we fake the requests anyway, there is no need to unnecessarily
853 expose ourselves to trouble the non-strict compare may cause on
854 release/capture/unplug/plug/similar-devices. */
855 return compare (mUsb, aDev2, true /* strict */);
856#endif
857}
858
859/**
860 * Compares two USB devices and decides which comes first.
861 *
862 * If @a aIsStrict is @c true then the comparison will indicate a difference
863 * even if the same physical device (represented by @a aDev1) has been just
864 * re-attached to the host computer (represented by @a aDev2) and got a
865 * different address from the host OS, etc.
866 *
867 * If @a aIsStrict is @c false, then such a re-attached device will be
868 * considered equal to the previous device definition and this function will
869 * retrun 0.
870 *
871 * @param aDev1 Device 1.
872 * @param aDev2 Device 2.
873 * @param aIsStrict @c true to do a strict check and @c false otherwise.
874
875 * @return < 0 if aDev1 should come before aDev2.
876 * @return 0 if aDev1 and aDev2 are equal.
877 * @return > 0 if aDev1 should come after aDev2.
878 */
879/*static*/
880int HostUSBDevice::compare (PCUSBDEVICE aDev1, PCUSBDEVICE aDev2,
881 bool aIsStrict /* = true */)
882{
883 int iDiff = aDev1->idVendor - aDev2->idVendor;
884 if (iDiff)
885 return iDiff;
886
887 iDiff = aDev1->idProduct - aDev2->idProduct;
888 if (iDiff)
889 return iDiff;
890
891 if (!aIsStrict)
892 return 0;
893
894 /* The rest is considered as a strict check. */
895
896 return strcmp (aDev1->pszAddress, aDev2->pszAddress);
897}
898
899/**
900 * Updates the state of the device.
901 *
902 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
903 * called to process the state change (complete the state change request,
904 * inform the VM process etc.).
905 *
906 * If this method returns @c false, it is assumed that the given state change
907 * is "minor": it doesn't require any further action other than update the
908 * mState field with the actual state value.
909 *
910 * Regardless of the return value, this method always takes ownership of the
911 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
912 * it using the values of the old structure.
913 *
914 * @param aDev The current device state as seen by the proxy backend.
915 *
916 * @note Locks this object for writing.
917 */
918bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
919{
920 LogFlowThisFunc (("\n"));
921
922 AssertReturn (isLockedOnCurrentThread(), false);
923
924 AutoCaller autoCaller (this);
925 AssertComRCReturn (autoCaller.rc(), false);
926
927 AutoLock alock (this);
928
929 /* Replace the existing structure by the new one */
930 if (mUsb != aDev)
931 {
932 aDev->pNext = mUsb->pNext;
933 aDev->pPrev = mUsb->pPrev;
934 USBProxyService::freeDevice (mUsb);
935 mUsb = aDev;
936 }
937
938 bool isImportant = false;
939
940 /*
941 * We have to be pretty conservative here because the proxy backend
942 * doesn't necessarily know everything that's going on. So, rather
943 * be overly careful than changing the state once when we shouldn't!
944 *
945 * In particular, we treat changing between three states Unavailable, Busy
946 * and Available as non-important (because they all mean that the device
947 * is owned by the host) and return false in this case. We may want to
948 * change it later and, e.g. re-run all USB filters when the device goes from
949 * from Busy to Available).
950 */
951
952 LogFlowThisFunc (("aDev->enmState=%d mState=%d mPendingState=%d\n",
953 aDev->enmState, mState, mPendingState));
954
955 switch (aDev->enmState)
956 {
957 default:
958 AssertMsgFailed (("aDev->enmState=%d\n", aDev->enmState));
959 case USBDEVICESTATE_UNSUPPORTED:
960 Assert (mState == USBDeviceState_USBDeviceNotSupported);
961 return false;
962
963 case USBDEVICESTATE_USED_BY_HOST:
964 switch (mState)
965 {
966 case USBDeviceState_USBDeviceUnavailable:
967 return false;
968 /* the following state changes don't require any action for now */
969 case USBDeviceState_USBDeviceBusy:
970 case USBDeviceState_USBDeviceAvailable:
971 isImportant = false;
972 break;
973#ifndef __WIN__ /* Only windows really knows whether the device is unavailable or captured. */
974 case USBDeviceState_USBDeviceCaptured:
975 if (!mIsStatePending)
976 return false;
977 /* fall thru */
978#endif
979 default:
980 isImportant = true;
981 }
982 LogFlowThisFunc (("%d -> %d\n",
983 mState, USBDeviceState_USBDeviceUnavailable));
984 mState = USBDeviceState_USBDeviceUnavailable;
985 return isImportant;
986
987 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
988 switch (mState)
989 {
990 case USBDeviceState_USBDeviceBusy:
991 return false;
992 /* the following state changes don't require any action for now */
993 case USBDeviceState_USBDeviceUnavailable:
994 case USBDeviceState_USBDeviceAvailable:
995 isImportant = false;
996 break;
997#ifndef __WIN__ /* Only Windows really knows whether the device is busy or captured. */
998 case USBDeviceState_USBDeviceCaptured:
999 if (!mIsStatePending)
1000 return false;
1001 /* fall thru */
1002#endif
1003 default:
1004 isImportant = true;
1005 }
1006 LogFlowThisFunc (("%d -> %d\n",
1007 mState, USBDeviceState_USBDeviceBusy));
1008 mState = USBDeviceState_USBDeviceBusy;
1009 return isImportant;
1010
1011 case USBDEVICESTATE_UNUSED:
1012 switch (mState)
1013 {
1014 case USBDeviceState_USBDeviceAvailable:
1015 return false;
1016#ifdef __LINUX__ /* Hack for /proc/bus/usb/devices not necessarily putting up a driver. */
1017 case USBDeviceState_USBDeviceCaptured:
1018 if (!mIsStatePending)
1019 return false;
1020 isImportant = true;
1021 break;
1022#endif
1023 /* the following state changes don't require any action for now */
1024 case USBDeviceState_USBDeviceUnavailable:
1025 case USBDeviceState_USBDeviceBusy:
1026 isImportant = false;
1027 break;
1028 default:
1029 isImportant = true;
1030 }
1031 LogFlowThisFunc (("%d -> %d\n",
1032 mState, USBDeviceState_USBDeviceAvailable));
1033 mState = USBDeviceState_USBDeviceAvailable;
1034 return isImportant;
1035
1036 case USBDEVICESTATE_HELD_BY_PROXY:
1037 switch (mState)
1038 {
1039 case USBDeviceState_USBDeviceHeld:
1040 return false;
1041#ifdef __WIN__
1042 case USBDeviceState_USBDeviceCaptured:
1043 if (!mIsStatePending)
1044 return false;
1045 /* no break */
1046#endif
1047 default:
1048 LogFlowThisFunc (("%d -> %d\n",
1049 mState, USBDeviceState_USBDeviceHeld));
1050 mState = USBDeviceState_USBDeviceHeld;
1051 return true;
1052 }
1053 break;
1054
1055 case USBDEVICESTATE_USED_BY_GUEST:
1056 /* @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
1057 * anywhere in the proxy code; it's quite logical because the
1058 * proxy doesn't know anything about guest VMs. */
1059 AssertFailed();
1060#if 0
1061 switch (mState)
1062 {
1063 case USBDeviceState_USBDeviceCaptured:
1064 /* the proxy may confuse following state(s) with captured */
1065 case USBDeviceState_USBDeviceHeld:
1066 case USBDeviceState_USBDeviceAvailable:
1067 case USBDeviceState_USBDeviceBusy:
1068 return false;
1069 default:
1070 LogFlowThisFunc (("%d -> %d\n",
1071 mState, USBDeviceState_USBDeviceHeld));
1072 mState = USBDeviceState_USBDeviceHeld;
1073 return true;
1074 }
1075#endif
1076 break;
1077 }
1078
1079 return false;
1080}
1081
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