diff options
Diffstat (limited to 'src/VBox/Main/src-server/USBControllerImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-server/USBControllerImpl.cpp | 1010 |
1 files changed, 86 insertions, 924 deletions
diff --git a/src/VBox/Main/src-server/USBControllerImpl.cpp b/src/VBox/Main/src-server/USBControllerImpl.cpp index 8f4d1c48..18c4f43e 100644 --- a/src/VBox/Main/src-server/USBControllerImpl.cpp +++ b/src/VBox/Main/src-server/USBControllerImpl.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2005-2012 Oracle Corporation + * Copyright (C) 2005-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -21,18 +21,13 @@ #include "MachineImpl.h" #include "VirtualBoxImpl.h" #include "HostImpl.h" -#ifdef VBOX_WITH_USB -# include "USBDeviceImpl.h" -# include "HostUSBDeviceImpl.h" -# include "USBProxyService.h" -# include "USBDeviceFilterImpl.h" -#endif #include <iprt/string.h> #include <iprt/cpp/utils.h> #include <VBox/err.h> #include <VBox/settings.h> +#include <VBox/com/array.h> #include <algorithm> @@ -43,41 +38,31 @@ // defines ///////////////////////////////////////////////////////////////////////////// -typedef std::list< ComObjPtr<USBDeviceFilter> > DeviceFilterList; - struct BackupableUSBData { BackupableUSBData() - : fEnabled(false), - fEnabledEHCI(false) + : enmType(USBControllerType_Null) { } - BOOL fEnabled; - BOOL fEnabledEHCI; + Utf8Str strName; + USBControllerType_T enmType; }; struct USBController::Data { Data(Machine *pMachine) - : pParent(pMachine), - pHost(pMachine->getVirtualBox()->host()) + : pParent(pMachine) { } ~Data() {}; Machine * const pParent; - Host * const pHost; // peer machine's USB controller const ComObjPtr<USBController> pPeer; Backupable<BackupableUSBData> bd; -#ifdef VBOX_WITH_USB - // the following fields need special backup/rollback/commit handling, - // so they cannot be a part of BackupableData - Backupable<DeviceFilterList> llDeviceFilters; -#endif }; @@ -106,12 +91,18 @@ void USBController::FinalRelease() * * @returns COM result indicator. * @param aParent Pointer to our parent object. + * @param aName The name of the USB controller. + * @param enmType The USB controller type. */ -HRESULT USBController::init(Machine *aParent) +HRESULT USBController::init(Machine *aParent, const Utf8Str &aName, USBControllerType_T enmType) { - LogFlowThisFunc(("aParent=%p\n", aParent)); + LogFlowThisFunc(("aParent=%p aName=\"%s\"\n", aParent, aName.c_str())); - ComAssertRet(aParent, E_INVALIDARG); + ComAssertRet(aParent && !aName.isEmpty(), E_INVALIDARG); + if ( (enmType <= USBControllerType_Null) + || (enmType > USBControllerType_EHCI)) + return setError(E_INVALIDARG, + tr("Invalid USB controller type")); /* Enclose the state transition NotReady->InInit->Ready */ AutoInitSpan autoInitSpan(this); @@ -122,9 +113,8 @@ HRESULT USBController::init(Machine *aParent) /* mPeer is left null */ m->bd.allocate(); -#ifdef VBOX_WITH_USB - m->llDeviceFilters.allocate(); -#endif + m->bd->strName = aName; + m->bd->enmType = enmType; /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -140,13 +130,22 @@ HRESULT USBController::init(Machine *aParent) * @returns COM result indicator. * @param aParent Pointer to our parent object. * @param aPeer The object to share. + * @param aReshare + * When false, the original object will remain a data owner. + * Otherwise, data ownership will be transferred from the original + * object to this one. + * + * @note This object must be destroyed before the original object + * it shares data with is destroyed. * - * @note This object must be destroyed before the original object - * it shares data with is destroyed. + * @note Locks @a aThat object for writing if @a aReshare is @c true, or for + * reading if @a aReshare is false. */ -HRESULT USBController::init(Machine *aParent, USBController *aPeer) +HRESULT USBController::init(Machine *aParent, USBController *aPeer, + bool fReshare /* = false */) { - LogFlowThisFunc(("aParent=%p, aPeer=%p\n", aParent, aPeer)); + LogFlowThisFunc(("aParent=%p, aPeer=%p, fReshare=%RTbool\n", + aParent, aPeer, fReshare)); ComAssertRet(aParent && aPeer, E_INVALIDARG); @@ -156,24 +155,24 @@ HRESULT USBController::init(Machine *aParent, USBController *aPeer) m = new Data(aParent); - unconst(m->pPeer) = aPeer; + /* sanity */ + AutoCaller peerCaller(aPeer); + AssertComRCReturnRC(peerCaller.rc()); - AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS); - m->bd.share(aPeer->m->bd); + if (fReshare) + { + AutoWriteLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS); -#ifdef VBOX_WITH_USB - /* create copies of all filters */ - m->llDeviceFilters.allocate(); - DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin(); - while (it != aPeer->m->llDeviceFilters->end()) + unconst(aPeer->m->pPeer) = this; + m->bd.attach (aPeer->m->bd); + } + else { - ComObjPtr<USBDeviceFilter> filter; - filter.createObject(); - filter->init(this, *it); - m->llDeviceFilters->push_back(filter); - ++it; + unconst(m->pPeer) = aPeer; + + AutoReadLock peerLock(aPeer COMMA_LOCKVAL_SRC_POS); + m->bd.share (aPeer->m->bd); } -#endif /* VBOX_WITH_USB */ /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -204,20 +203,6 @@ HRESULT USBController::initCopy(Machine *aParent, USBController *aPeer) AutoWriteLock thatlock(aPeer COMMA_LOCKVAL_SRC_POS); m->bd.attachCopy(aPeer->m->bd); -#ifdef VBOX_WITH_USB - /* create private copies of all filters */ - m->llDeviceFilters.allocate(); - DeviceFilterList::const_iterator it = aPeer->m->llDeviceFilters->begin(); - while (it != aPeer->m->llDeviceFilters->end()) - { - ComObjPtr<USBDeviceFilter> filter; - filter.createObject(); - filter->initCopy(this, *it); - m->llDeviceFilters->push_back(filter); - ++it; - } -#endif /* VBOX_WITH_USB */ - /* Confirm a successful initialization */ autoInitSpan.setSucceeded(); @@ -238,16 +223,6 @@ void USBController::uninit() if (autoUninitSpan.uninitDone()) return; -#ifdef VBOX_WITH_USB - // uninit all device filters on the list (it's a standard std::list not an ObjectsList - // so we must uninit() manually) - for (DeviceFilterList::iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - (*it)->uninit(); - - m->llDeviceFilters.free(); -#endif m->bd.free(); unconst(m->pPeer) = NULL; @@ -260,112 +235,29 @@ void USBController::uninit() // IUSBController properties ///////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP USBController::COMGETTER(Enabled)(BOOL *aEnabled) -{ - CheckComArgOutPointerValid(aEnabled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - *aEnabled = m->bd->fEnabled; - - return S_OK; -} - - -STDMETHODIMP USBController::COMSETTER(Enabled)(BOOL aEnabled) -{ - LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled)); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (m->bd->fEnabled != aEnabled) - { - m->bd.backup(); - m->bd->fEnabled = aEnabled; - - // leave the lock for safety - alock.release(); - - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - - m->pParent->onUSBControllerChange(); - } - - return S_OK; -} - -STDMETHODIMP USBController::COMGETTER(EnabledEHCI)(BOOL *aEnabled) -{ - CheckComArgOutPointerValid(aEnabled); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - *aEnabled = m->bd->fEnabledEHCI; - - return S_OK; -} - -STDMETHODIMP USBController::COMSETTER(EnabledEHCI)(BOOL aEnabled) +STDMETHODIMP USBController::COMGETTER(Name) (BSTR *aName) { - LogFlowThisFunc(("aEnabled=%RTbool\n", aEnabled)); + CheckComArgOutPointerValid(aName); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (m->bd->fEnabledEHCI != aEnabled) - { - m->bd.backup(); - m->bd->fEnabledEHCI = aEnabled; - - // leave the lock for safety - alock.release(); - - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - - m->pParent->onUSBControllerChange(); - } + /* strName is constant during life time, no need to lock */ + m->bd->strName.cloneTo(aName); return S_OK; } -STDMETHODIMP USBController::COMGETTER(ProxyAvailable)(BOOL *aEnabled) +STDMETHODIMP USBController::COMGETTER(Type)(USBControllerType_T *aType) { - CheckComArgOutPointerValid(aEnabled); + CheckComArgOutPointerValid(aType); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); -#ifdef VBOX_WITH_USB - *aEnabled = true; -#else - *aEnabled = false; -#endif + *aType = m->bd->enmType; return S_OK; } @@ -377,366 +269,27 @@ STDMETHODIMP USBController::COMGETTER(USBStandard)(USHORT *aUSBStandard) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - /* not accessing data -- no need to lock */ - - /** @todo This is no longer correct */ - *aUSBStandard = 0x0101; - - return S_OK; -} - -#ifndef VBOX_WITH_USB -/** - * Fake class for build without USB. - * We need an empty collection & enum for deviceFilters, that's all. - */ -class ATL_NO_VTABLE USBDeviceFilter : - public VirtualBoxBase, - VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilter) -{ -public: - DECLARE_NOT_AGGREGATABLE(USBDeviceFilter) - DECLARE_PROTECT_FINAL_CONSTRUCT() - BEGIN_COM_MAP(USBDeviceFilter) - VBOX_DEFAULT_INTERFACE_ENTRIES(IUSBDeviceFilter) - END_COM_MAP() - - DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilter) - - // IUSBDeviceFilter properties - STDMETHOD(COMGETTER(Name))(BSTR *aName); - STDMETHOD(COMSETTER(Name))(IN_BSTR aName); - STDMETHOD(COMGETTER(Active))(BOOL *aActive); - STDMETHOD(COMSETTER(Active))(BOOL aActive); - STDMETHOD(COMGETTER(VendorId))(BSTR *aVendorId); - STDMETHOD(COMSETTER(VendorId))(IN_BSTR aVendorId); - STDMETHOD(COMGETTER(ProductId))(BSTR *aProductId); - STDMETHOD(COMSETTER(ProductId))(IN_BSTR aProductId); - STDMETHOD(COMGETTER(Revision))(BSTR *aRevision); - STDMETHOD(COMSETTER(Revision))(IN_BSTR aRevision); - STDMETHOD(COMGETTER(Manufacturer))(BSTR *aManufacturer); - STDMETHOD(COMSETTER(Manufacturer))(IN_BSTR aManufacturer); - STDMETHOD(COMGETTER(Product))(BSTR *aProduct); - STDMETHOD(COMSETTER(Product))(IN_BSTR aProduct); - STDMETHOD(COMGETTER(SerialNumber))(BSTR *aSerialNumber); - STDMETHOD(COMSETTER(SerialNumber))(IN_BSTR aSerialNumber); - STDMETHOD(COMGETTER(Port))(BSTR *aPort); - STDMETHOD(COMSETTER(Port))(IN_BSTR aPort); - STDMETHOD(COMGETTER(Remote))(BSTR *aRemote); - STDMETHOD(COMSETTER(Remote))(IN_BSTR aRemote); - STDMETHOD(COMGETTER(MaskedInterfaces))(ULONG *aMaskedIfs); - STDMETHOD(COMSETTER(MaskedInterfaces))(ULONG aMaskedIfs); -}; -#endif /* !VBOX_WITH_USB */ - - -STDMETHODIMP USBController::COMGETTER(DeviceFilters)(ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters)) -{ -#ifdef VBOX_WITH_USB - CheckComArgOutSafeArrayPointerValid(aDevicesFilters); - - AutoCaller autoCaller(this); - if(FAILED(autoCaller.rc())) return autoCaller.rc(); - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - SafeIfaceArray<IUSBDeviceFilter> collection(*m->llDeviceFilters.data()); - collection.detachTo(ComSafeArrayOutArg(aDevicesFilters)); - - return S_OK; -#else - NOREF(aDevicesFilters); -# ifndef RT_OS_WINDOWS - NOREF(aDevicesFiltersSize); -# endif - ReturnComNotImplemented(); -#endif -} - -// IUSBController methods -///////////////////////////////////////////////////////////////////////////// - -STDMETHODIMP USBController::CreateDeviceFilter(IN_BSTR aName, - IUSBDeviceFilter **aFilter) -{ -#ifdef VBOX_WITH_USB - CheckComArgOutPointerValid(aFilter); - - CheckComArgStrNotEmptyOrNull(aName); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - ComObjPtr<USBDeviceFilter> filter; - filter.createObject(); - HRESULT rc = filter->init(this, aName); - ComAssertComRCRetRC(rc); - rc = filter.queryInterfaceTo(aFilter); - AssertComRCReturnRC(rc); - - return S_OK; -#else - NOREF(aName); - NOREF(aFilter); - ReturnComNotImplemented(); -#endif -} - -STDMETHODIMP USBController::InsertDeviceFilter(ULONG aPosition, - IUSBDeviceFilter *aFilter) -{ -#ifdef VBOX_WITH_USB - - CheckComArgNotNull(aFilter); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - ComObjPtr<USBDeviceFilter> filter = static_cast<USBDeviceFilter*>(aFilter); - // @todo r=dj make sure the input object is actually from us -// if (!filter) -// return setError(E_INVALIDARG, -// tr("The given USB device filter is not created within " -// "this VirtualBox instance")); - - if (filter->mInList) - return setError(VBOX_E_INVALID_OBJECT_STATE, - tr("The given USB device filter is already in the list")); - - /* backup the list before modification */ - m->llDeviceFilters.backup(); - - /* iterate to the position... */ - DeviceFilterList::iterator it; - if (aPosition < m->llDeviceFilters->size()) + switch (m->bd->enmType) { - it = m->llDeviceFilters->begin(); - std::advance(it, aPosition); - } - else - it = m->llDeviceFilters->end(); - /* ...and insert */ - m->llDeviceFilters->insert(it, filter); - filter->mInList = true; - - /* notify the proxy (only when it makes sense) */ - if (filter->getData().mActive && Global::IsOnline(adep.machineState()) - && filter->getData().mRemote.isMatch(false)) - { - USBProxyService *service = m->pHost->usbProxyService(); - ComAssertRet(service, E_FAIL); - - ComAssertRet(filter->getId() == NULL, E_FAIL); - filter->getId() = service->insertFilter(&filter->getData().mUSBFilter); + case USBControllerType_OHCI: + *aUSBStandard = 0x0101; + break; + case USBControllerType_EHCI: + *aUSBStandard = 0x0200; + break; + default: + AssertMsgFailedReturn(("Invalid controller type %d\n", m->bd->enmType), + E_FAIL); } - alock.release(); - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - return S_OK; - -#else /* VBOX_WITH_USB */ - - NOREF(aPosition); - NOREF(aFilter); - ReturnComNotImplemented(); - -#endif /* VBOX_WITH_USB */ -} - -STDMETHODIMP USBController::RemoveDeviceFilter(ULONG aPosition, - IUSBDeviceFilter **aFilter) -{ -#ifdef VBOX_WITH_USB - - CheckComArgOutPointerValid(aFilter); - - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - /* the machine needs to be mutable */ - AutoMutableStateDependency adep(m->pParent); - if (FAILED(adep.rc())) return adep.rc(); - - AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); - - if (!m->llDeviceFilters->size()) - return setError(E_INVALIDARG, - tr("The USB device filter list is empty")); - - if (aPosition >= m->llDeviceFilters->size()) - return setError(E_INVALIDARG, - tr("Invalid position: %lu (must be in range [0, %lu])"), - aPosition, m->llDeviceFilters->size() - 1); - - /* backup the list before modification */ - m->llDeviceFilters.backup(); - - ComObjPtr<USBDeviceFilter> filter; - { - /* iterate to the position... */ - DeviceFilterList::iterator it = m->llDeviceFilters->begin(); - std::advance(it, aPosition); - /* ...get an element from there... */ - filter = *it; - /* ...and remove */ - filter->mInList = false; - m->llDeviceFilters->erase(it); - } - - /* cancel sharing (make an independent copy of data) */ - filter->unshare(); - - filter.queryInterfaceTo(aFilter); - - /* notify the proxy (only when it makes sense) */ - if (filter->getData().mActive && Global::IsOnline(adep.machineState()) - && filter->getData().mRemote.isMatch(false)) - { - USBProxyService *service = m->pHost->usbProxyService(); - ComAssertRet(service, E_FAIL); - - ComAssertRet(filter->getId() != NULL, E_FAIL); - service->removeFilter(filter->getId()); - filter->getId() = NULL; - } - - alock.release(); - AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS); - m->pParent->setModified(Machine::IsModified_USB); - mlock.release(); - - return S_OK; - -#else /* VBOX_WITH_USB */ - - NOREF(aPosition); - NOREF(aFilter); - ReturnComNotImplemented(); - -#endif /* VBOX_WITH_USB */ } // public methods only for internal purposes ///////////////////////////////////////////////////////////////////////////// -/** - * Loads settings from the given machine node. - * May be called once right after this object creation. - * - * @param aMachineNode <Machine> node. - * - * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either. - */ -HRESULT USBController::loadSettings(const settings::USBController &data) -{ - AutoCaller autoCaller(this); - AssertComRCReturnRC(autoCaller.rc()); - - /* Note: we assume that the default values for attributes of optional - * nodes are assigned in the Data::Data() constructor and don't do it - * here. It implies that this method may only be called after constructing - * a new BIOSSettings object while all its data fields are in the default - * values. Exceptions are fields whose creation time defaults don't match - * values that should be applied when these fields are not explicitly set - * in the settings file (for backwards compatibility reasons). This takes - * place when a setting of a newly created object must default to A while - * the same setting of an object loaded from the old settings file must - * default to B. */ - - m->bd->fEnabled = data.fEnabled; - m->bd->fEnabledEHCI = data.fEnabledEHCI; - -#ifdef VBOX_WITH_USB - for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin(); - it != data.llDeviceFilters.end(); - ++it) - { - const settings::USBDeviceFilter &f = *it; - ComObjPtr<USBDeviceFilter> pFilter; - pFilter.createObject(); - HRESULT rc = pFilter->init(this, // parent - f); - if (FAILED(rc)) return rc; - - m->llDeviceFilters->push_back(pFilter); - pFilter->mInList = true; - } -#endif /* VBOX_WITH_USB */ - - return S_OK; -} - -/** - * Saves settings to the given machine node. - * - * @param aMachineNode <Machine> node. - * - * @note Locks this object for reading. - */ -HRESULT USBController::saveSettings(settings::USBController &data) -{ - AutoCaller autoCaller(this); - if (FAILED(autoCaller.rc())) return autoCaller.rc(); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - data.fEnabled = !!m->bd->fEnabled; - data.fEnabledEHCI = !!m->bd->fEnabledEHCI; - -#ifdef VBOX_WITH_USB - data.llDeviceFilters.clear(); - - for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - { - AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); - const USBDeviceFilter::Data &filterData = (*it)->getData(); - - Bstr str; - - settings::USBDeviceFilter f; - f.strName = filterData.mName; - f.fActive = !!filterData.mActive; - (*it)->COMGETTER(VendorId)(str.asOutParam()); - f.strVendorId = str; - (*it)->COMGETTER(ProductId)(str.asOutParam()); - f.strProductId = str; - (*it)->COMGETTER(Revision)(str.asOutParam()); - f.strRevision = str; - (*it)->COMGETTER(Manufacturer)(str.asOutParam()); - f.strManufacturer = str; - (*it)->COMGETTER(Product)(str.asOutParam()); - f.strProduct = str; - (*it)->COMGETTER(SerialNumber)(str.asOutParam()); - f.strSerialNumber = str; - (*it)->COMGETTER(Port)(str.asOutParam()); - f.strPort = str; - f.strRemote = filterData.mRemote.string(); - f.ulMaskedInterfaces = filterData.mMaskedIfs; - - data.llDeviceFilters.push_back(f); - } -#endif /* VBOX_WITH_USB */ - - return S_OK; -} - /** @note Locks objects for writing! */ void USBController::rollback() { @@ -750,82 +303,6 @@ void USBController::rollback() AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); m->bd.rollback(); - -#ifdef VBOX_WITH_USB - - if (m->llDeviceFilters.isBackedUp()) - { - USBProxyService *service = m->pHost->usbProxyService(); - Assert(service); - - /* uninitialize all new filters (absent in the backed up list) */ - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - DeviceFilterList *backedList = m->llDeviceFilters.backedUpData(); - while (it != m->llDeviceFilters->end()) - { - if (std::find(backedList->begin(), backedList->end(), *it) == - backedList->end()) - { - /* notify the proxy (only when it makes sense) */ - if ((*it)->getData().mActive && - Global::IsOnline(adep.machineState()) - && (*it)->getData().mRemote.isMatch(false)) - { - USBDeviceFilter *filter = *it; - Assert(filter->getId() != NULL); - service->removeFilter(filter->getId()); - filter->getId() = NULL; - } - - (*it)->uninit(); - } - ++it; - } - - if (Global::IsOnline(adep.machineState())) - { - /* find all removed old filters (absent in the new list) - * and insert them back to the USB proxy */ - it = backedList->begin(); - while (it != backedList->end()) - { - if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) == - m->llDeviceFilters->end()) - { - /* notify the proxy (only when necessary) */ - if ((*it)->getData().mActive - && (*it)->getData().mRemote.isMatch(false)) - { - USBDeviceFilter *flt = *it; /* resolve ambiguity */ - Assert(flt->getId() == NULL); - flt->getId() = service->insertFilter(&flt->getData().mUSBFilter); - } - } - ++it; - } - } - - /* restore the list */ - m->llDeviceFilters.rollback(); - } - - /* here we don't depend on the machine state any more */ - adep.release(); - - /* rollback any changes to filters after restoring the list */ - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - if ((*it)->isModified()) - { - (*it)->rollback(); - /* call this to notify the USB proxy about changes */ - onDeviceFilterChange(*it); - } - ++it; - } - -#endif /* VBOX_WITH_USB */ } /** @@ -856,82 +333,6 @@ void USBController::commit() m->pPeer->m->bd.attach(m->bd); } } - -#ifdef VBOX_WITH_USB - bool commitFilters = false; - - if (m->llDeviceFilters.isBackedUp()) - { - m->llDeviceFilters.commit(); - - /* apply changes to peer */ - if (m->pPeer) - { - AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS); - - /* commit all changes to new filters (this will reshare data with - * peers for those who have peers) */ - DeviceFilterList *newList = new DeviceFilterList(); - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - (*it)->commit(); - - /* look if this filter has a peer filter */ - ComObjPtr<USBDeviceFilter> peer = (*it)->peer(); - if (!peer) - { - /* no peer means the filter is a newly created one; - * create a peer owning data this filter share it with */ - peer.createObject(); - peer->init(m->pPeer, *it, true /* aReshare */); - } - else - { - /* remove peer from the old list */ - m->pPeer->m->llDeviceFilters->remove(peer); - } - /* and add it to the new list */ - newList->push_back(peer); - - ++it; - } - - /* uninit old peer's filters that are left */ - it = m->pPeer->m->llDeviceFilters->begin(); - while (it != m->pPeer->m->llDeviceFilters->end()) - { - (*it)->uninit(); - ++it; - } - - /* attach new list of filters to our peer */ - m->pPeer->m->llDeviceFilters.attach(newList); - } - else - { - /* we have no peer (our parent is the newly created machine); - * just commit changes to filters */ - commitFilters = true; - } - } - else - { - /* the list of filters itself is not changed, - * just commit changes to filters themselves */ - commitFilters = true; - } - - if (commitFilters) - { - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - (*it)->commit(); - ++it; - } - } -#endif /* VBOX_WITH_USB */ } /** @@ -963,295 +364,56 @@ void USBController::copyFrom(USBController *aThat) /* this will back up current data */ m->bd.assignCopy(aThat->m->bd); - -#ifdef VBOX_WITH_USB - - /* Note that we won't inform the USB proxy about new filters since the VM is - * not running when we are here and therefore no need to do so */ - - /* create private copies of all filters */ - m->llDeviceFilters.backup(); - m->llDeviceFilters->clear(); - for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin(); - it != aThat->m->llDeviceFilters->end(); - ++it) - { - ComObjPtr<USBDeviceFilter> filter; - filter.createObject(); - filter->initCopy(this, *it); - m->llDeviceFilters->push_back(filter); - } - -#endif /* VBOX_WITH_USB */ } -#ifdef VBOX_WITH_USB - /** - * Called by setter methods of all USB device filters. + * Cancels sharing (if any) by making an independent copy of data. + * This operation also resets this object's peer to NULL. * - * @note Locks nothing. + * @note Locks this object for writing, together with the peer object + * represented by @a aThat (locked for reading). */ -HRESULT USBController::onDeviceFilterChange(USBDeviceFilter *aFilter, - BOOL aActiveChanged /* = FALSE */) +void USBController::unshare() { + /* sanity */ AutoCaller autoCaller(this); - AssertComRCReturnRC(autoCaller.rc()); + AssertComRCReturnVoid (autoCaller.rc()); - /* we need the machine state */ - AutoAnyStateDependency adep(m->pParent); - AssertComRCReturnRC(adep.rc()); - - /* nothing to do if the machine isn't running */ - if (!Global::IsOnline(adep.machineState())) - return S_OK; + /* sanity too */ + AutoCaller peerCaller (m->pPeer); + AssertComRCReturnVoid (peerCaller.rc()); - /* we don't modify our data fields -- no need to lock */ + /* peer is not modified, lock it for reading (m->pPeer is "master" so locked + * first) */ + AutoReadLock rl(m->pPeer COMMA_LOCKVAL_SRC_POS); + AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS); - if ( aFilter->mInList - && m->pParent->isRegistered()) + if (m->bd.isShared()) { - USBProxyService *service = m->pHost->usbProxyService(); - ComAssertRet(service, E_FAIL); - - if (aActiveChanged) - { - if (aFilter->getData().mRemote.isMatch(false)) - { - /* insert/remove the filter from the proxy */ - if (aFilter->getData().mActive) - { - ComAssertRet(aFilter->getId() == NULL, E_FAIL); - aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter); - } - else - { - ComAssertRet(aFilter->getId() != NULL, E_FAIL); - service->removeFilter(aFilter->getId()); - aFilter->getId() = NULL; - } - } - } - else - { - if (aFilter->getData().mActive) - { - /* update the filter in the proxy */ - ComAssertRet(aFilter->getId() != NULL, E_FAIL); - service->removeFilter(aFilter->getId()); - if (aFilter->getData().mRemote.isMatch(false)) - { - aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter); - } - } - } - } - - return S_OK; -} - -/** - * Returns true if the given USB device matches to at least one of - * this controller's USB device filters. - * - * A HostUSBDevice specific version. - * - * @note Locks this object for reading. - */ -bool USBController::hasMatchingFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs) -{ - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), false); + if (!m->bd.isBackedUp()) + m->bd.backup(); - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - /* Disabled USB controllers cannot actually work with USB devices */ - if (!m->bd->fEnabled) - return false; - - /* apply self filters */ - for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - { - AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); - if (aDevice->isMatch((*it)->getData())) - { - *aMaskedIfs = (*it)->getData().mMaskedIfs; - return true; - } + m->bd.commit(); } - return false; + unconst(m->pPeer) = NULL; } -/** - * Returns true if the given USB device matches to at least one of - * this controller's USB device filters. - * - * A generic version that accepts any IUSBDevice on input. - * - * @note - * This method MUST correlate with HostUSBDevice::isMatch() - * in the sense of the device matching logic. - * - * @note Locks this object for reading. - */ -bool USBController::hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs) +const Utf8Str& USBController::getName() const { - LogFlowThisFuncEnter(); - - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), false); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - /* Disabled USB controllers cannot actually work with USB devices */ - if (!m->bd->fEnabled) - return false; - - HRESULT rc = S_OK; - - /* query fields */ - USBFILTER dev; - USBFilterInit(&dev, USBFILTERTYPE_CAPTURE); - - USHORT vendorId = 0; - rc = aUSBDevice->COMGETTER(VendorId)(&vendorId); - ComAssertComRCRet(rc, false); - ComAssertRet(vendorId, false); - int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc); - - USHORT productId = 0; - rc = aUSBDevice->COMGETTER(ProductId)(&productId); - ComAssertComRCRet(rc, false); - vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc); - - USHORT revision; - rc = aUSBDevice->COMGETTER(Revision)(&revision); - ComAssertComRCRet(rc, false); - vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc); - - Bstr manufacturer; - rc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam()); - ComAssertComRCRet(rc, false); - if (!manufacturer.isEmpty()) - USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true); - - Bstr product; - rc = aUSBDevice->COMGETTER(Product)(product.asOutParam()); - ComAssertComRCRet(rc, false); - if (!product.isEmpty()) - USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true); - - Bstr serialNumber; - rc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam()); - ComAssertComRCRet(rc, false); - if (!serialNumber.isEmpty()) - USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true); - - Bstr address; - rc = aUSBDevice->COMGETTER(Address)(address.asOutParam()); - ComAssertComRCRet(rc, false); - - USHORT port = 0; - rc = aUSBDevice->COMGETTER(Port)(&port); - ComAssertComRCRet(rc, false); - USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true); - - BOOL remote = FALSE; - rc = aUSBDevice->COMGETTER(Remote)(&remote); - ComAssertComRCRet(rc, false); - ComAssertRet(remote == TRUE, false); - - bool match = false; - - /* apply self filters */ - for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - it != m->llDeviceFilters->end(); - ++it) - { - AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS); - const USBDeviceFilter::Data &aData = (*it)->getData(); - - if (!aData.mActive) - continue; - if (!aData.mRemote.isMatch(remote)) - continue; - if (!USBFilterMatch(&aData.mUSBFilter, &dev)) - continue; - - match = true; - *aMaskedIfs = aData.mMaskedIfs; - break; - } - - LogFlowThisFunc(("returns: %d\n", match)); - LogFlowThisFuncLeave(); - - return match; + return m->bd->strName; } -/** - * Notifies the proxy service about all filters as requested by the - * @a aInsertFilters argument. - * - * @param aInsertFilters @c true to insert filters, @c false to remove. - * - * @note Locks this object for reading. - */ -HRESULT USBController::notifyProxy(bool aInsertFilters) +USBControllerType_T USBController::getControllerType() const { - LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters)); - - AutoCaller autoCaller(this); - AssertComRCReturn(autoCaller.rc(), false); - - AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - - USBProxyService *service = m->pHost->usbProxyService(); - AssertReturn(service, E_FAIL); - - DeviceFilterList::const_iterator it = m->llDeviceFilters->begin(); - while (it != m->llDeviceFilters->end()) - { - USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */ - - /* notify the proxy (only if the filter is active) */ - if ( flt->getData().mActive - && flt->getData().mRemote.isMatch(false) /* and if the filter is NOT remote */ - ) - { - if (aInsertFilters) - { - AssertReturn(flt->getId() == NULL, E_FAIL); - flt->getId() = service->insertFilter(&flt->getData().mUSBFilter); - } - else - { - /* It's possible that the given filter was not inserted the proxy - * when this method gets called (as a result of an early VM - * process crash for example. So, don't assert that ID != NULL. */ - if (flt->getId() != NULL) - { - service->removeFilter(flt->getId()); - flt->getId() = NULL; - } - } - } - ++it; - } - - return S_OK; + return m->bd->enmType; } -Machine* USBController::getMachine() +ComObjPtr<USBController> USBController::getPeer() { - return m->pParent; + return m->pPeer; } -#endif /* VBOX_WITH_USB */ - // private methods ///////////////////////////////////////////////////////////////////////////// /* vi: set tabstop=4 shiftwidth=4 expandtab: */ |