VirtualBox

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

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

USBFILTER for darwin.

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