VirtualBox

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

Last change on this file since 28292 was 27607, checked in by vboxsync, 15 years ago

Main: remove templates for 'weak' com pointers which do nothing anyway

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