VirtualBox

source: vbox/trunk/src/VBox/Main/USBControllerImpl.cpp@ 3467

Last change on this file since 3467 was 3421, checked in by vboxsync, 17 years ago

Main: Fixed an assertion when closing the direct machine session after changing machine controller properties but w/o saving them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.4 KB
Line 
1/** @file
2 *
3 * Implementation of IUSBController.
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
23
24#include "USBControllerImpl.h"
25#include "MachineImpl.h"
26#include "VirtualBoxImpl.h"
27#include "HostImpl.h"
28#include "USBDeviceImpl.h"
29#include "HostUSBDeviceImpl.h"
30#include "Logging.h"
31
32#include "USBProxyService.h"
33
34#include <iprt/string.h>
35#include <iprt/cpputils.h>
36#include <VBox/err.h>
37
38#include <algorithm>
39
40// defines
41/////////////////////////////////////////////////////////////////////////////
42
43// constructor / destructor
44/////////////////////////////////////////////////////////////////////////////
45
46DEFINE_EMPTY_CTOR_DTOR (USBController)
47
48HRESULT USBController::FinalConstruct()
49{
50 return S_OK;
51}
52
53void USBController::FinalRelease()
54{
55 uninit();
56}
57
58// public initializer/uninitializer for internal purposes only
59/////////////////////////////////////////////////////////////////////////////
60
61/**
62 * Initializes the USB controller object.
63 *
64 * @returns COM result indicator.
65 * @param aParent Pointer to our parent object.
66 */
67HRESULT USBController::init (Machine *aParent)
68{
69 LogFlowThisFunc (("aParent=%p\n", aParent));
70
71 ComAssertRet (aParent, E_INVALIDARG);
72
73 /* Enclose the state transition NotReady->InInit->Ready */
74 AutoInitSpan autoInitSpan (this);
75 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
76
77 unconst (mParent) = aParent;
78 /* mPeer is left null */
79
80 mData.allocate();
81 mDeviceFilters.allocate();
82
83 /* Confirm a successful initialization */
84 autoInitSpan.setSucceeded();
85
86 return S_OK;
87}
88
89
90/**
91 * Initializes the USB controller object given another USB controller object
92 * (a kind of copy constructor). This object shares data with
93 * the object passed as an argument.
94 *
95 * @returns COM result indicator.
96 * @param aParent Pointer to our parent object.
97 * @param aPeer The object to share.
98 *
99 * @note This object must be destroyed before the original object
100 * it shares data with is destroyed.
101 */
102HRESULT USBController::init (Machine *aParent, USBController *aPeer)
103{
104 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
105
106 ComAssertRet (aParent && aPeer, E_INVALIDARG);
107
108 /* Enclose the state transition NotReady->InInit->Ready */
109 AutoInitSpan autoInitSpan (this);
110 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
111
112 unconst (mParent) = aParent;
113 unconst (mPeer) = aPeer;
114
115 AutoLock thatlock (aPeer);
116 mData.share (aPeer->mData);
117
118 /* create copies of all filters */
119 mDeviceFilters.allocate();
120 DeviceFilterList::const_iterator it = aPeer->mDeviceFilters->begin();
121 while (it != aPeer->mDeviceFilters->end())
122 {
123 ComObjPtr <USBDeviceFilter> filter;
124 filter.createObject();
125 filter->init (this, *it);
126 mDeviceFilters->push_back (filter);
127 ++ it;
128 }
129
130 /* Confirm a successful initialization */
131 autoInitSpan.setSucceeded();
132
133 return S_OK;
134}
135
136
137/**
138 * Initializes the USB controller object given another guest object
139 * (a kind of copy constructor). This object makes a private copy of data
140 * of the original object passed as an argument.
141 */
142HRESULT USBController::initCopy (Machine *aParent, USBController *aPeer)
143{
144 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
145
146 ComAssertRet (aParent && aPeer, E_INVALIDARG);
147
148 /* Enclose the state transition NotReady->InInit->Ready */
149 AutoInitSpan autoInitSpan (this);
150 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
151
152 unconst (mParent) = aParent;
153 /* mPeer is left null */
154
155 AutoLock thatlock (aPeer);
156 mData.attachCopy (aPeer->mData);
157
158 /* create private copies of all filters */
159 mDeviceFilters.allocate();
160 DeviceFilterList::const_iterator it = aPeer->mDeviceFilters->begin();
161 while (it != aPeer->mDeviceFilters->end())
162 {
163 ComObjPtr <USBDeviceFilter> filter;
164 filter.createObject();
165 filter->initCopy (this, *it);
166 mDeviceFilters->push_back (filter);
167 ++ it;
168 }
169
170 /* Confirm a successful initialization */
171 autoInitSpan.setSucceeded();
172
173 return S_OK;
174}
175
176
177/**
178 * Uninitializes the instance and sets the ready flag to FALSE.
179 * Called either from FinalRelease() or by the parent when it gets destroyed.
180 */
181void USBController::uninit()
182{
183 LogFlowThisFunc (("\n"));
184
185 /* Enclose the state transition Ready->InUninit->NotReady */
186 AutoUninitSpan autoUninitSpan (this);
187 if (autoUninitSpan.uninitDone())
188 return;
189
190 /* uninit all filters (including those still referenced by clients) */
191 uninitDependentChildren();
192
193 mDeviceFilters.free();
194 mData.free();
195
196 unconst (mPeer).setNull();
197 unconst (mParent).setNull();
198}
199
200
201// IUSBController properties
202/////////////////////////////////////////////////////////////////////////////
203
204STDMETHODIMP USBController::COMGETTER(Enabled) (BOOL *aEnabled)
205{
206 if (!aEnabled)
207 return E_POINTER;
208
209 AutoCaller autoCaller (this);
210 CheckComRCReturnRC (autoCaller.rc());
211
212 AutoReaderLock alock (this);
213
214 *aEnabled = mData->mEnabled;
215
216 LogFlowThisFunc (("returns %RTbool\n", *aEnabled));
217
218 return S_OK;
219}
220
221
222STDMETHODIMP USBController::COMSETTER(Enabled) (BOOL aEnabled)
223{
224 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
225
226 AutoCaller autoCaller (this);
227 CheckComRCReturnRC (autoCaller.rc());
228
229 /* the machine needs to be mutable */
230 Machine::AutoMutableStateDependency adep (mParent);
231 CheckComRCReturnRC (adep.rc());
232
233 AutoLock alock (this);
234
235 if (mData->mEnabled != aEnabled)
236 {
237 mData.backup();
238 mData->mEnabled = aEnabled;
239
240 /* leave the lock for safety */
241 alock.leave();
242
243 mParent->onUSBControllerChange();
244 }
245
246 return S_OK;
247}
248
249STDMETHODIMP USBController::COMGETTER(USBStandard) (USHORT *aUSBStandard)
250{
251 if (!aUSBStandard)
252 return E_POINTER;
253
254 AutoCaller autoCaller (this);
255 CheckComRCReturnRC (autoCaller.rc());
256
257 /* not accessing data -- no need to lock */
258
259 *aUSBStandard = 0x0101;
260
261 LogFlowThisFunc (("returns %04hX\n", *aUSBStandard));
262
263 return S_OK;
264}
265
266STDMETHODIMP USBController::COMGETTER(DeviceFilters) (IUSBDeviceFilterCollection **aDevicesFilters)
267{
268 if (!aDevicesFilters)
269 return E_POINTER;
270
271 AutoCaller autoCaller (this);
272 CheckComRCReturnRC (autoCaller.rc());
273
274 AutoReaderLock alock (this);
275
276 ComObjPtr <USBDeviceFilterCollection> collection;
277 collection.createObject();
278 collection->init (*mDeviceFilters.data());
279 collection.queryInterfaceTo (aDevicesFilters);
280
281 return S_OK;
282}
283
284// IUSBController methods
285/////////////////////////////////////////////////////////////////////////////
286
287STDMETHODIMP USBController::CreateDeviceFilter (INPTR BSTR aName,
288 IUSBDeviceFilter **aFilter)
289{
290 if (!aFilter)
291 return E_POINTER;
292
293 if (!aName || *aName == 0)
294 return E_INVALIDARG;
295
296 AutoCaller autoCaller (this);
297 CheckComRCReturnRC (autoCaller.rc());
298
299 /* the machine needs to be mutable */
300 Machine::AutoMutableStateDependency adep (mParent);
301 CheckComRCReturnRC (adep.rc());
302
303 AutoLock alock (this);
304
305 ComObjPtr <USBDeviceFilter> filter;
306 filter.createObject();
307 HRESULT rc = filter->init (this, aName);
308 ComAssertComRCRetRC (rc);
309 rc = filter.queryInterfaceTo (aFilter);
310 AssertComRCReturnRC (rc);
311
312 return S_OK;
313}
314
315STDMETHODIMP USBController::InsertDeviceFilter (ULONG aPosition,
316 IUSBDeviceFilter *aFilter)
317{
318 if (!aFilter)
319 return E_INVALIDARG;
320
321 AutoCaller autoCaller (this);
322 CheckComRCReturnRC (autoCaller.rc());
323
324 /* the machine needs to be mutable */
325 Machine::AutoMutableStateDependency adep (mParent);
326 CheckComRCReturnRC (adep.rc());
327
328 AutoLock alock (this);
329
330 ComObjPtr <USBDeviceFilter> filter = getDependentChild (aFilter);
331 if (!filter)
332 return setError (E_INVALIDARG,
333 tr ("The given USB device filter is not created within "
334 "this VirtualBox instance"));
335
336 if (filter->mInList)
337 return setError (E_INVALIDARG,
338 tr ("The given USB device filter is already in the list"));
339
340 /* backup the list before modification */
341 mDeviceFilters.backup();
342
343 /* iterate to the position... */
344 DeviceFilterList::iterator it;
345 if (aPosition < mDeviceFilters->size())
346 {
347 it = mDeviceFilters->begin();
348 std::advance (it, aPosition);
349 }
350 else
351 it = mDeviceFilters->end();
352 /* ...and insert */
353 mDeviceFilters->insert (it, filter);
354 filter->mInList = true;
355
356 /// @todo After rewriting Win32 USB support, no more necessary;
357 // a candidate for removal.
358#if 0
359 /* notify the proxy (only when the filter is active) */
360 if (filter->data().mActive)
361#else
362 /* notify the proxy (only when it makes sense) */
363 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
364#endif
365 {
366 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
367 ComAssertRet (service, E_FAIL);
368
369 ComAssertRet (filter->id() == NULL, E_FAIL);
370 filter->id() = service->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
371 }
372
373 return S_OK;
374}
375
376STDMETHODIMP USBController::RemoveDeviceFilter (ULONG aPosition,
377 IUSBDeviceFilter **aFilter)
378{
379 if (!aFilter)
380 return E_POINTER;
381
382 AutoCaller autoCaller (this);
383 CheckComRCReturnRC (autoCaller.rc());
384
385 /* the machine needs to be mutable */
386 Machine::AutoMutableStateDependency adep (mParent);
387 CheckComRCReturnRC (adep.rc());
388
389 AutoLock alock (this);
390
391 if (!mDeviceFilters->size())
392 return setError (E_INVALIDARG,
393 tr ("The USB device filter list is empty"));
394
395 if (aPosition >= mDeviceFilters->size())
396 return setError (E_INVALIDARG,
397 tr ("Invalid position: %lu (must be in range [0, %lu])"),
398 aPosition, mDeviceFilters->size() - 1);
399
400 /* backup the list before modification */
401 mDeviceFilters.backup();
402
403 ComObjPtr <USBDeviceFilter> filter;
404 {
405 /* iterate to the position... */
406 DeviceFilterList::iterator it = mDeviceFilters->begin();
407 std::advance (it, aPosition);
408 /* ...get an element from there... */
409 filter = *it;
410 /* ...and remove */
411 filter->mInList = false;
412 mDeviceFilters->erase (it);
413 }
414
415 /* cancel sharing (make an independent copy of data) */
416 filter->unshare();
417
418 filter.queryInterfaceTo (aFilter);
419
420 /// @todo After rewriting Win32 USB support, no more necessary;
421 // a candidate for removal.
422#if 0
423 /* notify the proxy (only when the filter is active) */
424 if (filter->data().mActive)
425#else
426 /* notify the proxy (only when it makes sense) */
427 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
428#endif
429 {
430 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
431 ComAssertRet (service, E_FAIL);
432
433 ComAssertRet (filter->id() != NULL, E_FAIL);
434 service->removeFilter (filter->id());
435 filter->id() = NULL;
436 }
437
438 return S_OK;
439}
440
441// public methods only for internal purposes
442/////////////////////////////////////////////////////////////////////////////
443
444/**
445 * Loads settings from the configuration node.
446 *
447 * @note Locks objects for writing!
448 */
449HRESULT USBController::loadSettings (CFGNODE aMachine)
450{
451 AssertReturn (aMachine, E_FAIL);
452
453 AutoCaller autoCaller (this);
454 AssertComRCReturnRC (autoCaller.rc());
455
456 AutoLock alock (this);
457
458 CFGNODE controller = NULL;
459 CFGLDRGetChildNode (aMachine, "USBController", 0, &controller);
460 Assert (controller);
461
462 /* enabled */
463 bool enabled;
464 CFGLDRQueryBool (controller, "enabled", &enabled);
465 mData->mEnabled = enabled;
466
467 HRESULT rc = S_OK;
468
469 unsigned filterCount = 0;
470 CFGLDRCountChildren (controller, "DeviceFilter", &filterCount);
471 for (unsigned i = 0; i < filterCount && SUCCEEDED (rc); i++)
472 {
473 CFGNODE filter = NULL;
474 CFGLDRGetChildNode (controller, "DeviceFilter", i, &filter);
475 Assert (filter);
476
477 Bstr name;
478 CFGLDRQueryBSTR (filter, "name", name.asOutParam());
479 bool active;
480 CFGLDRQueryBool (filter, "active", &active);
481
482 Bstr vendorId;
483 CFGLDRQueryBSTR (filter, "vendorid", vendorId.asOutParam());
484 Bstr productId;
485 CFGLDRQueryBSTR (filter, "productid", productId.asOutParam());
486 Bstr revision;
487 CFGLDRQueryBSTR (filter, "revision", revision.asOutParam());
488 Bstr manufacturer;
489 CFGLDRQueryBSTR (filter, "manufacturer", manufacturer.asOutParam());
490 Bstr product;
491 CFGLDRQueryBSTR (filter, "product", product.asOutParam());
492 Bstr serialNumber;
493 CFGLDRQueryBSTR (filter, "serialnumber", serialNumber.asOutParam());
494 Bstr port;
495 CFGLDRQueryBSTR (filter, "port", port.asOutParam());
496 Bstr remote;
497 CFGLDRQueryBSTR (filter, "remote", remote.asOutParam());
498
499 ComObjPtr <USBDeviceFilter> filterObj;
500 filterObj.createObject();
501 rc = filterObj->init (this,
502 name, active, vendorId, productId, revision,
503 manufacturer, product, serialNumber,
504 port, remote);
505 /* error info is set by init() when appropriate */
506 if (SUCCEEDED (rc))
507 {
508 mDeviceFilters->push_back (filterObj);
509 filterObj->mInList = true;
510 }
511
512 CFGLDRReleaseNode (filter);
513 }
514
515 CFGLDRReleaseNode (controller);
516
517 return rc;
518}
519
520/**
521 * Saves settings to the configuration node.
522 *
523 * @note Locks objects for reading!
524 */
525HRESULT USBController::saveSettings (CFGNODE aMachine)
526{
527 AssertReturn (aMachine, E_FAIL);
528
529 AutoCaller autoCaller (this);
530 CheckComRCReturnRC (autoCaller.rc());
531
532 AutoReaderLock alock (this);
533
534 /* first, delete the entry */
535 CFGNODE controller = NULL;
536 int vrc = CFGLDRGetChildNode (aMachine, "USBController", 0, &controller);
537 if (VBOX_SUCCESS (vrc))
538 {
539 vrc = CFGLDRDeleteNode (controller);
540 ComAssertRCRet (vrc, E_FAIL);
541 }
542 /* then, recreate it */
543 vrc = CFGLDRCreateChildNode (aMachine, "USBController", &controller);
544 ComAssertRCRet (vrc, E_FAIL);
545
546 /* enabled */
547 CFGLDRSetBool (controller, "enabled", !!mData->mEnabled);
548
549 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
550 while (it != mDeviceFilters->end())
551 {
552 AutoLock filterLock (*it);
553 const USBDeviceFilter::Data &data = (*it)->data();
554
555 CFGNODE filter = NULL;
556 CFGLDRAppendChildNode (controller, "DeviceFilter", &filter);
557
558 CFGLDRSetBSTR (filter, "name", data.mName);
559 CFGLDRSetBool (filter, "active", !!data.mActive);
560
561 /* all are optional */
562 if (data.mVendorId.string())
563 CFGLDRSetBSTR (filter, "vendorid", data.mVendorId.string());
564 if (data.mProductId.string())
565 CFGLDRSetBSTR (filter, "productid", data.mProductId.string());
566 if (data.mRevision.string())
567 CFGLDRSetBSTR (filter, "revision", data.mRevision.string());
568 if (data.mManufacturer.string())
569 CFGLDRSetBSTR (filter, "manufacturer", data.mManufacturer.string());
570 if (data.mProduct.string())
571 CFGLDRSetBSTR (filter, "product", data.mProduct.string());
572 if (data.mSerialNumber.string())
573 CFGLDRSetBSTR (filter, "serialnumber", data.mSerialNumber.string());
574 if (data.mPort.string())
575 CFGLDRSetBSTR (filter, "port", data.mPort.string());
576 if (data.mRemote.string())
577 CFGLDRSetBSTR (filter, "remote", data.mRemote.string());
578
579 CFGLDRReleaseNode (filter);
580
581 ++ it;
582 }
583
584 CFGLDRReleaseNode (controller);
585
586 return S_OK;
587}
588
589/** @note Locks objects for reading! */
590bool USBController::isModified()
591{
592 AutoCaller autoCaller (this);
593 AssertComRCReturn (autoCaller.rc(), false);
594
595 AutoReaderLock alock (this);
596
597 if (mData.isBackedUp() || mDeviceFilters.isBackedUp())
598 return true;
599
600 /* see whether any of filters has changed its data */
601 for (DeviceFilterList::const_iterator
602 it = mDeviceFilters->begin();
603 it != mDeviceFilters->end();
604 ++ it)
605 {
606 if ((*it)->isModified())
607 return true;
608 }
609
610 return false;
611}
612
613/** @note Locks objects for reading! */
614bool USBController::isReallyModified()
615{
616 AutoCaller autoCaller (this);
617 AssertComRCReturn (autoCaller.rc(), false);
618
619 AutoReaderLock alock (this);
620
621 if (mData.hasActualChanges())
622 return true;
623
624 if (!mDeviceFilters.isBackedUp())
625 {
626 /* see whether any of filters has changed its data */
627 for (DeviceFilterList::const_iterator
628 it = mDeviceFilters->begin();
629 it != mDeviceFilters->end();
630 ++ it)
631 {
632 if ((*it)->isReallyModified())
633 return true;
634 }
635
636 return false;
637 }
638
639 if (mDeviceFilters->size() != mDeviceFilters.backedUpData()->size())
640 return true;
641
642 if (mDeviceFilters->size() == 0)
643 return false;
644
645 /* Make copies to speed up comparison */
646 DeviceFilterList devices = *mDeviceFilters.data();
647 DeviceFilterList backDevices = *mDeviceFilters.backedUpData();
648
649 DeviceFilterList::iterator it = devices.begin();
650 while (it != devices.end())
651 {
652 bool found = false;
653 DeviceFilterList::iterator thatIt = backDevices.begin();
654 while (thatIt != backDevices.end())
655 {
656 if ((*it)->data() == (*thatIt)->data())
657 {
658 backDevices.erase (thatIt);
659 found = true;
660 break;
661 }
662 else
663 ++ thatIt;
664 }
665 if (found)
666 it = devices.erase (it);
667 else
668 return false;
669 }
670
671 Assert (devices.size() == 0 && backDevices.size() == 0);
672
673 return false;
674}
675
676/** @note Locks objects for writing! */
677bool USBController::rollback()
678{
679 AutoCaller autoCaller (this);
680 AssertComRCReturn (autoCaller.rc(), false);
681
682 /* we need the machine state */
683 Machine::AutoAnyStateDependency adep (mParent);
684 AssertComRCReturn (adep.rc(), false);
685
686 AutoLock alock (this);
687
688 bool dataChanged = false;
689
690 if (mData.isBackedUp())
691 {
692 /* we need to check all data to see whether anything will be changed
693 * after rollback */
694 dataChanged = mData.hasActualChanges();
695 mData.rollback();
696 }
697
698 if (mDeviceFilters.isBackedUp())
699 {
700 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
701 ComAssertRet (service, false);
702
703 /* uninitialize all new filters (absent in the backed up list) */
704 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
705 DeviceFilterList *backedList = mDeviceFilters.backedUpData();
706 while (it != mDeviceFilters->end())
707 {
708 if (std::find (backedList->begin(), backedList->end(), *it) ==
709 backedList->end())
710 {
711 /// @todo After rewriting Win32 USB support, no more necessary;
712 // a candidate for removal.
713#if 0
714 /* notify the proxy (only when the filter is active) */
715 if ((*it)->data().mActive)
716#else
717 /* notify the proxy (only when it makes sense) */
718 if ((*it)->data().mActive &&
719 adep.machineState() >= MachineState_Running)
720#endif
721 {
722 USBDeviceFilter *filter = *it;
723 ComAssertRet (filter->id() != NULL, false);
724 service->removeFilter (filter->id());
725 filter->id() = NULL;
726 }
727
728 (*it)->uninit();
729 }
730 ++ it;
731 }
732
733 /// @todo After rewriting Win32 USB support, no more necessary;
734 // a candidate for removal.
735#if 0
736#else
737 if (adep.machineState() >= MachineState_Running)
738#endif
739 {
740 /* find all removed old filters (absent in the new list)
741 * and insert them back to the USB proxy */
742 it = backedList->begin();
743 while (it != backedList->end())
744 {
745 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
746 mDeviceFilters->end())
747 {
748 /* notify the proxy (only when necessary) */
749 if ((*it)->data().mActive)
750 {
751 USBDeviceFilter *flt = *it; /* resolve ambiguity */
752 ComAssertRet (flt->id() == NULL, false);
753 flt->id() = service->insertFilter
754 (ComPtr <IUSBDeviceFilter> (flt));
755 }
756 }
757 ++ it;
758 }
759 }
760
761 /* restore the list */
762 mDeviceFilters.rollback();
763 }
764
765 /* here we don't depend on the machine state any more */
766 adep.release();
767
768 /* rollback any changes to filters after restoring the list */
769 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
770 while (it != mDeviceFilters->end())
771 {
772 if ((*it)->isModified())
773 {
774 (*it)->rollback();
775 /* call this to notify the USB proxy about changes */
776 onDeviceFilterChange (*it);
777 }
778 ++ it;
779 }
780
781 return dataChanged;
782}
783
784/** @note Locks objects for writing! */
785void USBController::commit()
786{
787 AutoCaller autoCaller (this);
788 AssertComRCReturnVoid (autoCaller.rc());
789
790 AutoLock alock (this);
791
792 if (mData.isBackedUp())
793 {
794 mData.commit();
795 if (mPeer)
796 {
797 // attach new data to the peer and reshare it
798 AutoLock peerlock (mPeer);
799 mPeer->mData.attach (mData);
800 }
801 }
802
803 bool commitFilters = false;
804
805 if (mDeviceFilters.isBackedUp())
806 {
807 mDeviceFilters.commit();
808
809 // apply changes to peer
810 if (mPeer)
811 {
812 AutoLock peerlock (mPeer);
813 // commit all changes to new filters (this will reshare data with
814 // peers for those who have peers)
815 DeviceFilterList *newList = new DeviceFilterList();
816 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
817 while (it != mDeviceFilters->end())
818 {
819 (*it)->commit();
820
821 // look if this filter has a peer filter
822 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
823 if (!peer)
824 {
825 // no peer means the filter is a newly created one;
826 // create a peer owning data this filter share it with
827 peer.createObject();
828 peer->init (mPeer, *it, true /* aReshare */);
829 }
830 else
831 {
832 // remove peer from the old list
833 mPeer->mDeviceFilters->remove (peer);
834 }
835 // and add it to the new list
836 newList->push_back (peer);
837
838 ++ it;
839 }
840
841 // uninit old peer's filters that are left
842 it = mPeer->mDeviceFilters->begin();
843 while (it != mPeer->mDeviceFilters->end())
844 {
845 (*it)->uninit();
846 ++ it;
847 }
848
849 // attach new list of filters to our peer
850 mPeer->mDeviceFilters.attach (newList);
851 }
852 else
853 {
854 // we have no peer (our parent is the newly created machine);
855 // just commit changes to filters
856 commitFilters = true;
857 }
858 }
859 else
860 {
861 // the list of filters itself is not changed,
862 // just commit changes to filters themselves
863 commitFilters = true;
864 }
865
866 if (commitFilters)
867 {
868 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
869 while (it != mDeviceFilters->end())
870 {
871 (*it)->commit();
872 ++ it;
873 }
874 }
875}
876
877/** @note Locks object for writing and that object for reading! */
878void USBController::copyFrom (USBController *aThat)
879{
880 AutoCaller autoCaller (this);
881 AssertComRCReturnVoid (autoCaller.rc());
882
883 AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
884
885 if (mParent->isRegistered())
886 {
887 /* reuse onMachineRegistered to tell USB proxy to remove all current
888 filters */
889 HRESULT rc = onMachineRegistered (FALSE);
890 AssertComRCReturn (rc, (void) 0);
891 }
892
893 /* this will back up current data */
894 mData.assignCopy (aThat->mData);
895
896 /* create private copies of all filters */
897 mDeviceFilters.backup();
898 mDeviceFilters->clear();
899 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
900 it != aThat->mDeviceFilters->end();
901 ++ it)
902 {
903 ComObjPtr <USBDeviceFilter> filter;
904 filter.createObject();
905 filter->initCopy (this, *it);
906 mDeviceFilters->push_back (filter);
907 }
908
909 if (mParent->isRegistered())
910 {
911 /* reuse onMachineRegistered to tell USB proxy to insert all current
912 filters */
913 HRESULT rc = onMachineRegistered (TRUE);
914 AssertComRCReturn (rc, (void) 0);
915 }
916}
917
918/**
919 * Called by VirtualBox when it changes the registered state
920 * of the machine this USB controller belongs to.
921 *
922 * @param aRegistered new registered state of the machine
923 *
924 * @note Locks nothing.
925 */
926HRESULT USBController::onMachineRegistered (BOOL aRegistered)
927{
928 AutoCaller autoCaller (this);
929 AssertComRCReturnRC (autoCaller.rc());
930
931 /// @todo After rewriting Win32 USB support, no more necessary;
932 // a candidate for removal.
933#if 0
934 notifyProxy (!!aRegistered);
935#endif
936
937 return S_OK;
938}
939
940/**
941 * Called by setter methods of all USB device filters.
942 *
943 * @note Locks nothing.
944 */
945HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
946 BOOL aActiveChanged /* = FALSE */)
947{
948 AutoCaller autoCaller (this);
949 AssertComRCReturnRC (autoCaller.rc());
950
951 /// @todo After rewriting Win32 USB support, no more necessary;
952 // a candidate for removal.
953#if 0
954#else
955 /* we need the machine state */
956 Machine::AutoAnyStateDependency adep (mParent);
957 AssertComRCReturnRC (adep.rc());
958
959 /* nothing to do if the machine isn't running */
960 if (adep.machineState() < MachineState_Running)
961 return S_OK;
962#endif
963
964 /* we don't modify our data fields -- no need to lock */
965
966 if (aFilter->mInList && mParent->isRegistered())
967 {
968 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
969 ComAssertRet (service, E_FAIL);
970
971 if (aActiveChanged)
972 {
973 /* insert/remove the filter from the proxy */
974 if (aFilter->data().mActive)
975 {
976 ComAssertRet (aFilter->id() == NULL, E_FAIL);
977 aFilter->id() = service->insertFilter
978 (ComPtr <IUSBDeviceFilter> (aFilter));
979 }
980 else
981 {
982 ComAssertRet (aFilter->id() != NULL, E_FAIL);
983 service->removeFilter (aFilter->id());
984 aFilter->id() = NULL;
985 }
986 }
987 else
988 {
989 if (aFilter->data().mActive)
990 {
991 /* update the filter in the proxy */
992 ComAssertRet (aFilter->id() != NULL, E_FAIL);
993 service->removeFilter (aFilter->id());
994 aFilter->id() = service->insertFilter
995 (ComPtr <IUSBDeviceFilter> (aFilter));
996 }
997 }
998 }
999
1000 return S_OK;
1001}
1002
1003/**
1004 * Returns true if the given USB device matches to at least one of
1005 * this controller's USB device filters.
1006 *
1007 * A HostUSBDevice specific version.
1008 *
1009 * @note Locks this object for reading.
1010 */
1011bool USBController::hasMatchingFilter (ComObjPtr <HostUSBDevice> &aDevice)
1012{
1013 AutoCaller autoCaller (this);
1014 AssertComRCReturn (autoCaller.rc(), false);
1015
1016 AutoReaderLock alock (this);
1017
1018 /* Disabled USB controllers cannot actually work with USB devices */
1019 if (!mData->mEnabled)
1020 return false;
1021
1022 bool match = false;
1023
1024 /* apply self filters */
1025 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1026 !match && it != mDeviceFilters->end();
1027 ++ it)
1028 {
1029 AutoLock filterLock (*it);
1030 match = aDevice->isMatch ((*it)->data());
1031 }
1032
1033 return match;
1034}
1035
1036/**
1037 * Returns true if the given USB device matches to at least one of
1038 * this controller's USB device filters.
1039 *
1040 * A generic version that accepts any IUSBDevice on input.
1041 *
1042 * @note
1043 * This method MUST correlate with HostUSBDevice::isMatch()
1044 * in the sense of the device matching logic.
1045 *
1046 * @note Locks this object for reading.
1047 */
1048bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice)
1049{
1050 LogFlowThisFuncEnter();
1051
1052 AutoCaller autoCaller (this);
1053 AssertComRCReturn (autoCaller.rc(), false);
1054
1055 AutoReaderLock alock (this);
1056
1057 /* Disabled USB controllers cannot actually work with USB devices */
1058 if (!mData->mEnabled)
1059 return false;
1060
1061 HRESULT rc = S_OK;
1062
1063 /* query fields */
1064
1065 USHORT vendorId = 0;
1066 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1067 ComAssertComRCRet (rc, false);
1068 ComAssertRet (vendorId, false);
1069
1070 USHORT productId = 0;
1071 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1072 ComAssertComRCRet (rc, false);
1073 ComAssertRet (productId, false);
1074
1075 USHORT revision;
1076 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1077 ComAssertComRCRet (rc, false);
1078
1079 Bstr manufacturer;
1080 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1081 ComAssertComRCRet (rc, false);
1082
1083 Bstr product;
1084 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1085 ComAssertComRCRet (rc, false);
1086
1087 Bstr serialNumber;
1088 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1089 ComAssertComRCRet (rc, false);
1090
1091 Bstr address;
1092 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1093 ComAssertComRCRet (rc, false);
1094
1095 USHORT port = 0;
1096 rc = aUSBDevice->COMGETTER(Port)(&port);
1097 ComAssertComRCRet (rc, false);
1098
1099 BOOL remote = FALSE;
1100 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1101 ComAssertComRCRet (rc, false);
1102 ComAssertRet (remote == TRUE, false);
1103
1104 bool match = false;
1105
1106 /* apply self filters */
1107 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1108 it != mDeviceFilters->end();
1109 ++ it)
1110 {
1111 AutoLock filterLock (*it);
1112 const USBDeviceFilter::Data &aData = (*it)->data();
1113
1114 if (!aData.mActive)
1115 continue;
1116 if (!aData.mVendorId.isMatch (vendorId))
1117 continue;
1118 if (!aData.mProductId.isMatch (productId))
1119 continue;
1120 if (!aData.mRevision.isMatch (revision))
1121 continue;
1122
1123#if !defined (__WIN__)
1124 /* these filters are temporarily ignored on Win32 */
1125 if (!aData.mManufacturer.isMatch (manufacturer))
1126 continue;
1127 if (!aData.mProduct.isMatch (product))
1128 continue;
1129 if (!aData.mSerialNumber.isMatch (serialNumber))
1130 continue;
1131 if (!aData.mPort.isMatch (port))
1132 continue;
1133#endif
1134
1135 if (!aData.mRemote.isMatch (remote))
1136 continue;
1137
1138 match = true;
1139 break;
1140 }
1141
1142 LogFlowThisFunc (("returns: %d\n", match));
1143 LogFlowThisFuncLeave();
1144
1145 return match;
1146}
1147
1148/**
1149 * Notifies the proxy service about all filters as requested by the
1150 * @a aInsertFilters argument.
1151 *
1152 * @param aInsertFilters @c true to insert filters, @c false to remove.
1153 *
1154 * @note Locks this object for reading.
1155 */
1156HRESULT USBController::notifyProxy (bool aInsertFilters)
1157{
1158 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1159
1160 AutoCaller autoCaller (this);
1161 AssertComRCReturn (autoCaller.rc(), false);
1162
1163 AutoReaderLock alock (this);
1164
1165 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1166 AssertReturn (service, E_FAIL);
1167
1168 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1169 while (it != mDeviceFilters->end())
1170 {
1171 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1172
1173 /* notify the proxy (only if the filter is active) */
1174 if (flt->data().mActive)
1175 {
1176 if (aInsertFilters)
1177 {
1178 AssertReturn (flt->id() == NULL, E_FAIL);
1179 flt->id() = service->insertFilter
1180 (ComPtr <IUSBDeviceFilter> (flt));
1181 }
1182 else
1183 {
1184 /* It's possible that the given filter was not inserted the proxy
1185 * when this method gets called (as a result of an early VM
1186 * process crash for example. So, don't assert that ID != NULL. */
1187 if (flt->id() != NULL)
1188 {
1189 service->removeFilter (flt->id());
1190 flt->id() = NULL;
1191 }
1192 }
1193 }
1194 ++ it;
1195 }
1196
1197 return S_OK;
1198}
1199
1200// private methods
1201/////////////////////////////////////////////////////////////////////////////
1202
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