Index: /trunk/src/VBox/Main/include/USBProxyBackend.h
===================================================================
--- /trunk/src/VBox/Main/include/USBProxyBackend.h	(revision 60741)
+++ /trunk/src/VBox/Main/include/USBProxyBackend.h	(revision 60742)
@@ -67,6 +67,4 @@
     virtual int captureDevice(HostUSBDevice *aDevice);
     virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
-    /** @todo unused */
-    virtual void detachingDevice(HostUSBDevice *aDevice);
     virtual int releaseDevice(HostUSBDevice *aDevice);
     virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
@@ -74,14 +72,4 @@
 
     static void freeDevice(PUSBDEVICE pDevice);
-
-    HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
-                                  SessionMachinesList &llOpenedMachines,
-                                  SessionMachine *aIgnoreMachine);
-    bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
-
-    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
-    virtual void deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
-    virtual void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines, SessionMachine *aIgnoreMachine);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 protected:
@@ -94,5 +82,4 @@
     virtual int interruptWait(void);
     virtual PUSBDEVICE getDevices(void);
-    bool updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
     uint32_t incRef();
     uint32_t decRef();
@@ -102,4 +89,10 @@
     static void initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice);
     static void freeDeviceMembers(PUSBDEVICE pDevice);
+
+    /**
+     * Backend specific callback when a device was added.
+     * (Currently only Linux uses it to adjust the udev polling).
+     */
+    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE pDev);
 
 private:
@@ -110,4 +103,6 @@
 
     static DECLCALLBACK(int) serviceThread(RTTHREAD Thread, void *pvUser);
+
+    void updateDeviceList(PUSBDEVICE pDevices);
 
 protected:
@@ -126,4 +121,8 @@
     /** Reference counter which prevents the backend instance from being removed. */
     uint32_t           m_cRefs;
+    /** List of smart HostUSBDevice pointers. */
+    typedef std::list<ComObjPtr<HostUSBDevice> > HostUSBDeviceList;
+    /** List of the known USB devices for this backend. */
+    HostUSBDeviceList  m_llDevices;
 };
 
@@ -153,6 +152,4 @@
     virtual int captureDevice(HostUSBDevice *aDevice);
     virtual void captureDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
-    /** @todo unused */
-    virtual void detachingDevice(HostUSBDevice *aDevice);
     virtual int releaseDevice(HostUSBDevice *aDevice);
     virtual void releaseDeviceCompleted(HostUSBDevice *aDevice, bool aSuccess);
@@ -164,5 +161,4 @@
     virtual void serviceThreadInit (void);
     virtual void serviceThreadTerm (void);
-    virtual bool updateDeviceState (HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 private:
@@ -208,6 +204,5 @@
     virtual int interruptWait(void);
     virtual PUSBDEVICE getDevices(void);
-    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
+    virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice);
 
 private:
@@ -255,5 +250,4 @@
     virtual PUSBDEVICE getDevices(void);
     int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 private:
@@ -302,5 +296,4 @@
     virtual int interruptWait(void);
     virtual PUSBDEVICE getDevices(void);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 private:
@@ -334,5 +327,4 @@
     virtual int interruptWait(void);
     virtual PUSBDEVICE getDevices(void);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 private:
@@ -365,5 +357,4 @@
     int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc);
     virtual void deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 private:
@@ -413,5 +404,4 @@
     virtual int interruptWait(void);
     virtual PUSBDEVICE getDevices(void);
-    virtual bool updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine);
 
 private:
Index: /trunk/src/VBox/Main/include/USBProxyService.h
===================================================================
--- /trunk/src/VBox/Main/include/USBProxyService.h	(revision 60741)
+++ /trunk/src/VBox/Main/include/USBProxyService.h	(revision 60742)
@@ -83,9 +83,10 @@
     typedef std::list< ComObjPtr<HostUSBDeviceFilter> > USBDeviceFilterList;
 
-    void i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices);
-    void i_getUSBFilters(USBDeviceFilterList *pGlobalFilters);
-
     HRESULT i_loadSettings(const settings::USBDeviceSourcesList &llUSBDeviceSources);
     HRESULT i_saveSettings(settings::USBDeviceSourcesList &llUSBDeviceSources);
+
+    void i_deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice);
+    void i_deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice);
+    void i_updateDeviceState(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice, bool fFakeUpdate);
 
 protected:
@@ -101,4 +102,11 @@
 
 private:
+
+    HRESULT runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
+                                  SessionMachinesList &llOpenedMachines,
+                                  SessionMachine *aIgnoreMachine);
+    bool runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice);
+
+    void deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, bool fRunFilters, SessionMachine *aIgnoreMachine);
 
     /** Pointer to the Host object. */
Index: /trunk/src/VBox/Main/src-server/USBProxyBackend.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/USBProxyBackend.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/USBProxyBackend.cpp	(revision 60742)
@@ -87,4 +87,5 @@
     mTerminate = true;
     m_pUsbProxyService = NULL;
+    m_llDevices.clear();
 }
 
@@ -140,168 +141,4 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     return m_cRefs;
-}
-
-
-/**
- * Runs all the filters on the specified device.
- *
- * All filters mean global and active VM, with the exception of those
- * belonging to \a aMachine. If a global ignore filter matched or if
- * none of the filters matched, the device will be released back to
- * the host.
- *
- * The device calling us here will be in the HeldByProxy, Unused, or
- * Capturable state. The caller is aware that locks held might have
- * to be abandond because of IPC and that the device might be in
- * almost any state upon return.
- *
- *
- * @returns COM status code (only parameter & state checks will fail).
- * @param   aDevice         The USB device to apply filters to.
- * @param   aIgnoreMachine  The machine to ignore filters from (we've just
- *                          detached the device from this machine).
- *
- * @note    The caller is expected to own no locks.
- */
-HRESULT USBProxyBackend::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
-                                               SessionMachinesList &llOpenedMachines,
-                                               SessionMachine *aIgnoreMachine)
-{
-    LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine));
-
-    /*
-     * Verify preconditions.
-     */
-    AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL);
-
-    /*
-     * Get the lists we'll iterate.
-     */
-    Host::USBDeviceFilterList globalFilters;
-    m_pUsbProxyService->i_getUSBFilters(&globalFilters);
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-    AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(),
-                                                      aDevice->i_getStateName()), E_FAIL);
-
-    /*
-     * Run global filters filters first.
-     */
-    bool fHoldIt = false;
-    for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin();
-         it != globalFilters.end();
-         ++it)
-    {
-        AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
-        const HostUSBDeviceFilter::Data &data = (*it)->i_getData();
-        if (aDevice->i_isMatch(data))
-        {
-            USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
-            (*it)->COMGETTER(Action)(&action);
-            if (action == USBDeviceFilterAction_Ignore)
-            {
-                /*
-                 * Release the device to the host and we're done.
-                 */
-                filterLock.release();
-                devLock.release();
-                alock.release();
-                aDevice->i_requestReleaseToHost();
-                return S_OK;
-            }
-            if (action == USBDeviceFilterAction_Hold)
-            {
-                /*
-                 * A device held by the proxy needs to be subjected
-                 * to the machine filters.
-                 */
-                fHoldIt = true;
-                break;
-            }
-            AssertMsgFailed(("action=%d\n", action));
-        }
-    }
-    globalFilters.clear();
-
-    /*
-     * Run the per-machine filters.
-     */
-    for (SessionMachinesList::const_iterator it = llOpenedMachines.begin();
-         it != llOpenedMachines.end();
-         ++it)
-    {
-        ComObjPtr<SessionMachine> pMachine = *it;
-
-        /* Skip the machine the device was just detached from. */
-        if (    aIgnoreMachine
-            &&  pMachine == aIgnoreMachine)
-            continue;
-
-        /* runMachineFilters takes care of checking the machine state. */
-        devLock.release();
-        alock.release();
-        if (runMachineFilters(pMachine, aDevice))
-        {
-            LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine));
-            return S_OK;
-        }
-        alock.acquire();
-        devLock.acquire();
-    }
-
-    /*
-     * No matching machine, so request hold or release depending
-     * on global filter match.
-     */
-    devLock.release();
-    alock.release();
-    if (fHoldIt)
-        aDevice->i_requestHold();
-    else
-        aDevice->i_requestReleaseToHost();
-    return S_OK;
-}
-
-
-/**
- * Runs the USB filters of the machine on the device.
- *
- * If a match is found we will request capture for VM. This may cause
- * us to temporary abandon locks while doing IPC.
- *
- * @param   aMachine    Machine whose filters are to be run.
- * @param   aDevice     The USB device in question.
- * @returns @c true if the device has been or is being attached to the VM, @c false otherwise.
- *
- * @note    Locks several objects temporarily for reading or writing.
- */
-bool USBProxyBackend::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
-{
-    LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
-
-    /*
-     * Validate preconditions.
-     */
-    AssertReturn(aMachine, false);
-    AssertReturn(!isWriteLockOnCurrentThread(), false);
-    AssertReturn(!aMachine->isWriteLockOnCurrentThread(), false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-    /* Let HostUSBDevice::requestCaptureToVM() validate the state. */
-
-    /*
-     * Do the job.
-     */
-    ULONG ulMaskedIfs;
-    if (aMachine->i_hasMatchingUSBFilter(aDevice, &ulMaskedIfs))
-    {
-        /* try to capture the device */
-        HRESULT hrc = aDevice->i_requestCaptureForVM(aMachine, false /* aSetError */, Utf8Str(), ulMaskedIfs);
-        return SUCCEEDED(hrc)
-            || hrc == E_UNEXPECTED /* bad device state, give up */;
-    }
-
-    return false;
 }
 
@@ -361,17 +198,4 @@
     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     incRef();
-}
-
-
-/**
- * The device is going to be detached from a VM.
- *
- * @param   aDevice     The device in question.
- *
- * @todo unused
- */
-void USBProxyBackend::detachingDevice(HostUSBDevice *aDevice)
-{
-    NOREF(aDevice);
 }
 
@@ -430,5 +254,5 @@
         {
             PUSBDEVICE pDevices = getDevices();
-            m_pUsbProxyService->i_updateDeviceList(this, pDevices);
+            updateDeviceList(pDevices);
 
             /*
@@ -487,5 +311,5 @@
 
     /* Make sure there is no device from us in the list anymore. */
-    m_pUsbProxyService->i_updateDeviceList(this, NULL);
+    updateDeviceList(NULL);
 
     return rc;
@@ -518,5 +342,5 @@
 
         PUSBDEVICE pDevices = pThis->getDevices();
-        pThis->m_pUsbProxyService->i_updateDeviceList(pThis, pDevices);
+        pThis->updateDeviceList(pDevices);
     }
 
@@ -590,95 +414,4 @@
 
 /**
- * Performs the required actions when a device has been added.
- *
- * This means things like running filters and subsequent capturing and
- * VM attaching. This may result in IPC and temporary lock abandonment.
- *
- * @param   aDevice     The device in question.
- * @param   aUSBDevice  The USB device structure.
- */
-void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
-                                  SessionMachinesList &llOpenedMachines,
-                                  PUSBDEVICE aUSBDevice)
-{
-    /*
-     * Validate preconditions.
-     */
-    AssertReturnVoid(!isWriteLockOnCurrentThread());
-    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
-    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
-                     (HostUSBDevice *)aDevice,
-                     aDevice->i_getName().c_str(),
-                     aDevice->i_getStateName(),
-                     aDevice->i_getId().raw()));
-
-    /*
-     * Run filters on the device.
-     */
-    if (aDevice->i_isCapturableOrHeld())
-    {
-        devLock.release();
-        HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
-        AssertComRC(rc);
-    }
-
-    NOREF(aUSBDevice);
-}
-
-
-/**
- * Remove device notification hook for the OS specific code.
- *
- * This is means things like
- *
- * @param   aDevice     The device in question.
- */
-void USBProxyBackend::deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
-{
-    /*
-     * Validate preconditions.
-     */
-    AssertReturnVoid(!isWriteLockOnCurrentThread());
-    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
-    AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
-                     (HostUSBDevice *)aDevice,
-                     aDevice->i_getName().c_str(),
-                     aDevice->i_getStateName(),
-                     aDevice->i_getId().raw()));
-
-    /*
-     * Detach the device from any machine currently using it,
-     * reset all data and uninitialize the device object.
-     */
-    devLock.release();
-    aDevice->i_onPhysicalDetached();
-}
-
-
-/**
- * Implement fake capture, ++.
- *
- * @returns true if there is a state change.
- * @param   pDevice     The device in question.
- * @param   pUSBDevice  The USB device structure for the last enumeration.
- * @param   aRunFilters Whether or not to run filters.
- */
-bool USBProxyBackend::updateDeviceStateFake(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                            SessionMachine **aIgnoreMachine)
-{
-    *aRunFilters = false;
-    *aIgnoreMachine = NULL;
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-
-    /*
-     * Just hand it to the device, it knows best what needs to be done.
-     */
-    return aDevice->i_updateStateFake(aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-/**
  * Increments the reference counter.
  *
@@ -703,64 +436,4 @@
     return --m_cRefs;
 }
-
-/**
- * Updates the device state.
- *
- * This is responsible for calling HostUSBDevice::updateState().
- *
- * @returns true if there is a state change.
- * @param   aDevice         The device in question.
- * @param   aUSBDevice      The USB device structure for the last enumeration.
- * @param   aRunFilters     Whether or not to run filters.
- * @param   aIgnoreMachine  Machine to ignore when running filters.
- */
-bool USBProxyBackend::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                        SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-
-    return aDevice->i_updateState(aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-
-/**
- * Handle a device which state changed in some significant way.
- *
- * This means things like running filters and subsequent capturing and
- * VM attaching. This may result in IPC and temporary lock abandonment.
- *
- * @param   aDevice         The device.
- * @param   pllOpenedMachines list of running session machines (VirtualBox::getOpenedMachines()); if NULL, we don't run filters
- * @param   aIgnoreMachine  Machine to ignore when running filters.
- */
-void USBProxyBackend::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList *pllOpenedMachines,
-                                    SessionMachine *aIgnoreMachine)
-{
-    /*
-     * Validate preconditions.
-     */
-    AssertReturnVoid(!isWriteLockOnCurrentThread());
-    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
-    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
-                     (HostUSBDevice *)aDevice,
-                     aDevice->i_getName().c_str(),
-                     aDevice->i_getStateName(),
-                     aDevice->i_getId().raw(),
-                     (pllOpenedMachines != NULL),       // used to be "bool aRunFilters"
-                     aIgnoreMachine));
-    devLock.release();
-
-    /*
-     * Run filters if requested to do so.
-     */
-    if (pllOpenedMachines)
-    {
-        HRESULT rc = runAllFiltersOnDevice(aDevice, *pllOpenedMachines, aIgnoreMachine);
-        AssertComRC(rc);
-    }
-}
-
 
 
@@ -808,4 +481,10 @@
 }
 
+void USBProxyBackend::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE pDev)
+{
+    /* Nothing to do. */
+    NOREF(aDevice);
+    NOREF(pDev);
+}
 
 /**
@@ -858,7 +537,200 @@
 HRESULT USBProxyBackend::getType(com::Utf8Str &aType)
 {
-    aType = Utf8Str("");
+    aType = Utf8Str::Empty;
     return S_OK;
 }
 
+/**
+ * Sort a list of USB devices.
+ *
+ * @returns Pointer to the head of the sorted doubly linked list.
+ * @param   aDevices        Head pointer (can be both singly and doubly linked list).
+ */
+static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
+{
+    PUSBDEVICE pHead = NULL;
+    PUSBDEVICE pTail = NULL;
+    while (pDevices)
+    {
+        /* unlink head */
+        PUSBDEVICE pDev = pDevices;
+        pDevices = pDev->pNext;
+        if (pDevices)
+            pDevices->pPrev = NULL;
+
+        /* find location. */
+        PUSBDEVICE pCur = pTail;
+        while (     pCur
+               &&   HostUSBDevice::i_compare(pCur, pDev) > 0)
+            pCur = pCur->pPrev;
+
+        /* insert (after pCur) */
+        pDev->pPrev = pCur;
+        if (pCur)
+        {
+            pDev->pNext = pCur->pNext;
+            pCur->pNext = pDev;
+            if (pDev->pNext)
+                pDev->pNext->pPrev = pDev;
+            else
+                pTail = pDev;
+        }
+        else
+        {
+            pDev->pNext = pHead;
+            if (pHead)
+                pHead->pPrev = pDev;
+            else
+                pTail = pDev;
+            pHead = pDev;
+        }
+    }
+
+    LogFlowFuncLeave();
+    return pHead;
+}
+
+
+/**
+ * Process any relevant changes in the attached USB devices.
+ *
+ * This is called from any available USB proxy backends service thread when they discover
+ * a change.
+ */
+void USBProxyBackend::updateDeviceList(PUSBDEVICE pDevices)
+{
+    LogFlowThisFunc(("\n"));
+
+    pDevices = sortDevices(pDevices);
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /*
+     * Compare previous list with the new list of devices
+     * and merge in any changes while notifying Host.
+     */
+    HostUSBDeviceList::iterator it = this->m_llDevices.begin();
+    while (    it != m_llDevices.end()
+           || pDevices)
+    {
+        ComObjPtr<HostUSBDevice> pHostDevice;
+
+        if (it != m_llDevices.end())
+            pHostDevice = *it;
+
+        /*
+         * Assert that the object is still alive (we still reference it in
+         * the collection and we're the only one who calls uninit() on it.
+         */
+        AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
+        AssertComRC(devCaller.rc());
+
+        /*
+         * Lock the device object since we will read/write its
+         * properties. All Host callbacks also imply the object is locked.
+         */
+        AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
+                              COMMA_LOCKVAL_SRC_POS);
+
+        /* We should never get devices from other backends here. */
+        Assert(pHostDevice.isNull() || pHostDevice->i_getUsbProxyBackend() == this);
+
+        /*
+         * Compare.
+         */
+        int iDiff;
+        if (pHostDevice.isNull())
+            iDiff = 1;
+        else
+        {
+            if (!pDevices)
+                iDiff = -1;
+            else
+                iDiff = pHostDevice->i_compare(pDevices);
+        }
+        if (!iDiff)
+        {
+            /*
+             * The device still there, update the state and move on. The PUSBDEVICE
+             * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
+             */
+            PUSBDEVICE pCur = pDevices;
+            pDevices = pDevices->pNext;
+            pCur->pPrev = pCur->pNext = NULL;
+
+            devLock.release();
+            alock.release();
+            /** @todo: Add mthod for every backend indicating whether to use fake updating. */
+#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)
+            m_pUsbProxyService->i_updateDeviceState(pHostDevice, pCur, true /* fFakeUpdate */);
+#else
+            m_pUsbProxyService->i_updateDeviceState(pHostDevice, pCur, false /* fFakeUpdate */);
+#endif
+            alock.acquire();
+            ++it;
+        }
+        else
+        {
+            if (iDiff > 0)
+            {
+                /*
+                 * Head of pDevices was attached.
+                 */
+                PUSBDEVICE pNew = pDevices;
+                pDevices = pDevices->pNext;
+                pNew->pPrev = pNew->pNext = NULL;
+
+                ComObjPtr<HostUSBDevice> NewObj;
+                NewObj.createObject();
+                NewObj->init(pNew, this);
+                LogFlowThisFunc(("attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
+                     (HostUSBDevice *)NewObj,
+                     NewObj->i_getName().c_str(),
+                     NewObj->i_getStateName(),
+                     pNew,
+                     pNew->idVendor,
+                     pNew->idProduct,
+                     pNew->pszProduct,
+                     pNew->pszManufacturer));
+
+                m_llDevices.insert(it, NewObj);
+
+                devLock.release();
+                alock.release();
+                /* Do any backend specific work. */
+                deviceAdded(NewObj, pNew);
+                m_pUsbProxyService->i_deviceAdded(NewObj, pNew);
+                alock.acquire();
+            }
+            else
+            {
+                /*
+                 * Check if the device was actually detached or logically detached
+                 * as the result of a re-enumeration.
+                 */
+                if (!pHostDevice->i_wasActuallyDetached())
+                    ++it;
+                else
+                {
+                    it = m_llDevices.erase(it);
+                    devLock.release();
+                    alock.release();
+                    m_pUsbProxyService->i_deviceRemoved(pHostDevice);
+                    LogFlowThisFunc(("detached %p {%s}\n",
+                         (HostUSBDevice *)pHostDevice,
+                         pHostDevice->i_getName().c_str()));
+
+                    /* from now on, the object is no more valid,
+                     * uninitialize to avoid abuse */
+                    devCaller.release();
+                    pHostDevice->uninit();
+                    alock.acquire();
+                }
+            }
+        }
+    } /* while */
+
+    LogFlowThisFunc(("returns void\n"));
+}
+
 /* vi: set tabstop=4 shiftwidth=4 expandtab: */
Index: /trunk/src/VBox/Main/src-server/USBProxyService.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/USBProxyService.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/USBProxyService.cpp	(revision 60742)
@@ -349,5 +349,5 @@
         devLock.release();
         alock.release();
-        HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
+        HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
         ComAssertComRC(hrc2);
     }
@@ -402,5 +402,5 @@
             USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
             devLock.release();
-            pUsbProxyBackend->runMachineFilters(aMachine, pHostDevice);
+            runMachineFilters(aMachine, pHostDevice);
         }
     }
@@ -469,5 +469,5 @@
                 devLock.release();
                 alock.release();
-                HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
+                HRESULT hrc2 = runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
                 ComAssertComRC(hrc2);
                 alock.acquire();
@@ -485,218 +485,4 @@
 
 /**
- * Sort a list of USB devices.
- *
- * @returns Pointer to the head of the sorted doubly linked list.
- * @param   aDevices        Head pointer (can be both singly and doubly linked list).
- */
-static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
-{
-    PUSBDEVICE pHead = NULL;
-    PUSBDEVICE pTail = NULL;
-    while (pDevices)
-    {
-        /* unlink head */
-        PUSBDEVICE pDev = pDevices;
-        pDevices = pDev->pNext;
-        if (pDevices)
-            pDevices->pPrev = NULL;
-
-        /* find location. */
-        PUSBDEVICE pCur = pTail;
-        while (     pCur
-               &&   HostUSBDevice::i_compare(pCur, pDev) > 0)
-            pCur = pCur->pPrev;
-
-        /* insert (after pCur) */
-        pDev->pPrev = pCur;
-        if (pCur)
-        {
-            pDev->pNext = pCur->pNext;
-            pCur->pNext = pDev;
-            if (pDev->pNext)
-                pDev->pNext->pPrev = pDev;
-            else
-                pTail = pDev;
-        }
-        else
-        {
-            pDev->pNext = pHead;
-            if (pHead)
-                pHead->pPrev = pDev;
-            else
-                pTail = pDev;
-            pHead = pDev;
-        }
-    }
-
-    LogFlowFuncLeave();
-    return pHead;
-}
-
-
-/**
- * Process any relevant changes in the attached USB devices.
- *
- * This is called from any available USB proxy backends service thread when they discover
- * a change.
- */
-void USBProxyService::i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices)
-{
-    LogFlowThisFunc(("\n"));
-
-    pDevices = sortDevices(pDevices);
-
-    // get a list of all running machines while we're outside the lock
-    // (getOpenedMachines requests higher priority locks)
-    SessionMachinesList llOpenedMachines;
-    mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
-
-    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
-
-    /*
-     * Compare previous list with the new list of devices
-     * and merge in any changes while notifying Host.
-     */
-    HostUSBDeviceList::iterator it = this->mDevices.begin();
-    while (    it != mDevices.end()
-            || pDevices)
-    {
-        ComObjPtr<HostUSBDevice> pHostDevice;
-
-        if (it != mDevices.end())
-            pHostDevice = *it;
-
-        /*
-         * Assert that the object is still alive (we still reference it in
-         * the collection and we're the only one who calls uninit() on it.
-         */
-        AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
-        AssertComRC(devCaller.rc());
-
-        /*
-         * Lock the device object since we will read/write its
-         * properties. All Host callbacks also imply the object is locked.
-         */
-        AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
-                              COMMA_LOCKVAL_SRC_POS);
-
-        /* Skip all devices not belonging to the same backend. */
-        if (   !pHostDevice.isNull()
-            && pHostDevice->i_getUsbProxyBackend() != pUsbProxyBackend)
-        {
-            ++it;
-            continue;
-        }
-
-        /*
-         * Compare.
-         */
-        int iDiff;
-        if (pHostDevice.isNull())
-            iDiff = 1;
-        else
-        {
-            if (!pDevices)
-                iDiff = -1;
-            else
-                iDiff = pHostDevice->i_compare(pDevices);
-        }
-        if (!iDiff)
-        {
-            /*
-             * The device still there, update the state and move on. The PUSBDEVICE
-             * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
-             */
-            PUSBDEVICE pCur = pDevices;
-            pDevices = pDevices->pNext;
-            pCur->pPrev = pCur->pNext = NULL;
-
-            bool fRunFilters = false;
-            SessionMachine *pIgnoreMachine = NULL;
-            devLock.release();
-            alock.release();
-            if (pUsbProxyBackend->updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
-                pUsbProxyBackend->deviceChanged(pHostDevice,
-                                                (fRunFilters ? &llOpenedMachines : NULL),
-                                                pIgnoreMachine);
-            alock.acquire();
-            ++it;
-        }
-        else
-        {
-            if (iDiff > 0)
-            {
-                /*
-                 * Head of pDevices was attached.
-                 */
-                PUSBDEVICE pNew = pDevices;
-                pDevices = pDevices->pNext;
-                pNew->pPrev = pNew->pNext = NULL;
-
-                ComObjPtr<HostUSBDevice> NewObj;
-                NewObj.createObject();
-                NewObj->init(pNew, pUsbProxyBackend);
-                Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
-                     (HostUSBDevice *)NewObj,
-                     NewObj->i_getName().c_str(),
-                     NewObj->i_getStateName(),
-                     pNew,
-                     pNew->idVendor,
-                     pNew->idProduct,
-                     pNew->pszProduct,
-                     pNew->pszManufacturer));
-
-                mDevices.insert(it, NewObj);
-
-                devLock.release();
-                alock.release();
-                pUsbProxyBackend->deviceAdded(NewObj, llOpenedMachines, pNew);
-                alock.acquire();
-            }
-            else
-            {
-                /*
-                 * Check if the device was actually detached or logically detached
-                 * as the result of a re-enumeration.
-                 */
-                if (!pHostDevice->i_wasActuallyDetached())
-                    ++it;
-                else
-                {
-                    it = mDevices.erase(it);
-                    devLock.release();
-                    alock.release();
-                    pUsbProxyBackend->deviceRemoved(pHostDevice);
-                    Log(("USBProxyService::processChanges: detached %p {%s}\n",
-                         (HostUSBDevice *)pHostDevice,
-                         pHostDevice->i_getName().c_str()));
-
-                    /* from now on, the object is no more valid,
-                     * uninitialize to avoid abuse */
-                    devCaller.release();
-                    pHostDevice->uninit();
-                    alock.acquire();
-                }
-            }
-        }
-    } /* while */
-
-    LogFlowThisFunc(("returns void\n"));
-}
-
-
-/**
- * Returns the global USB filter list stored in the Host object.
- *
- * @returns nothing.
- * @param   pGlobalFilters    Where to store the global filter list on success.
- */
-void USBProxyService::i_getUSBFilters(USBDeviceFilterList *pGlobalFilters)
-{
-    mHost->i_getUSBFilters(pGlobalFilters);
-}
-
-
-/**
  * Loads the given settings and constructs the additional USB device sources.
  *
@@ -749,4 +535,328 @@
     return S_OK;
 }
+
+/**
+ * Performs the required actions when a device has been added.
+ *
+ * This means things like running filters and subsequent capturing and
+ * VM attaching. This may result in IPC and temporary lock abandonment.
+ *
+ * @param   aDevice     The device in question.
+ * @param   aUSBDevice  The USB device structure.
+ */
+void USBProxyService::i_deviceAdded(ComObjPtr<HostUSBDevice> &aDevice,
+                                    PUSBDEVICE aUSBDevice)
+{
+    /*
+     * Validate preconditions.
+     */
+    AssertReturnVoid(!isWriteLockOnCurrentThread());
+    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
+    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
+                     (HostUSBDevice *)aDevice,
+                     aDevice->i_getName().c_str(),
+                     aDevice->i_getStateName(),
+                     aDevice->i_getId().raw()));
+
+    /* Add to our list. */
+    PCUSBDEVICE pDev = aDevice->i_getUsbData();
+    HostUSBDeviceList::iterator it = mDevices.begin();
+    while (it != mDevices.end())
+    {
+        ComObjPtr<HostUSBDevice> pHostDevice = *it;
+
+        /* Assert that the object is still alive. */
+        AutoCaller devCaller(pHostDevice);
+        AssertComRC(devCaller.rc());
+
+        AutoWriteLock curLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
+        if (   pHostDevice->i_getUsbProxyBackend() == aDevice->i_getUsbProxyBackend()
+            && pHostDevice->i_compare(pDev) < 0)
+            break;
+
+        it++;
+    }
+
+    mDevices.insert(it, aDevice);
+
+    /*
+     * Run filters on the device.
+     */
+    if (aDevice->i_isCapturableOrHeld())
+    {
+        devLock.release();
+        alock.release();
+        SessionMachinesList llOpenedMachines;
+        mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
+        HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, NULL /* aIgnoreMachine */);
+        AssertComRC(rc);
+    }
+}
+
+/**
+ * Remove device notification hook for the USB proxy service.
+ *
+ * @param   aDevice     The device in question.
+ */
+void USBProxyService::i_deviceRemoved(ComObjPtr<HostUSBDevice> &aDevice)
+{
+    /*
+     * Validate preconditions.
+     */
+    AssertReturnVoid(!isWriteLockOnCurrentThread());
+    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
+    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid}\n",
+                     (HostUSBDevice *)aDevice,
+                     aDevice->i_getName().c_str(),
+                     aDevice->i_getStateName(),
+                     aDevice->i_getId().raw()));
+
+    mDevices.remove(aDevice);
+
+    /*
+     * Detach the device from any machine currently using it,
+     * reset all data and uninitialize the device object.
+     */
+    devLock.release();
+    alock.release();
+    aDevice->i_onPhysicalDetached();
+}
+
+/**
+ * Updates the device state.
+ *
+ * This is responsible for calling HostUSBDevice::updateState().
+ *
+ * @returns true if there is a state change.
+ * @param   aDevice         The device in question.
+ * @param   aUSBDevice      The USB device structure for the last enumeration.
+ * @param   fFakeUpdate     Flag whether to fake updating state.
+ */
+void USBProxyService::i_updateDeviceState(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE aUSBDevice, bool fFakeUpdate)
+{
+    AssertReturnVoid(aDevice);
+    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
+
+    bool fRunFilters = false;
+    SessionMachine *pIgnoreMachine = NULL;
+    bool fDevChanged = false;
+    if (fFakeUpdate)
+        fDevChanged = aDevice->i_updateStateFake(aUSBDevice, &fRunFilters, &pIgnoreMachine);
+    else
+        fDevChanged = aDevice->i_updateState(aUSBDevice, &fRunFilters, &pIgnoreMachine);
+
+    if (fDevChanged)
+        deviceChanged(aDevice, fRunFilters, pIgnoreMachine);
+}
+
+
+/**
+ * Handle a device which state changed in some significant way.
+ *
+ * This means things like running filters and subsequent capturing and
+ * VM attaching. This may result in IPC and temporary lock abandonment.
+ *
+ * @param   aDevice         The device.
+ * @param   fRunFilters     Flag whether to run filters.
+ * @param   aIgnoreMachine  Machine to ignore when running filters.
+ */
+void USBProxyService::deviceChanged(ComObjPtr<HostUSBDevice> &aDevice, bool fRunFilters,
+                                    SessionMachine *aIgnoreMachine)
+{
+    /*
+     * Validate preconditions.
+     */
+    AssertReturnVoid(!isWriteLockOnCurrentThread());
+    AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
+    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
+    LogFlowThisFunc(("aDevice=%p name={%s} state=%s id={%RTuuid} aRunFilters=%RTbool aIgnoreMachine=%p\n",
+                     (HostUSBDevice *)aDevice,
+                     aDevice->i_getName().c_str(),
+                     aDevice->i_getStateName(),
+                     aDevice->i_getId().raw(),
+                     fRunFilters,
+                     aIgnoreMachine));
+    devLock.release();
+
+    /*
+     * Run filters if requested to do so.
+     */
+    if (fRunFilters)
+    {
+        SessionMachinesList llOpenedMachines;
+        mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
+        HRESULT rc = runAllFiltersOnDevice(aDevice, llOpenedMachines, aIgnoreMachine);
+        AssertComRC(rc);
+    }
+}
+
+
+/**
+ * Runs all the filters on the specified device.
+ *
+ * All filters mean global and active VM, with the exception of those
+ * belonging to \a aMachine. If a global ignore filter matched or if
+ * none of the filters matched, the device will be released back to
+ * the host.
+ *
+ * The device calling us here will be in the HeldByProxy, Unused, or
+ * Capturable state. The caller is aware that locks held might have
+ * to be abandond because of IPC and that the device might be in
+ * almost any state upon return.
+ *
+ *
+ * @returns COM status code (only parameter & state checks will fail).
+ * @param   aDevice         The USB device to apply filters to.
+ * @param   aIgnoreMachine  The machine to ignore filters from (we've just
+ *                          detached the device from this machine).
+ *
+ * @note    The caller is expected to own no locks.
+ */
+HRESULT USBProxyService::runAllFiltersOnDevice(ComObjPtr<HostUSBDevice> &aDevice,
+                                               SessionMachinesList &llOpenedMachines,
+                                               SessionMachine *aIgnoreMachine)
+{
+    LogFlowThisFunc(("{%s} ignoring=%p\n", aDevice->i_getName().c_str(), aIgnoreMachine));
+
+    /*
+     * Verify preconditions.
+     */
+    AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
+    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), E_FAIL);
+
+    /*
+     * Get the lists we'll iterate.
+     */
+    Host::USBDeviceFilterList globalFilters;
+    mHost->i_getUSBFilters(&globalFilters);
+
+    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+    AutoWriteLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
+    AssertMsgReturn(aDevice->i_isCapturableOrHeld(), ("{%s} %s\n", aDevice->i_getName().c_str(),
+                                                      aDevice->i_getStateName()), E_FAIL);
+
+    /*
+     * Run global filters filters first.
+     */
+    bool fHoldIt = false;
+    for (Host::USBDeviceFilterList::const_iterator it = globalFilters.begin();
+         it != globalFilters.end();
+         ++it)
+    {
+        AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
+        const HostUSBDeviceFilter::Data &data = (*it)->i_getData();
+        if (aDevice->i_isMatch(data))
+        {
+            USBDeviceFilterAction_T action = USBDeviceFilterAction_Null;
+            (*it)->COMGETTER(Action)(&action);
+            if (action == USBDeviceFilterAction_Ignore)
+            {
+                /*
+                 * Release the device to the host and we're done.
+                 */
+                filterLock.release();
+                devLock.release();
+                alock.release();
+                aDevice->i_requestReleaseToHost();
+                return S_OK;
+            }
+            if (action == USBDeviceFilterAction_Hold)
+            {
+                /*
+                 * A device held by the proxy needs to be subjected
+                 * to the machine filters.
+                 */
+                fHoldIt = true;
+                break;
+            }
+            AssertMsgFailed(("action=%d\n", action));
+        }
+    }
+    globalFilters.clear();
+
+    /*
+     * Run the per-machine filters.
+     */
+    for (SessionMachinesList::const_iterator it = llOpenedMachines.begin();
+         it != llOpenedMachines.end();
+         ++it)
+    {
+        ComObjPtr<SessionMachine> pMachine = *it;
+
+        /* Skip the machine the device was just detached from. */
+        if (    aIgnoreMachine
+            &&  pMachine == aIgnoreMachine)
+            continue;
+
+        /* runMachineFilters takes care of checking the machine state. */
+        devLock.release();
+        alock.release();
+        if (runMachineFilters(pMachine, aDevice))
+        {
+            LogFlowThisFunc(("{%s} attached to %p\n", aDevice->i_getName().c_str(), (void *)pMachine));
+            return S_OK;
+        }
+        alock.acquire();
+        devLock.acquire();
+    }
+
+    /*
+     * No matching machine, so request hold or release depending
+     * on global filter match.
+     */
+    devLock.release();
+    alock.release();
+    if (fHoldIt)
+        aDevice->i_requestHold();
+    else
+        aDevice->i_requestReleaseToHost();
+    return S_OK;
+}
+
+
+/**
+ * Runs the USB filters of the machine on the device.
+ *
+ * If a match is found we will request capture for VM. This may cause
+ * us to temporary abandon locks while doing IPC.
+ *
+ * @param   aMachine    Machine whose filters are to be run.
+ * @param   aDevice     The USB device in question.
+ * @returns @c true if the device has been or is being attached to the VM, @c false otherwise.
+ *
+ * @note    Locks several objects temporarily for reading or writing.
+ */
+bool USBProxyService::runMachineFilters(SessionMachine *aMachine, ComObjPtr<HostUSBDevice> &aDevice)
+{
+    LogFlowThisFunc(("{%s} aMachine=%p \n", aDevice->i_getName().c_str(), aMachine));
+
+    /*
+     * Validate preconditions.
+     */
+    AssertReturn(aMachine, false);
+    AssertReturn(!isWriteLockOnCurrentThread(), false);
+    AssertReturn(!aMachine->isWriteLockOnCurrentThread(), false);
+    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
+    /* Let HostUSBDevice::requestCaptureToVM() validate the state. */
+
+    /*
+     * Do the job.
+     */
+    ULONG ulMaskedIfs;
+    if (aMachine->i_hasMatchingUSBFilter(aDevice, &ulMaskedIfs))
+    {
+        /* try to capture the device */
+        HRESULT hrc = aDevice->i_requestCaptureForVM(aMachine, false /* aSetError */, Utf8Str(), ulMaskedIfs);
+        return SUCCEEDED(hrc)
+            || hrc == E_UNEXPECTED /* bad device state, give up */;
+    }
+
+    return false;
+}
+
 
 /**
Index: /trunk/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp	(revision 60742)
@@ -222,20 +222,4 @@
 
 
-/** @todo unused */
-void USBProxyBackendDarwin::detachingDevice(HostUSBDevice *aDevice)
-{
-    NOREF(aDevice);
-}
-
-
-bool USBProxyBackendDarwin::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-    /* Nothing special here so far, so fall back on parent. */
-    return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-
 int USBProxyBackendDarwin::wait(RTMSINTERVAL aMillies)
 {
Index: /trunk/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp	(revision 60742)
@@ -153,25 +153,4 @@
 }
 
-
-bool USBProxyBackendFreeBSD::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                               SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-
-    return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-
-/**
- * A device was added
- *
- * See USBProxyService::deviceAdded for details.
- */
-void USBProxyBackendFreeBSD::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
-                                         PUSBDEVICE aUSBDevice)
-{
-    USBProxyBackend::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
-}
 
 int USBProxyBackendFreeBSD::wait(RTMSINTERVAL aMillies)
@@ -227,4 +206,5 @@
 }
 
+
 PUSBDEVICE USBProxyBackendFreeBSD::getDevices(void)
 {
Index: /trunk/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp	(revision 60742)
@@ -435,19 +435,4 @@
 
 
-bool USBProxyBackendUsbIp::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                             SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
-        &&  aDevice->i_getUsbData()->enmState == USBDEVICESTATE_USED_BY_HOST)
-        LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
-                aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
-    devLock.release();
-    return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-
 int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies)
 {
@@ -504,5 +489,6 @@
                 if (fEventsRecv & RTPOLL_EVT_READ)
                     rc = receiveData();
-                else if (fEventsRecv & RTPOLL_EVT_ERROR)
+                if (   RT_SUCCESS(rc)
+                    && (fEventsRecv & RTPOLL_EVT_ERROR))
                     rc = VERR_NET_SHUTDOWN;
 
Index: /trunk/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp	(revision 60742)
@@ -269,39 +269,20 @@
 
 
-bool USBProxyBackendLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                             SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-    AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
-        &&  aDevice->i_getUsbData()->enmState == USBDEVICESTATE_USED_BY_HOST)
-        LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
-                aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
-    devLock.release();
-    return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-
 /**
  * A device was added, we need to adjust mUdevPolls.
- *
- * See USBProxyService::deviceAdded for details.
- */
-void USBProxyBackendLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines,
-                                       PUSBDEVICE aUSBDevice)
+ */
+void USBProxyBackendLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, PUSBDEVICE pDev)
 {
     AssertReturnVoid(aDevice);
     AssertReturnVoid(!aDevice->isWriteLockOnCurrentThread());
     AutoReadLock devLock(aDevice COMMA_LOCKVAL_SRC_POS);
-    if (aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST)
-    {
-        LogRel(("USBProxy: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
-                aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
+    if (pDev->enmState == USBDEVICESTATE_USED_BY_HOST)
+    {
+        LogRel(("USBProxyBackendLinux: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
+                pDev->idVendor, pDev->idProduct, pDev->pszAddress));
         mUdevPolls = 10; /* (10 * 500ms = 5s) */
     }
 
     devLock.release();
-    USBProxyBackend::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
 }
 
Index: /trunk/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp	(revision 60742)
@@ -460,12 +460,4 @@
 
 
-bool USBProxyBackendSolaris::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                               SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-    return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
 /**
  * Wrapper called by walkDeviceNode.
Index: /trunk/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp	(revision 60741)
+++ /trunk/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp	(revision 60742)
@@ -227,14 +227,4 @@
 
 
-bool USBProxyBackendWindows::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters,
-                                               SessionMachine **aIgnoreMachine)
-{
-    AssertReturn(aDevice, false);
-    AssertReturn(!aDevice->isWriteLockOnCurrentThread(), false);
-    /* Nothing special here so far, so fall back on parent */
-    return USBProxyBackend::updateDeviceState(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
-}
-
-
 int USBProxyBackendWindows::wait(unsigned aMillies)
 {
