VirtualBox

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

Last change on this file since 20206 was 20206, checked in by vboxsync, 15 years ago

Main: OSE warnings

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