VirtualBox

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

Last change on this file since 3662 was 3566, checked in by vboxsync, 17 years ago

Async USB detach (for darwin) with async operation timeout (not enabled on windows). Drop the USBProxyService::reset method. (Hope I didn't break anything, it's only tested on Darwin...)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.2 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 mMachine.setNull();
790 mPendingStateEx = kNothingPending;
791 mIsStatePending = false;
792 break;
793
794 default:
795 AssertMsgFailed(("%d\n", mPendingStateEx));
796 break;
797 }
798}
799
800/**
801 * Returns true if this device matches the given filter data.
802 *
803 * @note It is assumed, that the filter data owner is appropriately
804 * locked before calling this method.
805 *
806 * @note
807 * This method MUST correlate with
808 * USBController::hasMatchingFilter (IUSBDevice *)
809 * in the sense of the device matching logic.
810 *
811 * @note Locks this object for reading.
812 */
813bool HostUSBDevice::isMatch (const USBDeviceFilter::Data &aData)
814{
815 AutoCaller autoCaller (this);
816 AssertComRCReturn (autoCaller.rc(), false);
817
818 AutoReaderLock alock (this);
819
820 if (!aData.mActive)
821 return false;
822
823 if (!aData.mVendorId.isMatch (mUsb->idVendor))
824 {
825 LogFlowThisFunc (("vendor not match %04X\n",
826 mUsb->idVendor));
827 return false;
828 }
829 if (!aData.mProductId.isMatch (mUsb->idProduct))
830 {
831 LogFlowThisFunc (("product id not match %04X\n",
832 mUsb->idProduct));
833 return false;
834 }
835 if (!aData.mRevision.isMatch (mUsb->bcdDevice))
836 {
837 LogFlowThisFunc (("rev not match %04X\n",
838 mUsb->bcdDevice));
839 return false;
840 }
841
842#if !defined (__WIN__)
843 // these filters are temporarily ignored on Win32
844 if (!aData.mManufacturer.isMatch (Bstr (mUsb->pszManufacturer)))
845 return false;
846 if (!aData.mProduct.isMatch (Bstr (mUsb->pszProduct)))
847 return false;
848 if (!aData.mSerialNumber.isMatch (Bstr (mUsb->pszSerialNumber)))
849 return false;
850 /// @todo (dmik) pusPort is yet absent
851// if (!aData.mPort.isMatch (Bstr (mUsb->pusPort)))
852// return false;
853#endif
854
855 // Host USB devices are local, so remote is always FALSE
856 if (!aData.mRemote.isMatch (FALSE))
857 {
858 LogFlowMember (("Host::HostUSBDevice: remote not match FALSE\n"));
859 return false;
860 }
861
862 /// @todo (dmik): bird, I assumed isMatch() is called only for devices
863 // that are suitable for holding/capturing (also assuming that when the device
864 // is just attached it first goes to our filter driver, and only after applying
865 // filters goes back to the system when appropriate). So the below
866 // doesn't look too correct; moreover, currently there is no determinable
867 // "any match" state for intervalic filters, and it will be not so easy
868 // to determine this state for an arbitrary regexp expression...
869 // For now, I just check that the string filter is empty (which doesn't
870 // actually reflect all possible "any match" filters).
871 //
872 // bird: This method was called for any device some weeks back, and it most certainly
873 // should be called for 'busy' devices still. However, we do *not* want 'busy' devices
874 // to match empty filters (because that will for instance capture all USB keyboards & mice).
875 // You assumption about a filter driver is not correct on linux. We're racing with
876 // everyone else in the system there - see your problem with usbfs access.
877 //
878 // The customer *requires* a way of matching all devices which the host isn't using,
879 // if that is now difficult or the below method opens holes in the matching, this *must*
880 // be addresses immediately.
881
882 /*
883 * If all the criteria is empty, devices which are used by the host will not match.
884 */
885 if ( mUsb->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
886 && aData.mVendorId.string().isEmpty()
887 && aData.mProductId.string().isEmpty()
888 && aData.mRevision.string().isEmpty()
889 && aData.mManufacturer.string().isEmpty()
890 && aData.mProduct.string().isEmpty()
891 && aData.mSerialNumber.string().isEmpty())
892 return false;
893
894 LogFlowThisFunc (("returns true\n"));
895 return true;
896}
897
898
899/**
900 * Compares this device with a USBDEVICE and decides which comes first.
901 *
902 * If the device has a pending state request, a non-strict comparison is made
903 * (to properly detect a re-attached device). Otherwise, a strict comparison
904 * is performed.
905 *
906 * @param aDev2 Device 2.
907 *
908 * @return < 0 if this should come before aDev2.
909 * @return 0 if this and aDev2 are equal.
910 * @return > 0 if this should come after aDev2.
911 *
912 * @note Must be called from under the object write lock.
913 */
914int HostUSBDevice::compare (PCUSBDEVICE aDev2)
915{
916 AssertReturn (isLockedOnCurrentThread(), -1);
917
918 return compare (mUsb, aDev2, !isStatePending());
919}
920
921/**
922 * Compares two USB devices and decides which comes first.
923 *
924 * If @a aIsStrict is @c true then the comparison will indicate a difference
925 * even if the same physical device (represented by @a aDev1) has been just
926 * re-attached to the host computer (represented by @a aDev2) and got a
927 * different address from the host OS, etc.
928 *
929 * If @a aIsStrict is @c false, then such a re-attached device will be
930 * considered equal to the previous device definition and this function will
931 * retrun 0.
932 *
933 * @param aDev1 Device 1.
934 * @param aDev2 Device 2.
935 * @param aIsStrict @c true to do a strict check and @c false otherwise.
936
937 * @return < 0 if aDev1 should come before aDev2.
938 * @return 0 if aDev1 and aDev2 are equal.
939 * @return > 0 if aDev1 should come after aDev2.
940 */
941/*static*/
942int HostUSBDevice::compare (PCUSBDEVICE aDev1, PCUSBDEVICE aDev2,
943 bool aIsStrict /* = true */)
944{
945 /* The non-strict checks tries as best as it can to distiguish between
946 different physical devices of the same product. Unfortunately this
947 isn't always possible and we might end up a bit confused in rare cases... */
948
949 int iDiff = aDev1->idVendor - aDev2->idVendor;
950 if (iDiff)
951 return iDiff;
952
953 iDiff = aDev1->idProduct - aDev2->idProduct;
954 if (iDiff)
955 return iDiff;
956
957 iDiff = aDev1->bcdDevice - aDev2->bcdDevice;
958 if (iDiff)
959 return iDiff;
960
961 if (aDev1->u64SerialHash != aDev2->u64SerialHash)
962 return aDev1->u64SerialHash < aDev2->u64SerialHash ? -1 : 1;
963
964 if (!aIsStrict)
965 return 0;
966
967 /* The rest is considered as a strict check since it includes bits that
968 may vary on logical reconnects (or whatever you wish to call it). */
969 return strcmp (aDev1->pszAddress, aDev2->pszAddress);
970}
971
972/**
973 * Updates the state of the device.
974 *
975 * If this method returns @c true, Host::onUSBDeviceStateChanged() will be
976 * called to process the state change (complete the state change request,
977 * inform the VM process etc.).
978 *
979 * If this method returns @c false, it is assumed that the given state change
980 * is "minor": it doesn't require any further action other than update the
981 * mState field with the actual state value.
982 *
983 * Regardless of the return value, this method always takes ownership of the
984 * new USBDEVICE structure passed in and updates the pNext and pPrev fiends in
985 * it using the values of the old structure.
986 *
987 * @param aDev The current device state as seen by the proxy backend.
988 *
989 * @return Whether the Host object should be bothered with this state change.
990 *
991 * @note Locks this object for writing.
992 */
993bool HostUSBDevice::updateState (PCUSBDEVICE aDev)
994{
995 LogFlowThisFunc (("\n"));
996
997 AssertReturn (isLockedOnCurrentThread(), false);
998
999 AutoCaller autoCaller (this);
1000 AssertComRCReturn (autoCaller.rc(), false);
1001
1002 AutoLock alock (this);
1003
1004 /* Replace the existing structure by the new one */
1005 if (mUsb != aDev)
1006 {
1007 aDev->pNext = mUsb->pNext;
1008 aDev->pPrev = mUsb->pPrev;
1009 USBProxyService::freeDevice (mUsb);
1010 mUsb = aDev;
1011 }
1012
1013 bool isImportant = false;
1014
1015 /*
1016 * We have to be pretty conservative here because the proxy backend
1017 * doesn't necessarily know everything that's going on. So, rather
1018 * be overly careful than changing the state once when we shouldn't!
1019 *
1020 * In particular, we treat changing between three states Unavailable, Busy
1021 * and Available as non-important (because they all mean that the device
1022 * is owned by the host) and return false in this case. We may want to
1023 * change it later and, e.g. re-run all USB filters when the device goes from
1024 * from Busy to Available).
1025 *
1026 * 2007-07-04: State transitions from Unavailable to Busy or Available
1027 * are now considered important and will cause filters to
1028 * be rerun on the device. (See #2030 and #1870.)
1029 */
1030
1031 LogFlowThisFunc (("aDev->enmState=%d mState=%d mPendingState=%d mPendingStateEx=%d\n",
1032 aDev->enmState, mState, mPendingState, mPendingStateEx));
1033
1034 switch (aDev->enmState)
1035 {
1036 default:
1037 AssertMsgFailed (("aDev->enmState=%d\n", aDev->enmState));
1038 case USBDEVICESTATE_UNSUPPORTED:
1039 Assert (mState == USBDeviceState_USBDeviceNotSupported);
1040 switch (mState)
1041 {
1042 case USBDeviceState_USBDeviceCaptured:
1043 isImportant = mIsStatePending;
1044 break;
1045 }
1046 return isImportant;
1047
1048 case USBDEVICESTATE_USED_BY_HOST:
1049 switch (mState)
1050 {
1051 case USBDeviceState_USBDeviceUnavailable:
1052 return false;
1053 /* the following state changes don't require any action for now */
1054 case USBDeviceState_USBDeviceBusy:
1055 case USBDeviceState_USBDeviceAvailable:
1056 isImportant = false;
1057 break;
1058#ifndef __WIN__ /* Only windows really knows whether the device is unavailable or captured. */
1059 case USBDeviceState_USBDeviceCaptured:
1060 if (!mIsStatePending)
1061 return false;
1062 /* fall thru */
1063#endif
1064 default:
1065 isImportant = true;
1066 }
1067 LogFlowThisFunc (("%d -> %d\n",
1068 mState, USBDeviceState_USBDeviceUnavailable));
1069 mState = USBDeviceState_USBDeviceUnavailable;
1070 return isImportant;
1071
1072 case USBDEVICESTATE_USED_BY_HOST_CAPTURABLE:
1073 switch (mState)
1074 {
1075 case USBDeviceState_USBDeviceBusy:
1076 return false;
1077 case USBDeviceState_USBDeviceAvailable:
1078 isImportant = false;
1079 break;
1080 case USBDeviceState_USBDeviceCaptured:
1081#ifndef __WIN__ /* Only Windows really knows whether the device is busy or captured. */
1082 if (!mIsStatePending)
1083 return false;
1084#endif
1085 /* Remain in the captured state if it's an async detach. */
1086 if (mPendingStateEx != kNothingPending)
1087 {
1088 LogFlowThisFunc (("USBDeviceCaptured - async detach completed (%d)\n", mPendingStateEx));
1089 return true;
1090 }
1091 /* fall thru */
1092 default:
1093 /* USBDeviceState_USBDeviceUnavailable: The device has become capturable, re-run filters. */
1094 /* USBDeviceState_USBDeviceHeld: Pending request. */
1095 /* USBDeviceState_USBDeviceCaptured: Pending request. */
1096 /* USBDeviceState_USBDeviceNotSupported: Something is broken. */
1097 isImportant = true;
1098 }
1099 LogFlowThisFunc (("%d -> %d\n",
1100 mState, USBDeviceState_USBDeviceBusy));
1101 mState = USBDeviceState_USBDeviceBusy;
1102 return isImportant;
1103
1104 case USBDEVICESTATE_UNUSED:
1105 switch (mState)
1106 {
1107 case USBDeviceState_USBDeviceAvailable:
1108 return false;
1109#ifdef __LINUX__ /* Hack for /proc/bus/usb/devices not necessarily putting up a driver. */
1110 case USBDeviceState_USBDeviceCaptured:
1111 if (!mIsStatePending)
1112 return false;
1113 isImportant = true;
1114 break;
1115#endif
1116 /* the following state changes don't require any action for now */
1117 case USBDeviceState_USBDeviceBusy:
1118 isImportant = false;
1119 break;
1120 default:
1121 /* USBDeviceState_USBDeviceUnavailable: The device has become available, re-run filters. */
1122 /* USBDeviceState_USBDeviceHeld: Pending request. */
1123 /* USBDeviceState_USBDeviceNotSupported: Something is broken. */
1124 isImportant = true;
1125 }
1126 LogFlowThisFunc (("%d -> %d\n",
1127 mState, USBDeviceState_USBDeviceAvailable));
1128 mState = USBDeviceState_USBDeviceAvailable;
1129 return isImportant;
1130
1131 case USBDEVICESTATE_HELD_BY_PROXY:
1132 switch (mState)
1133 {
1134 case USBDeviceState_USBDeviceHeld:
1135 return false;
1136#ifdef __WIN__
1137 case USBDeviceState_USBDeviceCaptured:
1138 if (!mIsStatePending)
1139 return false;
1140 /* no break */
1141#endif
1142 default:
1143 LogFlowThisFunc (("%d -> %d\n",
1144 mState, USBDeviceState_USBDeviceHeld));
1145 mState = USBDeviceState_USBDeviceHeld;
1146 return true;
1147 }
1148 break;
1149
1150 case USBDEVICESTATE_USED_BY_GUEST:
1151 /** @todo USBDEVICESTATE_USED_BY_GUEST seems not to be used
1152 * anywhere in the proxy code; it's quite logical because the
1153 * proxy doesn't know anything about guest VMs. */
1154 AssertFailed();
1155#if 0
1156 switch (mState)
1157 {
1158 case USBDeviceState_USBDeviceCaptured:
1159 /* the proxy may confuse following state(s) with captured */
1160 case USBDeviceState_USBDeviceHeld:
1161 case USBDeviceState_USBDeviceAvailable:
1162 case USBDeviceState_USBDeviceBusy:
1163 return false;
1164 default:
1165 LogFlowThisFunc (("%d -> %d\n",
1166 mState, USBDeviceState_USBDeviceHeld));
1167 mState = USBDeviceState_USBDeviceHeld;
1168 return true;
1169 }
1170#endif
1171 break;
1172 }
1173
1174 return false;
1175}
1176
1177/**
1178 * Checks for timeout of any pending async operation.
1179 *
1180 * The caller must write lock the object prior to calling
1181 * this method.
1182 */
1183void HostUSBDevice::checkForAsyncTimeout()
1184{
1185 AssertReturnVoid (isLockedOnCurrentThread());
1186
1187#ifndef __WIN__ /* no timeouts on windows yet since I don't have all the details here... */
1188 if (isStatePending() && mPendingSince)
1189 {
1190 uint64_t elapsedNanoseconds = RTTimeNanoTS() - mPendingSince;
1191 if (elapsedNanoseconds > UINT64_C (60000000000) ) /* 60 seconds */
1192 {
1193 LogRel (("USB: Async operation timed out; mPendingState=%d mPendingStateEx=%d idVendor=%04x (%s) idProduct=%04x (%s) bcdDevice=%04x\n",
1194 mPendingState, mPendingStateEx, mUsb->idVendor, mUsb->pszManufacturer, mUsb->idProduct, mUsb->pszProduct, mUsb->bcdDevice));
1195
1196 cancelPendingState (true);
1197 }
1198 }
1199#endif
1200}
1201
1202/**
1203 * This method is called by the USB proxy and Host to work the
1204 * logical reconnection operation.
1205 *
1206 * @param aStage kDeatchingPendingDetach, kDeatchingPendingDetachFilters,
1207 * kDetachingPendingAttach or kDetachingPendingAttachFilters.
1208 *
1209 * @returns Success indicator.
1210 */
1211bool HostUSBDevice::setLogicalReconnect (InternalState aStage)
1212{
1213 AssertReturn (isLockedOnCurrentThread(), false);
1214
1215 switch (aStage)
1216 {
1217 case kDetachingPendingDetach:
1218 AssertReturn (!mIsStatePending, false);
1219 mPendingState = mState;
1220 mIsStatePending = true;
1221 mPendingSince = RTTimeNanoTS();
1222 break;
1223
1224 case kDetachingPendingDetachFilters:
1225 AssertReturn (mIsStatePending, false);
1226 AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
1227 break;
1228
1229 case kDetachingPendingAttach:
1230 AssertReturn (mIsStatePending, false);
1231 AssertReturn (mPendingStateEx == kDetachingPendingDetach, false);
1232 break;
1233
1234 case kDetachingPendingAttachFilters:
1235 AssertReturn (mIsStatePending, false);
1236 AssertReturn ( mPendingStateEx == kDetachingPendingAttach
1237 || mPendingStateEx == kDetachingPendingDetachFilters, false);
1238 break;
1239
1240 default:
1241 AssertFailedReturn (false);
1242 }
1243 mPendingStateEx = aStage;
1244 return true;
1245}
1246
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