VirtualBox

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

Last change on this file since 2976 was 2845, checked in by vboxsync, 18 years ago

Main: Switched USBController to the new locking model.

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