VirtualBox

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

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

Forgot to load and save the EnabledEhci setting

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