VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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