VirtualBox

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

Last change on this file since 28800 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use