VirtualBox

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

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

Added vim modelines to aid following coding guidelines, like no tabs,
similar to what is already in the xidl file.

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