VirtualBox

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

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

The OSE case (no USB) didn't compile

  • 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 10535 2008-07-11 15:28:06Z 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 :
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 return E_NOTIMPL;
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 return E_NOTIMPL;
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 return E_NOTIMPL;
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
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use