VirtualBox

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

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

Main/Settings: Applied all current XML settings format todos and increased version from 1.3.pre to 1.3.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.7 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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will 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 given machine node.
485 * May be called once right after this object creation.
486 *
487 * @param aMachineNode <Machine> node.
488 *
489 * @note Locks this object for writing.
490 */
491HRESULT USBController::loadSettings (const settings::Key &aMachineNode)
492{
493 using namespace settings;
494
495 AssertReturn (!aMachineNode.isNull(), E_FAIL);
496
497 AutoCaller autoCaller (this);
498 AssertComRCReturnRC (autoCaller.rc());
499
500 AutoLock alock (this);
501
502 /* Note: we assume that the default values for attributes of optional
503 * nodes are assigned in the Data::Data() constructor and don't do it
504 * here. It implies that this method may only be called after constructing
505 * a new BIOSSettings object while all its data fields are in the default
506 * values. Exceptions are fields whose creation time defaults don't match
507 * values that should be applied when these fields are not explicitly set
508 * in the settings file (for backwards compatibility reasons). This takes
509 * place when a setting of a newly created object must default to A while
510 * the same setting of an object loaded from the old settings file must
511 * default to B. */
512
513 /* USB Controller node (required) */
514 Key controller = aMachineNode.key ("USBController");
515
516 /* enabled (required) */
517 mData->mEnabled = controller.value <bool> ("enabled");
518
519 /* enabledEhci (optiona, defaults to false) */
520 mData->mEnabledEhci = controller.value <bool> ("enabledEhci");
521
522 HRESULT rc = S_OK;
523
524 Key::List children = controller.keys ("DeviceFilter");
525 for (Key::List::const_iterator it = children.begin();
526 it != children.end(); ++ it)
527 {
528 /* required */
529 Bstr name = (*it).stringValue ("name");
530 bool active = (*it).value <bool> ("active");
531
532 /* optional */
533 Bstr vendorId = (*it).stringValue ("vendorId");
534 Bstr productId = (*it).stringValue ("productId");
535 Bstr revision = (*it).stringValue ("revision");
536 Bstr manufacturer = (*it).stringValue ("manufacturer");
537 Bstr product = (*it).stringValue ("product");
538 Bstr serialNumber = (*it).stringValue ("serialNumber");
539 Bstr port = (*it).stringValue ("port");
540 Bstr remote = (*it).stringValue ("remote");
541 ULONG maskedIfs = (*it).value <ULONG> ("maskedInterfaces");
542
543 ComObjPtr <USBDeviceFilter> filterObj;
544 filterObj.createObject();
545 rc = filterObj->init (this,
546 name, active, vendorId, productId, revision,
547 manufacturer, product, serialNumber,
548 port, remote, maskedIfs);
549 /* error info is set by init() when appropriate */
550 CheckComRCReturnRC (rc);
551
552 mDeviceFilters->push_back (filterObj);
553 filterObj->mInList = true;
554 }
555
556 return S_OK;
557}
558
559/**
560 * Saves settings to the given machine node.
561 *
562 * @param aMachineNode <Machine> node.
563 *
564 * @note Locks this object for reading.
565 */
566HRESULT USBController::saveSettings (settings::Key &aMachineNode)
567{
568 using namespace settings;
569
570 AssertReturn (!aMachineNode.isNull(), E_FAIL);
571
572 AutoCaller autoCaller (this);
573 CheckComRCReturnRC (autoCaller.rc());
574
575 AutoReaderLock alock (this);
576
577 /* first, delete the entry */
578 Key controller = aMachineNode.findKey ("USBController");
579 if (!controller.isNull())
580 controller.zap();
581 /* then, recreate it */
582 controller = aMachineNode.createKey ("USBController");
583
584 /* enabled */
585 controller.setValue <bool> ("enabled", !!mData->mEnabled);
586
587 /* enabledEhci */
588 controller.setValue <bool> ("enabledEhci", !!mData->mEnabledEhci);
589
590 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
591 while (it != mDeviceFilters->end())
592 {
593 AutoLock filterLock (*it);
594 const USBDeviceFilter::Data &data = (*it)->data();
595
596 Key filter = controller.appendKey ("DeviceFilter");
597
598 filter.setValue <Bstr> ("name", data.mName);
599 filter.setValue <bool> ("active", !!data.mActive);
600
601 /* all are optional */
602#ifndef VBOX_WITH_USBFILTER
603
604 if (data.mVendorId.string())
605 filter.setValue <Bstr> ("vendorId", data.mVendorId.string());
606 if (data.mProductId.string())
607 filter.setValue <Bstr> ("productId", data.mProductId.string());
608 if (data.mRevision.string())
609 filter.setValue <Bstr> ("revision", data.mRevision.string());
610 if (data.mManufacturer.string())
611 filter.setValue <Bstr> ("manufacturer", data.mManufacturer.string());
612 if (data.mProduct.string())
613 filter.setValue <Bstr> ("product", data.mProduct.string());
614 if (data.mSerialNumber.string())
615 filter.setValue <Bstr> ("serialNumber", data.mSerialNumber.string());
616 if (data.mPort.string())
617 filter.setValue <Bstr> ("port", data.mPort.string());
618 if (data.mRemote.string())
619 filter.setValue <Bstr> ("remote", data.mRemote.string());
620
621#else /* VBOX_WITH_USBFILTER */
622
623 Bstr str;
624 (*it)->COMGETTER (VendorId) (str.asOutParam());
625 if (!str.isNull())
626 filter.setValue <Bstr> ("vendorId", str);
627
628 (*it)->COMGETTER (ProductId) (str.asOutParam());
629 if (!str.isNull())
630 filter.setValue <Bstr> ("productId", str);
631
632 (*it)->COMGETTER (Revision) (str.asOutParam());
633 if (!str.isNull())
634 filter.setValue <Bstr> ("revision", str);
635
636 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
637 if (!str.isNull())
638 filter.setValue <Bstr> ("manufacturer", str);
639
640 (*it)->COMGETTER (Product) (str.asOutParam());
641 if (!str.isNull())
642 filter.setValue <Bstr> ("product", str);
643
644 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
645 if (!str.isNull())
646 filter.setValue <Bstr> ("serialNumber", str);
647
648 (*it)->COMGETTER (Port) (str.asOutParam());
649 if (!str.isNull())
650 filter.setValue <Bstr> ("port", str);
651
652 if (data.mRemote.string())
653 filter.setValue <Bstr> ("remote", data.mRemote.string());
654
655#endif /* VBOX_WITH_USBFILTER */
656
657 if (data.mMaskedIfs)
658 filter.setValue <ULONG> ("maskedInterfaces", data.mMaskedIfs);
659
660 ++ it;
661 }
662
663 return S_OK;
664}
665
666/** @note Locks objects for reading! */
667bool USBController::isModified()
668{
669 AutoCaller autoCaller (this);
670 AssertComRCReturn (autoCaller.rc(), false);
671
672 AutoReaderLock alock (this);
673
674 if (mData.isBackedUp() || mDeviceFilters.isBackedUp())
675 return true;
676
677 /* see whether any of filters has changed its data */
678 for (DeviceFilterList::const_iterator
679 it = mDeviceFilters->begin();
680 it != mDeviceFilters->end();
681 ++ it)
682 {
683 if ((*it)->isModified())
684 return true;
685 }
686
687 return false;
688}
689
690/** @note Locks objects for reading! */
691bool USBController::isReallyModified()
692{
693 AutoCaller autoCaller (this);
694 AssertComRCReturn (autoCaller.rc(), false);
695
696 AutoReaderLock alock (this);
697
698 if (mData.hasActualChanges())
699 return true;
700
701 if (!mDeviceFilters.isBackedUp())
702 {
703 /* see whether any of filters has changed its data */
704 for (DeviceFilterList::const_iterator
705 it = mDeviceFilters->begin();
706 it != mDeviceFilters->end();
707 ++ it)
708 {
709 if ((*it)->isReallyModified())
710 return true;
711 }
712
713 return false;
714 }
715
716 if (mDeviceFilters->size() != mDeviceFilters.backedUpData()->size())
717 return true;
718
719 if (mDeviceFilters->size() == 0)
720 return false;
721
722 /* Make copies to speed up comparison */
723 DeviceFilterList devices = *mDeviceFilters.data();
724 DeviceFilterList backDevices = *mDeviceFilters.backedUpData();
725
726 DeviceFilterList::iterator it = devices.begin();
727 while (it != devices.end())
728 {
729 bool found = false;
730 DeviceFilterList::iterator thatIt = backDevices.begin();
731 while (thatIt != backDevices.end())
732 {
733 if ((*it)->data() == (*thatIt)->data())
734 {
735 backDevices.erase (thatIt);
736 found = true;
737 break;
738 }
739 else
740 ++ thatIt;
741 }
742 if (found)
743 it = devices.erase (it);
744 else
745 return false;
746 }
747
748 Assert (devices.size() == 0 && backDevices.size() == 0);
749
750 return false;
751}
752
753/** @note Locks objects for writing! */
754bool USBController::rollback()
755{
756 AutoCaller autoCaller (this);
757 AssertComRCReturn (autoCaller.rc(), false);
758
759 /* we need the machine state */
760 Machine::AutoAnyStateDependency adep (mParent);
761 AssertComRCReturn (adep.rc(), false);
762
763 AutoLock alock (this);
764
765 bool dataChanged = false;
766
767 if (mData.isBackedUp())
768 {
769 /* we need to check all data to see whether anything will be changed
770 * after rollback */
771 dataChanged = mData.hasActualChanges();
772 mData.rollback();
773 }
774
775 if (mDeviceFilters.isBackedUp())
776 {
777 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
778 ComAssertRet (service, false);
779
780 /* uninitialize all new filters (absent in the backed up list) */
781 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
782 DeviceFilterList *backedList = mDeviceFilters.backedUpData();
783 while (it != mDeviceFilters->end())
784 {
785 if (std::find (backedList->begin(), backedList->end(), *it) ==
786 backedList->end())
787 {
788 /// @todo After rewriting Win32 USB support, no more necessary;
789 // a candidate for removal.
790#if 0
791 /* notify the proxy (only when the filter is active) */
792 if ((*it)->data().mActive)
793#else
794 /* notify the proxy (only when it makes sense) */
795 if ((*it)->data().mActive &&
796 adep.machineState() >= MachineState_Running)
797#endif
798 {
799 USBDeviceFilter *filter = *it;
800 ComAssertRet (filter->id() != NULL, false);
801 service->removeFilter (filter->id());
802 filter->id() = NULL;
803 }
804
805 (*it)->uninit();
806 }
807 ++ it;
808 }
809
810 /// @todo After rewriting Win32 USB support, no more necessary;
811 // a candidate for removal.
812#if 0
813#else
814 if (adep.machineState() >= MachineState_Running)
815#endif
816 {
817 /* find all removed old filters (absent in the new list)
818 * and insert them back to the USB proxy */
819 it = backedList->begin();
820 while (it != backedList->end())
821 {
822 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
823 mDeviceFilters->end())
824 {
825 /* notify the proxy (only when necessary) */
826 if ((*it)->data().mActive)
827 {
828 USBDeviceFilter *flt = *it; /* resolve ambiguity */
829 ComAssertRet (flt->id() == NULL, false);
830#ifndef VBOX_WITH_USBFILTER
831 flt->id() = service->insertFilter
832 (ComPtr <IUSBDeviceFilter> (flt));
833#else
834 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
835#endif
836 }
837 }
838 ++ it;
839 }
840 }
841
842 /* restore the list */
843 mDeviceFilters.rollback();
844 }
845
846 /* here we don't depend on the machine state any more */
847 adep.release();
848
849 /* rollback any changes to filters after restoring the list */
850 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
851 while (it != mDeviceFilters->end())
852 {
853 if ((*it)->isModified())
854 {
855 (*it)->rollback();
856 /* call this to notify the USB proxy about changes */
857 onDeviceFilterChange (*it);
858 }
859 ++ it;
860 }
861
862 return dataChanged;
863}
864
865/** @note Locks objects for writing! */
866void USBController::commit()
867{
868 AutoCaller autoCaller (this);
869 AssertComRCReturnVoid (autoCaller.rc());
870
871 AutoLock alock (this);
872
873 if (mData.isBackedUp())
874 {
875 mData.commit();
876 if (mPeer)
877 {
878 // attach new data to the peer and reshare it
879 AutoLock peerlock (mPeer);
880 mPeer->mData.attach (mData);
881 }
882 }
883
884 bool commitFilters = false;
885
886 if (mDeviceFilters.isBackedUp())
887 {
888 mDeviceFilters.commit();
889
890 // apply changes to peer
891 if (mPeer)
892 {
893 AutoLock peerlock (mPeer);
894 // commit all changes to new filters (this will reshare data with
895 // peers for those who have peers)
896 DeviceFilterList *newList = new DeviceFilterList();
897 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
898 while (it != mDeviceFilters->end())
899 {
900 (*it)->commit();
901
902 // look if this filter has a peer filter
903 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
904 if (!peer)
905 {
906 // no peer means the filter is a newly created one;
907 // create a peer owning data this filter share it with
908 peer.createObject();
909 peer->init (mPeer, *it, true /* aReshare */);
910 }
911 else
912 {
913 // remove peer from the old list
914 mPeer->mDeviceFilters->remove (peer);
915 }
916 // and add it to the new list
917 newList->push_back (peer);
918
919 ++ it;
920 }
921
922 // uninit old peer's filters that are left
923 it = mPeer->mDeviceFilters->begin();
924 while (it != mPeer->mDeviceFilters->end())
925 {
926 (*it)->uninit();
927 ++ it;
928 }
929
930 // attach new list of filters to our peer
931 mPeer->mDeviceFilters.attach (newList);
932 }
933 else
934 {
935 // we have no peer (our parent is the newly created machine);
936 // just commit changes to filters
937 commitFilters = true;
938 }
939 }
940 else
941 {
942 // the list of filters itself is not changed,
943 // just commit changes to filters themselves
944 commitFilters = true;
945 }
946
947 if (commitFilters)
948 {
949 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
950 while (it != mDeviceFilters->end())
951 {
952 (*it)->commit();
953 ++ it;
954 }
955 }
956}
957
958/** @note Locks object for writing and that object for reading! */
959void USBController::copyFrom (USBController *aThat)
960{
961 AutoCaller autoCaller (this);
962 AssertComRCReturnVoid (autoCaller.rc());
963
964 AutoMultiLock <2> alock (this->wlock(), aThat->rlock());
965
966 if (mParent->isRegistered())
967 {
968 /* reuse onMachineRegistered to tell USB proxy to remove all current
969 filters */
970 HRESULT rc = onMachineRegistered (FALSE);
971 AssertComRCReturn (rc, (void) 0);
972 }
973
974 /* this will back up current data */
975 mData.assignCopy (aThat->mData);
976
977 /* create private copies of all filters */
978 mDeviceFilters.backup();
979 mDeviceFilters->clear();
980 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
981 it != aThat->mDeviceFilters->end();
982 ++ it)
983 {
984 ComObjPtr <USBDeviceFilter> filter;
985 filter.createObject();
986 filter->initCopy (this, *it);
987 mDeviceFilters->push_back (filter);
988 }
989
990 if (mParent->isRegistered())
991 {
992 /* reuse onMachineRegistered to tell USB proxy to insert all current
993 filters */
994 HRESULT rc = onMachineRegistered (TRUE);
995 AssertComRCReturn (rc, (void) 0);
996 }
997}
998
999/**
1000 * Called by VirtualBox when it changes the registered state
1001 * of the machine this USB controller belongs to.
1002 *
1003 * @param aRegistered new registered state of the machine
1004 *
1005 * @note Locks nothing.
1006 */
1007HRESULT USBController::onMachineRegistered (BOOL aRegistered)
1008{
1009 AutoCaller autoCaller (this);
1010 AssertComRCReturnRC (autoCaller.rc());
1011
1012 /// @todo After rewriting Win32 USB support, no more necessary;
1013 // a candidate for removal.
1014#if 0
1015 notifyProxy (!!aRegistered);
1016#endif
1017
1018 return S_OK;
1019}
1020
1021/**
1022 * Called by setter methods of all USB device filters.
1023 *
1024 * @note Locks nothing.
1025 */
1026HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
1027 BOOL aActiveChanged /* = FALSE */)
1028{
1029 AutoCaller autoCaller (this);
1030 AssertComRCReturnRC (autoCaller.rc());
1031
1032 /// @todo After rewriting Win32 USB support, no more necessary;
1033 // a candidate for removal.
1034#if 0
1035#else
1036 /* we need the machine state */
1037 Machine::AutoAnyStateDependency adep (mParent);
1038 AssertComRCReturnRC (adep.rc());
1039
1040 /* nothing to do if the machine isn't running */
1041 if (adep.machineState() < MachineState_Running)
1042 return S_OK;
1043#endif
1044
1045 /* we don't modify our data fields -- no need to lock */
1046
1047 if (aFilter->mInList && mParent->isRegistered())
1048 {
1049 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1050 ComAssertRet (service, E_FAIL);
1051
1052 if (aActiveChanged)
1053 {
1054 /* insert/remove the filter from the proxy */
1055 if (aFilter->data().mActive)
1056 {
1057 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1058#ifndef VBOX_WITH_USBFILTER
1059 aFilter->id() = service->insertFilter
1060 (ComPtr <IUSBDeviceFilter> (aFilter));
1061#else
1062 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1063#endif
1064 }
1065 else
1066 {
1067 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1068 service->removeFilter (aFilter->id());
1069 aFilter->id() = NULL;
1070 }
1071 }
1072 else
1073 {
1074 if (aFilter->data().mActive)
1075 {
1076 /* update the filter in the proxy */
1077 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1078 service->removeFilter (aFilter->id());
1079#ifndef VBOX_WITH_USBFILTER
1080 aFilter->id() = service->insertFilter
1081 (ComPtr <IUSBDeviceFilter> (aFilter));
1082#else
1083 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1084#endif
1085 }
1086 }
1087 }
1088
1089 return S_OK;
1090}
1091
1092/**
1093 * Returns true if the given USB device matches to at least one of
1094 * this controller's USB device filters.
1095 *
1096 * A HostUSBDevice specific version.
1097 *
1098 * @note Locks this object for reading.
1099 */
1100bool USBController::hasMatchingFilter (const ComObjPtr <HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
1101{
1102 AutoCaller autoCaller (this);
1103 AssertComRCReturn (autoCaller.rc(), false);
1104
1105 AutoReaderLock alock (this);
1106
1107 /* Disabled USB controllers cannot actually work with USB devices */
1108 if (!mData->mEnabled)
1109 return false;
1110
1111 /* apply self filters */
1112 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1113 it != mDeviceFilters->end();
1114 ++ it)
1115 {
1116 AutoLock filterLock (*it);
1117 if (aDevice->isMatch ((*it)->data()))
1118 {
1119 *aMaskedIfs = (*it)->data().mMaskedIfs;
1120 return true;
1121 }
1122 }
1123
1124 return false;
1125}
1126
1127/**
1128 * Returns true if the given USB device matches to at least one of
1129 * this controller's USB device filters.
1130 *
1131 * A generic version that accepts any IUSBDevice on input.
1132 *
1133 * @note
1134 * This method MUST correlate with HostUSBDevice::isMatch()
1135 * in the sense of the device matching logic.
1136 *
1137 * @note Locks this object for reading.
1138 */
1139bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
1140{
1141 LogFlowThisFuncEnter();
1142
1143 AutoCaller autoCaller (this);
1144 AssertComRCReturn (autoCaller.rc(), false);
1145
1146 AutoReaderLock alock (this);
1147
1148 /* Disabled USB controllers cannot actually work with USB devices */
1149 if (!mData->mEnabled)
1150 return false;
1151
1152 HRESULT rc = S_OK;
1153
1154 /* query fields */
1155#ifdef VBOX_WITH_USBFILTER
1156 USBFILTER dev;
1157 USBFilterInit (&dev, USBFILTERTYPE_CAPTURE);
1158#endif
1159
1160 USHORT vendorId = 0;
1161 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1162 ComAssertComRCRet (rc, false);
1163 ComAssertRet (vendorId, false);
1164#ifdef VBOX_WITH_USBFILTER
1165 int vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
1166#endif
1167
1168 USHORT productId = 0;
1169 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1170 ComAssertComRCRet (rc, false);
1171 ComAssertRet (productId, false);
1172#ifdef VBOX_WITH_USBFILTER
1173 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
1174#endif
1175
1176 USHORT revision;
1177 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1178 ComAssertComRCRet (rc, false);
1179#ifdef VBOX_WITH_USBFILTER
1180 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
1181#endif
1182
1183 Bstr manufacturer;
1184 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1185 ComAssertComRCRet (rc, false);
1186#ifdef VBOX_WITH_USBFILTER
1187 if (!manufacturer.isNull())
1188 USBFilterSetStringExact (&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer), true);
1189#endif
1190
1191 Bstr product;
1192 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1193 ComAssertComRCRet (rc, false);
1194#ifdef VBOX_WITH_USBFILTER
1195 if (!product.isNull())
1196 USBFilterSetStringExact (&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product), true);
1197#endif
1198
1199 Bstr serialNumber;
1200 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1201 ComAssertComRCRet (rc, false);
1202#ifdef VBOX_WITH_USBFILTER
1203 if (!serialNumber.isNull())
1204 USBFilterSetStringExact (&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber), true);
1205#endif
1206
1207 Bstr address;
1208 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1209 ComAssertComRCRet (rc, false);
1210
1211 USHORT port = 0;
1212 rc = aUSBDevice->COMGETTER(Port)(&port);
1213 ComAssertComRCRet (rc, false);
1214#ifdef VBOX_WITH_USBFILTER
1215 USBFilterSetNumExact (&dev, USBFILTERIDX_PORT, port, true);
1216#endif
1217
1218 BOOL remote = FALSE;
1219 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1220 ComAssertComRCRet (rc, false);
1221 ComAssertRet (remote == TRUE, false);
1222
1223 bool match = false;
1224
1225 /* apply self filters */
1226 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1227 it != mDeviceFilters->end();
1228 ++ it)
1229 {
1230 AutoLock filterLock (*it);
1231 const USBDeviceFilter::Data &aData = (*it)->data();
1232
1233
1234 if (!aData.mActive)
1235 continue;
1236 if (!aData.mRemote.isMatch (remote))
1237 continue;
1238
1239#ifndef VBOX_WITH_USBFILTER
1240 if (!aData.mVendorId.isMatch (vendorId))
1241 continue;
1242 if (!aData.mProductId.isMatch (productId))
1243 continue;
1244 if (!aData.mRevision.isMatch (revision))
1245 continue;
1246
1247#if !defined (RT_OS_WINDOWS)
1248 /* these filters are temporarily ignored on Win32 */
1249 if (!aData.mManufacturer.isMatch (manufacturer))
1250 continue;
1251 if (!aData.mProduct.isMatch (product))
1252 continue;
1253 if (!aData.mSerialNumber.isMatch (serialNumber))
1254 continue;
1255 if (!aData.mPort.isMatch (port))
1256 continue;
1257#endif
1258
1259#else /* VBOX_WITH_USBFILTER */
1260 if (!USBFilterMatch (&aData.mUSBFilter, &dev))
1261 continue;
1262#endif /* VBOX_WITH_USBFILTER */
1263
1264 match = true;
1265 *aMaskedIfs = aData.mMaskedIfs;
1266 break;
1267 }
1268
1269 LogFlowThisFunc (("returns: %d\n", match));
1270 LogFlowThisFuncLeave();
1271
1272 return match;
1273}
1274
1275/**
1276 * Notifies the proxy service about all filters as requested by the
1277 * @a aInsertFilters argument.
1278 *
1279 * @param aInsertFilters @c true to insert filters, @c false to remove.
1280 *
1281 * @note Locks this object for reading.
1282 */
1283HRESULT USBController::notifyProxy (bool aInsertFilters)
1284{
1285 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1286
1287 AutoCaller autoCaller (this);
1288 AssertComRCReturn (autoCaller.rc(), false);
1289
1290 AutoReaderLock alock (this);
1291
1292 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1293 AssertReturn (service, E_FAIL);
1294
1295 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1296 while (it != mDeviceFilters->end())
1297 {
1298 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1299
1300 /* notify the proxy (only if the filter is active) */
1301 if (flt->data().mActive)
1302 {
1303 if (aInsertFilters)
1304 {
1305 AssertReturn (flt->id() == NULL, E_FAIL);
1306#ifndef VBOX_WITH_USBFILTER
1307 flt->id() = service->insertFilter
1308 (ComPtr <IUSBDeviceFilter> (flt));
1309#else
1310 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
1311#endif
1312 }
1313 else
1314 {
1315 /* It's possible that the given filter was not inserted the proxy
1316 * when this method gets called (as a result of an early VM
1317 * process crash for example. So, don't assert that ID != NULL. */
1318 if (flt->id() != NULL)
1319 {
1320 service->removeFilter (flt->id());
1321 flt->id() = NULL;
1322 }
1323 }
1324 }
1325 ++ it;
1326 }
1327
1328 return S_OK;
1329}
1330
1331// private methods
1332/////////////////////////////////////////////////////////////////////////////
1333
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