VirtualBox

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

Last change on this file since 7964 was 7964, checked in by vboxsync, 17 years ago

Attempt at making OSE build again.

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