VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBControllerImpl.cpp@ 43394

Last change on this file since 43394 was 42551, checked in by vboxsync, 12 years ago

Main: big API naming cleanup, use all caps acronyms everywhere, including SDK docs
Frontends/VBoxManage: implement guestcontrol execute for new API, disabled by default

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