VirtualBox

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

Last change on this file since 8155 was 8155, checked in by vboxsync, 16 years ago

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.8 KB
Line 
1/* $Id: USBControllerImpl.cpp 8155 2008-04-18 15:16:47Z 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
23
24#include "USBControllerImpl.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
36#include <iprt/string.h>
37#include <iprt/cpputils.h>
38#include <VBox/err.h>
39
40#include <algorithm>
41
42// defines
43/////////////////////////////////////////////////////////////////////////////
44
45// constructor / destructor
46/////////////////////////////////////////////////////////////////////////////
47
48DEFINE_EMPTY_CTOR_DTOR (USBController)
49
50HRESULT USBController::FinalConstruct()
51{
52 return S_OK;
53}
54
55void USBController::FinalRelease()
56{
57 uninit();
58}
59
60// public initializer/uninitializer for internal purposes only
61/////////////////////////////////////////////////////////////////////////////
62
63/**
64 * Initializes the USB controller object.
65 *
66 * @returns COM result indicator.
67 * @param aParent Pointer to our parent object.
68 */
69HRESULT USBController::init (Machine *aParent)
70{
71 LogFlowThisFunc (("aParent=%p\n", aParent));
72
73 ComAssertRet (aParent, E_INVALIDARG);
74
75 /* Enclose the state transition NotReady->InInit->Ready */
76 AutoInitSpan autoInitSpan (this);
77 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
78
79 unconst (mParent) = aParent;
80 /* mPeer is left null */
81
82 mData.allocate();
83#ifdef VBOX_WITH_USB
84 mDeviceFilters.allocate();
85#endif
86
87 /* Confirm a successful initialization */
88 autoInitSpan.setSucceeded();
89
90 return S_OK;
91}
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_UNEXPECTED);
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_UNEXPECTED);
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 if (!aEnabled)
217 return E_POINTER;
218
219 AutoCaller autoCaller (this);
220 CheckComRCReturnRC (autoCaller.rc());
221
222 AutoReadLock alock (this);
223
224 *aEnabled = mData->mEnabled;
225
226 return S_OK;
227}
228
229
230STDMETHODIMP USBController::COMSETTER(Enabled) (BOOL aEnabled)
231{
232 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
233
234 AutoCaller autoCaller (this);
235 CheckComRCReturnRC (autoCaller.rc());
236
237 /* the machine needs to be mutable */
238 Machine::AutoMutableStateDependency adep (mParent);
239 CheckComRCReturnRC (adep.rc());
240
241 AutoWriteLock alock (this);
242
243 if (mData->mEnabled != aEnabled)
244 {
245 mData.backup();
246 mData->mEnabled = aEnabled;
247
248 /* leave the lock for safety */
249 alock.leave();
250
251 mParent->onUSBControllerChange();
252 }
253
254 return S_OK;
255}
256
257STDMETHODIMP USBController::COMGETTER(EnabledEhci) (BOOL *aEnabled)
258{
259 if (!aEnabled)
260 return E_POINTER;
261
262 AutoCaller autoCaller (this);
263 CheckComRCReturnRC (autoCaller.rc());
264
265 AutoReadLock alock (this);
266
267 *aEnabled = mData->mEnabledEhci;
268
269 return S_OK;
270}
271
272STDMETHODIMP USBController::COMSETTER(EnabledEhci) (BOOL aEnabled)
273{
274 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
275
276 AutoCaller autoCaller (this);
277 CheckComRCReturnRC (autoCaller.rc());
278
279 /* the machine needs to be mutable */
280 Machine::AutoMutableStateDependency adep (mParent);
281 CheckComRCReturnRC (adep.rc());
282
283 AutoWriteLock alock (this);
284
285 if (mData->mEnabledEhci != aEnabled)
286 {
287 mData.backup();
288 mData->mEnabledEhci = aEnabled;
289
290 /* leave the lock for safety */
291 alock.leave();
292
293 mParent->onUSBControllerChange();
294 }
295
296 return S_OK;
297}
298
299STDMETHODIMP USBController::COMGETTER(USBStandard) (USHORT *aUSBStandard)
300{
301 if (!aUSBStandard)
302 return E_POINTER;
303
304 AutoCaller autoCaller (this);
305 CheckComRCReturnRC (autoCaller.rc());
306
307 /* not accessing data -- no need to lock */
308
309 /** @todo This is no longer correct */
310 *aUSBStandard = 0x0101;
311
312 return S_OK;
313}
314
315#ifndef VBOX_WITH_USB
316/**
317 * Fake class for build without USB.
318 * We need an empty collection & enum for deviceFilters, that's all.
319 */
320class ATL_NO_VTABLE USBDeviceFilter : public VirtualBoxBaseNEXT, public IUSBDeviceFilter
321{
322public:
323 DECLARE_NOT_AGGREGATABLE(USBDeviceFilter)
324 DECLARE_PROTECT_FINAL_CONSTRUCT()
325 BEGIN_COM_MAP(USBDeviceFilter)
326 COM_INTERFACE_ENTRY(ISupportErrorInfo)
327 COM_INTERFACE_ENTRY(IUSBDeviceFilter)
328 END_COM_MAP()
329
330 NS_DECL_ISUPPORTS
331
332 DECLARE_EMPTY_CTOR_DTOR (USBDeviceFilter)
333
334 // IUSBDeviceFilter properties
335 STDMETHOD(COMGETTER(Name)) (BSTR *aName);
336 STDMETHOD(COMSETTER(Name)) (INPTR BSTR aName);
337 STDMETHOD(COMGETTER(Active)) (BOOL *aActive);
338 STDMETHOD(COMSETTER(Active)) (BOOL aActive);
339 STDMETHOD(COMGETTER(VendorId)) (BSTR *aVendorId);
340 STDMETHOD(COMSETTER(VendorId)) (INPTR BSTR aVendorId);
341 STDMETHOD(COMGETTER(ProductId)) (BSTR *aProductId);
342 STDMETHOD(COMSETTER(ProductId)) (INPTR BSTR aProductId);
343 STDMETHOD(COMGETTER(Revision)) (BSTR *aRevision);
344 STDMETHOD(COMSETTER(Revision)) (INPTR BSTR aRevision);
345 STDMETHOD(COMGETTER(Manufacturer)) (BSTR *aManufacturer);
346 STDMETHOD(COMSETTER(Manufacturer)) (INPTR BSTR aManufacturer);
347 STDMETHOD(COMGETTER(Product)) (BSTR *aProduct);
348 STDMETHOD(COMSETTER(Product)) (INPTR BSTR aProduct);
349 STDMETHOD(COMGETTER(SerialNumber)) (BSTR *aSerialNumber);
350 STDMETHOD(COMSETTER(SerialNumber)) (INPTR BSTR aSerialNumber);
351 STDMETHOD(COMGETTER(Port)) (BSTR *aPort);
352 STDMETHOD(COMSETTER(Port)) (INPTR BSTR aPort);
353 STDMETHOD(COMGETTER(Remote)) (BSTR *aRemote);
354 STDMETHOD(COMSETTER(Remote)) (INPTR BSTR aRemote);
355 STDMETHOD(COMGETTER(MaskedInterfaces)) (ULONG *aMaskedIfs);
356 STDMETHOD(COMSETTER(MaskedInterfaces)) (ULONG aMaskedIfs);
357};
358COM_DECL_READONLY_ENUM_AND_COLLECTION (USBDeviceFilter);
359COM_IMPL_READONLY_ENUM_AND_COLLECTION (USBDeviceFilter);
360#endif /* !VBOX_WITH_USB */
361
362
363STDMETHODIMP USBController::COMGETTER(DeviceFilters) (IUSBDeviceFilterCollection **aDevicesFilters)
364{
365 if (!aDevicesFilters)
366 return E_POINTER;
367
368 AutoCaller autoCaller (this);
369 CheckComRCReturnRC (autoCaller.rc());
370
371 AutoReadLock alock (this);
372
373 ComObjPtr <USBDeviceFilterCollection> collection;
374 collection.createObject();
375#ifdef VBOX_WITH_USB
376 collection->init (*mDeviceFilters.data());
377#endif
378 collection.queryInterfaceTo (aDevicesFilters);
379
380 return S_OK;
381}
382
383// IUSBController methods
384/////////////////////////////////////////////////////////////////////////////
385
386STDMETHODIMP USBController::CreateDeviceFilter (INPTR BSTR aName,
387 IUSBDeviceFilter **aFilter)
388{
389#ifdef VBOX_WITH_USB
390 if (!aFilter)
391 return E_POINTER;
392
393 if (!aName || *aName == 0)
394 return E_INVALIDARG;
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 return E_NOTIMPL;
415#endif
416}
417
418STDMETHODIMP USBController::InsertDeviceFilter (ULONG aPosition,
419 IUSBDeviceFilter *aFilter)
420{
421#ifdef VBOX_WITH_USB
422 if (!aFilter)
423 return E_INVALIDARG;
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 (E_INVALIDARG,
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 /// @todo After rewriting Win32 USB support, no more necessary;
461 // a candidate for removal.
462#if 0
463 /* notify the proxy (only when the filter is active) */
464 if (filter->data().mActive)
465#else
466 /* notify the proxy (only when it makes sense) */
467 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
468#endif
469 {
470 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
471 ComAssertRet (service, E_FAIL);
472
473 ComAssertRet (filter->id() == NULL, E_FAIL);
474 filter->id() = service->insertFilter (&filter->data().mUSBFilter);
475 }
476
477 return S_OK;
478#else
479 return E_NOTIMPL;
480#endif
481}
482
483STDMETHODIMP USBController::RemoveDeviceFilter (ULONG aPosition,
484 IUSBDeviceFilter **aFilter)
485{
486#ifdef VBOX_WITH_USB
487 if (!aFilter)
488 return E_POINTER;
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 /// @todo After rewriting Win32 USB support, no more necessary;
529 // a candidate for removal.
530#if 0
531 /* notify the proxy (only when the filter is active) */
532 if (filter->data().mActive)
533#else
534 /* notify the proxy (only when it makes sense) */
535 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
536#endif
537 {
538 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
539 ComAssertRet (service, E_FAIL);
540
541 ComAssertRet (filter->id() != NULL, E_FAIL);
542 service->removeFilter (filter->id());
543 filter->id() = NULL;
544 }
545
546 return S_OK;
547#else
548 return E_NOTIMPL;
549#endif
550}
551
552// public methods only for internal purposes
553/////////////////////////////////////////////////////////////////////////////
554
555/**
556 * Loads settings from the given machine node.
557 * May be called once right after this object creation.
558 *
559 * @param aMachineNode <Machine> node.
560 *
561 * @note Locks this object for writing.
562 */
563HRESULT USBController::loadSettings (const settings::Key &aMachineNode)
564{
565 using namespace settings;
566
567 AssertReturn (!aMachineNode.isNull(), E_FAIL);
568
569 AutoCaller autoCaller (this);
570 AssertComRCReturnRC (autoCaller.rc());
571
572 AutoWriteLock alock (this);
573
574 /* Note: we assume that the default values for attributes of optional
575 * nodes are assigned in the Data::Data() constructor and don't do it
576 * here. It implies that this method may only be called after constructing
577 * a new BIOSSettings object while all its data fields are in the default
578 * values. Exceptions are fields whose creation time defaults don't match
579 * values that should be applied when these fields are not explicitly set
580 * in the settings file (for backwards compatibility reasons). This takes
581 * place when a setting of a newly created object must default to A while
582 * the same setting of an object loaded from the old settings file must
583 * default to B. */
584
585 /* USB Controller node (required) */
586 Key controller = aMachineNode.key ("USBController");
587
588 /* enabled (required) */
589 mData->mEnabled = controller.value <bool> ("enabled");
590
591 /* enabledEhci (optiona, defaults to false) */
592 mData->mEnabledEhci = controller.value <bool> ("enabledEhci");
593
594#ifdef VBOX_WITH_USB
595 HRESULT rc = S_OK;
596
597 Key::List children = controller.keys ("DeviceFilter");
598 for (Key::List::const_iterator it = children.begin();
599 it != children.end(); ++ it)
600 {
601 /* required */
602 Bstr name = (*it).stringValue ("name");
603 bool active = (*it).value <bool> ("active");
604
605 /* optional */
606 Bstr vendorId = (*it).stringValue ("vendorId");
607 Bstr productId = (*it).stringValue ("productId");
608 Bstr revision = (*it).stringValue ("revision");
609 Bstr manufacturer = (*it).stringValue ("manufacturer");
610 Bstr product = (*it).stringValue ("product");
611 Bstr serialNumber = (*it).stringValue ("serialNumber");
612 Bstr port = (*it).stringValue ("port");
613 Bstr remote = (*it).stringValue ("remote");
614 ULONG maskedIfs = (*it).value <ULONG> ("maskedInterfaces");
615
616 ComObjPtr <USBDeviceFilter> filterObj;
617 filterObj.createObject();
618 rc = filterObj->init (this,
619 name, active, vendorId, productId, revision,
620 manufacturer, product, serialNumber,
621 port, remote, maskedIfs);
622 /* error info is set by init() when appropriate */
623 CheckComRCReturnRC (rc);
624
625 mDeviceFilters->push_back (filterObj);
626 filterObj->mInList = true;
627 }
628#endif /* VBOX_WITH_USB */
629
630 return S_OK;
631}
632
633/**
634 * Saves settings to the given machine node.
635 *
636 * @param aMachineNode <Machine> node.
637 *
638 * @note Locks this object for reading.
639 */
640HRESULT USBController::saveSettings (settings::Key &aMachineNode)
641{
642 using namespace settings;
643
644 AssertReturn (!aMachineNode.isNull(), E_FAIL);
645
646 AutoCaller autoCaller (this);
647 CheckComRCReturnRC (autoCaller.rc());
648
649 AutoReadLock alock (this);
650
651 /* first, delete the entry */
652 Key controller = aMachineNode.findKey ("USBController");
653#ifdef VBOX_WITH_USB
654 if (!controller.isNull())
655 controller.zap();
656 /* then, recreate it */
657 controller = aMachineNode.createKey ("USBController");
658#else
659 /* don't zap it. */
660 if (controller.isNull())
661 controller = aMachineNode.createKey ("USBController");
662#endif
663
664 /* enabled */
665 controller.setValue <bool> ("enabled", !!mData->mEnabled);
666
667 /* enabledEhci */
668 controller.setValue <bool> ("enabledEhci", !!mData->mEnabledEhci);
669
670#ifdef VBOX_WITH_USB
671 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
672 while (it != mDeviceFilters->end())
673 {
674 AutoWriteLock filterLock (*it);
675 const USBDeviceFilter::Data &data = (*it)->data();
676
677 Key filter = controller.appendKey ("DeviceFilter");
678
679 filter.setValue <Bstr> ("name", data.mName);
680 filter.setValue <bool> ("active", !!data.mActive);
681
682 /* all are optional */
683 Bstr str;
684 (*it)->COMGETTER (VendorId) (str.asOutParam());
685 if (!str.isNull())
686 filter.setValue <Bstr> ("vendorId", str);
687
688 (*it)->COMGETTER (ProductId) (str.asOutParam());
689 if (!str.isNull())
690 filter.setValue <Bstr> ("productId", str);
691
692 (*it)->COMGETTER (Revision) (str.asOutParam());
693 if (!str.isNull())
694 filter.setValue <Bstr> ("revision", str);
695
696 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
697 if (!str.isNull())
698 filter.setValue <Bstr> ("manufacturer", str);
699
700 (*it)->COMGETTER (Product) (str.asOutParam());
701 if (!str.isNull())
702 filter.setValue <Bstr> ("product", str);
703
704 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
705 if (!str.isNull())
706 filter.setValue <Bstr> ("serialNumber", str);
707
708 (*it)->COMGETTER (Port) (str.asOutParam());
709 if (!str.isNull())
710 filter.setValue <Bstr> ("port", str);
711
712 if (data.mRemote.string())
713 filter.setValue <Bstr> ("remote", data.mRemote.string());
714
715 if (data.mMaskedIfs)
716 filter.setValue <ULONG> ("maskedInterfaces", data.mMaskedIfs);
717
718 ++ it;
719 }
720#endif /* VBOX_WITH_USB */
721
722 return S_OK;
723}
724
725/** @note Locks objects for reading! */
726bool USBController::isModified()
727{
728 AutoCaller autoCaller (this);
729 AssertComRCReturn (autoCaller.rc(), false);
730
731 AutoReadLock alock (this);
732
733 if (mData.isBackedUp()
734#ifdef VBOX_WITH_USB
735 || mDeviceFilters.isBackedUp()
736#endif
737 )
738 return true;
739
740#ifdef VBOX_WITH_USB
741 /* see whether any of filters has changed its data */
742 for (DeviceFilterList::const_iterator
743 it = mDeviceFilters->begin();
744 it != mDeviceFilters->end();
745 ++ it)
746 {
747 if ((*it)->isModified())
748 return true;
749 }
750#endif /* VBOX_WITH_USB */
751
752 return false;
753}
754
755/** @note Locks objects for reading! */
756bool USBController::isReallyModified()
757{
758 AutoCaller autoCaller (this);
759 AssertComRCReturn (autoCaller.rc(), false);
760
761 AutoReadLock alock (this);
762
763 if (mData.hasActualChanges())
764 return true;
765
766#ifdef VBOX_WITH_USB
767 if (!mDeviceFilters.isBackedUp())
768 {
769 /* see whether any of filters has changed its data */
770 for (DeviceFilterList::const_iterator
771 it = mDeviceFilters->begin();
772 it != mDeviceFilters->end();
773 ++ it)
774 {
775 if ((*it)->isReallyModified())
776 return true;
777 }
778
779 return false;
780 }
781
782 if (mDeviceFilters->size() != mDeviceFilters.backedUpData()->size())
783 return true;
784
785 if (mDeviceFilters->size() == 0)
786 return false;
787
788 /* Make copies to speed up comparison */
789 DeviceFilterList devices = *mDeviceFilters.data();
790 DeviceFilterList backDevices = *mDeviceFilters.backedUpData();
791
792 DeviceFilterList::iterator it = devices.begin();
793 while (it != devices.end())
794 {
795 bool found = false;
796 DeviceFilterList::iterator thatIt = backDevices.begin();
797 while (thatIt != backDevices.end())
798 {
799 if ((*it)->data() == (*thatIt)->data())
800 {
801 backDevices.erase (thatIt);
802 found = true;
803 break;
804 }
805 else
806 ++ thatIt;
807 }
808 if (found)
809 it = devices.erase (it);
810 else
811 return false;
812 }
813
814 Assert (devices.size() == 0 && backDevices.size() == 0);
815#endif /* VBOX_WITH_USB */
816
817 return false;
818}
819
820/** @note Locks objects for writing! */
821bool USBController::rollback()
822{
823 AutoCaller autoCaller (this);
824 AssertComRCReturn (autoCaller.rc(), false);
825
826 /* we need the machine state */
827 Machine::AutoAnyStateDependency adep (mParent);
828 AssertComRCReturn (adep.rc(), false);
829
830 AutoWriteLock alock (this);
831
832 bool dataChanged = false;
833
834 if (mData.isBackedUp())
835 {
836 /* we need to check all data to see whether anything will be changed
837 * after rollback */
838 dataChanged = mData.hasActualChanges();
839 mData.rollback();
840 }
841
842#ifdef VBOX_WITH_USB
843 if (mDeviceFilters.isBackedUp())
844 {
845 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
846 ComAssertRet (service, false);
847
848 /* uninitialize all new filters (absent in the backed up list) */
849 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
850 DeviceFilterList *backedList = mDeviceFilters.backedUpData();
851 while (it != mDeviceFilters->end())
852 {
853 if (std::find (backedList->begin(), backedList->end(), *it) ==
854 backedList->end())
855 {
856 /// @todo After rewriting Win32 USB support, no more necessary;
857 // a candidate for removal.
858#if 0
859 /* notify the proxy (only when the filter is active) */
860 if ((*it)->data().mActive)
861#else
862 /* notify the proxy (only when it makes sense) */
863 if ((*it)->data().mActive &&
864 adep.machineState() >= MachineState_Running)
865#endif
866 {
867 USBDeviceFilter *filter = *it;
868 ComAssertRet (filter->id() != NULL, false);
869 service->removeFilter (filter->id());
870 filter->id() = NULL;
871 }
872
873 (*it)->uninit();
874 }
875 ++ it;
876 }
877
878 /// @todo After rewriting Win32 USB support, no more necessary;
879 // a candidate for removal.
880#if 0
881#else
882 if (adep.machineState() >= MachineState_Running)
883#endif
884 {
885 /* find all removed old filters (absent in the new list)
886 * and insert them back to the USB proxy */
887 it = backedList->begin();
888 while (it != backedList->end())
889 {
890 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
891 mDeviceFilters->end())
892 {
893 /* notify the proxy (only when necessary) */
894 if ((*it)->data().mActive)
895 {
896 USBDeviceFilter *flt = *it; /* resolve ambiguity */
897 ComAssertRet (flt->id() == NULL, false);
898 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
899 }
900 }
901 ++ it;
902 }
903 }
904
905 /* restore the list */
906 mDeviceFilters.rollback();
907 }
908
909 /* here we don't depend on the machine state any more */
910 adep.release();
911
912 /* rollback any changes to filters after restoring the list */
913 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
914 while (it != mDeviceFilters->end())
915 {
916 if ((*it)->isModified())
917 {
918 (*it)->rollback();
919 /* call this to notify the USB proxy about changes */
920 onDeviceFilterChange (*it);
921 }
922 ++ it;
923 }
924#endif /* VBOX_WITH_USB */
925
926 return dataChanged;
927}
928
929/**
930 * @note Locks this object for writing, together with the peer object (also
931 * for writing) if there is one.
932 */
933void USBController::commit()
934{
935 /* sanity */
936 AutoCaller autoCaller (this);
937 AssertComRCReturnVoid (autoCaller.rc());
938
939 /* sanity too */
940 AutoCaller peerCaller (mPeer);
941 AssertComRCReturnVoid (peerCaller.rc());
942
943 /* lock both for writing since we modify both (mPeer is "master" so locked
944 * first) */
945 AutoMultiWriteLock2 alock (mPeer, this);
946
947 if (mData.isBackedUp())
948 {
949 mData.commit();
950 if (mPeer)
951 {
952 /* attach new data to the peer and reshare it */
953 AutoWriteLock peerlock (mPeer);
954 mPeer->mData.attach (mData);
955 }
956 }
957
958#ifdef VBOX_WITH_USB
959 bool commitFilters = false;
960
961 if (mDeviceFilters.isBackedUp())
962 {
963 mDeviceFilters.commit();
964
965 /* apply changes to peer */
966 if (mPeer)
967 {
968 AutoWriteLock peerlock (mPeer);
969 /* commit all changes to new filters (this will reshare data with
970 * peers for those who have peers) */
971 DeviceFilterList *newList = new DeviceFilterList();
972 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
973 while (it != mDeviceFilters->end())
974 {
975 (*it)->commit();
976
977 /* look if this filter has a peer filter */
978 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
979 if (!peer)
980 {
981 /* no peer means the filter is a newly created one;
982 * create a peer owning data this filter share it with */
983 peer.createObject();
984 peer->init (mPeer, *it, true /* aReshare */);
985 }
986 else
987 {
988 /* remove peer from the old list */
989 mPeer->mDeviceFilters->remove (peer);
990 }
991 /* and add it to the new list */
992 newList->push_back (peer);
993
994 ++ it;
995 }
996
997 /* uninit old peer's filters that are left */
998 it = mPeer->mDeviceFilters->begin();
999 while (it != mPeer->mDeviceFilters->end())
1000 {
1001 (*it)->uninit();
1002 ++ it;
1003 }
1004
1005 /* attach new list of filters to our peer */
1006 mPeer->mDeviceFilters.attach (newList);
1007 }
1008 else
1009 {
1010 /* we have no peer (our parent is the newly created machine);
1011 * just commit changes to filters */
1012 commitFilters = true;
1013 }
1014 }
1015 else
1016 {
1017 /* the list of filters itself is not changed,
1018 * just commit changes to filters themselves */
1019 commitFilters = true;
1020 }
1021
1022 if (commitFilters)
1023 {
1024 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1025 while (it != mDeviceFilters->end())
1026 {
1027 (*it)->commit();
1028 ++ it;
1029 }
1030 }
1031#endif /* VBOX_WITH_USB */
1032}
1033
1034/**
1035 * @note Locks this object for writing, together with the peer object
1036 * represented by @a aThat (locked for reading).
1037 */
1038void USBController::copyFrom (USBController *aThat)
1039{
1040 AssertReturnVoid (aThat != NULL);
1041
1042 /* sanity */
1043 AutoCaller autoCaller (this);
1044 AssertComRCReturnVoid (autoCaller.rc());
1045
1046 /* sanity too */
1047 AutoCaller thatCaller (aThat);
1048 AssertComRCReturnVoid (thatCaller.rc());
1049
1050 /* peer is not modified, lock it for reading (aThat is "master" so locked
1051 * first) */
1052 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1053
1054 if (mParent->isRegistered())
1055 {
1056 /* reuse onMachineRegistered to tell USB proxy to remove all current
1057 filters */
1058 HRESULT rc = onMachineRegistered (FALSE);
1059 AssertComRCReturn (rc, (void) 0);
1060 }
1061
1062 /* this will back up current data */
1063 mData.assignCopy (aThat->mData);
1064
1065#ifdef VBOX_WITH_USB
1066 /* create private copies of all filters */
1067 mDeviceFilters.backup();
1068 mDeviceFilters->clear();
1069 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
1070 it != aThat->mDeviceFilters->end();
1071 ++ it)
1072 {
1073 ComObjPtr <USBDeviceFilter> filter;
1074 filter.createObject();
1075 filter->initCopy (this, *it);
1076 mDeviceFilters->push_back (filter);
1077 }
1078#endif /* VBOX_WITH_USB */
1079
1080 if (mParent->isRegistered())
1081 {
1082 /* reuse onMachineRegistered to tell USB proxy to insert all current
1083 filters */
1084 HRESULT rc = onMachineRegistered (TRUE);
1085 AssertComRCReturn (rc, (void) 0);
1086 }
1087}
1088
1089/**
1090 * Called by VirtualBox when it changes the registered state
1091 * of the machine this USB controller belongs to.
1092 *
1093 * @param aRegistered new registered state of the machine
1094 *
1095 * @note Locks nothing.
1096 */
1097HRESULT USBController::onMachineRegistered (BOOL aRegistered)
1098{
1099 AutoCaller autoCaller (this);
1100 AssertComRCReturnRC (autoCaller.rc());
1101
1102 /// @todo After rewriting Win32 USB support, no more necessary;
1103 // a candidate for removal.
1104#if 0
1105 notifyProxy (!!aRegistered);
1106#endif
1107
1108 return S_OK;
1109}
1110
1111#ifdef VBOX_WITH_USB
1112
1113/**
1114 * Called by setter methods of all USB device filters.
1115 *
1116 * @note Locks nothing.
1117 */
1118HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
1119 BOOL aActiveChanged /* = FALSE */)
1120{
1121 AutoCaller autoCaller (this);
1122 AssertComRCReturnRC (autoCaller.rc());
1123
1124 /// @todo After rewriting Win32 USB support, no more necessary;
1125 // a candidate for removal.
1126#if 0
1127#else
1128 /* we need the machine state */
1129 Machine::AutoAnyStateDependency adep (mParent);
1130 AssertComRCReturnRC (adep.rc());
1131
1132 /* nothing to do if the machine isn't running */
1133 if (adep.machineState() < MachineState_Running)
1134 return S_OK;
1135#endif
1136
1137 /* we don't modify our data fields -- no need to lock */
1138
1139 if (aFilter->mInList && mParent->isRegistered())
1140 {
1141 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1142 ComAssertRet (service, E_FAIL);
1143
1144 if (aActiveChanged)
1145 {
1146 /* insert/remove the filter from the proxy */
1147 if (aFilter->data().mActive)
1148 {
1149 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1150 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1151 }
1152 else
1153 {
1154 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1155 service->removeFilter (aFilter->id());
1156 aFilter->id() = NULL;
1157 }
1158 }
1159 else
1160 {
1161 if (aFilter->data().mActive)
1162 {
1163 /* update the filter in the proxy */
1164 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1165 service->removeFilter (aFilter->id());
1166 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1167 }
1168 }
1169 }
1170
1171 return S_OK;
1172}
1173
1174/**
1175 * Returns true if the given USB device matches to at least one of
1176 * this controller's USB device filters.
1177 *
1178 * A HostUSBDevice specific version.
1179 *
1180 * @note Locks this object for reading.
1181 */
1182bool USBController::hasMatchingFilter (const ComObjPtr <HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
1183{
1184 AutoCaller autoCaller (this);
1185 AssertComRCReturn (autoCaller.rc(), false);
1186
1187 AutoReadLock alock (this);
1188
1189 /* Disabled USB controllers cannot actually work with USB devices */
1190 if (!mData->mEnabled)
1191 return false;
1192
1193 /* apply self filters */
1194 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1195 it != mDeviceFilters->end();
1196 ++ it)
1197 {
1198 AutoWriteLock filterLock (*it);
1199 if (aDevice->isMatch ((*it)->data()))
1200 {
1201 *aMaskedIfs = (*it)->data().mMaskedIfs;
1202 return true;
1203 }
1204 }
1205
1206 return false;
1207}
1208
1209/**
1210 * Returns true if the given USB device matches to at least one of
1211 * this controller's USB device filters.
1212 *
1213 * A generic version that accepts any IUSBDevice on input.
1214 *
1215 * @note
1216 * This method MUST correlate with HostUSBDevice::isMatch()
1217 * in the sense of the device matching logic.
1218 *
1219 * @note Locks this object for reading.
1220 */
1221bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
1222{
1223 LogFlowThisFuncEnter();
1224
1225 AutoCaller autoCaller (this);
1226 AssertComRCReturn (autoCaller.rc(), false);
1227
1228 AutoReadLock alock (this);
1229
1230 /* Disabled USB controllers cannot actually work with USB devices */
1231 if (!mData->mEnabled)
1232 return false;
1233
1234 HRESULT rc = S_OK;
1235
1236 /* query fields */
1237 USBFILTER dev;
1238 USBFilterInit (&dev, USBFILTERTYPE_CAPTURE);
1239
1240 USHORT vendorId = 0;
1241 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1242 ComAssertComRCRet (rc, false);
1243 ComAssertRet (vendorId, false);
1244 int vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
1245
1246 USHORT productId = 0;
1247 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1248 ComAssertComRCRet (rc, false);
1249 ComAssertRet (productId, false);
1250 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
1251
1252 USHORT revision;
1253 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1254 ComAssertComRCRet (rc, false);
1255 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
1256
1257 Bstr manufacturer;
1258 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1259 ComAssertComRCRet (rc, false);
1260 if (!manufacturer.isNull())
1261 USBFilterSetStringExact (&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer), true);
1262
1263 Bstr product;
1264 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1265 ComAssertComRCRet (rc, false);
1266 if (!product.isNull())
1267 USBFilterSetStringExact (&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product), true);
1268
1269 Bstr serialNumber;
1270 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1271 ComAssertComRCRet (rc, false);
1272 if (!serialNumber.isNull())
1273 USBFilterSetStringExact (&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber), true);
1274
1275 Bstr address;
1276 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1277 ComAssertComRCRet (rc, false);
1278
1279 USHORT port = 0;
1280 rc = aUSBDevice->COMGETTER(Port)(&port);
1281 ComAssertComRCRet (rc, false);
1282 USBFilterSetNumExact (&dev, USBFILTERIDX_PORT, port, true);
1283
1284 BOOL remote = FALSE;
1285 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1286 ComAssertComRCRet (rc, false);
1287 ComAssertRet (remote == TRUE, false);
1288
1289 bool match = false;
1290
1291 /* apply self filters */
1292 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1293 it != mDeviceFilters->end();
1294 ++ it)
1295 {
1296 AutoWriteLock filterLock (*it);
1297 const USBDeviceFilter::Data &aData = (*it)->data();
1298
1299 if (!aData.mActive)
1300 continue;
1301 if (!aData.mRemote.isMatch (remote))
1302 continue;
1303 if (!USBFilterMatch (&aData.mUSBFilter, &dev))
1304 continue;
1305
1306 match = true;
1307 *aMaskedIfs = aData.mMaskedIfs;
1308 break;
1309 }
1310
1311 LogFlowThisFunc (("returns: %d\n", match));
1312 LogFlowThisFuncLeave();
1313
1314 return match;
1315}
1316
1317/**
1318 * Notifies the proxy service about all filters as requested by the
1319 * @a aInsertFilters argument.
1320 *
1321 * @param aInsertFilters @c true to insert filters, @c false to remove.
1322 *
1323 * @note Locks this object for reading.
1324 */
1325HRESULT USBController::notifyProxy (bool aInsertFilters)
1326{
1327 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1328
1329 AutoCaller autoCaller (this);
1330 AssertComRCReturn (autoCaller.rc(), false);
1331
1332 AutoReadLock alock (this);
1333
1334 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1335 AssertReturn (service, E_FAIL);
1336
1337 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1338 while (it != mDeviceFilters->end())
1339 {
1340 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1341
1342 /* notify the proxy (only if the filter is active) */
1343 if (flt->data().mActive)
1344 {
1345 if (aInsertFilters)
1346 {
1347 AssertReturn (flt->id() == NULL, E_FAIL);
1348 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
1349 }
1350 else
1351 {
1352 /* It's possible that the given filter was not inserted the proxy
1353 * when this method gets called (as a result of an early VM
1354 * process crash for example. So, don't assert that ID != NULL. */
1355 if (flt->id() != NULL)
1356 {
1357 service->removeFilter (flt->id());
1358 flt->id() = NULL;
1359 }
1360 }
1361 }
1362 ++ it;
1363 }
1364
1365 return S_OK;
1366}
1367
1368#endif /* VBOX_WITH_USB */
1369
1370// private methods
1371/////////////////////////////////////////////////////////////////////////////
1372
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use