VirtualBox

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

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

win OSE fixes

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