Index: /trunk/src/VBox/RDP/client/vrdp/USBProxyDevice-linux.c
===================================================================
--- /trunk/src/VBox/RDP/client/vrdp/USBProxyDevice-linux.c	(revision 31246)
+++ /trunk/src/VBox/RDP/client/vrdp/USBProxyDevice-linux.c	(revision 31247)
@@ -1,5 +1,5 @@
+/* $Id$ */
 /** @file
- *
- * VUSB Device - USB Device Proxy, the Linux backend.
+ * USB device proxy - the Linux backend.
  */
 
@@ -7,11 +7,6 @@
  * Copyright (C) 2006-2007 Oracle Corporation
  *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * Oracle Corporation confidential
+ * All rights reserved
  */
 
@@ -31,5 +26,5 @@
 *******************************************************************************/
 #define LOG_GROUP LOG_GROUP_DRV_USBPROXY
-#if defined(VBOX) && !defined(RDESKTOP)
+#ifndef RDESKTOP
 # include <iprt/stdint.h>
 #endif
@@ -47,5 +42,4 @@
 #include <fcntl.h>
 #include <errno.h>
-#include <ctype.h>
 #ifdef VBOX_WITH_LINUX_COMPILER_H
 # include <linux/compiler.h>
@@ -71,21 +65,27 @@
 #endif
 
-#if defined(VBOX) && !defined(RDESKTOP)
+#ifndef RDESKTOP
 # include <VBox/pdm.h>
 # include <VBox/err.h>
 # include <VBox/log.h>
+# include <iprt/alloc.h>
 # include <iprt/assert.h>
+# include <iprt/asm.h>
+# include <iprt/ctype.h>
+# include <iprt/file.h>
+# include <iprt/linux/sysfs.h>
 # include <iprt/stream.h>
-# include <iprt/alloc.h>
+# include <iprt/string.h>
 # include <iprt/thread.h>
 # include <iprt/time.h>
-# include <iprt/asm.h>
-# include <iprt/string.h>
-# include <iprt/file.h>
 # include "../USBProxyDevice.h"
 #else
 
 # include "../rdesktop.h"
-# include "vrdpusb.h"
+# include "runtime.h"
+# include "USBProxyDevice.h"
+# ifdef VBOX_USB_WITH_SYSFS
+#  include "sysfs.h"
+# endif
 #endif
 
@@ -102,4 +102,6 @@
     /** The kernel URB data */
     struct usbdevfs_urb     KUrb;
+    /** Space filler for the isochronous packets. */
+    struct usbdevfs_iso_packet_desc aIsocPktsDonUseTheseUseTheOnesInKUrb[8];
     /** The millisecond timestamp when this URB was submitted. */
     uint64_t                u64SubmitTS;
@@ -120,4 +122,6 @@
     /** This split element is reaped. */
     bool                    fSplitElementReaped;
+    /** Size to transfer in remaining fragments of a split URB */
+    uint32_t                cbSplitRemaining;
 } USBPROXYURBLNX, *PUSBPROXYURBLNX;
 
@@ -142,4 +146,9 @@
     /** The tail of the landed linux URBs. */
     PUSBPROXYURBLNX     pTaxingTail;
+    /** Are we using sysfs to find the active configuration? */
+    bool                fUsingSysfs;
+    /** The device node/sysfs path of the device.
+     * Used to figure out the configuration after a reset. */
+    char                szPath[1];
 } USBPROXYDEVLNX, *PUSBPROXYDEVLNX;
 
@@ -148,5 +157,5 @@
 *   Internal Functions                                                         *
 *******************************************************************************/
-static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, int iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries);
+static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries);
 static void usbProxLinuxUrbUnplugged(PUSBPROXYDEV pProxyDev);
 static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProyxDev, int iIf, bool fConnect, bool fQuiet);
@@ -154,5 +163,5 @@
 static void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
 static void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
-static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszAddress, int *iFirstCfg);
+static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg);
 
 
@@ -172,5 +181,5 @@
  * @internal
  */
-static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, int iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries)
+static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries)
 {
     int rc;
@@ -188,5 +197,5 @@
         {
             usbProxLinuxUrbUnplugged(pProxyDev);
-            Log(("usb-linux: ENODEV -> unplugged. pProxyDev=%p[%s]\n", pProxyDev, pProxyDev->Dev.pszName));
+            Log(("usb-linux: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
             errno = ENODEV;
             break;
@@ -212,4 +221,5 @@
      */
     RTCritSectEnter(&pDevLnx->CritSect);
+    pProxyDev->fDetached = true;
 
     PUSBPROXYURBLNX pUrbTaxing = NULL;
@@ -250,6 +260,4 @@
 
     RTCritSectLeave(&pDevLnx->CritSect);
-
-    vusbDevUnplugged(&pProxyDev->Dev);
 }
 
@@ -261,16 +269,20 @@
 static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProxyDev, int iIf, bool fConnect, bool fQuiet)
 {
-    struct usbdevfs_ioctl IoCtl;
-    if (!fQuiet)
-        LogFlow(("usbProxyLinuxSetConnected: pProxyDev=%p[%s] iIf=%#x fConnect=%d\n",
-                 pProxyDev, pProxyDev->Dev.pszName, iIf, fConnect));
-
-    IoCtl.ifno = iIf;
-    IoCtl.ioctl_code = fConnect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT;
-    IoCtl.data = NULL;
-    if (    usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_IOCTL, &IoCtl, true, UINT32_MAX)
-        &&  !fQuiet)
-        Log(("usbProxyLinuxSetConnected: failure, errno=%d. pProxyDev=%p[%s]\n",
-             errno, pProxyDev, pProxyDev->Dev.pszName));
+    if (    iIf >= 32
+        ||  !(pProxyDev->fMaskedIfs & RT_BIT(iIf)))
+    {
+        struct usbdevfs_ioctl IoCtl;
+        if (!fQuiet)
+            LogFlow(("usbProxyLinuxSetConnected: pProxyDev=%s iIf=%#x fConnect=%RTbool\n",
+                     usbProxyGetName(pProxyDev), iIf, fConnect));
+
+        IoCtl.ifno = iIf;
+        IoCtl.ioctl_code = fConnect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT;
+        IoCtl.data = NULL;
+        if (    usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_IOCTL, &IoCtl, true, UINT32_MAX)
+            &&  !fQuiet)
+            Log(("usbProxyLinuxSetConnected: failure, errno=%d. pProxyDev=%s\n",
+                 errno, usbProxyGetName(pProxyDev)));
+    }
 }
 
@@ -400,10 +412,11 @@
  * @returns The Cfg#.
  * @returns -1 if no active config.
- * @param   pszAddress      The path to the device. We infere the location of the
- *                          devices file, which bus and device number we're looking for.
+ * @param   pszDevNode      The path to the device. We infere the location of
+ *                          the devices file, which bus and device number we're
+ *                          looking for.
  * @param   iFirstCfg       The first configuration. (optional)
  * @internal
  */
-static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszAddress, int *piFirstCfg)
+static int usbProxyLinuxFindActiveConfigUsbfs(PUSBPROXYDEV pProxyDev, const char *pszDevNode, int *piFirstCfg)
 {
     /*
@@ -415,12 +428,13 @@
 
     /*
-     * Interpret the address and turn it into a path to the devices file.
-     */
-    size_t cchAddress = strlen(pszAddress);
-    char *pszDevices = (char *)RTMemDupEx(pszAddress, cchAddress, sizeof("devices"));
+     * Parse the usbfs device node path and turn it into a path to the "devices" file,
+     * picking up the device number and bus along the way.
+     */
+    size_t cchDevNode = strlen(pszDevNode);
+    char *pszDevices = (char *)RTMemDupEx(pszDevNode, cchDevNode, sizeof("devices"));
     AssertReturn(pszDevices, iActiveCfg);
 
     /* the device number */
-    char *psz = pszDevices + cchAddress;
+    char *psz = pszDevices + cchDevNode;
     while (*psz != '/')
         psz--;
@@ -525,24 +539,71 @@
 }
 
-int dev2fd (PUSBPROXYDEV pProxyDev)
-{
-    if (pProxyDev)
-    {
-        PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
-
-	if (pDevLnx)
-	{
-	    return pDevLnx->File;
-	}
-    }
+
+/**
+ * This finds the active configuration from sysfs.
+ *
+ * @returns The Cfg#.
+ * @returns -1 if no active config.
+ * @param   pszPath         The sysfs path for the device.
+ * @param   piFirstCfg      The first configuration. (optional)
+ * @internal
+ */
+static int usbProxyLinuxFindActiveConfigSysfs(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg)
+{
+#ifdef VBOX_USB_WITH_SYSFS
+    if (piFirstCfg != NULL)
+        *piFirstCfg = pProxyDev->paCfgDescs != NULL
+                    ? pProxyDev->paCfgDescs[0].Core.bConfigurationValue
+                    : 1;
+    return RTLinuxSysFsReadIntFile(10, "%s/bConfigurationValue", pszPath); /* returns -1 on failure */
+#else  /* !VBOX_USB_WITH_SYSFS */
     return -1;
-}
-
-/**
- * Opens the /proc/bus/usb/bus/addr file.
+#endif /* !VBOX_USB_WITH_SYSFS */
+}
+
+
+/**
+ * This finds the active configuration.
+ *
+ * @returns The Cfg#.
+ * @returns -1 if no active config.
+ * @param   pszPath         The sysfs path for the device, or the usbfs device
+ *                          node path.
+ * @param   iFirstCfg       The first configuration. (optional)
+ * @internal
+ */
+static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg)
+{
+    PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
+    if (pDevLnx->fUsingSysfs)
+        return usbProxyLinuxFindActiveConfigSysfs(pProxyDev, pszPath, piFirstCfg);
+    return usbProxyLinuxFindActiveConfigUsbfs(pProxyDev, pszPath, piFirstCfg);
+}
+
+
+/**
+ * Extracts the Linux file descriptor associated with the kernel USB device.
+ * This is used by rdesktop-vrdp for polling for events.
+ * @returns  the FD, or asserts and returns -1 on error
+ * @param    pProxyDev    The device instance
+ */
+RTDECL(int) USBProxyDeviceLinuxGetFD(PUSBPROXYDEV pProxyDev)
+{
+    PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
+    AssertReturn(pDevLnx->File != NIL_RTFILE, -1);
+    return pDevLnx->File;
+}
+
+
+/**
+ * Opens the device file.
  *
  * @returns VBox status code.
  * @param   pProxyDev       The device instance.
- * @param   pszAddress      The path to the device.
+ * @param   pszAddress      If we are using usbfs, this is the path to the
+ *                          device.  If we are using sysfs, this is a string of
+ *                          the form "sysfs:<sysfs path>//device:<device node>".
+ *                          In the second case, the two paths are guaranteed
+ *                          not to contain the substring "//".
  * @param   pvBackend       Backend specific pointer, unused for the linux backend.
  */
@@ -550,6 +611,43 @@
 {
     LogFlow(("usbProxyLinuxOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
+    const char *pszDevNode;
+    const char *pszPath;
+    size_t      cchPath;
+    bool        fUsingSysfs;
+
+    /*
+     * Are we using sysfs or usbfs?
+     */
+#ifdef VBOX_USB_WITH_SYSFS
+    fUsingSysfs = strncmp(pszAddress, "sysfs:", sizeof("sysfs:") - 1) == 0;
+    if (fUsingSysfs)
+    {
+        pszDevNode = strstr(pszAddress, "//device:");
+        if (!pszDevNode)
+        {
+            LogRel(("usbProxyLinuxOpen: Invalid device address: '%s'\n", pszAddress));
+            pProxyDev->Backend.pv = NULL;
+            return VERR_INVALID_PARAMETER;
+        }
+
+        pszPath = pszAddress + sizeof("sysfs:") - 1;
+        cchPath = pszDevNode - pszPath;
+        pszDevNode += sizeof("//device:") - 1;
+    }
+    else
+#endif  /* VBOX_USB_WITH_SYSFS */
+    {
+#ifndef VBOX_USB_WITH_SYSFS
+        fUsingSysfs = false;
+#endif
+        pszPath = pszDevNode = pszAddress;
+        cchPath = strlen(pszPath);
+    }
+
+    /*
+     * Try open the device node.
+     */
     RTFILE File;
-    int rc = RTFileOpen(&File, pszAddress, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
+    int rc = RTFileOpen(&File, pszDevNode, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
     if (RT_SUCCESS(rc))
     {
@@ -557,7 +655,10 @@
          * Allocate and initialize the linux backend data.
          */
-        PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)RTMemAllocZ(sizeof(*pDevLnx));
+        PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)RTMemAllocZVar(sizeof(*pDevLnx) + cchPath);
         if (pDevLnx)
         {
+            pDevLnx->fUsingSysfs = fUsingSysfs;
+            memcpy(&pDevLnx->szPath[0], pszPath, cchPath);
+            pDevLnx->szPath[cchPath] = '\0';
             pDevLnx->File = File;
             rc = RTCritSectInit(&pDevLnx->CritSect);
@@ -566,26 +667,4 @@
                 pProxyDev->Backend.pv = pDevLnx;
 
-                /* brute force rulez */
-		unsigned iIf;
-                for (iIf = 0; iIf < 256; iIf++)
-                    usbProxyLinuxSetConnected(pProxyDev, iIf, false, true);
-
-                /*
-                 * Determin the active configuration.
-                 *
-                 * If there isn't any active configuration, we will get EHOSTUNREACH (113) errors
-                 * when trying to read the device descriptors in usbProxyDevCreate. So, we'll make
-                 * the first one active (usually 1) then.
-                 */
-                pProxyDev->cIgnoreSetConfigs = 1;
-                int iFirstCfg;
-                pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pszAddress, &iFirstCfg);
-                if (pProxyDev->iActiveCfg == -1)
-                {
-                    usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETCONFIGURATION, &iFirstCfg, false, UINT32_MAX);
-                    pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pszAddress, NULL);
-                    Log(("usbProxyLinuxOpen: No active config! Tried to set %d: iActiveCfg=%d\n", iFirstCfg, pProxyDev->iActiveCfg));
-                }
-
                 LogFlow(("usbProxyLinuxOpen(%p, %s): returns successfully File=%d iActiveCfg=%d\n",
                          pProxyDev, pszAddress, pDevLnx->File, pProxyDev->iActiveCfg));
@@ -603,5 +682,5 @@
         rc = VERR_VUSB_USBFS_PERMISSION;
 
-    Log(("usbProxyLinuxOpen(%p, %s) failed, rc=%d!\n", pProxyDev, pszAddress, rc));
+    Log(("usbProxyLinuxOpen(%p, %s) failed, rc=%Rrc!\n", pProxyDev, pszAddress, rc));
     pProxyDev->Backend.pv = NULL;
 
@@ -612,9 +691,50 @@
 
 /**
+ * Claims all the interfaces and figures out the
+ * current configuration.
+ *
+ * @returns VINF_SUCCESS.
+ * @param   pProxyDev       The proxy device.
+ */
+static int usbProxyLinuxInit(PUSBPROXYDEV pProxyDev)
+{
+    PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
+
+    /*
+     * Brute force rulez.
+     * usbProxyLinuxSetConnected check for masked interfaces.
+     */
+    unsigned iIf;
+    for (iIf = 0; iIf < 256; iIf++)
+        usbProxyLinuxSetConnected(pProxyDev, iIf, false, true);
+
+    /*
+     * Determin the active configuration.
+     *
+     * If there isn't any active configuration, we will get EHOSTUNREACH (113) errors
+     * when trying to read the device descriptors in usbProxyDevCreate. So, we'll make
+     * the first one active (usually 1) then.
+     */
+    pProxyDev->cIgnoreSetConfigs = 1;
+    int iFirstCfg;
+    pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->szPath, &iFirstCfg);
+    if (pProxyDev->iActiveCfg == -1)
+    {
+        usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETCONFIGURATION, &iFirstCfg, false, UINT32_MAX);
+        pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->szPath, NULL);
+        Log(("usbProxyLinuxInit: No active config! Tried to set %d: iActiveCfg=%d\n", iFirstCfg, pProxyDev->iActiveCfg));
+    }
+    else
+        Log(("usbProxyLinuxInit(%p): iActiveCfg=%d\n", pProxyDev, pProxyDev->iActiveCfg));
+    return VINF_SUCCESS;
+}
+
+
+/**
  * Closes the proxy device.
  */
 static void usbProxyLinuxClose(PUSBPROXYDEV pProxyDev)
 {
-    LogFlow(("usbProxyLinuxClose: pProxyDev=%p[%s]\n", pProxyDev, pProxyDev->Dev.pszName));
+    LogFlow(("usbProxyLinuxClose: pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
     Assert(pDevLnx);
@@ -626,22 +746,28 @@
      * Resetting it would be a nice start, although we must remember
      * that it might have been disconnected...
-     */
-    /* ASSUMES: thread == EMT */
-    if (!usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
-    {
-        /* Connect drivers. */
-	unsigned iIf;
-        for (iIf = 0; iIf < 256; iIf++)
-            usbProxyLinuxSetConnected(pProxyDev, iIf, true, true);
-    }
-    else
-        Log(("usbProxyLinuxClose: Reset failed, errno=%d.\n", errno));
-
-    /*
-     * Now we can close it and free all the resources.
-     */
-    RTFileClose(pDevLnx->File);
-    pDevLnx->File = NIL_RTFILE;
-
+     *
+     * Don't reset if we're masking interfaces or if construction failed.
+     */
+    if (pProxyDev->fInited)
+    {
+        /* ASSUMES: thread == EMT */
+        if (    pProxyDev->fMaskedIfs
+            ||  !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
+        {
+            /* Connect drivers. */
+            unsigned iIf;
+            for (iIf = 0; iIf < 256; iIf++)
+                usbProxyLinuxSetConnected(pProxyDev, iIf, true, true);
+            LogRel(("USB: Successfully reset device pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
+        }
+        else if (errno != ENODEV)
+            LogRel(("USB: Reset failed, errno=%d, pProxyDev=%s.\n", errno, usbProxyGetName(pProxyDev)));
+        else
+            Log(("USB: Reset failed, errno=%d (ENODEV), pProxyDev=%s.\n", errno, usbProxyGetName(pProxyDev)));
+    }
+
+    /*
+     * Now we can free all the resources and close the device.
+     */
     RTCritSectDelete(&pDevLnx->CritSect);
 
@@ -679,4 +805,7 @@
         RTMemFree(pUrbLnx);
     }
+
+    RTFileClose(pDevLnx->File);
+    pDevLnx->File = NIL_RTFILE;
 
     RTMemFree(pDevLnx);
@@ -808,5 +937,5 @@
                 /* Skip past "S:" and then the whitespace */
                 for(psz = buf + 2; *psz != '\0'; psz++)
-                    if ( !isspace(*psz) )
+                    if ( !RT_C_IS_SPACE(*psz) )
                         break;
 
@@ -878,12 +1007,48 @@
  * @param   pDev    The device to reset.
  */
-static int usbProxyLinuxReset(PUSBPROXYDEV pProxyDev)
+static int usbProxyLinuxReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
 {
 #ifdef NO_PORT_RESET
-    LogFlow(("usbProxyLinuxReset: pProxyDev=%p[%s] - NO_PORT_RESET\n", pProxyDev, pProxyDev->Dev.pszName));
+    PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
+
+    /*
+     * Specific device resets are NOPs.
+     * Root hub resets that affects all devices are executed.
+     *
+     * The reasoning is that when a root hub reset is done, the guest shouldn't
+     * will have to re enumerate the devices after doing this kind of reset.
+     * So, it doesn't really matter if a device is 'logically disconnected'.
+     */
+    if (    !fResetOnLinux
+        ||  pProxyDev->fMaskedIfs)
+        LogFlow(("usbProxyLinuxReset: pProxyDev=%s - NO_PORT_RESET\n", usbProxyGetName(pProxyDev)));
+    else
+    {
+        LogFlow(("usbProxyLinuxReset: pProxyDev=%s - Real Reset!\n", usbProxyGetName(pProxyDev)));
+        if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
+        {
+            int rc = errno;
+            Log(("usb-linux: Reset failed, rc=%Rrc errno=%d.\n", RTErrConvertFromErrno(rc), rc));
+            pProxyDev->iActiveCfg = -1;
+            return RTErrConvertFromErrno(rc);
+        }
+
+        /* find the active config - damn annoying. */
+        pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->szPath, NULL);
+        LogFlow(("usbProxyLinuxReset: returns successfully iActiveCfg=%d\n", pProxyDev->iActiveCfg));
+    }
     pProxyDev->cIgnoreSetConfigs = 2;
 
 #else /* !NO_PORT_RESET */
-    LogFlow(("usbProxyLinuxReset: pProxyDev=%p[%s]\n", pProxyDev, pProxyDev->Dev.pszName));
+
+    /*
+     * This is the alternative, we will allways reset when asked to do so.
+     *
+     * The problem we're facing here is that on reset failure linux will do
+     * a 'logical reconnect' on the device. This will invalidate the current
+     * handle and we'll have to reopen the device. This is problematic to say
+     * the least, especially since it happens pretty often.
+     */
+    LogFlow(("usbProxyLinuxReset: pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
 # ifndef NO_LOGICAL_RECONNECT
     ASMAtomicIncU32(&g_cResetActive);
@@ -941,6 +1106,6 @@
 static int usbProxyLinuxSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
 {
-    LogFlow(("usbProxyLinuxSetConfig: pProxyDev=%p[%s] cfg=%#x\n",
-             pProxyDev, pProxyDev->Dev.pszName, iCfg));
+    LogFlow(("usbProxyLinuxSetConfig: pProxyDev=%s cfg=%#x\n",
+             usbProxyGetName(pProxyDev), iCfg));
 
     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETCONFIGURATION, &iCfg, true, UINT32_MAX))
@@ -959,10 +1124,10 @@
 static int usbProxyLinuxClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
 {
-    LogFlow(("usbProxyLinuxClaimInterface: pProxyDev=%p[%s] ifnum=%#x\n", pProxyDev, pProxyDev->Dev.pszName, iIf));
+    LogFlow(("usbProxyLinuxClaimInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
     usbProxyLinuxSetConnected(pProxyDev, iIf, false, false);
 
     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_CLAIMINTERFACE, &iIf, true, UINT32_MAX))
     {
-        Log(("usb-linux: Claim interface. errno=%d pProxyDev=%p[%s]\n", errno, pProxyDev, pProxyDev->Dev.pszName));
+        Log(("usb-linux: Claim interface. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
         return false;
     }
@@ -977,9 +1142,9 @@
 static int usbProxyLinuxReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
 {
-    LogFlow(("usbProxyLinuxReleaseInterface: pProxyDev=%p[%s] ifnum=%#x\n", pProxyDev, pProxyDev->Dev.pszName, iIf));
+    LogFlow(("usbProxyLinuxReleaseInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
 
     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RELEASEINTERFACE, &iIf, true, UINT32_MAX))
     {
-        Log(("usb-linux: Release interface, errno=%d. pProxyDev=%p[%s]\n", errno, pProxyDev, pProxyDev->Dev.pszName));
+        Log(("usb-linux: Release interface, errno=%d. pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
         return false;
     }
@@ -1002,5 +1167,5 @@
     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETINTERFACE, &SetIf, true, UINT32_MAX))
     {
-        Log(("usb-linux: Set interface, errno=%d. pProxyDev=%p[%s]\n", errno, pProxyDev, pProxyDev->Dev.pszName));
+        Log(("usb-linux: Set interface, errno=%d. pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
         return false;
     }
@@ -1014,5 +1179,5 @@
 static bool usbProxyLinuxClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
 {
-    LogFlow(("usbProxyLinuxClearHaltedEp: pProxyDev=%p[%s] EndPt=%u\n", pProxyDev, pProxyDev->Dev.pszName, EndPt));
+    LogFlow(("usbProxyLinuxClearHaltedEp: pProxyDev=%s EndPt=%u\n", usbProxyGetName(pProxyDev), EndPt));
 
     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_CLEAR_HALT, &EndPt, true, UINT32_MAX))
@@ -1025,10 +1190,10 @@
         if (errno == ENOENT)
         {
-            Log(("usb-linux: clear_halted_ep failed errno=%d. pProxyDev=%p[%s] ep=%d - IGNORED\n",
-                 errno, pProxyDev, pProxyDev->Dev.pszName, EndPt));
+            Log(("usb-linux: clear_halted_ep failed errno=%d. pProxyDev=%s ep=%d - IGNORED\n",
+                 errno, usbProxyGetName(pProxyDev), EndPt));
             return true;
         }
-        Log(("usb-linux: clear_halted_ep failed errno=%d. pProxyDev=%p[%s] ep=%d\n",
-             errno, pProxyDev, pProxyDev->Dev.pszName, EndPt));
+        Log(("usb-linux: clear_halted_ep failed errno=%d. pProxyDev=%s ep=%d\n",
+             errno, usbProxyGetName(pProxyDev), EndPt));
         return false;
     }
@@ -1042,16 +1207,135 @@
 static void usbProxyLinuxUrbSwapSetup(PVUSBSETUP pSetup)
 {
-    pSetup->wValue = RT_LE2H_U16(pSetup->wValue);
-    pSetup->wIndex = RT_LE2H_U16(pSetup->wIndex);
-    pSetup->wLength = RT_LE2H_U16(pSetup->wLength);
-}
-
-
-/** The split size. */
-#define SPLIT_SIZE 0x2000
-
-/**
- * Try split up a VUSB URB into smaller URBs which the
- * linux kernel can deal with.
+    pSetup->wValue = RT_H2LE_U16(pSetup->wValue);
+    pSetup->wIndex = RT_H2LE_U16(pSetup->wIndex);
+    pSetup->wLength = RT_H2LE_U16(pSetup->wLength);
+}
+
+
+/**
+ * Clean up after a failed URB submit.
+ */
+static void usbProxyLinuxCleanupFailedSubmit(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx, PUSBPROXYURBLNX pCur, PVUSBURB pUrb, bool *pfUnplugged)
+{
+    if (pUrb->enmType == VUSBXFERTYPE_MSG)
+        usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
+
+    /* discard and reap later (walking with pUrbLnx). */
+    if (pUrbLnx != pCur)
+    {
+        for (;;)
+        {
+            pUrbLnx->fCanceledBySubmit = true;
+            pUrbLnx->KUrb.usercontext = NULL;
+            if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbLnx->KUrb, false, UINT32_MAX))
+            {
+                if (errno == ENODEV)
+                    *pfUnplugged = true;
+                else if (errno == ENOENT)
+                    pUrbLnx->fSplitElementReaped = true;
+                else
+                    LogRel(("USB: Failed to discard %p! errno=%d (pUrb=%p)\n", pUrbLnx->KUrb.usercontext, errno, pUrb)); /* serious! */
+            }
+            if (pUrbLnx->pSplitNext == pCur)
+            {
+                pUrbLnx->pSplitNext = NULL;
+                break;
+            }
+            pUrbLnx = pUrbLnx->pSplitNext; Assert(pUrbLnx);
+        }
+    }
+
+    /* free the unsubmitted ones. */
+    while (pCur)
+    {
+        PUSBPROXYURBLNX pFree = pCur;
+        pCur = pCur->pSplitNext;
+        usbProxyLinuxUrbFree(pProxyDev, pFree);
+    }
+
+    /* send unplug event if we failed with ENODEV originally. */
+    if (*pfUnplugged)
+        usbProxLinuxUrbUnplugged(pProxyDev);
+}
+
+/**
+ * Submit one URB through the usbfs IOCTL interface, with
+ * retries
+ *
+ * @returns true / false.
+ */
+static bool usbProxyLinuxSubmitURB(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pCur, PVUSBURB pUrb, bool *pfUnplugged)
+{
+    PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
+    unsigned        cTries = 0;
+
+    while (ioctl(pDevLnx->File, USBDEVFS_SUBMITURB, &pCur->KUrb))
+    {
+        if (errno == EINTR)
+            continue;
+        if (errno == ENODEV)
+        {
+            Log(("usbProxyLinuxSubmitURB: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
+            *pfUnplugged = true;
+            return false;
+        }
+
+        Log(("usb-linux: Submit URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n",
+             pUrb, errno, pCur->KUrb.type, pCur->KUrb.endpoint, pCur->KUrb.buffer_length, cTries));
+        if (errno != EBUSY && ++cTries < 3) /* this doesn't work for the floppy :/ */
+        {
+            pCur->u64SubmitTS = RTTimeMilliTS();
+            continue;
+        }
+        return false;
+    }
+    return true;
+}
+
+/** The split size. 16K in known Linux kernel versions. */
+#define SPLIT_SIZE 0x4000
+
+/**
+ * Create a URB fragment of up to SPLIT_SIZE size and hook it
+ * into the list of fragments.
+ *
+ * @returns pointer to newly allocated URB fragment or NULL.
+ */
+static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pHead, PUSBPROXYURBLNX pCur)
+{
+    PUSBPROXYURBLNX     pNew;
+    uint32_t            cbLeft = pCur->cbSplitRemaining;
+    uint8_t             *pb = (uint8_t *)pCur->KUrb.buffer;
+
+    Assert(cbLeft != 0);
+    pNew = pCur->pSplitNext = usbProxyLinuxUrbAlloc(pProxyDev, pHead);
+    if (!pNew)
+    {
+        usbProxyLinuxUrbFreeSplitList(pProxyDev, pHead);
+        return NULL;
+    }
+    Assert(pHead->pNext != pNew); Assert(pHead->pPrev != pNew); Assert(pNew->pNext == pNew->pPrev);
+    Assert(pNew->pSplitHead == pHead);
+    Assert(pNew->pSplitNext == NULL);
+
+    pNew->KUrb = pHead->KUrb;
+    pNew->KUrb.buffer = pb + pCur->KUrb.buffer_length;
+    pNew->KUrb.buffer_length = RT_MIN(cbLeft, SPLIT_SIZE);
+    pNew->KUrb.actual_length = 0;
+
+    cbLeft -= pNew->KUrb.buffer_length;
+    Assert(cbLeft < INT32_MAX);
+    pNew->cbSplitRemaining = cbLeft;
+    return pNew;
+}
+
+/**
+ * Try splitting up a VUSB URB into smaller URBs which the
+ * linux kernel (usbfs) can deal with.
+ *
+ * NB: For ShortOK reads things get a little tricky - we don't
+ * know how much data is going to arrive and not all the
+ * fragment URBs might be filled. We can only safely set up one
+ * URB at a time -> worse performance but correct behaviour.
  *
  * @returns true / false.
@@ -1062,7 +1346,4 @@
 static int usbProxyLinuxUrbQueueSplit(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx, PVUSBURB pUrb)
 {
-    unsigned        cTries;
-    PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
-
     /*
      * Split it up into SPLIT_SIZE sized blocks.
@@ -1080,6 +1361,9 @@
         case VUSBXFERTYPE_BULK: pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_BULK; break;
         case VUSBXFERTYPE_INTR: pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_INTERRUPT; break;
-        case VUSBXFERTYPE_ISOC: pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_ISO; break;
         case VUSBXFERTYPE_MSG:  pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_CONTROL; break;
+        case VUSBXFERTYPE_ISOC:
+            AssertMsgFailed(("We can't split isochronous URBs!\n"));
+            usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
+            return false;
     }
     pUrbLnx->KUrb.endpoint          = pUrb->EndPt;
@@ -1089,5 +1373,5 @@
     pUrbLnx->KUrb.flags             = pUrb->fShortNotOk ? USBDEVFS_URB_SHORT_NOT_OK : 0; /* ISO_ASAP too? */
     pUrbLnx->KUrb.buffer            = pb;
-    pUrbLnx->KUrb.buffer_length     = MIN(cbLeft, SPLIT_SIZE);
+    pUrbLnx->KUrb.buffer_length     = RT_MIN(cbLeft, SPLIT_SIZE);
     pUrbLnx->KUrb.actual_length     = 0;
     pUrbLnx->KUrb.start_frame       = 0;
@@ -1099,65 +1383,46 @@
     pUrbLnx->pSplitNext = NULL;
 
-    pb += pUrbLnx->KUrb.buffer_length;
+    PUSBPROXYURBLNX pCur = pUrbLnx;
+
     cbLeft -= pUrbLnx->KUrb.buffer_length;
-
-    /* the rest. */
-    unsigned i;
-    PUSBPROXYURBLNX pCur = pUrbLnx;
-    for (i = 1; i < cKUrbs; i++)
-    {
-        Assert(cbLeft != 0);
-        pCur = pCur->pSplitNext = usbProxyLinuxUrbAlloc(pProxyDev, pUrbLnx);
-        if (!pCur)
-        {
-            usbProxyLinuxUrbFreeSplitList(pProxyDev, pUrbLnx);
-            return false;
-        }
-        Assert(pUrbLnx->pNext != pCur); Assert(pUrbLnx->pPrev != pCur); Assert(pCur->pNext == pCur->pPrev);
-        Assert(pCur->pSplitHead == pUrbLnx);
-        Assert(pCur->pSplitNext == NULL);
-
-        pCur->KUrb = pUrbLnx->KUrb;
-        pCur->KUrb.buffer = pb;
-        pCur->KUrb.buffer_length = MIN(cbLeft, SPLIT_SIZE);
-        pCur->KUrb.actual_length = 0;
-
-        pb += pCur->KUrb.buffer_length;
-        cbLeft -= pCur->KUrb.buffer_length;
-    }
-    Assert(cbLeft == 0);
-
-    /*
-     * Submit them.
-     */
+    pUrbLnx->cbSplitRemaining = cbLeft;
+
+    bool fSucceeded = false;
     bool fUnplugged = false;
-    bool fFailed = false;
-    pCur = pUrbLnx;
-    for (i = 0; i < cKUrbs; i++, pCur = pCur->pSplitNext)
-    {
-        cTries = 0;
-        while (ioctl(pDevLnx->File, USBDEVFS_SUBMITURB, &pCur->KUrb))
-        {
-            if (errno == EINTR)
-                continue;
-            if (errno == ENODEV)
+    if (pUrb->enmDir == VUSBDIRECTION_IN && !pUrb->fShortNotOk)
+    {
+        /* Subsequent fragments will be queued only after the previous fragment is reaped
+         * and only if necessary.
+         */
+        fSucceeded = true;
+        Log(("usb-linux: Large ShortOK read, only queuing first fragment.\n"));
+        Assert(pUrbLnx->cbSplitRemaining > 0 && pUrbLnx->cbSplitRemaining < 256 * _1K);
+        fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pUrbLnx, pUrb, &fUnplugged);
+    }
+    else
+    {
+        /* the rest. */
+        unsigned i;
+        for (i = 1; i < cKUrbs; i++)
+        {
+            pCur = usbProxyLinuxSplitURBFragment(pProxyDev, pUrbLnx, pCur);
+            if (!pCur)
             {
-                Log(("usbProxyLinuxUrbQueueSplit: ENODEV -> unplugged. pProxyDev=%p[%s]\n", pProxyDev, pProxyDev->Dev.pszName));
-                fFailed = fUnplugged = true;
+                return false;
+            }
+        }
+        Assert(pCur->cbSplitRemaining == 0);
+
+        /* Submit the blocks. */
+        pCur = pUrbLnx;
+        for (i = 0; i < cKUrbs; i++, pCur = pCur->pSplitNext)
+        {
+            fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pCur, pUrb, &fUnplugged);
+            if (!fSucceeded)
                 break;
-            }
-
-            Log(("usb-linux: Queue URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n",
-                 pUrb, errno, pCur->KUrb.type, pCur->KUrb.endpoint, pCur->KUrb.buffer_length, cTries));
-            if (errno != EBUSY && ++cTries < 3) /* this doesn't work for the floppy :/ */
-                continue;
-            fFailed = true;
-            break;
-        }
-        if (fFailed)
-            break;
-        pCur->u64SubmitTS = RTTimeMilliTS();
-    }
-    if (!fFailed)
+        }
+    }
+
+    if (fSucceeded)
     {
         pUrb->Dev.pvPrivate = pUrbLnx;
@@ -1166,46 +1431,5 @@
     }
 
-    /*
-     * Clean up.
-     */
-    if (pUrb->enmType == VUSBXFERTYPE_MSG)
-        usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
-
-    /* discard and reap later (walking with pUrbLnx). */
-    if (pUrbLnx != pCur)
-    {
-        for (;;)
-        {
-            pUrbLnx->fCanceledBySubmit = true;
-            pUrbLnx->KUrb.usercontext = NULL;
-            if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbLnx->KUrb, false, UINT32_MAX))
-            {
-                if (errno == ENODEV)
-                    fUnplugged = true;
-                else if (errno == ENOENT)
-                    pUrbLnx->fSplitElementReaped = true;
-                else
-                    LogRel(("SUB: Failed to discard %p! errno=%d (pUrb=%p)\n", pUrbLnx->KUrb.usercontext, errno, pUrb)); /* serious! */
-            }
-            if (pUrbLnx->pSplitNext == pCur)
-            {
-                pUrbLnx->pSplitNext = NULL;
-                break;
-            }
-            pUrbLnx = pUrbLnx->pSplitNext; Assert(pUrbLnx);
-        }
-    }
-
-    /* free the unsubmitted ones. */
-    while (pCur)
-    {
-        PUSBPROXYURBLNX pFree = pCur;
-        pCur = pCur->pSplitNext;
-        usbProxyLinuxUrbFree(pProxyDev, pFree);
-    }
-
-    /* send unplug event if we failed with ENODEV originally. */
-    if (fUnplugged)
-        usbProxLinuxUrbUnplugged(pProxyDev);
+    usbProxyLinuxCleanupFailedSubmit(pProxyDev, pUrbLnx, pCur, pUrb, &fUnplugged);
     return false;
 }
@@ -1213,13 +1437,17 @@
 
 /**
- * @copydoc USBPROXYBACK::pfbUrbQueue
+ * @copydoc USBPROXYBACK::pfnUrbQueue
  */
 static int usbProxyLinuxUrbQueue(PVUSBURB pUrb)
 {
     unsigned        cTries;
-    PUSBPROXYDEV    pProxyDev = (PUSBPROXYDEV)pUrb->pDev;
+#ifndef RDESKTOP
+    PUSBPROXYDEV    pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
+#else
+    PUSBPROXYDEV    pProxyDev = usbProxyFromVusbDev(pUrb->pDev);
+#endif
     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
-    LogFlow(("usbProxyLinuxUrbQueue: pProxyDev=%p[%s] pUrb=%p EndPt=%d cbData=%d\n",
-             pProxyDev, pProxyDev->Dev.pszName, pUrb, pUrb->EndPt, pUrb->cbData));
+    LogFlow(("usbProxyLinuxUrbQueue: pProxyDev=%s pUrb=%p EndPt=%d cbData=%d\n",
+             usbProxyGetName(pProxyDev), pUrb, pUrb->EndPt, pUrb->cbData));
 
     /*
@@ -1229,4 +1457,16 @@
     if (!pUrbLnx)
         return false;
+
+    pUrbLnx->KUrb.endpoint          = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
+    pUrbLnx->KUrb.status            = 0;
+    pUrbLnx->KUrb.flags             = pUrb->fShortNotOk ? USBDEVFS_URB_SHORT_NOT_OK : 0;
+    pUrbLnx->KUrb.buffer            = pUrb->abData;
+    pUrbLnx->KUrb.buffer_length     = pUrb->cbData;
+    pUrbLnx->KUrb.actual_length     = 0;
+    pUrbLnx->KUrb.start_frame       = 0;
+    pUrbLnx->KUrb.number_of_packets = 0;
+    pUrbLnx->KUrb.error_count       = 0;
+    pUrbLnx->KUrb.signr             = 0;
+    pUrbLnx->KUrb.usercontext       = pUrb;
 
     switch (pUrb->enmType)
@@ -1247,4 +1487,13 @@
         case VUSBXFERTYPE_ISOC:
             pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_ISO;
+            pUrbLnx->KUrb.flags |= USBDEVFS_URB_ISO_ASAP;
+            pUrbLnx->KUrb.number_of_packets = pUrb->cIsocPkts;
+            unsigned i;
+            for (i = 0; i < pUrb->cIsocPkts; i++)
+            {
+                pUrbLnx->KUrb.iso_frame_desc[i].length = pUrb->aIsocPkts[i].cb;
+                pUrbLnx->KUrb.iso_frame_desc[i].actual_length = 0;
+                pUrbLnx->KUrb.iso_frame_desc[i].status = 0x7fff;
+            }
             break;
         case VUSBXFERTYPE_INTR:
@@ -1254,26 +1503,4 @@
             goto l_err;
     }
-    pUrbLnx->KUrb.endpoint          = pUrb->EndPt;
-    pUrbLnx->KUrb.status            = 0;
-    pUrbLnx->KUrb.flags             = pUrb->fShortNotOk ? USBDEVFS_URB_SHORT_NOT_OK : 0; /* ISO_ASAP too? */
-    pUrbLnx->KUrb.buffer            = pUrb->abData;
-    pUrbLnx->KUrb.buffer_length     = pUrb->cbData;
-    pUrbLnx->KUrb.actual_length     = 0;
-    pUrbLnx->KUrb.start_frame       = 0;
-    pUrbLnx->KUrb.number_of_packets = 0;
-    pUrbLnx->KUrb.error_count       = 0;
-    pUrbLnx->KUrb.signr             = 0;
-    pUrbLnx->KUrb.usercontext       = pUrb;
-    switch (pUrb->enmDir)
-    {
-        case VUSBDIRECTION_IN:
-            pUrbLnx->KUrb.endpoint |= 0x80;
-            break;
-        case VUSBDIRECTION_OUT:
-            break;
-        default:
-            AssertMsgFailed(("usbProxyLinuxUrbQueue: Invalid directorion %d\n", pUrb->enmDir));
-            goto l_err;
-    }
 
     /*
@@ -1287,5 +1514,5 @@
         if (errno == ENODEV)
         {
-            Log(("usbProxyLinuxUrbQueue: ENODEV -> unplugged. pProxyDev=%p[%s]\n", pProxyDev, pProxyDev->Dev.pszName));
+            Log(("usbProxyLinuxUrbQueue: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
             if (pUrb->enmType == VUSBXFERTYPE_MSG)
                 usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
@@ -1356,6 +1583,6 @@
                 Assert(pCur == pCur->pSplitHead);
                 unsigned cFailures = 0;
-		PUSBPROXYURBLNX pCur2;
-                for ( pCur2 = pCur; pCur2; pCur2 = pCur2->pSplitNext)
+                PUSBPROXYURBLNX pCur2;
+                for (pCur2 = pCur; pCur2; pCur2 = pCur2->pSplitNext)
                 {
                     if (pCur2->fSplitElementReaped)
@@ -1370,6 +1597,6 @@
                         goto l_leave; /* ENODEV means break and everything cancelled elsewhere. */
                 }
-                LogRel(("USB: Cancelled URB (%p) after %lldms!! (cFailures=%d)\n",
-                        pCur->KUrb.usercontext, u64MilliTS - pCur->u64SubmitTS, cFailures));
+                LogRel(("USB: Cancelled URB (%p) after %llums!! (cFailures=%d)\n",
+                        pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS, cFailures));
             }
             else
@@ -1380,5 +1607,5 @@
                 {
                     pCur->fCanceledByTimedOut = true;
-                    LogRel(("USB: Cancelled URB (%p) after %lldms!!\n", pCur->KUrb.usercontext, u64MilliTS - pCur->u64SubmitTS));
+                    LogRel(("USB: Cancelled URB (%p) after %llums!!\n", pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS));
                 }
                 else if (errno != ENODEV)
@@ -1388,6 +1615,10 @@
             }
         }
+#if 0
+        /* Disabled for the time beeing as some USB devices have URBs pending for an unknown amount of time.
+         * One example is the OmniKey CardMan 3821. */
         else if (u64MilliTS - pCur->u64SubmitTS >= 200*1000 /* 200 sec (180 sec has been observed with XP) */)
             pCur->fTimedOut = true;
+#endif
     }
 
@@ -1398,14 +1629,18 @@
 
 /**
- * Get and translates the linux status to a VUSB status.
- */
-static VUSBSTATUS vusbProxyLinuxUrbGetStatus(PUSBPROXYURBLNX pUrbLnx)
-{
-    switch (pUrbLnx->KUrb.status)
-    {
+ * Translate the linux status to a VUSB status.
+ *
+ * @remarks see cc_to_error in ohci.h, uhci_map_status in uhci-q.c,
+ *          sitd_complete+itd_complete in ehci-sched.c, and qtd_copy_status in
+ *          ehci-q.c.
+ */
+static VUSBSTATUS vusbProxyLinuxStatusToVUsbStatus(int iStatus)
+{
+    switch (iStatus)
+    {
+        /** @todo VUSBSTATUS_NOT_ACCESSED */
+        case -EXDEV: /* iso transfer, partial result. */
         case 0:
-            if (!pUrbLnx->fCanceledByTimedOut)
-                return VUSBSTATUS_OK;
-            /* fall thru */
+            return VUSBSTATUS_OK;
 
         case -EILSEQ:
@@ -1413,6 +1648,9 @@
 
         case -EREMOTEIO: /* ehci and ohci uses this for underflow error. */
-            return VUSBSTATUS_UNDERFLOW;
-
+            return VUSBSTATUS_DATA_UNDERRUN;
+        case -EOVERFLOW:
+            return VUSBSTATUS_DATA_OVERRUN;
+
+        case -ETIME:
         case -ENODEV:
             return VUSBSTATUS_DNR;
@@ -1426,8 +1664,28 @@
         //    return VUSBSTATUS_BIT_STUFFING;
 
+        case -EPIPE:
+            Log(("vusbProxyLinuxStatusToVUsbStatus: STALL/EPIPE!!\n"));
+            return VUSBSTATUS_STALL;
+
+        case -ESHUTDOWN:
+            Log(("vusbProxyLinuxStatusToVUsbStatus: SHUTDOWN!!\n"));
+            return VUSBSTATUS_STALL;
+
         default:
-            Log(("usbProxyLinuxUrbReap: pKUrb status %d!!\n", pUrbLnx->KUrb.status));
+            Log(("vusbProxyLinuxStatusToVUsbStatus: status %d!!\n", iStatus));
             return VUSBSTATUS_STALL;
     }
+}
+
+
+/**
+ * Get and translates the linux status to a VUSB status.
+ */
+static VUSBSTATUS vusbProxyLinuxUrbGetStatus(PUSBPROXYURBLNX pUrbLnx)
+{
+    if (    pUrbLnx->fCanceledByTimedOut
+        &&  pUrbLnx->KUrb.status == 0)
+        return VUSBSTATUS_CRC;
+    return vusbProxyLinuxStatusToVUsbStatus(pUrbLnx->KUrb.status);
 }
 
@@ -1441,5 +1699,5 @@
  * @param   cMillies    Number of milliseconds to wait. Use 0 to not wait at all.
  */
-static PVUSBURB usbProxyLinuxUrbReap(PUSBPROXYDEV pProxyDev, unsigned cMillies)
+static PVUSBURB usbProxyLinuxUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
 {
     PUSBPROXYURBLNX pUrbLnx = NULL;
@@ -1511,5 +1769,5 @@
                 if (errno != EAGAIN)
                 {
-                    Log(("usb-linux: Reap URB - poll -> %d errno=%d pProxyDev=%p[%s]\n", rc, errno, pProxyDev, pProxyDev->Dev.pszName));
+                    Log(("usb-linux: Reap URB - poll -> %d errno=%d pProxyDev=%s\n", rc, errno, usbProxyGetName(pProxyDev)));
                     return NULL;
                 }
@@ -1532,5 +1790,5 @@
                         vusbProxyLinuxUrbDoTimeouts(pProxyDev, pDevLnx);
                     else
-                        Log(("usb-linux: Reap URB. errno=%d pProxyDev=%p[%s]\n", errno, pProxyDev, pProxyDev->Dev.pszName));
+                        Log(("usb-linux: Reap URB. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
                     return NULL;
                 }
@@ -1541,5 +1799,28 @@
             {
                 pUrbLnx->fSplitElementReaped = true;
-		PUSBPROXYURBLNX pCur;
+
+                /* for variable size URBs, we may need to queue more if the just-reaped URB was completely filled */
+                if (pUrbLnx->cbSplitRemaining && (pKUrb->actual_length == pKUrb->buffer_length) && !pUrbLnx->pSplitNext)
+                {
+                    bool fUnplugged = false;
+                    bool fSucceeded;
+
+                    Assert(pUrbLnx->pSplitHead);
+                    Assert((pKUrb->endpoint & 0x80) && (!pKUrb->flags & USBDEVFS_URB_SHORT_NOT_OK));
+                    PUSBPROXYURBLNX pNew = usbProxyLinuxSplitURBFragment(pProxyDev, pUrbLnx->pSplitHead, pUrbLnx);
+                    if (!pNew)
+                    {
+                        Log(("usb-linux: Allocating URB fragment failed. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
+                        return NULL;
+                    }
+                    PVUSBURB pUrb = (PVUSBURB)pUrbLnx->KUrb.usercontext;
+                    fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pNew, pUrb, &fUnplugged);
+                    if (fUnplugged)
+                        usbProxLinuxUrbUnplugged(pProxyDev);
+                    if (!fSucceeded)
+                        return NULL;
+                    continue;   /* try reaping another URB */
+                }
+                PUSBPROXYURBLNX pCur;
                 for (pCur = pUrbLnx->pSplitHead; pCur; pCur = pCur->pSplitNext)
                     if (!pCur->fSplitElementReaped)
@@ -1569,5 +1850,5 @@
             uint8_t *pbEnd = &pUrb->abData[0];
             pUrb->enmStatus = VUSBSTATUS_OK;
-	    PUSBPROXYURBLNX pCur;
+            PUSBPROXYURBLNX pCur;
             for (pCur = pUrbLnx; pCur; pCur = pCur->pSplitNext)
             {
@@ -1585,4 +1866,15 @@
             pUrb->enmStatus = vusbProxyLinuxUrbGetStatus(pUrbLnx);
             pUrb->cbData = pUrbLnx->KUrb.actual_length;
+            if (pUrb->enmType == VUSBXFERTYPE_ISOC)
+            {
+                unsigned i, off;
+                for (i = 0, off = 0; i < pUrb->cIsocPkts; i++)
+                {
+                    pUrb->aIsocPkts[i].enmStatus = vusbProxyLinuxStatusToVUsbStatus(pUrbLnx->KUrb.iso_frame_desc[i].status);
+                    Assert(pUrb->aIsocPkts[i].off == off);
+                    pUrb->aIsocPkts[i].cb = pUrbLnx->KUrb.iso_frame_desc[i].actual_length;
+                    off += pUrbLnx->KUrb.iso_frame_desc[i].length;
+                }
+            }
             usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
         }
@@ -1602,5 +1894,5 @@
     }
 
-    LogFlow(("usbProxyLinuxUrbReap: dev=%p[%s] returns %p\n", pProxyDev, pProxyDev->Dev.pszName, pUrb));
+    LogFlow(("usbProxyLinuxUrbReap: pProxyDev=%s returns %p\n", usbProxyGetName(pProxyDev), pUrb));
     return pUrb;
 }
@@ -1613,5 +1905,9 @@
 static void usbProxyLinuxUrbCancel(PVUSBURB pUrb)
 {
-    PUSBPROXYDEV pProxyDev = (PUSBPROXYDEV)pUrb->pDev;
+#ifndef RDESKTOP
+    PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
+#else
+    PUSBPROXYDEV pProxyDev = usbProxyFromVusbDev(pUrb->pDev);
+#endif
     PUSBPROXYURBLNX pUrbLnx = (PUSBPROXYURBLNX)pUrb->Dev.pvPrivate;
     if (pUrbLnx->pSplitHead)
@@ -1619,5 +1915,5 @@
         /* split */
         Assert(pUrbLnx == pUrbLnx->pSplitHead);
-	PUSBPROXYURBLNX pCur;
+        PUSBPROXYURBLNX pCur;
         for (pCur = pUrbLnx; pCur; pCur = pCur->pSplitNext)
         {
@@ -1629,6 +1925,6 @@
             if (errno == ENODEV)
                 break;
-            Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%p[%s]!!! (split)\n",
-                 pUrb, errno, pProxyDev, pProxyDev->Dev.pszName));
+            Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!! (split)\n",
+                 pUrb, errno, usbProxyGetName(pProxyDev)));
         }
     }
@@ -1639,6 +1935,6 @@
             &&  errno != ENODEV /* deal with elsewhere. */
             &&  errno != ENOENT)
-            Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%p[%s]!!!\n",
-                 pUrb, errno, pProxyDev, pProxyDev->Dev.pszName));
+            Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!!\n",
+                 pUrb, errno, usbProxyGetName(pProxyDev)));
     }
 }
@@ -1648,11 +1944,9 @@
  * The Linux USB Proxy Backend.
  */
-#ifdef __cplusplus
-extern
-#endif
 const USBPROXYBACK g_USBProxyDeviceHost =
 {
     "host",
     usbProxyLinuxOpen,
+    usbProxyLinuxInit,
     usbProxyLinuxClose,
     usbProxyLinuxReset,
Index: /trunk/src/VBox/RDP/client/vrdp/USBProxyDevice.h
===================================================================
--- /trunk/src/VBox/RDP/client/vrdp/USBProxyDevice.h	(revision 31247)
+++ /trunk/src/VBox/RDP/client/vrdp/USBProxyDevice.h	(revision 31247)
@@ -0,0 +1,246 @@
+/* $Id$ */
+/** @file
+ * USBPROXY - USB proxy header
+ */
+
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * Oracle Corporation confidential
+ * All rights reserved
+ */
+
+#ifndef ___USBProxyDevice_h
+#define ___USBProxyDevice_h
+
+#ifndef RDESKTOP
+# include <VBox/cdefs.h>
+# include <VBox/vusb.h>
+#else
+# include "runtime.h"
+# include "vusb.h"
+#endif
+
+RT_C_DECLS_BEGIN
+
+
+/**
+ * Arguments passed to the USB proxy device constructor.
+ */
+typedef struct USBPROXYDEVARGS
+{
+    /** Whether this is a remote (VRDP) or local (Host) device. */
+    bool        fRemote;
+    /** Host specific USB device address. */
+    const char *pszAddress;
+    /** Pointer to backend specific data. */
+    void       *pvBackend;
+} USBPROXYDEVARGS;
+/** Pointer to proxy device creation structure. */
+typedef USBPROXYDEVARGS *PUSBPROXYDEVARGS;
+
+
+/** Pointer to a USB proxy device. */
+typedef struct USBPROXYDEV *PUSBPROXYDEV;
+
+/**
+ * USB Proxy Device Backend
+ */
+typedef struct USBPROXYBACK
+{
+    /** Name of the backend. */
+    const char *pszName;
+
+    /**
+     * Opens the USB device specfied by pszAddress.
+     *
+     * This method will initialize backend private data. If the backend has
+     * already selected a configuration for the device, this must be indicated
+     * in USBPROXYDEV::iActiveCfg.
+     *
+     * @returns VBox status code.
+     * @param   pProxyDev   The USB Proxy Device instance.
+     * @param   pszAddress  Host specific USB device address.
+     * @param   pvBackend   Pointer to backend specific data.
+     */
+    int  (* pfnOpen)(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend);
+
+    /**
+     * Optional callback for initalizing the device after the configuration
+     * has been established.
+     *
+     * @returns VBox status code.
+     * @param   pProxyDev   The USB Proxy Device instance.
+     */
+    int  (* pfnInit)(PUSBPROXYDEV pProxyDev);
+
+    /**         Closes handle to the host USB device.
+     *
+     * @param   pDev        The USB Proxy Device instance.
+     */
+    void (* pfnClose)(PUSBPROXYDEV pProxyDev);
+
+    /**
+     * Reset a device.
+     *
+     * The backend must update iActualCfg and fIgnoreEqualSetConfig.
+     *
+     * @returns VBox status code.
+     * @param   pDev            The device to reset.
+     * @param   fResetOnLinux   It's safe to do reset on linux, we can deal with devices
+     *                          being logically reconnected.
+     */
+    int  (* pfnReset)(PUSBPROXYDEV pProxyDev, bool fResetOnLinux);
+
+    /** @todo make it return a VBox status code! */
+    int  (* pfnSetConfig)(PUSBPROXYDEV pProxyDev, int iCfg);
+
+    /** @todo make it return a VBox status code! */
+    int  (* pfnClaimInterface)(PUSBPROXYDEV pProxyDev, int iIf);
+
+    /** @todo make it return a VBox status code! */
+    int  (* pfnReleaseInterface)(PUSBPROXYDEV pProxyDev, int iIf);
+
+    /** @todo make it return a VBox status code! */
+    int  (* pfnSetInterface)(PUSBPROXYDEV pProxyDev, int iIf, int setting);
+
+    /** @todo make it return a VBox status code! */
+    bool (* pfnClearHaltedEndpoint)(PUSBPROXYDEV  pDev, unsigned int iEp);
+
+    /** @todo make it return a VBox status code! Add pDev. */
+    int  (* pfnUrbQueue)(PVUSBURB pUrb);
+
+    /**
+     * Cancel an in-flight URB.
+     *
+     * @param   pUrb        The URB to cancel.
+     * @todo make it return a VBox status code! Add pDev.
+     */
+    void (* pfnUrbCancel)(PVUSBURB pUrb);
+
+    /**
+     * Reap URBs in-flight on a device.
+     *
+     * @returns Pointer to a completed URB.
+     * @returns NULL if no URB was completed.
+     * @param   pDev        The device.
+     * @param   cMillies    Number of milliseconds to wait. Use 0 to not
+     *                      wait at all.
+     */
+    PVUSBURB (* pfnUrbReap)(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies);
+
+    /** Dummy entry for making sure we've got all members initialized. */
+    uint32_t uDummy;
+} USBPROXYBACK;
+/** Pointer to a USB Proxy Device Backend. */
+typedef USBPROXYBACK *PUSBPROXYBACK;
+/** Pointer to a const USB Proxy Device Backend. */
+typedef const USBPROXYBACK *PCUSBPROXYBACK;
+
+/** The Host backend. */
+extern const USBPROXYBACK g_USBProxyDeviceHost;
+#ifdef VBOX_WITH_VRDP
+/** The VRDP backend. */
+extern const USBPROXYBACK g_USBProxyDeviceVRDP;
+#endif /* VBOX_WITH_VRDP */
+
+#ifdef RDESKTOP
+typedef struct VUSBDEV
+{
+    char* pszName;
+} VUSBDEV, *PVUSBDEV;
+#endif
+
+/**
+ * USB Proxy device.
+ */
+typedef struct USBPROXYDEV
+{
+#ifdef RDESKTOP
+    /** The VUSB device structure - must be the first structure member. */
+    VUSBDEV             Dev;
+    /** The next device in rdesktop-vrdp's linked list */
+    PUSBPROXYDEV        pNext;
+    /** The previous device in rdesktop-vrdp's linked list */
+    PUSBPROXYDEV        pPrev;
+    /** The vrdp device ID */
+    uint32_t devid;
+    /** Linked list of in-flight URBs */
+    PVUSBURB            pUrbs;
+#endif
+    /** The device descriptor. */
+    VUSBDESCDEVICE      DevDesc;
+    /** The configuration descriptor array. */
+    PVUSBDESCCONFIGEX   paCfgDescs;
+#ifndef RDESKTOP
+    /** The descriptor cache.
+     * Contains &DevDesc and paConfigDescs. */
+    PDMUSBDESCCACHE     DescCache;
+    /** Pointer to the PDM USB device instance. */
+    PPDMUSBINS          pUsbIns;
+#endif
+
+    /** Pointer to the backend. */
+    PCUSBPROXYBACK      pOps;
+    /** The currently active configration.
+     * It's -1 if no configuration is active. This is set to -1 before open and reset,
+     * the backend will change it if open or reset implies SET_CONFIGURATION. */
+    int                 iActiveCfg;
+    /** Ignore one or two SET_CONFIGURATION operation.
+     * See usbProxyDevSetCfg for details. */
+    int                 cIgnoreSetConfigs;
+    /** Mask of the interfaces that the guest shall doesn't see.
+     * This is experimental!
+     */
+    uint32_t            fMaskedIfs;
+    /** Whether we've opened the device or not.
+     * For dealing with failed construction (the destruct method is always called). */
+    bool                fOpened;
+    /** Whether we've called pfnInit or not.
+     * For dealing with failed construction (the destruct method is always called). */
+    bool                fInited;
+    /** Whether the device has been detached.
+     * This is hack for making PDMUSBREG::pfnUsbQueue return the right status code. */
+    bool                fDetached;
+    /** Backend specific data */
+    union USBPROXYBACKENDDATA
+    {
+        /** Pointer to some backend data.
+         * The Linux and Darwin backends are making use of this. */
+        void *pv;
+        RTFILE File;
+        int fd;
+#ifdef VBOX_WITH_VRDP
+        struct vrdp_priv
+        {
+            void *pCallback;
+            void *pDevice;
+        } vrdp;
+#endif /* VBOX_WITH_VRDP */
+    } Backend;
+} USBPROXYDEV;
+
+static inline char *usbProxyGetName(PUSBPROXYDEV pProxyDev)
+{
+#ifndef RDESKTOP
+    return pProxyDev->pUsbIns->pszName;
+#else
+    return pProxyDev->Dev.pszName;
+#endif
+}
+
+#ifdef RDESKTOP
+static inline PUSBPROXYDEV usbProxyFromVusbDev(PVUSBDEV pDev)
+{
+    return (PUSBPROXYDEV)pDev;
+}
+#endif
+
+#ifdef RT_OS_LINUX
+RTDECL(int) USBProxyDeviceLinuxGetFD(PUSBPROXYDEV pProxyDev);
+#endif
+
+RT_C_DECLS_END
+
+#endif
+
Index: /trunk/src/VBox/RDP/client/vrdp/rdpusb.c
===================================================================
--- /trunk/src/VBox/RDP/client/vrdp/rdpusb.c	(revision 31246)
+++ /trunk/src/VBox/RDP/client/vrdp/rdpusb.c	(revision 31247)
@@ -24,5 +24,7 @@
 #include <fcntl.h>
 
+#include "runtime.h"
 #include "vrdpusb.h"
+#include "USBProxyDevice.h"
 
 #define RDPUSB_REQ_OPEN              (0)
@@ -64,4 +66,59 @@
 #pragma pack ()
 
+static inline int op_usbproxy_back_open(PUSBPROXYDEV p, const char *pszAddress)
+{
+     return g_USBProxyDeviceHost.pfnOpen (p, pszAddress, NULL);
+}
+
+static inline void op_usbproxy_back_close(PUSBPROXYDEV pDev)
+{
+     return g_USBProxyDeviceHost.pfnClose (pDev);
+}
+
+static inline int op_usbproxy_back_reset(PUSBPROXYDEV pDev)
+{
+    return g_USBProxyDeviceHost.pfnReset (pDev, false);
+}
+
+static inline int op_usbproxy_back_set_config(PUSBPROXYDEV pDev, int cfg)
+{
+    return g_USBProxyDeviceHost.pfnSetConfig (pDev, cfg);
+}
+
+static inline int op_usbproxy_back_claim_interface(PUSBPROXYDEV pDev, int ifnum)
+{
+    return g_USBProxyDeviceHost.pfnClaimInterface (pDev, ifnum);
+}
+
+static inline int op_usbproxy_back_release_interface(PUSBPROXYDEV pDev, int ifnum)
+{
+    return g_USBProxyDeviceHost.pfnReleaseInterface (pDev, ifnum);
+}
+
+static inline int op_usbproxy_back_interface_setting(PUSBPROXYDEV pDev, int ifnum, int setting)
+{
+    return g_USBProxyDeviceHost.pfnSetInterface (pDev, ifnum, setting);
+}
+
+static inline int op_usbproxy_back_queue_urb(PVUSBURB pUrb)
+{
+    return g_USBProxyDeviceHost.pfnUrbQueue(pUrb);
+}
+
+static inline PVUSBURB op_usbproxy_back_reap_urb(PUSBPROXYDEV pDev, unsigned cMillies)
+{
+    return g_USBProxyDeviceHost.pfnUrbReap (pDev, cMillies);
+}
+
+static inline bool op_usbproxy_back_clear_halted_ep(PUSBPROXYDEV pDev, unsigned EndPoint)
+{
+    return g_USBProxyDeviceHost.pfnClearHaltedEndpoint (pDev, EndPoint);
+}
+
+static inline void op_usbproxy_back_cancel_urb(PVUSBURB pUrb)
+{
+    return g_USBProxyDeviceHost.pfnUrbCancel (pUrb);
+}
+
 static uint16 getBcd (const char *str, const char *prefix)
 {
@@ -405,5 +462,5 @@
 vrdp_usb_status (int rc, VUSBDEV *pdev)
 {
-	if (!rc || pdev->request_detach)
+	if (!rc || usbProxyFromVusbDev(pdev)->fDetached)
 	{
 		return VRDP_USB_STATUS_DEVICE_REMOVED;
@@ -413,14 +470,14 @@
 }
 
-static struct usb_proxy *g_proxies = NULL;
-
-static struct usb_proxy *
+static PUSBPROXYDEV g_proxies = NULL;
+
+static PUSBPROXYDEV 
 devid2proxy (uint32_t devid)
 {
-	struct usb_proxy *proxy = g_proxies;
+	PUSBPROXYDEV proxy = g_proxies;
 
 	while (proxy && proxy->devid != devid)
 	{
-		proxy = proxy->next;
+		proxy = proxy->pNext;
 	}
 
@@ -435,5 +492,5 @@
 	PVUSBURB pUrb = NULL;
 
-	struct usb_proxy *proxy = g_proxies;
+	PUSBPROXYDEV proxy = g_proxies;
 
 	while (proxy)
@@ -467,19 +524,19 @@
 			rdpusb_send(s);
 
-			if (pUrb->prev || pUrb->next || pUrb == proxy->urbs)
+			if (pUrb->pPrev || pUrb->pNext || pUrb == proxy->pUrbs)
 			{
 				/* Remove the URB from list. */
-				if (pUrb->prev)
-				{
-					pUrb->prev->next = pUrb->next;
+				if (pUrb->pPrev)
+				{
+					pUrb->pPrev->pNext = pUrb->pNext;
 				}
 				else
 				{
-					proxy->urbs = pUrb->next;
+					proxy->pUrbs = pUrb->pNext;
 				}
 
-				if (pUrb->next)
-				{
-					pUrb->next->prev = pUrb->prev;
+				if (pUrb->pNext)
+				{
+					pUrb->pNext->pPrev = pUrb->pPrev;
 				}
 			}
@@ -494,5 +551,5 @@
 		}
 
-		proxy = proxy->next;
+		proxy = proxy->pNext;
 	}
 
@@ -509,5 +566,5 @@
 	uint32 devid;
 
-	struct usb_proxy *proxy = NULL;
+	PUSBPROXYDEV proxy = NULL;
 
 #ifdef RDPUSB_DEBUG
@@ -535,7 +592,7 @@
 	        	in_uint32_le(s, devid);
 
-			proxy = (struct usb_proxy *)xmalloc (sizeof (struct usb_proxy));
-
-			memset (proxy, 0, sizeof (struct usb_proxy));
+			proxy = (PUSBPROXYDEV )xmalloc (sizeof (USBPROXYDEV));
+
+			memset (proxy, 0, sizeof (USBPROXYDEV));
 
 			proxy->Dev.pszName = "Remote device";
@@ -556,8 +613,8 @@
 				if (g_proxies)
 				{
-					g_proxies->prev = proxy;
+					g_proxies->pPrev = proxy;
 				}
 
-				proxy->next = g_proxies;
+				proxy->pNext = g_proxies;
 				g_proxies = proxy;
 			}
@@ -573,16 +630,16 @@
 				op_usbproxy_back_close(proxy);
 
-				if (proxy->prev)
-				{
-					proxy->prev->next = proxy->next;
+				if (proxy->pPrev)
+				{
+					proxy->pPrev->pNext = proxy->pNext;
 				}
 				else
 				{
-					g_proxies = proxy->next;
+					g_proxies = proxy->pNext;
 				}
 
-				if (proxy->next)
-				{
-					proxy->next->prev = proxy->prev;
+				if (proxy->pNext)
+				{
+					proxy->pNext->pPrev = proxy->pPrev;
 				}
 
@@ -760,11 +817,11 @@
 			if (rc)
 			{
-				if (proxy->urbs)
-				{
-					proxy->urbs->prev = pUrb;
+				if (proxy->pUrbs)
+				{
+					proxy->pUrbs->pPrev = pUrb;
 				}
 
-				pUrb->next = proxy->urbs;
-				proxy->urbs = pUrb;
+				pUrb->pNext = proxy->pUrbs;
+				proxy->pUrbs = pUrb;
 			}
 			else
@@ -818,9 +875,9 @@
 	        	in_uint32_le(s, handle);
 
-			pUrb = proxy->urbs;
+			pUrb = proxy->pUrbs;
 
 			while (pUrb && pUrb->handle != handle)
 			{
-				pUrb = pUrb->next;
+				pUrb = pUrb->pNext;
 			}
 
@@ -832,19 +889,19 @@
 
 				/* Remove URB from list. */
-				if (pUrb->prev)
-				{
-					pUrb->prev->next = pUrb->next;
+				if (pUrb->pPrev)
+				{
+					pUrb->pPrev->pNext = pUrb->pNext;
 				}
 				else
 				{
-					proxy->urbs = pUrb->next;
+					proxy->pUrbs = pUrb->pNext;
 				}
 
-				if (pUrb->next)
-				{
-					pUrb->next->prev = pUrb->prev;
+				if (pUrb->pNext)
+				{
+					pUrb->pNext->pPrev = pUrb->pPrev;
 				}
 
-				pUrb->next = pUrb->prev = NULL;
+				pUrb->pNext = pUrb->pPrev = NULL;
 
 				Log(("Cancelled URB %p\n", pUrb));
@@ -896,5 +953,5 @@
 rdpusb_add_fds(int *n, fd_set * rfds, fd_set * wfds)
 {
-	struct usb_proxy *proxy = g_proxies;
+	PUSBPROXYDEV proxy = g_proxies;
 
 //	Log(("RDPUSB: rdpusb_add_fds: begin *n = %d\n", *n));
@@ -902,5 +959,5 @@
 	while (proxy)
 	{
-		int fd = dev2fd(proxy);
+		int fd = USBProxyDeviceLinuxGetFD(proxy);
 
 		if (fd != -1)
@@ -913,5 +970,5 @@
 		}
 
-		proxy = proxy->next;
+		proxy = proxy->pNext;
 	}
 
@@ -924,10 +981,26 @@
 rdpusb_check_fds(fd_set * rfds, fd_set * wfds)
 {
-	(void)rfds;
-	(void)wfds;
+	PUSBPROXYDEV proxy = g_proxies;
+	unsigned found = 0;
+
+	while (proxy)
+	{
+		int fd = USBProxyDeviceLinuxGetFD(proxy);
+
+		if (fd != -1)
+		{
+			if (FD_ISSET(fd, rfds))
+                found = 1;
+			if (FD_ISSET(fd, wfds))
+                found = 1;
+		}
+
+		proxy = proxy->pNext;
+	}
 
 //	Log(("RDPUSB: rdpusb_check_fds: begin\n"));
 
-	rdpusb_reap_urbs ();
+	if (found)
+        rdpusb_reap_urbs ();
 
 //	Log(("RDPUSB: rdpusb_check_fds: end\n"));
@@ -948,9 +1021,9 @@
 rdpusb_close (void)
 {
-	struct usb_proxy *proxy = g_proxies;
+	PUSBPROXYDEV proxy = g_proxies;
 
 	while (proxy)
 	{
-		struct usb_proxy *next = proxy->next;
+		PUSBPROXYDEV pNext = proxy->pNext;
 
 		Log(("RDPUSB: closing proxy %p\n", proxy));
@@ -959,5 +1032,5 @@
 		xfree (proxy);
 
-		proxy = next;
+		proxy = pNext;
 	}
 
Index: /trunk/src/VBox/RDP/client/vrdp/runtime.h
===================================================================
--- /trunk/src/VBox/RDP/client/vrdp/runtime.h	(revision 31247)
+++ /trunk/src/VBox/RDP/client/vrdp/runtime.h	(revision 31247)
@@ -0,0 +1,280 @@
+/** @file
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __RUNTIME__H
+#define __RUNTIME__H
+
+#include <endian.h>
+#include <byteswap.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifndef cpu_to_le16
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define cpu_to_le16(_le16) (_le16)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le16(_le16) bswap_16(_le16)
+#else
+#error Unsupported host byte order!
+#endif
+#endif /* cpu_to_le16 */
+
+//#include <asm/byteorder.h>
+//#define cpu_to_le16 __cpu_to_le16
+
+#if 0
+#define uint8_t uint8
+#define uint16_t uint16
+#define uint32_t uint32
+#define uint64_t long long
+#endif
+#define bool int
+#define false 0
+#define true 1
+
+#define OPSTATIC
+#define RDPUSB_DEBUG
+#ifdef RDPUSB_DEBUG
+#define DoLog(a) do { \
+        printf("Time %llu: ", RTTimeMilliTS()); \
+        printf a; \
+} while(0)
+
+#define LogFlow(a) DoLog(a)
+#define Log(a) DoLog(a)
+#define Log2(a) DoLog(a)
+#else
+#define LogFlow(a) do {} while (0)
+#define Log(a)     do {} while (0)
+#define Log2(a)    do {} while (0)
+#endif
+
+#define LogRel(a) printf a
+
+/* Runtime wrappers. */
+#define RTMemAlloc xmalloc
+#define RTMemRealloc xrealloc
+#define RTMemFree xfree
+
+#define _1K 1024
+
+#ifdef RT_BIG_ENDIAN
+# define RT_H2LE_U16(u16)   RT_BSWAP_U16(u16)
+# define RT_LE2H_U16(u16)   RT_BSWAP_U16(u16)
+#else
+# define RT_H2LE_U16(u16)   (u16)
+# define RT_LE2H_U16(u16)   (u16)
+#endif
+#define RT_BSWAP_U16(u16) RT_MAKE_U16(RT_HIBYTE(u16), RT_LOBYTE(u16))
+#define RT_MAKE_U16(Lo, Hi) \
+    ((uint16_t)(  (uint16_t)((uint8_t)(Hi)) << 8 \
+                | (uint8_t)(Lo) ))
+#define RT_LOBYTE(a)                            ( (a) & 0xff )
+#define RT_HIBYTE(a)                            ( (a) >> 8 )
+
+#define VINF_SUCCESS 0
+#define VERR_NO_MEMORY        (-8)
+#define VERR_UNRESOLVED_ERROR (-35)
+#define VERR_NOT_SUPPORTED    (-37)
+#define VERR_ACCESS_DENIED    (-38)
+#define VERR_VUSB_USBFS_PERMISSION (-2005)
+
+static inline int RTErrConvertFromErrno(int iErrno)
+{
+    return   iErrno == 0 ? VINF_SUCCESS
+           : iErrno == ENOMEM ? VERR_NO_MEMORY
+           : iErrno == ENODEV ? VERR_NOT_SUPPORTED
+           : iErrno == ENOSYS ? VERR_NOT_SUPPORTED
+           : iErrno == EPERM ? VERR_ACCESS_DENIED
+           : iErrno == EACCES ? VERR_ACCESS_DENIED
+           : VERR_UNRESOLVED_ERROR;
+}
+
+#define RT_SUCCESS(_rc) ((_rc) >= 0)
+
+#define RTFILE int
+#define RTCRITSECT void *
+
+#define Assert(_expr) do {                            \
+    if (!(_expr))                                     \
+    {                                                 \
+        Log(("Assertion failed: {%s}!!!\n", #_expr)); \
+    }                                                 \
+} while (0)
+
+#define AssertMsgFailed(_msg) do {                    \
+        Log(("Assertion failed msg:!!!\n"));          \
+	Log(_msg);                                    \
+} while (0)
+
+#define AssertReturn(_expr, _retval) do {             \
+    if (!(_expr))                                     \
+    {                                                 \
+        Log(("Assertion failed: {%s}, returning 0x%08X!!!\n", #_expr, _retval)); \
+	return (_retval);                             \
+    }                                                 \
+} while (0)
+
+#define AssertRC(_rc) Assert(RT_SUCCESS(_rc))
+
+#define RT_FAILURE(_rc) (!RT_SUCCESS(_rc))
+
+#define NOREF(_a) ((void)_a)
+
+#define RT_C_DECLS_BEGIN
+#define RT_C_DECLS_END
+
+#define RTCALL
+#define DECLR3CALLBACKMEMBER(type, name, args)  type (RTCALL * name) args
+#define DECLINLINE(type) static __inline__ type
+#define DECLCALLBACK(type)      type RTCALL
+#define DECLCALLBACKMEMBER(type, name)  type (RTCALL * name)
+#define RTDECL(type)       RTCALL type
+
+#define RT_BIT(bit)                             ( 1U << (bit) )
+#define RT_MAX(Value1, Value2)                  ( (Value1) >= (Value2) ? (Value1) : (Value2) )
+#define RT_MIN(Value1, Value2)                  ( (Value1) <= (Value2) ? (Value1) : (Value2) )
+typedef uint32_t            RTGCPHYS32;
+typedef uint32_t            RTMSINTERVAL;
+
+static inline uint64_t RTTimeMilliTS (void)
+{
+     struct timeval tv;
+     gettimeofday (&tv, NULL);
+     return (uint64_t)tv.tv_sec * (uint64_t)(1000)
+            + (uint64_t)(tv.tv_usec / 1000);
+}
+
+static inline int RTCritSectInit (RTCRITSECT *pCritSect)
+{
+    return VINF_SUCCESS;
+}
+
+static inline int RTCritSectDelete (RTCRITSECT *pCritSect)
+{
+    return VINF_SUCCESS;
+}
+
+static inline int RTCritSectEnter (RTCRITSECT *pCritSect)
+{
+    return VINF_SUCCESS;
+}
+
+static inline int RTCritSectLeave (RTCRITSECT *pCritSect)
+{
+    return VINF_SUCCESS;
+}
+
+static inline void *RTMemDupEx (const void *pvSrc, size_t cbSrc, size_t cbExtra)
+{
+    void *p = RTMemAlloc (cbSrc + cbExtra);
+
+    if (p)
+    {
+         memcpy (p, pvSrc, cbSrc);
+         memset ((char *)p + cbSrc, 0, cbExtra);
+    }
+
+    return p;
+}
+
+static inline void *RTMemAllocZ (size_t cb)
+{
+    void *p = RTMemAlloc (cb);
+
+    if (p)
+    {
+         memset (p, 0, cb);
+    }
+
+    return p;
+}
+
+static inline void *RTMemAllocZVar (size_t cbUnaligned)
+{
+    return RTMemAllocZ(cbUnaligned);
+}
+
+static inline int RTStrToUInt32Ex (const char *pszValue, char **ppszNext, unsigned uBase, uint32_t *pu32)
+{
+    *pu32 = strtoul (pszValue, ppszNext, uBase);
+    return VINF_SUCCESS;
+}
+
+#define PRTSTREAM FILE *
+
+static inline int RTStrmOpen (const char *pszFileName, const char *pszMode, PRTSTREAM *ppStream)
+{
+    *ppStream = fopen (pszFileName, pszMode);
+
+    if (*ppStream)
+    {
+        return VINF_SUCCESS;
+    }
+
+    return VERR_NOT_SUPPORTED;
+}
+
+static inline int RTStrmClose (PRTSTREAM pStream)
+{
+    fclose (pStream);
+    return VINF_SUCCESS;
+}
+
+static inline int RTStrmGetLine (PRTSTREAM pStream, char *pszString, size_t cchString)
+{
+    if (fgets (pszString, cchString, pStream))
+    {
+        return VINF_SUCCESS;
+    }
+
+    return VERR_NOT_SUPPORTED;
+}
+
+static inline char *RTStrStripL (const char *psz)
+{
+    while (isspace (*psz))
+        psz++;
+    return (char *)psz;
+}
+
+#define NIL_RTFILE -1
+
+#define RTFILE_O_READWRITE 0x00000003
+#define RTFILE_O_OPEN      0x00000000
+#define RTFILE_O_DENY_NONE 0x00000000
+
+static inline int RTFileOpen (RTFILE *pFile, const char *pszFileName, unsigned fOpen)
+{
+    Assert (fOpen == RTFILE_O_READWRITE);
+
+    *pFile = open (pszFileName, O_RDWR, 00600);
+
+    if (*pFile != -1)
+    {
+        return VINF_SUCCESS;
+    }
+
+    return VERR_ACCESS_DENIED;
+}
+
+static inline int RTFileClose (RTFILE file)
+{
+    close (file);
+    return VINF_SUCCESS;
+}
+#endif /* __RUNTIME__H  */
Index: /trunk/src/VBox/RDP/client/vrdp/vrdpusb.h
===================================================================
--- /trunk/src/VBox/RDP/client/vrdp/vrdpusb.h	(revision 31246)
+++ /trunk/src/VBox/RDP/client/vrdp/vrdpusb.h	(revision 31247)
@@ -18,209 +18,4 @@
 #define __VRDPUSB__H
 
-#include <endian.h>
-#include <byteswap.h>
-
-#ifndef cpu_to_le16
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define cpu_to_le16(_le16) (_le16)
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define cpu_to_le16(_le16) bswap_16(_le16)
-#else
-#error Unsupported host byte order!
-#endif
-#endif /* cpu_to_le16 */
-
-//#include <asm/byteorder.h>
-//#define cpu_to_le16 __cpu_to_le16
-
-#define uint8_t uint8
-#define uint16_t uint16
-#define uint32_t uint32
-#define uint64_t long long
-#define bool int
-#define false 0
-#define true 1
-
-#define OPSTATIC
-#ifdef RDPUSB_DEBUG
-#define LogFlow(a) printf a
-#define Log(a) printf a
-#define Log2(a) printf a
-#else
-#define LogFlow(a) do {} while (0)
-#define Log(a)     do {} while (0)
-#define Log2(a)    do {} while (0)
-#endif
-
-#define LogRel(a) printf a
-
-/* Runtime wrappers. */
-#define RTMemAlloc xmalloc
-#define RTMemRealloc xrealloc
-#define RTMemFree xfree
-
-#define _1K 1024
-
-#define RT_LE2H_U16(_le16) (cpu_to_le16 (_le16))
-
-#define VINF_SUCCESS 0
-#define VERR_NO_MEMORY     (-8)
-#define VERR_NOT_SUPPORTED (-37)
-#define VERR_ACCESS_DENIED (-38)
-#define VERR_VUSB_USBFS_PERMISSION (-2005)
-
-#define RT_SUCCESS(_rc) ((_rc) >= 0)
-
-#define RTFILE int
-#define RTCRITSECT void *
-
-#define Assert(_expr) do {                            \
-    if (!(_expr))                                     \
-    {                                                 \
-        Log(("Assertion failed: {%s}!!!\n", #_expr)); \
-    }                                                 \
-} while (0)
-
-#define AssertMsgFailed(_msg) do {                    \
-        Log(("Assertion failed msg:!!!\n"));          \
-	Log(_msg);                                    \
-} while (0)
-
-#define AssertReturn(_expr, _retval) do {             \
-    if (!(_expr))                                     \
-    {                                                 \
-        Log(("Assertion failed: {%s}, returning 0x%08X!!!\n", #_expr, _retval)); \
-	return (_retval);                             \
-    }                                                 \
-} while (0)
-
-#define AssertRC(_rc) Assert(RT_SUCCESS(_rc))
-
-#define RT_FAILURE(_rc) (!RT_SUCCESS(_rc))
-
-#define NOREF(_a) ((void)_a)
-
-static inline int RTCritSectInit (RTCRITSECT *pCritSect)
-{
-    return VINF_SUCCESS;
-}
-
-static inline int RTCritSectDelete (RTCRITSECT *pCritSect)
-{
-    return VINF_SUCCESS;
-}
-
-static inline int RTCritSectEnter (RTCRITSECT *pCritSect)
-{
-    return VINF_SUCCESS;
-}
-
-static inline int RTCritSectLeave (RTCRITSECT *pCritSect)
-{
-    return VINF_SUCCESS;
-}
-
-static inline void *RTMemDupEx (const void *pvSrc, size_t cbSrc, size_t cbExtra)
-{
-    void *p = RTMemAlloc (cbSrc + cbExtra);
-
-    if (p)
-    {
-         memcpy (p, pvSrc, cbSrc);
-         memset ((char *)p + cbSrc, 0, cbExtra);
-    }
-
-    return p;
-}
-
-static inline void *RTMemAllocZ (size_t cb)
-{
-    void *p = RTMemAlloc (cb);
-
-    if (p)
-    {
-         memset (p, 0, cb);
-    }
-
-    return p;
-}
-
-static inline int RTStrToUInt32Ex (const char *pszValue, char **ppszNext, unsigned uBase, uint32_t *pu32)
-{
-    *pu32 = strtoul (pszValue, ppszNext, uBase);
-    return VINF_SUCCESS;
-}
-
-#define PRTSTREAM FILE *
-
-static inline int RTStrmOpen (const char *pszFileName, const char *pszMode, PRTSTREAM *ppStream)
-{
-    *ppStream = fopen (pszFileName, pszMode);
-
-    if (*ppStream)
-    {
-        return VINF_SUCCESS;
-    }
-
-    return VERR_NOT_SUPPORTED;
-}
-
-static inline int RTStrmClose (PRTSTREAM pStream)
-{
-    fclose (pStream);
-    return VINF_SUCCESS;
-}
-
-static inline int RTStrmGetLine (PRTSTREAM pStream, char *pszString, size_t cchString)
-{
-    if (fgets (pszString, cchString, pStream))
-    {
-        return VINF_SUCCESS;
-    }
-
-    return VERR_NOT_SUPPORTED;
-}
-
-static inline char *RTStrStripL (const char *psz)
-{
-    while (isspace (*psz))
-        psz++;
-    return (char *)psz;
-}
-
-#define NIL_RTFILE -1
-
-#define RTFILE_O_READWRITE 0x00000003
-#define RTFILE_O_OPEN      0x00000000
-#define RTFILE_O_DENY_NONE 0x00000000
-
-static inline int RTFileOpen (RTFILE *pFile, const char *pszFileName, unsigned fOpen)
-{
-    Assert (fOpen == RTFILE_O_READWRITE);
-
-    *pFile = open (pszFileName, O_RDWR, 00600);
-
-    if (*pFile != -1)
-    {
-        return VINF_SUCCESS;
-    }
-
-    return VERR_ACCESS_DENIED;
-}
-
-static inline int RTFileClose (RTFILE file)
-{
-    close (file);
-    return VINF_SUCCESS;
-}
-
-static inline uint64_t RTTimeMilliTS (void)
-{
-     struct timeval tv;
-     gettimeofday (&tv, NULL);
-     return (uint64_t)tv.tv_sec * (uint64_t)(1000)
-            + (uint64_t)(tv.tv_usec / 1000);
-}
-
 #define VRDP_USB_STATUS_SUCCESS         0
 #define VRDP_USB_STATUS_ACCESS_DENIED   1
@@ -233,129 +28,3 @@
 #define VRDP_USB_CAPS_FLAG_POLL     (1)
 
-#pragma pack(1)
-
-#include "vusb.h"
-
-typedef struct VUSBDEV
-{
-        char* pszName;
-	int request_detach;
-} VUSBDEV, *PVUSBDEV;
-
-typedef struct usb_proxy {
-    /* Note: the backend code assumes that the dev member is the first in the structure. */
-    VUSBDEV Dev;
-    /* 'union' because backend accesses the file handle as priv.File. */
-    union {
-        void *pv;
-	int File;
-    } Backend;
-
-    struct usb_proxy *next;
-    struct usb_proxy *prev;
-
-    uint32_t devid;
-
-    PVUSBURB urbs;
-
-    int iActiveCfg;
-    int cIgnoreSetConfigs;
-} *PUSBPROXYDEV;
-
-typedef struct vusb_setup {
-	uint8_t  bmRequestType;
-	uint8_t  bRequest;
-	uint16_t wValue;
-	uint16_t wIndex;
-	uint16_t wLength;
-} VUSBSETUP, *PVUSBSETUP;
-#pragma pack()
-
-
-static inline void vusbDevUnplugged(PVUSBDEV dev)
-{
-	dev->request_detach = 1;
-}
-
-int dev2fd (PUSBPROXYDEV pProxyDev);
-
-
-typedef struct USBPROXYBACK
-{
-    /** Name of the backend. */
-    const char *pszName;
-
-    int  (* pfnOpen)(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend);
-    void (* pfnClose)(PUSBPROXYDEV pProxyDev);
-    int  (* pfnReset)(PUSBPROXYDEV pProxyDev);
-    int  (* pfnSetConfig)(PUSBPROXYDEV pProxyDev, int iCfg);
-    int  (* pfnClaimInterface)(PUSBPROXYDEV pProxyDev, int iIf);
-    int  (* pfnReleaseInterface)(PUSBPROXYDEV pProxyDev, int iIf);
-    int  (* pfnSetInterface)(PUSBPROXYDEV pProxyDev, int iIf, int setting);
-    bool (* pfnClearHaltedEndpoint)(PUSBPROXYDEV  pDev, unsigned int iEp);
-    int  (* pfnUrbQueue)(PVUSBURB urb);
-    void (* pfnUrbCancel)(PVUSBURB pUrb);
-    PVUSBURB (* pfnUrbReap)(PUSBPROXYDEV pProxyDev, unsigned cMillies);
-    uint32_t uDummy;
-} USBPROXYBACK;
-
-typedef USBPROXYBACK *PUSBPROXYBACK;
-
-extern const USBPROXYBACK g_USBProxyDeviceHost;
-
-static inline int op_usbproxy_back_open(struct usb_proxy *p, const char *pszAddress)
-{
-     return g_USBProxyDeviceHost.pfnOpen (p, pszAddress, NULL);
-}
-
-static inline void op_usbproxy_back_close(PUSBPROXYDEV pDev)
-{
-     return g_USBProxyDeviceHost.pfnClose (pDev);
-}
-
-static inline int op_usbproxy_back_reset(PUSBPROXYDEV pDev)
-{
-    return g_USBProxyDeviceHost.pfnReset (pDev);
-}
-
-static inline int op_usbproxy_back_set_config(PUSBPROXYDEV pDev, int cfg)
-{
-    return g_USBProxyDeviceHost.pfnSetConfig (pDev, cfg);
-}
-
-static inline int op_usbproxy_back_claim_interface(PUSBPROXYDEV pDev, int ifnum)
-{
-    return g_USBProxyDeviceHost.pfnClaimInterface (pDev, ifnum);
-}
-
-static inline int op_usbproxy_back_release_interface(PUSBPROXYDEV pDev, int ifnum)
-{
-    return g_USBProxyDeviceHost.pfnReleaseInterface (pDev, ifnum);
-}
-
-static inline int op_usbproxy_back_interface_setting(PUSBPROXYDEV pDev, int ifnum, int setting)
-{
-    return g_USBProxyDeviceHost.pfnSetInterface (pDev, ifnum, setting);
-}
-
-static inline int op_usbproxy_back_queue_urb(PVUSBURB pUrb)
-{
-    return g_USBProxyDeviceHost.pfnUrbQueue(pUrb);
-}
-
-static inline PVUSBURB op_usbproxy_back_reap_urb(PUSBPROXYDEV pDev, unsigned cMillies)
-{
-    return g_USBProxyDeviceHost.pfnUrbReap (pDev, cMillies);
-}
-
-static inline bool op_usbproxy_back_clear_halted_ep(PUSBPROXYDEV pDev, unsigned EndPoint)
-{
-    return g_USBProxyDeviceHost.pfnClearHaltedEndpoint (pDev, EndPoint);
-}
-
-static inline void op_usbproxy_back_cancel_urb(PVUSBURB pUrb)
-{
-    return g_USBProxyDeviceHost.pfnUrbCancel (pUrb);
-}
-
 #endif /* __VRDPUSB__H  */
Index: /trunk/src/VBox/RDP/client/vrdp/vusb.h
===================================================================
--- /trunk/src/VBox/RDP/client/vrdp/vusb.h	(revision 31246)
+++ /trunk/src/VBox/RDP/client/vrdp/vusb.h	(revision 31247)
@@ -1,4 +1,4 @@
 /** @file
- *
+ * VUSB - VirtualBox USB. (DEV,VMM)
  */
 
@@ -13,5 +13,324 @@
  * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
  * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_vusb_h
+#define ___VBox_vusb_h
+
+#ifndef RDESKTOP
+# include <VBox/cdefs.h>
+# include <VBox/types.h>
+#else
+# include "runtime.h"
+#endif
+
+RT_C_DECLS_BEGIN
+
+/** @defgroup grp_vusb  VBox USB API
+ * @{
+ */
+
+/** @defgroup grp_vusb_std  Standard Stuff
+ * @{ */
+
+/** Frequency of USB bus (from spec). */
+#define VUSB_BUS_HZ                 12000000
+
+
+/** @name USB Descriptor types (from spec)
+ * @{ */
+#define VUSB_DT_DEVICE                  0x01
+#define VUSB_DT_CONFIG                  0x02
+#define VUSB_DT_STRING                  0x03
+#define VUSB_DT_INTERFACE               0x04
+#define VUSB_DT_ENDPOINT                0x05
+#define VUSB_DT_DEVICE_QUALIFIER        0x06
+#define VUSB_DT_OTHER_SPEED_CFG         0x07
+#define VUSB_DT_INTERFACE_POWER         0x08
+/** @} */
+
+/** @name USB Descriptor minimum sizes (from spec)
+ * @{ */
+#define VUSB_DT_DEVICE_MIN_LEN          18
+#define VUSB_DT_CONFIG_MIN_LEN          9
+#define VUSB_DT_CONFIG_STRING_MIN_LEN   2
+#define VUSB_DT_INTERFACE_MIN_LEN       9
+#define VUSB_DT_ENDPOINT_MIN_LEN        7
+/** @} */
+
+
+#pragma pack(1) /* ensure byte packing of the descriptors. */
+
+/**
+ * USB language id descriptor (from specs).
+ */
+typedef struct VUSBDESCLANGID
+{
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+} VUSBDESCLANGID;
+/** Pointer to a USB language id descriptor. */
+typedef VUSBDESCLANGID *PVUSBDESCLANGID;
+/** Pointer to a const USB language id descriptor. */
+typedef const VUSBDESCLANGID *PCVUSBDESCLANGID;
+
+
+/**
+ * USB string descriptor (from specs).
+ */
+typedef struct VUSBDESCSTRING
+{
+    uint8_t bLength;
+    uint8_t bDescriptorType;
+} VUSBDESCSTRING;
+/** Pointer to a USB string descriptor. */
+typedef VUSBDESCSTRING *PVUSBDESCSTRING;
+/** Pointer to a const USB string descriptor. */
+typedef const VUSBDESCSTRING *PCVUSBDESCSTRING;
+
+
+/**
+ * USB device descriptor (from spec)
+ */
+typedef struct VUSBDESCDEVICE
+{
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint16_t bcdUSB;
+    uint8_t  bDeviceClass;
+    uint8_t  bDeviceSubClass;
+    uint8_t  bDeviceProtocol;
+    uint8_t  bMaxPacketSize0;
+    uint16_t idVendor;
+    uint16_t idProduct;
+    uint16_t bcdDevice;
+    uint8_t  iManufacturer;
+    uint8_t  iProduct;
+    uint8_t  iSerialNumber;
+    uint8_t  bNumConfigurations;
+} VUSBDESCDEVICE;
+/** Pointer to a USB device descriptor. */
+typedef VUSBDESCDEVICE *PVUSBDESCDEVICE;
+/** Pointer to a const USB device descriptor. */
+typedef const VUSBDESCDEVICE *PCVUSBDESCDEVICE;
+
+
+/**
+ * USB configuration descriptor (from spec).
+ */
+typedef struct VUSBDESCCONFIG
+{
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint16_t wTotalLength; /**< recalculated by VUSB when involved in URB. */
+    uint8_t  bNumInterfaces;
+    uint8_t  bConfigurationValue;
+    uint8_t  iConfiguration;
+    uint8_t  bmAttributes;
+    uint8_t  MaxPower;
+} VUSBDESCCONFIG;
+/** Pointer to a USB configuration descriptor. */
+typedef VUSBDESCCONFIG *PVUSBDESCCONFIG;
+/** Pointer to a readonly USB configuration descriptor. */
+typedef const VUSBDESCCONFIG *PCVUSBDESCCONFIG;
+
+
+/**
+ * USB interface descriptor (from spec)
+ */
+typedef struct VUSBDESCINTERFACE
+{
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint8_t  bInterfaceNumber;
+    uint8_t  bAlternateSetting;
+    uint8_t  bNumEndpoints;
+    uint8_t  bInterfaceClass;
+    uint8_t  bInterfaceSubClass;
+    uint8_t  bInterfaceProtocol;
+    uint8_t  iInterface;
+} VUSBDESCINTERFACE;
+/** Pointer to an USB interface descriptor. */
+typedef VUSBDESCINTERFACE *PVUSBDESCINTERFACE;
+/** Pointer to a const USB interface descriptor. */
+typedef const VUSBDESCINTERFACE *PCVUSBDESCINTERFACE;
+
+
+/**
+ * USB endpoint descriptor (from spec)
+ */
+typedef struct VUSBDESCENDPOINT
+{
+    uint8_t  bLength;
+    uint8_t  bDescriptorType;
+    uint8_t  bEndpointAddress;
+    uint8_t  bmAttributes;
+    uint16_t wMaxPacketSize;
+    uint8_t  bInterval;
+} VUSBDESCENDPOINT;
+/** Pointer to an USB endpoint descriptor. */
+typedef VUSBDESCENDPOINT *PVUSBDESCENDPOINT;
+/** Pointer to a const USB endpoint descriptor. */
+typedef const VUSBDESCENDPOINT *PCVUSBDESCENDPOINT;
+
+#pragma pack() /* end of the byte packing. */
+
+
+/**
+ * USB configuration descriptor, the parsed variant used by VUSB.
+ */
+typedef struct VUSBDESCCONFIGEX
+{
+    /** The USB descriptor data.
+     * @remark  The wTotalLength member is recalculated before the data is passed to the guest. */
+    VUSBDESCCONFIG Core;
+    /** Pointer to additional descriptor bytes following what's covered by VUSBDESCCONFIG. */
+    void *pvMore;
+    /** Pointer to an array of the interfaces referenced in the configuration.
+     * Core.bNumInterfaces in size. */
+    const struct VUSBINTERFACE *paIfs;
+} VUSBDESCCONFIGEX;
+/** Pointer to a parsed USB configuration descriptor. */
+typedef VUSBDESCCONFIGEX *PVUSBDESCCONFIGEX;
+/** Pointer to a const parsed USB configuration descriptor. */
+typedef const VUSBDESCCONFIGEX *PCVUSBDESCCONFIGEX;
+
+
+/**
+ * For tracking the alternate interface settings of a configuration.
+ */
+typedef struct VUSBINTERFACE
+{
+    /** Pointer to an array of interfaces. */
+    const struct VUSBDESCINTERFACEEX *paSettings;
+    /** The number of entries in the array. */
+    uint32_t cSettings;
+} VUSBINTERFACE;
+/** Pointer to a VUSBINTERFACE. */
+typedef VUSBINTERFACE *PVUSBINTERFACE;
+/** Pointer to a const VUSBINTERFACE. */
+typedef const VUSBINTERFACE *PCVUSBINTERFACE;
+
+
+/**
+ * USB interface descriptor, the parsed variant used by VUSB.
+ */
+typedef struct VUSBDESCINTERFACEEX
+{
+    /** The USB descriptor data. */
+    VUSBDESCINTERFACE Core;
+    /** Pointer to additional descriptor bytes following what's covered by VUSBDESCINTERFACE. */
+    const void *pvMore;
+    /** Pointer to additional class- or vendor-specific interface descriptors. */
+    const void *pvClass;
+    /** Size of class- or vendor-specific descriptors. */
+    uint16_t cbClass;
+    /** Pointer to an array of the endpoints referenced by the interface.
+     * Core.bNumEndpoints in size. */
+    const struct VUSBDESCENDPOINTEX *paEndpoints;
+} VUSBDESCINTERFACEEX;
+/** Pointer to an prased USB interface descriptor. */
+typedef VUSBDESCINTERFACEEX *PVUSBDESCINTERFACEEX;
+/** Pointer to a const parsed USB interface descriptor. */
+typedef const VUSBDESCINTERFACEEX *PCVUSBDESCINTERFACEEX;
+
+
+/**
+ * USB endpoint descriptor, the parsed variant used by VUSB.
+ */
+typedef struct VUSBDESCENDPOINTEX
+{
+    /** The USB descriptor data.
+     * @remark The wMaxPacketSize member is converted to native endian. */
+    VUSBDESCENDPOINT Core;
+    /** Pointer to additional descriptor bytes following what's covered by VUSBDESCENDPOINT. */
+    const void *pvMore;
+    /** Pointer to additional class- or vendor-specific interface descriptors. */
+    const void *pvClass;
+    /** Size of class- or vendor-specific descriptors. */
+    uint16_t cbClass;
+} VUSBDESCENDPOINTEX;
+/** Pointer to a parsed USB endpoint descriptor. */
+typedef VUSBDESCENDPOINTEX *PVUSBDESCENDPOINTEX;
+/** Pointer to a const parsed USB endpoint descriptor. */
+typedef const VUSBDESCENDPOINTEX *PCVUSBDESCENDPOINTEX;
+
+
+/** @name USB Control message recipient codes (from spec)
+ * @{ */
+#define VUSB_TO_DEVICE          0x0
+#define VUSB_TO_INTERFACE       0x1
+#define VUSB_TO_ENDPOINT        0x2
+#define VUSB_TO_OTHER           0x3
+#define VUSB_RECIP_MASK         0x1f
+/** @} */
+
+/** @name USB control pipe setup packet structure (from spec)
+ * @{ */
+#define VUSB_REQ_SHIFT          (5)
+#define VUSB_REQ_STANDARD       (0x0 << VUSB_REQ_SHIFT)
+#define VUSB_REQ_CLASS          (0x1 << VUSB_REQ_SHIFT)
+#define VUSB_REQ_VENDOR         (0x2 << VUSB_REQ_SHIFT)
+#define VUSB_REQ_RESERVED       (0x3 << VUSB_REQ_SHIFT)
+#define VUSB_REQ_MASK           (0x3 << VUSB_REQ_SHIFT)
+/** @} */
+
+#define VUSB_DIR_TO_DEVICE      0x00
+#define VUSB_DIR_TO_HOST        0x80
+#define VUSB_DIR_MASK           0x80
+
+/**
+ * USB Setup request (from spec)
+ */
+typedef struct vusb_setup
+{
+    uint8_t  bmRequestType;
+    uint8_t  bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+} VUSBSETUP;
+/** Pointer to a setup request. */
+typedef VUSBSETUP *PVUSBSETUP;
+/** Pointer to a const setup request. */
+typedef const VUSBSETUP *PCVUSBSETUP;
+
+/** @name USB Standard device requests (from spec)
+ * @{ */
+#define VUSB_REQ_GET_STATUS         0x00
+#define VUSB_REQ_CLEAR_FEATURE      0x01
+#define VUSB_REQ_SET_FEATURE        0x03
+#define VUSB_REQ_SET_ADDRESS        0x05
+#define VUSB_REQ_GET_DESCRIPTOR     0x06
+#define VUSB_REQ_SET_DESCRIPTOR     0x07
+#define VUSB_REQ_GET_CONFIGURATION  0x08
+#define VUSB_REQ_SET_CONFIGURATION  0x09
+#define VUSB_REQ_GET_INTERFACE      0x0a
+#define VUSB_REQ_SET_INTERFACE      0x0b
+#define VUSB_REQ_SYNCH_FRAME        0x0c
+#define VUSB_REQ_MAX                0x0d
+/** @} */
+
+/** @} */ /* end of grp_vusb_std */
+
+
+
+/** @name USB Standard version flags.
+ * @{ */
+/** Indicates USB 1.1 support. */
+#define VUSB_STDVER_11              RT_BIT(1)
+/** Indicates USB 2.0 support. */
+#define VUSB_STDVER_20              RT_BIT(2)
+/** @} */
+
 
 /** Pointer to a VBox USB device interface. */
@@ -25,4 +344,450 @@
 
 
+
+/**
+ * VBox USB port bitmap.
+ *
+ * Bit 0 == Port 0, ... , Bit 127 == Port 127.
+ */
+typedef struct VUSBPORTBITMAP
+{
+    /** 128 bits */
+    char ach[16];
+} VUSBPORTBITMAP;
+/** Pointer to a VBox USB port bitmap. */
+typedef VUSBPORTBITMAP *PVUSBPORTBITMAP;
+
+#ifndef RDESKTOP
+
+/**
+ * The VUSB RootHub port interface provided by the HCI (down).
+ * Pair with VUSBIROOTCONNECTOR
+ */
+typedef struct VUSBIROOTHUBPORT
+{
+    /**
+     * Get the number of avilable ports in the hub.
+     *
+     * @returns The number of ports available.
+     * @param   pInterface      Pointer to this structure.
+     * @param   pAvailable      Bitmap indicating the available ports. Set bit == available port.
+     */
+    DECLR3CALLBACKMEMBER(unsigned, pfnGetAvailablePorts,(PVUSBIROOTHUBPORT pInterface, PVUSBPORTBITMAP pAvailable));
+
+    /**
+     * Gets the supported USB versions.
+     *
+     * @returns The mask of supported USB versions.
+     * @param   pInterface      Pointer to this structure.
+     */
+    DECLR3CALLBACKMEMBER(uint32_t, pfnGetUSBVersions,(PVUSBIROOTHUBPORT pInterface));
+
+    /**
+     * A device is being attached to a port in the roothub.
+     *
+     * @param   pInterface      Pointer to this structure.
+     * @param   pDev            Pointer to the device being attached.
+     * @param   uPort           The port number assigned to the device.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnAttach,(PVUSBIROOTHUBPORT pInterface, PVUSBIDEVICE pDev, unsigned uPort));
+
+    /**
+     * A device is being detached from a port in the roothub.
+     *
+     * @param   pInterface      Pointer to this structure.
+     * @param   pDev            Pointer to the device being detached.
+     * @param   uPort           The port number assigned to the device.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnDetach,(PVUSBIROOTHUBPORT pInterface, PVUSBIDEVICE pDev, unsigned uPort));
+
+    /**
+     * Reset the root hub.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to this structure.
+     * @param   pResetOnLinux   Whether or not to do real reset on linux.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIROOTHUBPORT pInterface, bool fResetOnLinux));
+
+    /**
+     * Transfer completion callback routine.
+     *
+     * VUSB will call this when a transfer have been completed
+     * in a one or another way.
+     *
+     * @param   pInterface      Pointer to this structure.
+     * @param   pUrb            Pointer to the URB in question.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnXferCompletion,(PVUSBIROOTHUBPORT pInterface, PVUSBURB urb));
+
+    /**
+     * Handle transfer errors.
+     *
+     * VUSB calls this when a transfer attempt failed. This function will respond
+     * indicating wheter to retry or complete the URB with failure.
+     *
+     * @returns Retry indicator.
+     * @param   pInterface      Pointer to this structure.
+     * @param   pUrb            Pointer to the URB in question.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnXferError,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb));
+
+    /** Alignment dummy. */
+    RTR3PTR Alignment;
+
+} VUSBIROOTHUBPORT;
+/** VUSBIROOTHUBPORT interface ID. */
+#define VUSBIROOTHUBPORT_IID                    "e38e2978-7aa2-4860-94b6-9ef4a066d8a0"
+
+
+/** Pointer to a VUSB RootHub connector interface. */
+typedef struct VUSBIROOTHUBCONNECTOR *PVUSBIROOTHUBCONNECTOR;
+/**
+ * The VUSB RootHub connector interface provided by the VBox USB RootHub driver
+ * (up).
+ * Pair with VUSBIROOTHUBPORT.
+ */
+typedef struct VUSBIROOTHUBCONNECTOR
+{
+    /**
+     * Allocates a new URB for a transfer.
+     *
+     * Either submit using pfnSubmitUrb or free using VUSBUrbFree().
+     *
+     * @returns Pointer to a new URB.
+     * @returns NULL on failure - try again later.
+     *          This will not fail if the device wasn't found. We'll fail it
+     *          at submit time, since that makes the usage of this api simpler.
+     * @param   pInterface  Pointer to this struct.
+     * @param   DstAddress  The destination address of the URB.
+     * @param   cbData      The amount of data space required.
+     * @param   cTds        The amount of TD space.
+     */
+    DECLR3CALLBACKMEMBER(PVUSBURB, pfnNewUrb,(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t cbData, uint32_t cTds));
+
+    /**
+     * Submits a URB for transfer.
+     * The transfer will do asynchronously if possible.
+     *
+     * @returns VBox status code.
+     * @param   pInterface  Pointer to this struct.
+     * @param   pUrb        Pointer to the URB returned by pfnNewUrb.
+     *                      The URB will be freed in case of failure.
+     * @param   pLed        Pointer to USB Status LED
+     */
+    DECLR3CALLBACKMEMBER(int, pfnSubmitUrb,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed));
+
+    /**
+     * Call to service asynchronous URB completions in a polling fashion.
+     *
+     * Reaped URBs will be finished by calling the completion callback,
+     * thus there is no return code or input or anything from this function
+     * except for potential state changes elsewhere.
+     *
+     * @returns VINF_SUCCESS if no URBs are pending upon return.
+     * @returns VERR_TIMEOUT if one or more URBs are still in flight upon returning.
+     * @returns Other VBox status code.
+     *
+     * @param   pInterface  Pointer to this struct.
+     * @param   cMillies    Number of milliseconds to poll for completion.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnReapAsyncUrbs,(PVUSBIROOTHUBCONNECTOR pInterface, RTMSINTERVAL cMillies));
+
+    /**
+     * Cancels and completes - with CRC failure - all in-flight async URBs.
+     * This is typically done before saving a state.
+     *
+     * @param   pInterface  Pointer to this struct.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnCancelAllUrbs,(PVUSBIROOTHUBCONNECTOR pInterface));
+
+    /**
+     * Attach the device to the root hub.
+     * The device must not be attached to any hub for this call to succeed.
+     *
+     * @returns VBox status code.
+     * @param   pInterface  Pointer to this struct.
+     * @param   pDevice     Pointer to the device (interface) attach.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice));
+
+    /**
+     * Detach the device from the root hub.
+     * The device must already be attached for this call to succeed.
+     *
+     * @returns VBox status code.
+     * @param   pInterface  Pointer to this struct.
+     * @param   pDevice     Pointer to the device (interface) to detach.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice));
+
+} VUSBIROOTHUBCONNECTOR;
+/** VUSBIROOTHUBCONNECTOR interface ID. */
+#define VUSBIROOTHUBCONNECTOR_IID               "d9a90c59-e3ff-4dff-9754-844557c3f7a0"
+
+
+#ifdef IN_RING3
+/** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */
+DECLINLINE(PVUSBURB) VUSBIRhNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t DstAddress, uint32_t cbData, uint32_t cTds)
+{
+    return pInterface->pfnNewUrb(pInterface, DstAddress, cbData, cTds);
+}
+
+/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSubmitUrb */
+DECLINLINE(int) VUSBIRhSubmitUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed)
+{
+    return pInterface->pfnSubmitUrb(pInterface, pUrb, pLed);
+}
+
+/** @copydoc VUSBIROOTHUBCONNECTOR::pfnReapAsyncUrbs */
+DECLINLINE(void) VUSBIRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, RTMSINTERVAL cMillies)
+{
+    pInterface->pfnReapAsyncUrbs(pInterface, cMillies);
+}
+
+/** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelAllUrbs */
+DECLINLINE(void) VUSBIRhCancelAllUrbs(PVUSBIROOTHUBCONNECTOR pInterface)
+{
+    pInterface->pfnCancelAllUrbs(pInterface);
+}
+
+/** @copydoc VUSBIROOTHUBCONNECTOR::pfnAttachDevice */
+DECLINLINE(int) VUSBIRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
+{
+    return pInterface->pfnAttachDevice(pInterface, pDevice);
+}
+
+/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDetachDevice */
+DECLINLINE(int) VUSBIRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBIDEVICE pDevice)
+{
+    return pInterface->pfnDetachDevice(pInterface, pDevice);
+}
+#endif /* IN_RING3 */
+
+
+
+/** Pointer to a Root Hub Configuration Interface. */
+typedef struct VUSBIRHCONFIG *PVUSBIRHCONFIG;
+/**
+ * Root Hub Configuration Interface (intended for MAIN).
+ * No interface pair.
+ */
+typedef struct VUSBIRHCONFIG
+{
+    /**
+     * Creates a USB proxy device and attaches it to the root hub.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the root hub configuration interface structure.
+     * @param   pUuid           Pointer to the UUID for the new device.
+     * @param   fRemote         Whether the device must use the VRDP backend.
+     * @param   pszAddress      OS specific device address.
+     * @param   pvBackend       An opaque pointer for the backend. Only used by
+     *                          the VRDP backend so far.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnCreateProxyDevice,(PVUSBIRHCONFIG pInterface, PCRTUUID pUuid, bool fRemote, const char *pszAddress, void *pvBackend));
+
+    /**
+     * Removes a USB proxy device from the root hub and destroys it.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the root hub configuration interface structure.
+     * @param   pUuid           Pointer to the UUID for the device.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnDestroyProxyDevice,(PVUSBIRHCONFIG pInterface, PCRTUUID pUuid));
+
+} VUSBIRHCONFIG;
+/** VUSBIRHCONFIG interface ID. */
+#define VUSBIRHCONFIG_IID                       "c354cd97-e85f-465e-bc12-b58798465f52"
+
+
+#ifdef IN_RING3
+/** @copydoc  VUSBIRHCONFIG::pfnCreateProxyDevice */
+DECLINLINE(int) VUSBIRhCreateProxyDevice(PVUSBIRHCONFIG pInterface, PCRTUUID pUuid, bool fRemote, const char *pszAddress, void *pvBackend)
+{
+    return pInterface->pfnCreateProxyDevice(pInterface, pUuid, fRemote, pszAddress, pvBackend);
+}
+
+/** @copydoc VUSBIRHCONFIG::pfnDestroyProxyDevice */
+DECLINLINE(int) VUSBIRhDestroyProxyDevice(PVUSBIRHCONFIG pInterface, PCRTUUID pUuid)
+{
+    return pInterface->pfnDestroyProxyDevice(pInterface, pUuid);
+}
+#endif /* IN_RING3 */
+
+#endif /* ! RDESKTOP */
+
+
+/**
+ * VUSB device reset completion callback function.
+ * This is called by the reset thread when the reset has been completed.
+ *
+ * @param   pDev        Pointer to the virtual USB device core.
+ * @param   rc      The VBox status code of the reset operation.
+ * @param   pvUser      User specific argument.
+ *
+ * @thread  The reset thread or EMT.
+ */
+typedef DECLCALLBACK(void) FNVUSBRESETDONE(PVUSBIDEVICE pDevice, int rc, void *pvUser);
+/** Pointer to a device reset completion callback function (FNUSBRESETDONE). */
+typedef FNVUSBRESETDONE *PFNVUSBRESETDONE;
+
+/**
+ * The state of a VUSB Device.
+ *
+ * @remark  The order of these states is vital.
+ */
+typedef enum VUSBDEVICESTATE
+{
+    VUSB_DEVICE_STATE_INVALID = 0,
+    VUSB_DEVICE_STATE_DETACHED,
+    VUSB_DEVICE_STATE_ATTACHED,
+    VUSB_DEVICE_STATE_POWERED,
+    VUSB_DEVICE_STATE_DEFAULT,
+    VUSB_DEVICE_STATE_ADDRESS,
+    VUSB_DEVICE_STATE_CONFIGURED,
+    VUSB_DEVICE_STATE_SUSPENDED,
+    /** The device is being reset. Don't mess with it.
+     * Next states: VUSB_DEVICE_STATE_DEFAULT, VUSB_DEVICE_STATE_DESTROYED
+     */
+    VUSB_DEVICE_STATE_RESET,
+    /** The device has been destroy. */
+    VUSB_DEVICE_STATE_DESTROYED,
+    /** The usual 32-bit hack. */
+    VUSB_DEVICE_STATE_32BIT_HACK = 0x7fffffff
+} VUSBDEVICESTATE;
+
+#ifndef RDESKTOP
+
+/**
+ * USB Device Interface (up).
+ * No interface pair.
+ */
+typedef struct VUSBIDEVICE
+{
+    /**
+     * Resets the device.
+     *
+     * Since a device reset shall take at least 10ms from the guest point of view,
+     * it must be performed asynchronously. We create a thread which performs this
+     * operation and ensures it will take at least 10ms.
+     *
+     * At times - like init - a synchronous reset is required, this can be done
+     * by passing NULL for pfnDone.
+     *
+     * -- internal stuff, move it --
+     * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
+     * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
+     * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
+     * -- internal stuff, move it --
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to this structure.
+     * @param   fResetOnLinux   Set if we can permit a real reset and a potential logical
+     *                          device reconnect on linux hosts.
+     * @param   pfnDone         Pointer to the completion routine. If NULL a synchronous
+     *                          reset  is preformed not respecting the 10ms.
+     * @param   pvUser          User argument to the completion routine.
+     * @param   pVM             Pointer to the VM handle if callback in EMT is required. (optional)
+     */
+    DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIDEVICE pInterface, bool fResetOnLinux,
+                                        PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM));
+
+    /**
+     * Powers on the device.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the device interface structure.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPowerOn,(PVUSBIDEVICE pInterface));
+
+    /**
+     * Powers off the device.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the device interface structure.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPowerOff,(PVUSBIDEVICE pInterface));
+
+    /**
+     * Get the state of the device.
+     *
+     * @returns Device state.
+     * @param   pInterface      Pointer to the device interface structure.
+     */
+    DECLR3CALLBACKMEMBER(VUSBDEVICESTATE, pfnGetState,(PVUSBIDEVICE pInterface));
+
+} VUSBIDEVICE;
+/** VUSBIDEVICE interface ID. */
+#define VUSBIDEVICE_IID                         "88732dd3-0ccd-4625-b040-48804ac7a217"
+
+
+#ifdef IN_RING3
+/**
+ * Resets the device.
+ *
+ * Since a device reset shall take at least 10ms from the guest point of view,
+ * it must be performed asynchronously. We create a thread which performs this
+ * operation and ensures it will take at least 10ms.
+ *
+ * At times - like init - a synchronous reset is required, this can be done
+ * by passing NULL for pfnDone.
+ *
+ * -- internal stuff, move it --
+ * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state.
+ * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful,
+ * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed.
+ * -- internal stuff, move it --
+ *
+ * @returns VBox status code.
+ * @param   pInterface      Pointer to the device interface structure.
+ * @param   fResetOnLinux   Set if we can permit a real reset and a potential logical
+ *                          device reconnect on linux hosts.
+ * @param   pfnDone         Pointer to the completion routine. If NULL a synchronous
+ *                          reset  is preformed not respecting the 10ms.
+ * @param   pvUser          User argument to the completion routine.
+ * @param   pVM             Pointer to the VM handle if callback in EMT is required. (optional)
+ */
+DECLINLINE(int) VUSBIDevReset(PVUSBIDEVICE pInterface, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)
+{
+    return pInterface->pfnReset(pInterface, fResetOnLinux, pfnDone, pvUser, pVM);
+}
+
+/**
+ * Powers on the device.
+ *
+ * @returns VBox status code.
+ * @param   pInterface      Pointer to the device interface structure.
+ */
+DECLINLINE(int) VUSBIDevPowerOn(PVUSBIDEVICE pInterface)
+{
+    return pInterface->pfnPowerOn(pInterface);
+}
+
+/**
+ * Powers off the device.
+ *
+ * @returns VBox status code.
+ * @param   pInterface      Pointer to the device interface structure.
+ */
+DECLINLINE(int) VUSBIDevPowerOff(PVUSBIDEVICE pInterface)
+{
+    return pInterface->pfnPowerOff(pInterface);
+}
+
+/**
+ * Get the state of the device.
+ *
+ * @returns Device state.
+ * @param   pInterface      Pointer to the device interface structure.
+ */
+DECLINLINE(VUSBDEVICESTATE) VUSBIDevGetState(PVUSBIDEVICE pInterface)
+{
+    return pInterface->pfnGetState(pInterface);
+}
+#endif /* IN_RING3 */
+
+#endif /* ! RDESKTOP */
+
 /** @name URB
  * @{ */
@@ -35,16 +800,16 @@
     /** Transer was ok. */
     VUSBSTATUS_OK = 0,
-#define VUSB_XFER_OK    VUSBSTATUS_OK
     /** Transfer stalled, endpoint halted. */
     VUSBSTATUS_STALL,
-#define VUSB_XFER_STALL VUSBSTATUS_STALL
     /** Device not responding. */
     VUSBSTATUS_DNR,
-#define VUSB_XFER_DNR   VUSBSTATUS_DNR
     /** CRC error. */
     VUSBSTATUS_CRC,
-#define VUSB_XFER_CRC	VUSBSTATUS_CRC
-    /** Underflow error. */
-    VUSBSTATUS_UNDERFLOW,
+    /** Data overrun error. */
+    VUSBSTATUS_DATA_UNDERRUN,
+    /** Data overrun error. */
+    VUSBSTATUS_DATA_OVERRUN,
+    /** The isochronous buffer hasn't been touched. */
+    VUSBSTATUS_NOT_ACCESSED,
     /** Invalid status. */
     VUSBSTATUS_INVALID = 0x7f
@@ -59,17 +824,12 @@
     /** Control message. Used to represent a single control transfer. */
     VUSBXFERTYPE_CTRL = 0,
-#define VUSB_TRANSFER_TYPE_CTRL	VUSBXFERTYPE_CTRL
     /* Isochronous transfer. */
     VUSBXFERTYPE_ISOC,
-#define VUSB_TRANSFER_TYPE_ISOC	VUSBXFERTYPE_ISOC
     /** Bulk transfer. */
     VUSBXFERTYPE_BULK,
-#define VUSB_TRANSFER_TYPE_BULK	VUSBXFERTYPE_BULK
     /** Interrupt transfer. */
     VUSBXFERTYPE_INTR,
-#define VUSB_TRANSFER_TYPE_INTR	VUSBXFERTYPE_INTR
     /** Complete control message. Used to represent an entire control message. */
     VUSBXFERTYPE_MSG,
-#define VUSB_TRANSFER_TYPE_MSG	VUSBXFERTYPE_MSG
     /** Invalid transfer type. */
     VUSBXFERTYPE_INVALID = 0x7f
@@ -90,5 +850,5 @@
     /** Out - Host to device. */
     VUSBDIRECTION_OUT = 2,
-#define VUSB_DIRECTION_OUT	VUSBDIRECTION_OUT
+#define VUSB_DIRECTION_OUT  VUSBDIRECTION_OUT
     /** Invalid direction */
     VUSBDIRECTION_INVALID = 0x7f
@@ -125,4 +885,26 @@
 
 /**
+ * Information about a isochronous packet.
+ */
+typedef struct VUSBURBISOCPKT
+{
+    /** The size of the packet.
+     * IN: The packet size. I.e. the number of bytes to the next packet or end of buffer.
+     * OUT: The actual size transfered. */
+    uint16_t        cb;
+    /** The offset of the packet. (Relative to VUSBURB::abData[0].)
+     * OUT: This can be changed by the USB device if it does some kind of buffer squeezing. */
+    uint16_t        off;
+    /** The status of the transfer.
+     * IN: VUSBSTATUS_INVALID
+     * OUT: VUSBSTATUS_INVALID if nothing was done, otherwise the correct status. */
+    VUSBSTATUS      enmStatus;
+} VUSBURBISOCPKT;
+/** Pointer to a isochronous packet. */
+typedef VUSBURBISOCPKT *PVUSBURBISOCPTK;
+/** Pointer to a const isochronous packet. */
+typedef const VUSBURBISOCPKT *PCVUSBURBISOCPKT;
+
+/**
  * Asynchronous USB request descriptor
  */
@@ -133,9 +915,17 @@
     /** The USR state. */
     VUSBURBSTATE    enmState;
-
-    /* Private fields not accessed by the backend. */
-    PVUSBURB        next;
-    PVUSBURB        prev;
+    /** URB description, can be null. intended for logging. */
+    char           *pszDesc;
+
+#ifdef RDESKTOP
+    /** The next URB in rdesktop-vrdp's linked list */
+    PVUSBURB        pNext;
+    /** The previous URB in rdesktop-vrdp's linked list */
+    PVUSBURB        pPrev;
+    /** The vrdp handle for the URB */
     uint32_t        handle;
+    /** Pointer used to find the usb proxy device */
+    struct VUSBDEV *pDev;
+#endif
 
     /** The VUSB data. */
@@ -148,6 +938,14 @@
         /** Pointer to the original for control messages. */
         PVUSBURB        pCtrlUrb;
+        /** Pointer to the VUSB device.
+         * This may be NULL if the destination address is invalid. */
+        struct VUSBDEV *pDev;
         /** Sepcific to the pfnFree function. */
         void           *pvFreeCtx;
+        /**
+         * Callback which will free the URB once it's reaped and completed.
+         * @param   pUrb    The URB.
+         */
+        DECLCALLBACKMEMBER(void, pfnFree)(PVUSBURB pUrb);
         /** Submit timestamp. (logging only) */
         uint64_t        u64SubmitTS;
@@ -162,5 +960,5 @@
     {
         /** The endpoint descriptor address. */
-        uint32_t        EdAddr;
+        RTGCPHYS32      EdAddr;
         /** Number of Tds in the array. */
         uint32_t        cTds;
@@ -168,12 +966,15 @@
         struct VUSBURBHCITD
         {
+            /** Type of TD (private) */
+            uint32_t        TdType;
             /** The address of the */
-            uint32_t        TdAddr;
+            RTGCPHYS32      TdAddr;
             /** A copy of the TD. */
-            uint32_t        TdCopy[4];
+            uint32_t        TdCopy[16];
         }              *paTds;
         /** URB chain pointer. */
         PVUSBURB        pNext;
-        /** When this URB was created. (logging only) */
+        /** When this URB was created.
+         * (Used for isochronous frames and for logging.) */
         uint32_t        u32FrameNo;
         /** Flag indicating that the TDs have been unlinked. */
@@ -190,7 +991,9 @@
     } Dev;
 
-    /** The device - can be NULL untill submit is attempted.
-     * This is set when allocating the URB. */
-    struct VUSBDEV *pDev;
+#ifndef RDESKTOP
+    /** The USB device instance this belongs to.
+     * This is NULL if the device address is invalid, in which case this belongs to the hub. */
+    PPDMUSBINS      pUsbIns;
+#endif
     /** The device address.
      * This is set at allocation time. */
@@ -198,5 +1001,6 @@
 
     /** The endpoint.
-     * IN: Must be set before submitting the URB. */
+     * IN: Must be set before submitting the URB.
+     * @remark This does not have the high bit (direction) set! */
     uint8_t         EndPt;
     /** The transfer type.
@@ -212,4 +1016,12 @@
      * OUT: This is set when reaping the URB. */
     VUSBSTATUS      enmStatus;
+
+    /** The number of isochronous packets describe in aIsocPkts.
+     * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */
+    uint32_t        cIsocPkts;
+    /** The iso packets within abData.
+     * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */
+    VUSBURBISOCPKT  aIsocPkts[8];
+
     /** The message length.
      * IN: The amount of data to send / receive - set at allocation time.
@@ -223,5 +1035,12 @@
 
 /** The magic value of a valid VUSBURB. (Murakami Haruki) */
-#define VUSBURB_MAGIC   0x19490112
+#define VUSBURB_MAGIC       UINT32_C(0x19490112)
 
 /** @} */
+
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif
