VirtualBox

Changeset 31557 in vbox


Ignore:
Timestamp:
Aug 11, 2010 9:15:04 AM (15 years ago)
Author:
vboxsync
Message:

Devices/USB and RDP/client: share USB code

Location:
trunk/src/VBox
Files:
4 added
2 deleted
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Makefile.kmk

    r31551 r31557  
    11661166
    11671167#
    1168 # USBProxyDevice-linux.cpp and USBProxyDevice-linux.c should be kept in sync.
    1169 #
    1170 # Hence this bit of ugliness that checks that they are identical, apart from
    1171 # the first line of the files (svn keywords).
    1172 # If you are updating the code, build with VBOX_WITH_TESTCASES= as long as you
    1173 # haven't synced.
    1174 #
    1175 ifeq (0,1)
    1176 if defined(VBOX_WITH_USB) && defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_SDK)
    1177  TESTING += $(PATH_Drivers)/tstSameUSBProxyDevLinux.run
    1178  OTHERS  += $(PATH_Drivers)/tstSameUSBProxyDevLinux.run
    1179  VBOX_PRX_DEV_LNX = $(PATH_ROOT)/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp
    1180  VRDP_PRX_DEV_LNX = $(PATH_ROOT)/src/VBox/RDP/client/vrdp/USBProxyDevice-linux.c
    1181 $$(PATH_Drivers)/tstSameUSBProxyDevLinux.run: $(VBOX_PRX_DEV_LNX) $(VRDP_PRX_DEV_LNX) | $$(PATH_Drivers)/
    1182         $(QUIET)$(call MSG_L1,Source correctness - ensuring that files are identical: $^)
    1183         $(QUIET)$(CMP) $^ \
    1184                 $(foreach i,$^,$(length $(shell $(SED) -n '1,\?/\* START \*/?p' $(i))))
    1185         $(QUIET)$(APPEND) -t "$@" "done"
    1186 endif # USB + TESTCASES + !SDK
    1187 endif
    1188 
    1189 
    1190 #
    11911168# Internal Networking - Ring-3 Testcase for the Ring-0 code (a bit hackish).
    11921169#
  • trunk/src/VBox/RDP/client/Makefile.kmk

    r28800 r31557  
    2121# Globals
    2222VBOX_PATH_RDESKTOP_SRC := $(PATH_SUB_CURRENT)
     23VBOX_PATH_DEVICES_USB  := $(PATH_ROOT)/src/VBox/Devices/USB
    2324VBOX_RDESKTOP_SRC_SUBDIR = rdesktop-1.6.0-vrdp
    2425
     
    9293        vrdp/rdpusb.c \
    9394        vrdp/USBProxyDevice-linux.c
     95rdesktop-vrdp_INCS += \
     96    $(VBOX_PATH_RDESKTOP_SRC) \
     97    $(VBOX_PATH_RDESKTOP_SRC)/vrdp \
     98    $(VBOX_PATH_DEVICES_USB) \
     99    $(PATH_ROOT)/include/VBox
    94100# @todo implement usb proxy for Solaris
    95101rdesktop-vrdp_SOURCES.solaris = \
     
    120126## @todo change this to an INSTALLS target.
    121127OTHERS += $(PATH_BIN)/rdesktop-vrdp.tar.gz
    122 OTHER_CLEAN += $(OTHERS) $(PATH_TARGET)/$(VBOX_RDESKTOP_SRC_SUBDIR)
     128OTHER_CLEAN += $(OTHERS)
    123129
    124130
    125131include $(KBUILD_PATH)/subfooter.kmk
    126132
    127 rdesktop-vrdp_TARSOURCES = \
    128         COPYING \
    129         README \
    130         configure \
    131         configure.ac \
    132         config.sub \
    133         config.guess \
    134         bootstrap \
    135         install-sh \
    136         Makefile.in \
    137         proto.head \
    138         proto.tail \
    139         rdesktop.spec \
    140         *.c \
    141         *.h \
    142         keymaps/?? \
    143         keymaps/??-?? \
    144         keymaps/common \
    145         keymaps/modifiers \
    146         keymaps/convert-map \
    147         doc/HACKING \
    148         doc/AUTHORS \
    149         doc/TODO \
    150         doc/ChangeLog \
    151         doc/keymapping.txt \
    152         doc/keymap-names.txt \
    153         doc/ipv6.txt \
    154         doc/licensing.txt \
    155         doc/patches.txt \
    156         doc/redirection.txt \
    157         doc/rdesktop.1 \
    158         vrdp/*.c \
    159         vrdp/*.h
     133INSTALLS += rdesktop-bin
     134rdesktop-bin_INST    = obj/$(VBOX_RDESKTOP_SRC_SUBDIR)
     135rdesktop-bin_MODE    = a+rx,u+w
     136rdesktop-bin_SOURCES = \
     137    $(foreach i,configure \
     138                config.sub \
     139                config.guess \
     140                bootstrap \
     141                install-sh, \
     142            client/$i=>$i)
    160143
    161 $(PATH_TARGET)/$(VBOX_RDESKTOP_SRC_SUBDIR):
    162         $(MKDIR) -p $(@D)
    163         $(LN_SYMLINK) $(abspath $(VBOX_PATH_RDESKTOP_SRC)) $@
     144INSTALLS += rdesktop-nonbin
     145rdesktop-nonbin_INST    = obj/$(VBOX_RDESKTOP_SRC_SUBDIR)
     146rdesktop-nonbin_MODE    = a+r,u+w
     147rdesktop-nonbin_SOURCES = \
     148    $(foreach i,COPYING \
     149                README \
     150                configure.ac \
     151                Makefile.in \
     152                proto.head \
     153                proto.tail \
     154                rdesktop.spec \
     155                keymaps/common \
     156                keymaps/modifiers \
     157                keymaps/convert-map \
     158                doc/HACKING \
     159                doc/AUTHORS \
     160                doc/TODO \
     161                doc/ChangeLog \
     162                doc/keymapping.txt \
     163                doc/keymap-names.txt \
     164                doc/ipv6.txt \
     165                doc/licensing.txt \
     166                doc/patches.txt \
     167                doc/redirection.txt \
     168                doc/rdesktop.1 \
     169                vrdp/rdpusb.c \
     170                vrdp/runtime.h \
     171                vrdp/vrdpusb.h, \
     172            client/$i=>$i) \
     173    $(PATH_ROOT)/include/VBox/vusb.h=>vrdp/vusb.h \
     174    $(VBOX_PATH_DEVICES_USB)/linux/USBProxyDevice-linux.cpp=>vrdp/USBProxyDevice-linux.c \
     175    $(VBOX_PATH_DEVICES_USB)/USBProxyDevice.h=>vrdp/USBProxyDevice.h \
     176    $(foreach i,*.c *.h keymaps/?? keymaps/??-??, \
     177        $(foreach j,$(wildcard $(VBOX_PATH_RDESKTOP_SRC)/$i), \
     178            client/$(dir $i)$(notdir $j)=>$(dir $i)$(notdir $j)))
    164179
    165180$(PATH_BIN)/rdesktop-vrdp.tar.gz: \
    166                 $(addprefix $(PATH_ROOT)/src/VBox/RDP/client/,$(rdesktop-vrdp_TARSOURCES)) \
    167                 | $(PATH_TARGET)/$(VBOX_RDESKTOP_SRC_SUBDIR)
     181                rdesktop-bin \
     182                rdesktop-nonbin
    168183        $(call MSG_TOOL,tar/gzip,,$@)
    169         $(QUIET)cd $(PATH_TARGET) && tar -chf - $(addprefix $(VBOX_RDESKTOP_SRC_SUBDIR)/,$(rdesktop-vrdp_TARSOURCES)) | gzip - > $@
    170 
     184        $(QUIET)cd $(PATH_TARGET) && tar -cf - $(VBOX_RDESKTOP_SRC_SUBDIR) | gzip - > $@
  • trunk/src/VBox/RDP/client/vrdp/USBProxyDevice-linux.c

    r31538 r31557  
    1616 */
    1717
    18 /* START */
    19 
    20 /*******************************************************************************
    21 *   Defined Constants And Macros                                               *
    22 *******************************************************************************/
    23 /** Define NO_PORT_RESET to skip the slow and broken linux port reset.
    24  * Resetting will break PalmOne. */
    25 #define NO_PORT_RESET
    26 /** Define NO_LOGICAL_RECONNECT to skip the broken logical reconnect handling. */
    27 #define NO_LOGICAL_RECONNECT
    28 
    29 
    30 /*******************************************************************************
    31 *   Header Files                                                               *
    32 *******************************************************************************/
    33 #define LOG_GROUP LOG_GROUP_DRV_USBPROXY
    34 #ifndef RDESKTOP
    35 # include <iprt/stdint.h>
    36 #endif
    37 #include <sys/types.h>
    38 #include <sys/stat.h>
    39 #include <sys/vfs.h>
    40 #include <sys/ioctl.h>
    41 #include <sys/poll.h>
    42 #include <stdint.h>
    43 #include <stdio.h>
    44 #include <string.h>
    45 #include <stdlib.h>
    46 #include <limits.h>
    47 #include <unistd.h>
    48 #include <fcntl.h>
    49 #include <errno.h>
    50 #ifdef VBOX_WITH_LINUX_COMPILER_H
    51 # include <linux/compiler.h>
    52 #endif
    53 #include <linux/usbdevice_fs.h>
    54 /*
    55  * Backlevel 2.4 headers doesn't have these two defines.
    56  * They were added some time between 2.4.21 and 2.4.26, probably in 2.4.23.
    57  */
    58 #ifndef USBDEVFS_DISCONNECT
    59 # define USBDEVFS_DISCONNECT        _IO('U', 22)
    60 # define USBDEVFS_CONNECT           _IO('U', 23)
    61 #endif
    62 
    63 #ifndef USBDEVFS_URB_SHORT_NOT_OK
    64 # define USBDEVFS_URB_SHORT_NOT_OK  0 /* rhel3 doesn't have this. darn! */
    65 #endif
    66 
    67 
    68 /* FedoraCore 4 does not have the bit defined by default. */
    69 #ifndef POLLWRNORM
    70 # define POLLWRNORM 0x0100
    71 #endif
    72 
    73 #ifndef RDESKTOP
    74 # include <VBox/pdm.h>
    75 # include <VBox/err.h>
    76 # include <VBox/log.h>
    77 # include <iprt/alloc.h>
    78 # include <iprt/assert.h>
    79 # include <iprt/asm.h>
    80 # include <iprt/ctype.h>
    81 # include <iprt/file.h>
    82 # include <iprt/linux/sysfs.h>
    83 # include <iprt/stream.h>
    84 # include <iprt/string.h>
    85 # include <iprt/thread.h>
    86 # include <iprt/time.h>
    87 # include "../USBProxyDevice.h"
    88 #else
    89 
    90 # include "../rdesktop.h"
    91 # include "runtime.h"
    92 # include "USBProxyDevice.h"
    93 # ifdef VBOX_USB_WITH_SYSFS
    94 #  include "sysfs.h"
    95 # endif
    96 #endif
    97 
    98 
    99 /*******************************************************************************
    100 *   Structures and Typedefs                                                    *
    101 *******************************************************************************/
    102 /**
    103  * Wrapper around the linux urb request structure.
    104  * This is required to track in-flight and landed URBs.
    105  */
    106 typedef struct USBPROXYURBLNX
    107 {
    108     /** The kernel URB data */
    109     struct usbdevfs_urb     KUrb;
    110     /** Space filler for the isochronous packets. */
    111     struct usbdevfs_iso_packet_desc aIsocPktsDonUseTheseUseTheOnesInKUrb[8];
    112     /** The millisecond timestamp when this URB was submitted. */
    113     uint64_t                u64SubmitTS;
    114     /** Pointer to the next linux URB. */
    115     struct USBPROXYURBLNX  *pNext;
    116     /** Pointer to the previous linux URB. */
    117     struct USBPROXYURBLNX  *pPrev;
    118     /** If we've split the VUSBURB up into multiple linux URBs, this is points to the head. */
    119     struct USBPROXYURBLNX  *pSplitHead;
    120     /** The next linux URB if split up. */
    121     struct USBPROXYURBLNX  *pSplitNext;
    122     /** Whether it has timed out and should be shot down on the next failing reap call. */
    123     bool                    fTimedOut;
    124     /** Indicates that this URB has been canceled by timeout and should return an CRC error. */
    125     bool                    fCanceledByTimedOut;
    126     /** Don't report these back. */
    127     bool                    fCanceledBySubmit;
    128     /** This split element is reaped. */
    129     bool                    fSplitElementReaped;
    130     /** Size to transfer in remaining fragments of a split URB */
    131     uint32_t                cbSplitRemaining;
    132 } USBPROXYURBLNX, *PUSBPROXYURBLNX;
    133 
    134 /**
    135  * Data for the linux usb proxy backend.
    136  */
    137 typedef struct USBPROXYDEVLNX
    138 {
    139     /** The open file. */
    140     RTFILE              File;
    141     /** Critical section protecting the two lists. */
    142     RTCRITSECT          CritSect;
    143     /** The list of free linux URBs. Singly linked. */
    144     PUSBPROXYURBLNX     pFreeHead;
    145     /** The list of active linux URBs. Doubly linked.
    146      * We must maintain this so we can properly reap URBs of a detached device.
    147      * Only the split head will appear in this list. */
    148     PUSBPROXYURBLNX     pInFlightHead;
    149     /** The list of landed linux URBs. Doubly linked.
    150      * Only the split head will appear in this list. */
    151     PUSBPROXYURBLNX     pTaxingHead;
    152     /** The tail of the landed linux URBs. */
    153     PUSBPROXYURBLNX     pTaxingTail;
    154     /** Are we using sysfs to find the active configuration? */
    155     bool                fUsingSysfs;
    156     /** The device node/sysfs path of the device.
    157      * Used to figure out the configuration after a reset. */
    158     char                szPath[1];
    159 } USBPROXYDEVLNX, *PUSBPROXYDEVLNX;
    160 
    161 
    162 /*******************************************************************************
    163 *   Internal Functions                                                         *
    164 *******************************************************************************/
    165 static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries);
    166 static void usbProxLinuxUrbUnplugged(PUSBPROXYDEV pProxyDev);
    167 static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProyxDev, int iIf, bool fConnect, bool fQuiet);
    168 static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pSplitHead);
    169 static void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
    170 static void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
    171 static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg);
    172 
    173 
    174 
    175 /**
    176  * Wrapper for the ioctl call.
    177  *
    178  * This wrapper will repeate the call if we get an EINTR or EAGAIN. It can also
    179  * handle ENODEV (detached device) errors.
    180  *
    181  * @returns whatever ioctl returns.
    182  * @param   pProxyDev       The proxy device.
    183  * @param   iCmd            The ioctl command / function.
    184  * @param   pvArg           The ioctl argument / data.
    185  * @param   fHandleNoDev    Whether to handle ENODEV.
    186  * @param   cTries          The number of retries. Use UINT32_MAX for (kind of) indefinite retries.
    187  * @internal
    188  */
    189 static int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries)
    190 {
    191     int rc;
    192     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    193     do
    194     {
    195         do
    196         {
    197             rc = ioctl(pDevLnx->File, iCmd, pvArg);
    198             if (rc >= 0)
    199                 return rc;
    200         } while (errno == EINTR);
    201 
    202         if (errno == ENODEV && fHandleNoDev)
    203         {
    204             usbProxLinuxUrbUnplugged(pProxyDev);
    205             Log(("usb-linux: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    206             errno = ENODEV;
    207             break;
    208         }
    209         if (errno != EAGAIN)
    210             break;
    211     } while (cTries-- > 0);
    212 
    213     return rc;
    214 }
    215 
    216 
    217 /**
    218  * The device has been unplugged.
    219  * Cancel all in-flight URBs and put them up for reaping.
    220  */
    221 static void usbProxLinuxUrbUnplugged(PUSBPROXYDEV pProxyDev)
    222 {
    223     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    224 
    225     /*
    226      * Shoot down all flying URBs.
    227      */
    228     RTCritSectEnter(&pDevLnx->CritSect);
    229     pProxyDev->fDetached = true;
    230 
    231     PUSBPROXYURBLNX pUrbTaxing = NULL;
    232     PUSBPROXYURBLNX pUrbLnx = pDevLnx->pInFlightHead;
    233     pDevLnx->pInFlightHead = NULL;
    234     while (pUrbLnx)
    235     {
    236         PUSBPROXYURBLNX pCur = pUrbLnx;
    237         pUrbLnx = pUrbLnx->pNext;
    238 
    239         ioctl(pDevLnx->File, USBDEVFS_DISCARDURB, &pCur->KUrb); /* not sure if this is required.. */
    240         if (!pCur->KUrb.status)
    241             pCur->KUrb.status = -ENODEV;
    242 
    243         /* insert into the taxing list. */
    244         pCur->pPrev = NULL;
    245         if (    !pCur->pSplitHead
    246             ||  pCur == pCur->pSplitHead)
    247         {
    248             pCur->pNext = pUrbTaxing;
    249             if (pUrbTaxing)
    250                 pUrbTaxing->pPrev = pCur;
    251             pUrbTaxing = pCur;
    252         }
    253         else
    254             pCur->pNext = NULL;
    255     }
    256 
    257     /* Append the URBs we shot down to the taxing queue. */
    258     if (pUrbTaxing)
    259     {
    260         pUrbTaxing->pPrev = pDevLnx->pTaxingTail;
    261         if (pUrbTaxing->pPrev)
    262             pUrbTaxing->pPrev->pNext = pUrbTaxing;
    263         else
    264             pDevLnx->pTaxingTail = pDevLnx->pTaxingHead = pUrbTaxing;
    265     }
    266 
    267     RTCritSectLeave(&pDevLnx->CritSect);
    268 }
    269 
    270 
    271 /**
    272  * Set the connect state seen by kernel drivers
    273  * @internal
    274  */
    275 static void usbProxyLinuxSetConnected(PUSBPROXYDEV pProxyDev, int iIf, bool fConnect, bool fQuiet)
    276 {
    277     if (    iIf >= 32
    278         ||  !(pProxyDev->fMaskedIfs & RT_BIT(iIf)))
    279     {
    280         struct usbdevfs_ioctl IoCtl;
    281         if (!fQuiet)
    282             LogFlow(("usbProxyLinuxSetConnected: pProxyDev=%s iIf=%#x fConnect=%RTbool\n",
    283                      usbProxyGetName(pProxyDev), iIf, fConnect));
    284 
    285         IoCtl.ifno = iIf;
    286         IoCtl.ioctl_code = fConnect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT;
    287         IoCtl.data = NULL;
    288         if (    usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_IOCTL, &IoCtl, true, UINT32_MAX)
    289             &&  !fQuiet)
    290             Log(("usbProxyLinuxSetConnected: failure, errno=%d. pProxyDev=%s\n",
    291                  errno, usbProxyGetName(pProxyDev)));
    292     }
    293 }
    294 
    295 
    296 /**
    297  * Allocates a linux URB request structure.
    298  * @returns Pointer to an active URB request.
    299  * @returns NULL on failure.
    300  * @param   pProxyDev       The proxy device instance.
    301  * @param   pSplitHead      The split list head if allocating for a split list.
    302  */
    303 static PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pSplitHead)
    304 {
    305     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    306     PUSBPROXYURBLNX pUrbLnx;
    307 
    308     RTCritSectEnter(&pDevLnx->CritSect);
    309 
    310     /*
    311      * Try remove a linux URB from the free list, if none there allocate a new one.
    312      */
    313     pUrbLnx = pDevLnx->pFreeHead;
    314     if (pUrbLnx)
    315         pDevLnx->pFreeHead = pUrbLnx->pNext;
    316     else
    317     {
    318         RTCritSectLeave(&pDevLnx->CritSect);
    319         pUrbLnx = (PUSBPROXYURBLNX)RTMemAlloc(sizeof(*pUrbLnx));
    320         if (!pUrbLnx)
    321             return NULL;
    322         RTCritSectEnter(&pDevLnx->CritSect);
    323     }
    324     pUrbLnx->pSplitHead = pSplitHead;
    325     pUrbLnx->pSplitNext = NULL;
    326     pUrbLnx->fTimedOut = false;
    327     pUrbLnx->fCanceledByTimedOut = false;
    328     pUrbLnx->fCanceledBySubmit = false;
    329     pUrbLnx->fSplitElementReaped = false;
    330 
    331     /*
    332      * Link it into the active list
    333      */
    334     if (!pSplitHead)
    335     {
    336         pUrbLnx->pPrev = NULL;
    337         pUrbLnx->pNext = pDevLnx->pInFlightHead;
    338         if (pUrbLnx->pNext)
    339             pUrbLnx->pNext->pPrev = pUrbLnx;
    340         pDevLnx->pInFlightHead = pUrbLnx;
    341     }
    342     else
    343         pUrbLnx->pPrev = pUrbLnx->pNext = (PUSBPROXYURBLNX)0xdead;
    344 
    345     RTCritSectLeave(&pDevLnx->CritSect);
    346     return pUrbLnx;
    347 }
    348 
    349 
    350 /**
    351  * Frees a linux URB request structure.
    352  *
    353  * @param   pProxyDev       The proxy device instance.
    354  * @param   pUrbLnx         The linux URB to free.
    355  */
    356 static void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx)
    357 {
    358     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    359 
    360     RTCritSectEnter(&pDevLnx->CritSect);
    361 
    362     /*
    363      * Remove from the active list.
    364      */
    365     if (    !pUrbLnx->pSplitHead
    366         ||  pUrbLnx->pSplitHead == pUrbLnx)
    367     {
    368         if (pUrbLnx->pNext)
    369             pUrbLnx->pNext->pPrev = pUrbLnx->pPrev;
    370         if (pUrbLnx->pPrev)
    371             pUrbLnx->pPrev->pNext = pUrbLnx->pNext;
    372         else
    373             pDevLnx->pInFlightHead  = pUrbLnx->pNext;
    374     }
    375     pUrbLnx->pSplitHead = pUrbLnx->pSplitNext = NULL;
    376 
    377     /*
    378      * Link it into the free list.
    379      */
    380     pUrbLnx->pPrev = NULL;
    381     pUrbLnx->pNext = pDevLnx->pFreeHead;
    382     pDevLnx->pFreeHead = pUrbLnx;
    383 
    384     RTCritSectLeave(&pDevLnx->CritSect);
    385 }
    386 
    387 
    388 /**
    389  * Frees split list of a linux URB request structure.
    390  *
    391  * @param   pProxyDev       The proxy device instance.
    392  * @param   pUrbLnx         A linux URB to in the split list to be freed.
    393  */
    394 static void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx)
    395 {
    396     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    397 
    398     RTCritSectEnter(&pDevLnx->CritSect);
    399 
    400     pUrbLnx = pUrbLnx->pSplitHead;
    401     Assert(pUrbLnx);
    402     while (pUrbLnx)
    403     {
    404         PUSBPROXYURBLNX pFree = pUrbLnx;
    405         pUrbLnx = pUrbLnx->pSplitNext;
    406         Assert(pFree->pSplitHead);
    407         usbProxyLinuxUrbFree(pProxyDev, pFree);
    408     }
    409 
    410     RTCritSectLeave(&pDevLnx->CritSect);
    411 }
    412 
    413 
    414 /**
    415  * This finds the device in the /proc/bus/usb/bus/addr file and finds
    416  * the config with an asterix.
    417  *
    418  * @returns The Cfg#.
    419  * @returns -1 if no active config.
    420  * @param   pszDevNode      The path to the device. We infere the location of
    421  *                          the devices file, which bus and device number we're
    422  *                          looking for.
    423  * @param   iFirstCfg       The first configuration. (optional)
    424  * @internal
    425  */
    426 static int usbProxyLinuxFindActiveConfigUsbfs(PUSBPROXYDEV pProxyDev, const char *pszDevNode, int *piFirstCfg)
    427 {
    428     /*
    429      * Set return defaults.
    430      */
    431     int iActiveCfg = -1;
    432     if (piFirstCfg)
    433         *piFirstCfg = 1;
    434 
    435     /*
    436      * Parse the usbfs device node path and turn it into a path to the "devices" file,
    437      * picking up the device number and bus along the way.
    438      */
    439     size_t cchDevNode = strlen(pszDevNode);
    440     char *pszDevices = (char *)RTMemDupEx(pszDevNode, cchDevNode, sizeof("devices"));
    441     AssertReturn(pszDevices, iActiveCfg);
    442 
    443     /* the device number */
    444     char *psz = pszDevices + cchDevNode;
    445     while (*psz != '/')
    446         psz--;
    447     Assert(pszDevices < psz);
    448     uint32_t uDev;
    449     int rc = RTStrToUInt32Ex(psz + 1, NULL, 10, &uDev);
    450     if (RT_SUCCESS(rc))
    451     {
    452         /* the bus number */
    453         *psz-- = '\0';
    454         while (*psz != '/')
    455             psz--;
    456         Assert(pszDevices < psz);
    457         uint32_t uBus;
    458         rc = RTStrToUInt32Ex(psz + 1, NULL, 10, &uBus);
    459         if (RT_SUCCESS(rc))
    460         {
    461             strcpy(psz + 1, "devices");
    462 
    463             /*
    464              * Open and scan the devices file.
    465              * We're ASSUMING that each device starts off with a 'T:' line.
    466              */
    467             PRTSTREAM pFile;
    468             rc = RTStrmOpen(pszDevices, "r", &pFile);
    469             if (RT_SUCCESS(rc))
    470             {
    471                 char szLine[1024];
    472                 while (RT_SUCCESS(RTStrmGetLine(pFile, szLine, sizeof(szLine))))
    473                 {
    474                     /* we're only interested in 'T:' lines. */
    475                     psz = RTStrStripL(szLine);
    476                     if (psz[0] != 'T' || psz[1] != ':')
    477                         continue;
    478 
    479                     /* Skip ahead to 'Bus' and compare */
    480                     psz = RTStrStripL(psz + 2); Assert(!strncmp(psz, "Bus=", 4));
    481                     psz = RTStrStripL(psz + 4);
    482                     char *pszNext;
    483                     uint32_t u;
    484                     rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u); AssertRC(rc);
    485                     if (RT_FAILURE(rc))
    486                         continue;
    487                     if (u != uBus)
    488                         continue;
    489 
    490                     /* Skip ahead to 'Dev#' and compare */
    491                     psz = strstr(psz, "Dev#="); Assert(psz);
    492                     if (!psz)
    493                         continue;
    494                     psz = RTStrStripL(psz + 5);
    495                     rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u); AssertRC(rc);
    496                     if (RT_FAILURE(rc))
    497                         continue;
    498                     if (u != uDev)
    499                         continue;
    500 
    501                     /*
    502                      * Ok, we've found the device.
    503                      * Scan until we find a selected configuration, the next device, or EOF.
    504                      */
    505                     while (RT_SUCCESS(RTStrmGetLine(pFile, szLine, sizeof(szLine))))
    506                     {
    507                         psz = RTStrStripL(szLine);
    508                         if (psz[0] == 'T')
    509                             break;
    510                         if (psz[0] != 'C' || psz[1] != ':')
    511                             continue;
    512                         const bool fActive = psz[2] == '*';
    513                         if (!fActive && !piFirstCfg)
    514                             continue;
    515 
    516                         /* Get the 'Cfg#' value. */
    517                         psz = strstr(psz, "Cfg#="); Assert(psz);
    518                         if (psz)
    519                         {
    520                             psz = RTStrStripL(psz + 5);
    521                             rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u); AssertRC(rc);
    522                             if (RT_SUCCESS(rc))
    523                             {
    524                                 if (piFirstCfg)
    525                                 {
    526                                     *piFirstCfg = u;
    527                                     piFirstCfg = NULL;
    528                                 }
    529                                 if (fActive)
    530                                     iActiveCfg = u;
    531                             }
    532                         }
    533                         if (fActive)
    534                             break;
    535                     }
    536                     break;
    537                 }
    538                 RTStrmClose(pFile);
    539             }
    540         }
    541     }
    542     RTMemFree(pszDevices);
    543 
    544     return iActiveCfg;
    545 }
    546 
    547 
    548 /**
    549  * This finds the active configuration from sysfs.
    550  *
    551  * @returns The Cfg#.
    552  * @returns -1 if no active config.
    553  * @param   pszPath         The sysfs path for the device.
    554  * @param   piFirstCfg      The first configuration. (optional)
    555  * @internal
    556  */
    557 static int usbProxyLinuxFindActiveConfigSysfs(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg)
    558 {
    559 #ifdef VBOX_USB_WITH_SYSFS
    560     if (piFirstCfg != NULL)
    561         *piFirstCfg = pProxyDev->paCfgDescs != NULL
    562                     ? pProxyDev->paCfgDescs[0].Core.bConfigurationValue
    563                     : 1;
    564     return RTLinuxSysFsReadIntFile(10, "%s/bConfigurationValue", pszPath); /* returns -1 on failure */
    565 #else  /* !VBOX_USB_WITH_SYSFS */
    566     return -1;
    567 #endif /* !VBOX_USB_WITH_SYSFS */
    568 }
    569 
    570 
    571 /**
    572  * This finds the active configuration.
    573  *
    574  * @returns The Cfg#.
    575  * @returns -1 if no active config.
    576  * @param   pszPath         The sysfs path for the device, or the usbfs device
    577  *                          node path.
    578  * @param   iFirstCfg       The first configuration. (optional)
    579  * @internal
    580  */
    581 static int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg)
    582 {
    583     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    584     if (pDevLnx->fUsingSysfs)
    585         return usbProxyLinuxFindActiveConfigSysfs(pProxyDev, pszPath, piFirstCfg);
    586     return usbProxyLinuxFindActiveConfigUsbfs(pProxyDev, pszPath, piFirstCfg);
    587 }
    588 
    589 
    590 /**
    591  * Extracts the Linux file descriptor associated with the kernel USB device.
    592  * This is used by rdesktop-vrdp for polling for events.
    593  * @returns  the FD, or asserts and returns -1 on error
    594  * @param    pProxyDev    The device instance
    595  */
    596 RTDECL(int) USBProxyDeviceLinuxGetFD(PUSBPROXYDEV pProxyDev)
    597 {
    598     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    599     AssertReturn(pDevLnx->File != NIL_RTFILE, -1);
    600     return pDevLnx->File;
    601 }
    602 
    603 
    604 /**
    605  * Opens the device file.
    606  *
    607  * @returns VBox status code.
    608  * @param   pProxyDev       The device instance.
    609  * @param   pszAddress      If we are using usbfs, this is the path to the
    610  *                          device.  If we are using sysfs, this is a string of
    611  *                          the form "sysfs:<sysfs path>//device:<device node>".
    612  *                          In the second case, the two paths are guaranteed
    613  *                          not to contain the substring "//".
    614  * @param   pvBackend       Backend specific pointer, unused for the linux backend.
    615  */
    616 static int usbProxyLinuxOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
    617 {
    618     LogFlow(("usbProxyLinuxOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
    619     const char *pszDevNode;
    620     const char *pszPath;
    621     size_t      cchPath;
    622     bool        fUsingSysfs;
    623 
    624     /*
    625      * Are we using sysfs or usbfs?
    626      */
    627 #ifdef VBOX_USB_WITH_SYSFS
    628     fUsingSysfs = strncmp(pszAddress, "sysfs:", sizeof("sysfs:") - 1) == 0;
    629     if (fUsingSysfs)
    630     {
    631         pszDevNode = strstr(pszAddress, "//device:");
    632         if (!pszDevNode)
    633         {
    634             LogRel(("usbProxyLinuxOpen: Invalid device address: '%s'\n", pszAddress));
    635             pProxyDev->Backend.pv = NULL;
    636             return VERR_INVALID_PARAMETER;
    637         }
    638 
    639         pszPath = pszAddress + sizeof("sysfs:") - 1;
    640         cchPath = pszDevNode - pszPath;
    641         pszDevNode += sizeof("//device:") - 1;
    642     }
    643     else
    644 #endif  /* VBOX_USB_WITH_SYSFS */
    645     {
    646 #ifndef VBOX_USB_WITH_SYSFS
    647         fUsingSysfs = false;
    648 #endif
    649         pszPath = pszDevNode = pszAddress;
    650         cchPath = strlen(pszPath);
    651     }
    652 
    653     /*
    654      * Try open the device node.
    655      */
    656     RTFILE File;
    657     int rc = RTFileOpen(&File, pszDevNode, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    658     if (RT_SUCCESS(rc))
    659     {
    660         /*
    661          * Allocate and initialize the linux backend data.
    662          */
    663         PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)RTMemAllocZVar(sizeof(*pDevLnx) + cchPath);
    664         if (pDevLnx)
    665         {
    666             pDevLnx->fUsingSysfs = fUsingSysfs;
    667             memcpy(&pDevLnx->szPath[0], pszPath, cchPath);
    668             pDevLnx->szPath[cchPath] = '\0';
    669             pDevLnx->File = File;
    670             rc = RTCritSectInit(&pDevLnx->CritSect);
    671             if (RT_SUCCESS(rc))
    672             {
    673                 pProxyDev->Backend.pv = pDevLnx;
    674 
    675                 LogFlow(("usbProxyLinuxOpen(%p, %s): returns successfully File=%d iActiveCfg=%d\n",
    676                          pProxyDev, pszAddress, pDevLnx->File, pProxyDev->iActiveCfg));
    677 
    678                 return VINF_SUCCESS;
    679             }
    680 
    681             RTMemFree(pDevLnx);
    682         }
    683         else
    684             rc = VERR_NO_MEMORY;
    685         RTFileClose(File);
    686     }
    687     else if (rc == VERR_ACCESS_DENIED)
    688         rc = VERR_VUSB_USBFS_PERMISSION;
    689 
    690     Log(("usbProxyLinuxOpen(%p, %s) failed, rc=%Rrc!\n", pProxyDev, pszAddress, rc));
    691     pProxyDev->Backend.pv = NULL;
    692 
    693     NOREF(pvBackend);
    694     return rc;
    695 }
    696 
    697 
    698 /**
    699  * Claims all the interfaces and figures out the
    700  * current configuration.
    701  *
    702  * @returns VINF_SUCCESS.
    703  * @param   pProxyDev       The proxy device.
    704  */
    705 static int usbProxyLinuxInit(PUSBPROXYDEV pProxyDev)
    706 {
    707     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    708 
    709     /*
    710      * Brute force rulez.
    711      * usbProxyLinuxSetConnected check for masked interfaces.
    712      */
    713     unsigned iIf;
    714     for (iIf = 0; iIf < 256; iIf++)
    715         usbProxyLinuxSetConnected(pProxyDev, iIf, false, true);
    716 
    717     /*
    718      * Determin the active configuration.
    719      *
    720      * If there isn't any active configuration, we will get EHOSTUNREACH (113) errors
    721      * when trying to read the device descriptors in usbProxyDevCreate. So, we'll make
    722      * the first one active (usually 1) then.
    723      */
    724     pProxyDev->cIgnoreSetConfigs = 1;
    725     int iFirstCfg;
    726     pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->szPath, &iFirstCfg);
    727     if (pProxyDev->iActiveCfg == -1)
    728     {
    729         usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETCONFIGURATION, &iFirstCfg, false, UINT32_MAX);
    730         pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->szPath, NULL);
    731         Log(("usbProxyLinuxInit: No active config! Tried to set %d: iActiveCfg=%d\n", iFirstCfg, pProxyDev->iActiveCfg));
    732     }
    733     else
    734         Log(("usbProxyLinuxInit(%p): iActiveCfg=%d\n", pProxyDev, pProxyDev->iActiveCfg));
    735     return VINF_SUCCESS;
    736 }
    737 
    738 
    739 /**
    740  * Closes the proxy device.
    741  */
    742 static void usbProxyLinuxClose(PUSBPROXYDEV pProxyDev)
    743 {
    744     LogFlow(("usbProxyLinuxClose: pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    745     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    746     Assert(pDevLnx);
    747     if (!pDevLnx)
    748         return;
    749 
    750     /*
    751      * Try put the device in a state which linux can cope with before we release it.
    752      * Resetting it would be a nice start, although we must remember
    753      * that it might have been disconnected...
    754      *
    755      * Don't reset if we're masking interfaces or if construction failed.
    756      */
    757     if (pProxyDev->fInited)
    758     {
    759         /* ASSUMES: thread == EMT */
    760         if (    pProxyDev->fMaskedIfs
    761             ||  !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
    762         {
    763             /* Connect drivers. */
    764             unsigned iIf;
    765             for (iIf = 0; iIf < 256; iIf++)
    766                 usbProxyLinuxSetConnected(pProxyDev, iIf, true, true);
    767             LogRel(("USB: Successfully reset device pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    768         }
    769         else if (errno != ENODEV)
    770             LogRel(("USB: Reset failed, errno=%d, pProxyDev=%s.\n", errno, usbProxyGetName(pProxyDev)));
    771         else
    772             Log(("USB: Reset failed, errno=%d (ENODEV), pProxyDev=%s.\n", errno, usbProxyGetName(pProxyDev)));
    773     }
    774 
    775     /*
    776      * Now we can free all the resources and close the device.
    777      */
    778     RTCritSectDelete(&pDevLnx->CritSect);
    779 
    780     PUSBPROXYURBLNX pUrbLnx;
    781     while ((pUrbLnx = pDevLnx->pInFlightHead) != NULL)
    782     {
    783         pDevLnx->pInFlightHead = pUrbLnx->pNext;
    784         if (    usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbLnx->KUrb, false, UINT32_MAX)
    785             &&  errno != ENODEV
    786             &&  errno != ENOENT)
    787             AssertMsgFailed(("errno=%d\n", errno));
    788         if (pUrbLnx->pSplitHead)
    789         {
    790             PUSBPROXYURBLNX pCur = pUrbLnx->pSplitNext;
    791             while (pCur)
    792             {
    793                 PUSBPROXYURBLNX pFree = pCur;
    794                 pCur = pFree->pSplitNext;
    795                 if (    !pFree->fSplitElementReaped
    796                     &&  usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pFree->KUrb, false, UINT32_MAX)
    797                     &&  errno != ENODEV
    798                     &&  errno != ENOENT)
    799                     AssertMsgFailed(("errno=%d\n", errno));
    800                 RTMemFree(pFree);
    801             }
    802         }
    803         else
    804             Assert(!pUrbLnx->pSplitNext);
    805         RTMemFree(pUrbLnx);
    806     }
    807 
    808     while ((pUrbLnx = pDevLnx->pFreeHead) != NULL)
    809     {
    810         pDevLnx->pFreeHead = pUrbLnx->pNext;
    811         RTMemFree(pUrbLnx);
    812     }
    813 
    814     RTFileClose(pDevLnx->File);
    815     pDevLnx->File = NIL_RTFILE;
    816 
    817     RTMemFree(pDevLnx);
    818     pProxyDev->Backend.pv = NULL;
    819     LogFlow(("usbProxyLinuxClose: returns\n"));
    820 }
    821 
    822 
    823 #if defined(NO_PORT_RESET) && !defined(NO_LOGICAL_RECONNECT)
    824 /**
    825  * Look for the logically reconnected device.
    826  * After 5 seconds we'll give up.
    827  *
    828  * @returns VBox status code.
    829  * @thread  Reset thread or EMT.
    830  */
    831 static int usb_reset_logical_reconnect(PUSBPROXYDEV pDev)
    832 {
    833     FILE *          pFile;
    834     uint64_t        u64StartTS = RTTimeMilliTS();
    835 
    836     Log2(("usb_reset_logical_reconnect: pDev=%p:{.bBus=%#x, .bDevNum=%#x, .idVendor=%#x, .idProduct=%#x, .bcdDevice=%#x, .u64SerialHash=%#llx .bDevNumParent=%#x .bPort=%#x .bLevel=%#x}\n",
    837           pDev, pDev->Info.bBus, pDev->Info.bDevNum, pDev->Info.idVendor, pDev->Info.idProduct, pDev->Info.bcdDevice,
    838           pDev->Info.u64SerialHash, pDev->Info.bDevNumParent, pDev->Info.bPort, pDev->Info.bLevel));
    839 
    840     /* First, let hubd get a chance to logically reconnect the device. */
    841     if (!RTThreadYield())
    842         RTThreadSleep(1);
    843 
    844     /*
    845      * Search for the new device address.
    846      */
    847     pFile = get_devices_file();
    848     if (!pFile)
    849         return VERR_FILE_NOT_FOUND;
    850 
    851     /*
    852      * Loop until found or 5seconds have elapsed.
    853      */
    854     for (;;) {
    855         struct pollfd   pfd;
    856         uint8_t     tmp;
    857         int         rc;
    858         char        buf[512];
    859         uint64_t    u64Elapsed;
    860         int         got = 0;
    861         struct usb_dev_entry id = {0};
    862 
    863         /*
    864          * Since this is kernel ABI we don't need to be too fussy about
    865          * the parsing.
    866          */
    867         while (fgets(buf, sizeof(buf), pFile)) {
    868             char *psz = strchr(buf, '\n');
    869             if ( psz == NULL ) {
    870                 AssertMsgFailed(("usb_reset_logical_reconnect: Line to long!!\n"));
    871                 break;
    872             }
    873             *psz = '\0';
    874 
    875             switch ( buf[0] ) {
    876             case 'T': /* topology */
    877                 /* Check if we've got enough for a device. */
    878                 if (got >= 2) {
    879                     Log2(("usb_reset_logical_reconnect: {.bBus=%#x, .bDevNum=%#x, .idVendor=%#x, .idProduct=%#x, .bcdDevice=%#x, .u64SerialHash=%#llx, .bDevNumParent=%#x, .bPort=%#x, .bLevel=%#x}\n",
    880                           id.bBus, id.bDevNum, id.idVendor, id.idProduct, id.bcdDevice, id.u64SerialHash, id.bDevNumParent, id.bPort, id.bLevel));
    881                     if (    id.bDevNumParent == pDev->Info.bDevNumParent
    882                         &&  id.idVendor == pDev->Info.idVendor
    883                         &&  id.idProduct == pDev->Info.idProduct
    884                         &&  id.bcdDevice == pDev->Info.bcdDevice
    885                         &&  id.u64SerialHash == pDev->Info.u64SerialHash
    886                         &&  id.bBus == pDev->Info.bBus
    887                         &&  id.bPort == pDev->Info.bPort
    888                         &&  id.bLevel == pDev->Info.bLevel) {
    889                         goto l_found;
    890                     }
    891                 }
    892 
    893                 /* restart */
    894                 got = 0;
    895                 memset(&id, 0, sizeof(id));
    896 
    897                 /*T:  Bus=04 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0*/
    898                 Log2(("usb_reset_logical_reconnect: %s\n", buf));
    899                 buf[10] = '\0';
    900                 if ( !get_u8(buf + 8, &id.bBus) )
    901                     break;
    902                 buf[49] = '\0';
    903                 psz = buf + 46;
    904                 while ( *psz == ' ' )
    905                     psz++;
    906                 if ( !get_u8(psz, &id.bDevNum) )
    907                     break;
    908 
    909                 buf[17] = '\0';
    910                 if ( !get_u8(buf + 15, &id.bLevel) )
    911                     break;
    912                 buf[25] = '\0';
    913                 if ( !get_u8(buf + 23, &id.bDevNumParent) )
    914                     break;
    915                 buf[33] = '\0';
    916                 if ( !get_u8(buf + 31, &id.bPort) )
    917                     break;
    918                 got++;
    919                 break;
    920 
    921             case 'P': /* product */
    922                 Log2(("usb_reset_logical_reconnect: %s\n", buf));
    923                 buf[15] = '\0';
    924                 if ( !get_x16(buf + 11, &id.idVendor) )
    925                     break;
    926                 buf[27] = '\0';
    927                 if ( !get_x16(buf + 23, &id.idProduct) )
    928                     break;
    929                 buf[34] = '\0';
    930                 if ( buf[32] == ' ' )
    931                     buf[32] = '0';
    932                 id.bcdDevice = 0;
    933                 if ( !get_x8(buf + 32, &tmp) )
    934                     break;
    935                 id.bcdDevice = tmp << 8;
    936                 if ( !get_x8(buf + 35, &tmp) )
    937                     break;
    938                 id.bcdDevice |= tmp;
    939                 got++;
    940                 break;
    941 
    942             case 'S': /* String descriptor */
    943                 /* Skip past "S:" and then the whitespace */
    944                 for(psz = buf + 2; *psz != '\0'; psz++)
    945                     if ( !RT_C_IS_SPACE(*psz) )
    946                         break;
    947 
    948                 /* If it is a serial number string, skip past
    949                  * "SerialNumber="
    950                  */
    951                 if ( strncmp(psz, "SerialNumber=", sizeof("SerialNumber=") - 1) )
    952                     break;
    953 
    954                 Log2(("usb_reset_logical_reconnect: %s\n", buf));
    955                 psz += sizeof("SerialNumber=") - 1;
    956 
    957                 usb_serial_hash(psz, &id.u64SerialHash);
    958                 break;
    959             }
    960         }
    961 
    962         /*
    963          * Check last.
    964          */
    965         if (    got >= 2
    966             &&  id.bDevNumParent == pDev->Info.bDevNumParent
    967             &&  id.idVendor == pDev->Info.idVendor
    968             &&  id.idProduct == pDev->Info.idProduct
    969             &&  id.bcdDevice == pDev->Info.bcdDevice
    970             &&  id.u64SerialHash == pDev->Info.u64SerialHash
    971             &&  id.bBus == pDev->Info.bBus
    972             &&  id.bPort == pDev->Info.bPort
    973             &&  id.bLevel == pDev->Info.bLevel) {
    974         l_found:
    975             /* close the existing file descriptor. */
    976             RTFileClose(pDevLnx->File);
    977             pDevLnx->File = NIL_RTFILE;
    978 
    979             /* open stuff at the new address. */
    980             pDev->Info = id;
    981             if (usbProxyLinuxOpen(pDev, &id))
    982                 return VINF_SUCCESS;
    983             break;
    984         }
    985 
    986         /*
    987          * Wait for a while and then check the file again.
    988          */
    989         u64Elapsed = RTTimeMilliTS() - u64StartTS;
    990         if (u64Elapsed >= 5000/*ms*/)
    991             break; /* done */
    992 
    993         pfd.fd = fileno(pFile);
    994         pfd.events = POLLIN;
    995         rc = poll(&pfd, 1, 5000 - u64Elapsed);
    996         if (rc < 0) {
    997             AssertMsg(errno == EINTR, ("errno=%d\n", errno));
    998             RTThreadSleep(32); /* paranoia: don't eat cpu on failure */
    999         }
    1000 
    1001         rewind(pFile);
    1002     } /* for loop */
    1003 
    1004     return VERR_GENERAL_FAILURE;
    1005 }
    1006 #endif /* !NO_PORT_RESET && !NO_LOGICAL_RECONNECT */
    1007 
    1008 
    1009 /**
    1010  * Reset a device.
    1011  *
    1012  * @returns VBox status code.
    1013  * @param   pDev    The device to reset.
    1014  */
    1015 static int usbProxyLinuxReset(PUSBPROXYDEV pProxyDev, bool fResetOnLinux)
    1016 {
    1017 #ifdef NO_PORT_RESET
    1018     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    1019 
    1020     /*
    1021      * Specific device resets are NOPs.
    1022      * Root hub resets that affects all devices are executed.
    1023      *
    1024      * The reasoning is that when a root hub reset is done, the guest shouldn't
    1025      * will have to re enumerate the devices after doing this kind of reset.
    1026      * So, it doesn't really matter if a device is 'logically disconnected'.
    1027      */
    1028     if (    !fResetOnLinux
    1029         ||  pProxyDev->fMaskedIfs)
    1030         LogFlow(("usbProxyLinuxReset: pProxyDev=%s - NO_PORT_RESET\n", usbProxyGetName(pProxyDev)));
    1031     else
    1032     {
    1033         LogFlow(("usbProxyLinuxReset: pProxyDev=%s - Real Reset!\n", usbProxyGetName(pProxyDev)));
    1034         if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
    1035         {
    1036             int rc = errno;
    1037             Log(("usb-linux: Reset failed, rc=%Rrc errno=%d.\n", RTErrConvertFromErrno(rc), rc));
    1038             pProxyDev->iActiveCfg = -1;
    1039             return RTErrConvertFromErrno(rc);
    1040         }
    1041 
    1042         /* find the active config - damn annoying. */
    1043         pProxyDev->iActiveCfg = usbProxyLinuxFindActiveConfig(pProxyDev, pDevLnx->szPath, NULL);
    1044         LogFlow(("usbProxyLinuxReset: returns successfully iActiveCfg=%d\n", pProxyDev->iActiveCfg));
    1045     }
    1046     pProxyDev->cIgnoreSetConfigs = 2;
    1047 
    1048 #else /* !NO_PORT_RESET */
    1049 
    1050     /*
    1051      * This is the alternative, we will allways reset when asked to do so.
    1052      *
    1053      * The problem we're facing here is that on reset failure linux will do
    1054      * a 'logical reconnect' on the device. This will invalidate the current
    1055      * handle and we'll have to reopen the device. This is problematic to say
    1056      * the least, especially since it happens pretty often.
    1057      */
    1058     LogFlow(("usbProxyLinuxReset: pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    1059 # ifndef NO_LOGICAL_RECONNECT
    1060     ASMAtomicIncU32(&g_cResetActive);
    1061 # endif
    1062 
    1063     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RESET, NULL, false, 10))
    1064     {
    1065         int rc = errno;
    1066 # ifndef NO_LOGICAL_RECONNECT
    1067         if (rc == ENODEV)
    1068         {
    1069             /*
    1070              * This usually happens because of a 'logical disconnection'.
    1071              * So, we're in for a real treat from our excellent OS now...
    1072              */
    1073             rc2 = usb_reset_logical_reconnect(pProxyDev);
    1074             if (RT_FAILURE(rc2))
    1075                 usbProxLinuxUrbUnplugged(pProxyDev);
    1076             if (RT_SUCCESS(rc2))
    1077             {
    1078                 ASMAtomicDecU32(&g_cResetActive);
    1079                 LogFlow(("usbProxyLinuxReset: returns success (after recovering disconnected device!)\n"));
    1080                 return VINF_SUCCESS;
    1081             }
    1082         }
    1083         ASMAtomicDecU32(&g_cResetActive);
    1084 # endif /* NO_LOGICAL_RECONNECT */
    1085 
    1086         Log(("usb-linux: Reset failed, rc=%Rrc errno=%d.\n", RTErrConvertFromErrno(rc), rc));
    1087         pProxyDev->iActiveCfg = -1;
    1088         return RTErrConvertFromErrno(rc);
    1089     }
    1090 
    1091 # ifndef NO_LOGICAL_RECONNECT
    1092     ASMAtomicDecU32(&g_cResetActive);
    1093 # endif
    1094 
    1095     pProxyDev->cIgnoreSetConfigs = 2;
    1096     LogFlow(("usbProxyLinuxReset: returns success\n"));
    1097 #endif /* !NO_PORT_RESET */
    1098     return VINF_SUCCESS;
    1099 }
    1100 
    1101 
    1102 /**
    1103  * SET_CONFIGURATION.
    1104  *
    1105  * The caller makes sure that it's not called first time after open or reset
    1106  * with the active interface.
    1107  *
    1108  * @returns success indicator.
    1109  * @param   pProxyDev       The device instance data.
    1110  * @param   iCfg            The configuration to set.
    1111  */
    1112 static int usbProxyLinuxSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
    1113 {
    1114     LogFlow(("usbProxyLinuxSetConfig: pProxyDev=%s cfg=%#x\n",
    1115              usbProxyGetName(pProxyDev), iCfg));
    1116 
    1117     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETCONFIGURATION, &iCfg, true, UINT32_MAX))
    1118     {
    1119         Log(("usb-linux: Set configuration. errno=%d\n", errno));
    1120         return false;
    1121     }
    1122     return true;
    1123 }
    1124 
    1125 
    1126 /**
    1127  * Claims an interface.
    1128  * @returns success indicator.
    1129  */
    1130 static int usbProxyLinuxClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
    1131 {
    1132     LogFlow(("usbProxyLinuxClaimInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
    1133     usbProxyLinuxSetConnected(pProxyDev, iIf, false, false);
    1134 
    1135     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_CLAIMINTERFACE, &iIf, true, UINT32_MAX))
    1136     {
    1137         Log(("usb-linux: Claim interface. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1138         return false;
    1139     }
    1140     return true;
    1141 }
    1142 
    1143 
    1144 /**
    1145  * Releases an interface.
    1146  * @returns success indicator.
    1147  */
    1148 static int usbProxyLinuxReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
    1149 {
    1150     LogFlow(("usbProxyLinuxReleaseInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
    1151 
    1152     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_RELEASEINTERFACE, &iIf, true, UINT32_MAX))
    1153     {
    1154         Log(("usb-linux: Release interface, errno=%d. pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1155         return false;
    1156     }
    1157     return true;
    1158 }
    1159 
    1160 
    1161 /**
    1162  * SET_INTERFACE.
    1163  *
    1164  * @returns success indicator.
    1165  */
    1166 static int usbProxyLinuxSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
    1167 {
    1168     struct usbdevfs_setinterface SetIf;
    1169     LogFlow(("usbProxyLinuxSetInterface: pProxyDev=%p iIf=%#x iAlt=%#x\n", pProxyDev, iIf, iAlt));
    1170 
    1171     SetIf.interface  = iIf;
    1172     SetIf.altsetting = iAlt;
    1173     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_SETINTERFACE, &SetIf, true, UINT32_MAX))
    1174     {
    1175         Log(("usb-linux: Set interface, errno=%d. pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1176         return false;
    1177     }
    1178     return true;
    1179 }
    1180 
    1181 
    1182 /**
    1183  * Clears the halted endpoint 'EndPt'.
    1184  */
    1185 static bool usbProxyLinuxClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
    1186 {
    1187     LogFlow(("usbProxyLinuxClearHaltedEp: pProxyDev=%s EndPt=%u\n", usbProxyGetName(pProxyDev), EndPt));
    1188 
    1189     if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_CLEAR_HALT, &EndPt, true, UINT32_MAX))
    1190     {
    1191         /*
    1192          * Unfortunately this doesn't work on control pipes.
    1193          * Windows doing this on the default endpoint and possibly other pipes too,
    1194          * so we'll feign success for ENOENT errors.
    1195          */
    1196         if (errno == ENOENT)
    1197         {
    1198             Log(("usb-linux: clear_halted_ep failed errno=%d. pProxyDev=%s ep=%d - IGNORED\n",
    1199                  errno, usbProxyGetName(pProxyDev), EndPt));
    1200             return true;
    1201         }
    1202         Log(("usb-linux: clear_halted_ep failed errno=%d. pProxyDev=%s ep=%d\n",
    1203              errno, usbProxyGetName(pProxyDev), EndPt));
    1204         return false;
    1205     }
    1206     return true;
    1207 }
    1208 
    1209 
    1210 /**
    1211  * Setup packet byte-swapping routines.
    1212  */
    1213 static void usbProxyLinuxUrbSwapSetup(PVUSBSETUP pSetup)
    1214 {
    1215     pSetup->wValue = RT_H2LE_U16(pSetup->wValue);
    1216     pSetup->wIndex = RT_H2LE_U16(pSetup->wIndex);
    1217     pSetup->wLength = RT_H2LE_U16(pSetup->wLength);
    1218 }
    1219 
    1220 
    1221 /**
    1222  * Clean up after a failed URB submit.
    1223  */
    1224 static void usbProxyLinuxCleanupFailedSubmit(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx, PUSBPROXYURBLNX pCur, PVUSBURB pUrb, bool *pfUnplugged)
    1225 {
    1226     if (pUrb->enmType == VUSBXFERTYPE_MSG)
    1227         usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
    1228 
    1229     /* discard and reap later (walking with pUrbLnx). */
    1230     if (pUrbLnx != pCur)
    1231     {
    1232         for (;;)
    1233         {
    1234             pUrbLnx->fCanceledBySubmit = true;
    1235             pUrbLnx->KUrb.usercontext = NULL;
    1236             if (usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbLnx->KUrb, false, UINT32_MAX))
    1237             {
    1238                 if (errno == ENODEV)
    1239                     *pfUnplugged = true;
    1240                 else if (errno == ENOENT)
    1241                     pUrbLnx->fSplitElementReaped = true;
    1242                 else
    1243                     LogRel(("USB: Failed to discard %p! errno=%d (pUrb=%p)\n", pUrbLnx->KUrb.usercontext, errno, pUrb)); /* serious! */
    1244             }
    1245             if (pUrbLnx->pSplitNext == pCur)
    1246             {
    1247                 pUrbLnx->pSplitNext = NULL;
    1248                 break;
    1249             }
    1250             pUrbLnx = pUrbLnx->pSplitNext; Assert(pUrbLnx);
    1251         }
    1252     }
    1253 
    1254     /* free the unsubmitted ones. */
    1255     while (pCur)
    1256     {
    1257         PUSBPROXYURBLNX pFree = pCur;
    1258         pCur = pCur->pSplitNext;
    1259         usbProxyLinuxUrbFree(pProxyDev, pFree);
    1260     }
    1261 
    1262     /* send unplug event if we failed with ENODEV originally. */
    1263     if (*pfUnplugged)
    1264         usbProxLinuxUrbUnplugged(pProxyDev);
    1265 }
    1266 
    1267 /**
    1268  * Submit one URB through the usbfs IOCTL interface, with
    1269  * retries
    1270  *
    1271  * @returns true / false.
    1272  */
    1273 static bool usbProxyLinuxSubmitURB(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pCur, PVUSBURB pUrb, bool *pfUnplugged)
    1274 {
    1275     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    1276     unsigned        cTries = 0;
    1277 
    1278     while (ioctl(pDevLnx->File, USBDEVFS_SUBMITURB, &pCur->KUrb))
    1279     {
    1280         if (errno == EINTR)
    1281             continue;
    1282         if (errno == ENODEV)
    1283         {
    1284             Log(("usbProxyLinuxSubmitURB: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    1285             *pfUnplugged = true;
    1286             return false;
    1287         }
    1288 
    1289         Log(("usb-linux: Submit URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n",
    1290              pUrb, errno, pCur->KUrb.type, pCur->KUrb.endpoint, pCur->KUrb.buffer_length, cTries));
    1291         if (errno != EBUSY && ++cTries < 3) /* this doesn't work for the floppy :/ */
    1292         {
    1293             pCur->u64SubmitTS = RTTimeMilliTS();
    1294             continue;
    1295         }
    1296         return false;
    1297     }
    1298     return true;
    1299 }
    1300 
    1301 /** The split size. 16K in known Linux kernel versions. */
    1302 #define SPLIT_SIZE 0x4000
    1303 
    1304 /**
    1305  * Create a URB fragment of up to SPLIT_SIZE size and hook it
    1306  * into the list of fragments.
    1307  *
    1308  * @returns pointer to newly allocated URB fragment or NULL.
    1309  */
    1310 static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pHead, PUSBPROXYURBLNX pCur)
    1311 {
    1312     PUSBPROXYURBLNX     pNew;
    1313     uint32_t            cbLeft = pCur->cbSplitRemaining;
    1314     uint8_t             *pb = (uint8_t *)pCur->KUrb.buffer;
    1315 
    1316     Assert(cbLeft != 0);
    1317     pNew = pCur->pSplitNext = usbProxyLinuxUrbAlloc(pProxyDev, pHead);
    1318     if (!pNew)
    1319     {
    1320         usbProxyLinuxUrbFreeSplitList(pProxyDev, pHead);
    1321         return NULL;
    1322     }
    1323     Assert(pHead->pNext != pNew); Assert(pHead->pPrev != pNew); Assert(pNew->pNext == pNew->pPrev);
    1324     Assert(pNew->pSplitHead == pHead);
    1325     Assert(pNew->pSplitNext == NULL);
    1326 
    1327     pNew->KUrb = pHead->KUrb;
    1328     pNew->KUrb.buffer = pb + pCur->KUrb.buffer_length;
    1329     pNew->KUrb.buffer_length = RT_MIN(cbLeft, SPLIT_SIZE);
    1330     pNew->KUrb.actual_length = 0;
    1331 
    1332     cbLeft -= pNew->KUrb.buffer_length;
    1333     Assert(cbLeft < INT32_MAX);
    1334     pNew->cbSplitRemaining = cbLeft;
    1335     return pNew;
    1336 }
    1337 
    1338 /**
    1339  * Try splitting up a VUSB URB into smaller URBs which the
    1340  * linux kernel (usbfs) can deal with.
    1341  *
    1342  * NB: For ShortOK reads things get a little tricky - we don't
    1343  * know how much data is going to arrive and not all the
    1344  * fragment URBs might be filled. We can only safely set up one
    1345  * URB at a time -> worse performance but correct behaviour.
    1346  *
    1347  * @returns true / false.
    1348  * @param   pProxyDev   The proxy device.
    1349  * @param   pUrbLnx     The linux URB which was rejected because of being too big.
    1350  * @param   pUrb        The VUSB URB.
    1351  */
    1352 static int usbProxyLinuxUrbQueueSplit(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx, PVUSBURB pUrb)
    1353 {
    1354     /*
    1355      * Split it up into SPLIT_SIZE sized blocks.
    1356      */
    1357     const unsigned cKUrbs = (pUrb->cbData + SPLIT_SIZE - 1) / SPLIT_SIZE;
    1358     LogFlow(("usbProxyLinuxUrbQueueSplit: pUrb=%p cKUrbs=%d cbData=%d\n", pUrb, cKUrbs, pUrb->cbData));
    1359 
    1360     uint32_t cbLeft = pUrb->cbData;
    1361     uint8_t *pb = &pUrb->abData[0];
    1362 
    1363     /* the first one (already allocated) */
    1364     switch (pUrb->enmType)
    1365     {
    1366         default: /* shut up gcc */
    1367         case VUSBXFERTYPE_BULK: pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_BULK; break;
    1368         case VUSBXFERTYPE_INTR: pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_INTERRUPT; break;
    1369         case VUSBXFERTYPE_MSG:  pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_CONTROL; break;
    1370         case VUSBXFERTYPE_ISOC:
    1371             AssertMsgFailed(("We can't split isochronous URBs!\n"));
    1372             usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
    1373             return false;
    1374     }
    1375     pUrbLnx->KUrb.endpoint          = pUrb->EndPt;
    1376     if (pUrb->enmDir == VUSBDIRECTION_IN)
    1377         pUrbLnx->KUrb.endpoint |= 0x80;
    1378     pUrbLnx->KUrb.status            = 0;
    1379     pUrbLnx->KUrb.flags             = pUrb->fShortNotOk ? USBDEVFS_URB_SHORT_NOT_OK : 0; /* ISO_ASAP too? */
    1380     pUrbLnx->KUrb.buffer            = pb;
    1381     pUrbLnx->KUrb.buffer_length     = RT_MIN(cbLeft, SPLIT_SIZE);
    1382     pUrbLnx->KUrb.actual_length     = 0;
    1383     pUrbLnx->KUrb.start_frame       = 0;
    1384     pUrbLnx->KUrb.number_of_packets = 0;
    1385     pUrbLnx->KUrb.error_count       = 0;
    1386     pUrbLnx->KUrb.signr             = 0;
    1387     pUrbLnx->KUrb.usercontext       = pUrb;
    1388     pUrbLnx->pSplitHead = pUrbLnx;
    1389     pUrbLnx->pSplitNext = NULL;
    1390 
    1391     PUSBPROXYURBLNX pCur = pUrbLnx;
    1392 
    1393     cbLeft -= pUrbLnx->KUrb.buffer_length;
    1394     pUrbLnx->cbSplitRemaining = cbLeft;
    1395 
    1396     bool fSucceeded = false;
    1397     bool fUnplugged = false;
    1398     if (pUrb->enmDir == VUSBDIRECTION_IN && !pUrb->fShortNotOk)
    1399     {
    1400         /* Subsequent fragments will be queued only after the previous fragment is reaped
    1401          * and only if necessary.
    1402          */
    1403         fSucceeded = true;
    1404         Log(("usb-linux: Large ShortOK read, only queuing first fragment.\n"));
    1405         Assert(pUrbLnx->cbSplitRemaining > 0 && pUrbLnx->cbSplitRemaining < 256 * _1K);
    1406         fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pUrbLnx, pUrb, &fUnplugged);
    1407     }
    1408     else
    1409     {
    1410         /* the rest. */
    1411         unsigned i;
    1412         for (i = 1; i < cKUrbs; i++)
    1413         {
    1414             pCur = usbProxyLinuxSplitURBFragment(pProxyDev, pUrbLnx, pCur);
    1415             if (!pCur)
    1416             {
    1417                 return false;
    1418             }
    1419         }
    1420         Assert(pCur->cbSplitRemaining == 0);
    1421 
    1422         /* Submit the blocks. */
    1423         pCur = pUrbLnx;
    1424         for (i = 0; i < cKUrbs; i++, pCur = pCur->pSplitNext)
    1425         {
    1426             fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pCur, pUrb, &fUnplugged);
    1427             if (!fSucceeded)
    1428                 break;
    1429         }
    1430     }
    1431 
    1432     if (fSucceeded)
    1433     {
    1434         pUrb->Dev.pvPrivate = pUrbLnx;
    1435         LogFlow(("usbProxyLinuxUrbQueueSplit: ok\n"));
    1436         return true;
    1437     }
    1438 
    1439     usbProxyLinuxCleanupFailedSubmit(pProxyDev, pUrbLnx, pCur, pUrb, &fUnplugged);
    1440     return false;
    1441 }
    1442 
    1443 
    1444 /**
    1445  * @copydoc USBPROXYBACK::pfnUrbQueue
    1446  */
    1447 static int usbProxyLinuxUrbQueue(PVUSBURB pUrb)
    1448 {
    1449     unsigned        cTries;
    1450 #ifndef RDESKTOP
    1451     PUSBPROXYDEV    pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
    1452 #else
    1453     PUSBPROXYDEV    pProxyDev = usbProxyFromVusbDev(pUrb->pDev);
    1454 #endif
    1455     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    1456     LogFlow(("usbProxyLinuxUrbQueue: pProxyDev=%s pUrb=%p EndPt=%d cbData=%d\n",
    1457              usbProxyGetName(pProxyDev), pUrb, pUrb->EndPt, pUrb->cbData));
    1458 
    1459     /*
    1460      * Allocate a linux urb.
    1461      */
    1462     PUSBPROXYURBLNX pUrbLnx = usbProxyLinuxUrbAlloc(pProxyDev, NULL);
    1463     if (!pUrbLnx)
    1464         return false;
    1465 
    1466     pUrbLnx->KUrb.endpoint          = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
    1467     pUrbLnx->KUrb.status            = 0;
    1468     pUrbLnx->KUrb.flags             = pUrb->fShortNotOk ? USBDEVFS_URB_SHORT_NOT_OK : 0;
    1469     pUrbLnx->KUrb.buffer            = pUrb->abData;
    1470     pUrbLnx->KUrb.buffer_length     = pUrb->cbData;
    1471     pUrbLnx->KUrb.actual_length     = 0;
    1472     pUrbLnx->KUrb.start_frame       = 0;
    1473     pUrbLnx->KUrb.number_of_packets = 0;
    1474     pUrbLnx->KUrb.error_count       = 0;
    1475     pUrbLnx->KUrb.signr             = 0;
    1476     pUrbLnx->KUrb.usercontext       = pUrb;
    1477 
    1478     switch (pUrb->enmType)
    1479     {
    1480         case VUSBXFERTYPE_MSG:
    1481             pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_CONTROL;
    1482             if (pUrb->cbData < sizeof(VUSBSETUP))
    1483             {
    1484                 usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
    1485                 return false;
    1486             }
    1487             usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
    1488             LogFlow(("usbProxyLinuxUrbQueue: message\n"));
    1489             break;
    1490         case VUSBXFERTYPE_BULK:
    1491             pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_BULK;
    1492             break;
    1493         case VUSBXFERTYPE_ISOC:
    1494             pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_ISO;
    1495             pUrbLnx->KUrb.flags |= USBDEVFS_URB_ISO_ASAP;
    1496             pUrbLnx->KUrb.number_of_packets = pUrb->cIsocPkts;
    1497             unsigned i;
    1498             for (i = 0; i < pUrb->cIsocPkts; i++)
    1499             {
    1500                 pUrbLnx->KUrb.iso_frame_desc[i].length = pUrb->aIsocPkts[i].cb;
    1501                 pUrbLnx->KUrb.iso_frame_desc[i].actual_length = 0;
    1502                 pUrbLnx->KUrb.iso_frame_desc[i].status = 0x7fff;
    1503             }
    1504             break;
    1505         case VUSBXFERTYPE_INTR:
    1506             pUrbLnx->KUrb.type = USBDEVFS_URB_TYPE_INTERRUPT;
    1507             break;
    1508         default:
    1509             goto l_err;
    1510     }
    1511 
    1512     /*
    1513      * Submit it.
    1514      */
    1515     cTries = 0;
    1516     while (ioctl(pDevLnx->File, USBDEVFS_SUBMITURB, &pUrbLnx->KUrb))
    1517     {
    1518         if (errno == EINTR)
    1519             continue;
    1520         if (errno == ENODEV)
    1521         {
    1522             Log(("usbProxyLinuxUrbQueue: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
    1523             if (pUrb->enmType == VUSBXFERTYPE_MSG)
    1524                 usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
    1525             usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
    1526 
    1527             usbProxLinuxUrbUnplugged(pProxyDev);
    1528             return false;
    1529         }
    1530 
    1531         /*
    1532          * usbfs has or used to have a low buffer limit (16KB) in order to prevent
    1533          * processes wasting kmalloc'ed memory. It will return EINVAL if break that
    1534          * limit, and we'll have to split the VUSB URB up into multiple linux URBs.
    1535          *
    1536          * Since this is a limit which is subject to change, we cannot check for it
    1537          * before submitting the URB. We just have to try and fail.
    1538          */
    1539         if (    errno == EINVAL
    1540             &&  pUrb->cbData >= 8*_1K)
    1541             return usbProxyLinuxUrbQueueSplit(pProxyDev, pUrbLnx, pUrb);
    1542 
    1543         Log(("usb-linux: Queue URB %p -> %d!!! type=%d ep=%#x buffer_length=%#x cTries=%d\n",
    1544              pUrb, errno, pUrbLnx->KUrb.type, pUrbLnx->KUrb.endpoint, pUrbLnx->KUrb.buffer_length, cTries));
    1545         if (errno != EBUSY && ++cTries < 3) /* this doesn't work for the floppy :/ */
    1546             continue;
    1547 l_err:
    1548         if (pUrb->enmType == VUSBXFERTYPE_MSG)
    1549             usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
    1550         usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
    1551         return false;
    1552     }
    1553     pUrbLnx->u64SubmitTS = RTTimeMilliTS();
    1554 
    1555     LogFlow(("usbProxyLinuxUrbQueue: ok\n"));
    1556     pUrb->Dev.pvPrivate = pUrbLnx;
    1557     return true;
    1558 }
    1559 
    1560 
    1561 /**
    1562  * Check if any or the in-flight URBs are taking too long and should be cancelled.
    1563  *
    1564  * Cancelling is done in three turns, first a URB is marked for timeout if it's
    1565  * exceeding a certain time limit. Then the next time it's encountered it is actually
    1566  * cancelled. The idea now is that it's supposed to be reaped and returned in the next
    1567  * round of calls.
    1568  *
    1569  * @param   pProxyDev   The proxy device.
    1570  * @param   pDevLnx     The linux backend data.
    1571  *
    1572  * @todo    Make the HCI do proper timeout handling! Current timeout is 3 min and 20 seconds
    1573  *          as not to break bloomberg which queues IN packages with 3 min timeouts.
    1574  */
    1575 static void vusbProxyLinuxUrbDoTimeouts(PUSBPROXYDEV pProxyDev, PUSBPROXYDEVLNX pDevLnx)
    1576 {
    1577     RTCritSectEnter(&pDevLnx->CritSect);
    1578     uint64_t u64MilliTS = RTTimeMilliTS();
    1579     PUSBPROXYURBLNX pCur;
    1580     for (pCur = pDevLnx->pInFlightHead;
    1581          pCur;
    1582          pCur = pCur->pNext)
    1583     {
    1584         if (pCur->fTimedOut)
    1585         {
    1586             if (pCur->pSplitHead)
    1587             {
    1588                 /* split */
    1589                 Assert(pCur == pCur->pSplitHead);
    1590                 unsigned cFailures = 0;
    1591                 PUSBPROXYURBLNX pCur2;
    1592                 for (pCur2 = pCur; pCur2; pCur2 = pCur2->pSplitNext)
    1593                 {
    1594                     if (pCur2->fSplitElementReaped)
    1595                         continue;
    1596 
    1597                     if (    !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur2->KUrb, true, UINT32_MAX)
    1598                         ||  errno == ENOENT)
    1599                         pCur2->fCanceledByTimedOut = true;
    1600                     else if (errno != ENODEV)
    1601                         Log(("vusbProxyLinuxUrbDoTimeouts: pUrb=%p failed errno=%d (!!split!!)\n", pCur2->KUrb.usercontext, errno));
    1602                     else
    1603                         goto l_leave; /* ENODEV means break and everything cancelled elsewhere. */
    1604                 }
    1605                 LogRel(("USB: Cancelled URB (%p) after %llums!! (cFailures=%d)\n",
    1606                         pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS, cFailures));
    1607             }
    1608             else
    1609             {
    1610                 /* unsplit */
    1611                 if (    !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur->KUrb, true, UINT32_MAX)
    1612                     ||  errno == -ENOENT)
    1613                 {
    1614                     pCur->fCanceledByTimedOut = true;
    1615                     LogRel(("USB: Cancelled URB (%p) after %llums!!\n", pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS));
    1616                 }
    1617                 else if (errno != ENODEV)
    1618                     LogFlow(("vusbProxyLinuxUrbDoTimeouts: pUrb=%p failed errno=%d\n", pCur->KUrb.usercontext, errno));
    1619                 else
    1620                     goto l_leave; /* ENODEV means break and everything cancelled elsewhere. */
    1621             }
    1622         }
    1623 #if 0
    1624         /* Disabled for the time beeing as some USB devices have URBs pending for an unknown amount of time.
    1625          * One example is the OmniKey CardMan 3821. */
    1626         else if (u64MilliTS - pCur->u64SubmitTS >= 200*1000 /* 200 sec (180 sec has been observed with XP) */)
    1627             pCur->fTimedOut = true;
    1628 #endif
    1629     }
    1630 
    1631 l_leave:
    1632     RTCritSectLeave(&pDevLnx->CritSect);
    1633 }
    1634 
    1635 
    1636 /**
    1637  * Translate the linux status to a VUSB status.
    1638  *
    1639  * @remarks see cc_to_error in ohci.h, uhci_map_status in uhci-q.c,
    1640  *          sitd_complete+itd_complete in ehci-sched.c, and qtd_copy_status in
    1641  *          ehci-q.c.
    1642  */
    1643 static VUSBSTATUS vusbProxyLinuxStatusToVUsbStatus(int iStatus)
    1644 {
    1645     switch (iStatus)
    1646     {
    1647         /** @todo VUSBSTATUS_NOT_ACCESSED */
    1648         case -EXDEV: /* iso transfer, partial result. */
    1649         case 0:
    1650             return VUSBSTATUS_OK;
    1651 
    1652         case -EILSEQ:
    1653             return VUSBSTATUS_CRC;
    1654 
    1655         case -EREMOTEIO: /* ehci and ohci uses this for underflow error. */
    1656             return VUSBSTATUS_DATA_UNDERRUN;
    1657         case -EOVERFLOW:
    1658             return VUSBSTATUS_DATA_OVERRUN;
    1659 
    1660         case -ETIME:
    1661         case -ENODEV:
    1662             return VUSBSTATUS_DNR;
    1663 
    1664         //case -ECOMM:
    1665         //    return VUSBSTATUS_BUFFER_OVERRUN;
    1666         //case -ENOSR:
    1667         //    return VUSBSTATUS_BUFFER_UNDERRUN;
    1668 
    1669         //case -EPROTO:
    1670         //    return VUSBSTATUS_BIT_STUFFING;
    1671 
    1672         case -EPIPE:
    1673             Log(("vusbProxyLinuxStatusToVUsbStatus: STALL/EPIPE!!\n"));
    1674             return VUSBSTATUS_STALL;
    1675 
    1676         case -ESHUTDOWN:
    1677             Log(("vusbProxyLinuxStatusToVUsbStatus: SHUTDOWN!!\n"));
    1678             return VUSBSTATUS_STALL;
    1679 
    1680         default:
    1681             Log(("vusbProxyLinuxStatusToVUsbStatus: status %d!!\n", iStatus));
    1682             return VUSBSTATUS_STALL;
    1683     }
    1684 }
    1685 
    1686 
    1687 /**
    1688  * Get and translates the linux status to a VUSB status.
    1689  */
    1690 static VUSBSTATUS vusbProxyLinuxUrbGetStatus(PUSBPROXYURBLNX pUrbLnx)
    1691 {
    1692     if (    pUrbLnx->fCanceledByTimedOut
    1693         &&  pUrbLnx->KUrb.status == 0)
    1694         return VUSBSTATUS_CRC;
    1695     return vusbProxyLinuxStatusToVUsbStatus(pUrbLnx->KUrb.status);
    1696 }
    1697 
    1698 
    1699 /**
    1700  * Reap URBs in-flight on a device.
    1701  *
    1702  * @returns Pointer to a completed URB.
    1703  * @returns NULL if no URB was completed.
    1704  * @param   pProxyDev   The device.
    1705  * @param   cMillies    Number of milliseconds to wait. Use 0 to not wait at all.
    1706  */
    1707 static PVUSBURB usbProxyLinuxUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
    1708 {
    1709     PUSBPROXYURBLNX pUrbLnx = NULL;
    1710     PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
    1711 
    1712     /*
    1713      * Any URBs pending delivery?
    1714      */
    1715     if (pDevLnx->pTaxingHead)
    1716     {
    1717         RTCritSectEnter(&pDevLnx->CritSect);
    1718         pUrbLnx = pDevLnx->pTaxingHead;
    1719         if (pUrbLnx)
    1720         {
    1721             /* unlink from the pending delivery list */
    1722             if (pUrbLnx->pNext)
    1723             {
    1724                 pUrbLnx->pNext->pPrev = NULL;
    1725                 pDevLnx->pTaxingHead = pUrbLnx->pNext;
    1726             }
    1727             else
    1728                 pDevLnx->pTaxingHead = pDevLnx->pTaxingTail = NULL;
    1729 
    1730             /* temporarily into the active list, so free works right. */
    1731             pUrbLnx->pPrev = NULL;
    1732             pUrbLnx->pNext = pDevLnx->pInFlightHead;
    1733             if (pUrbLnx->pNext)
    1734                 pUrbLnx->pNext->pPrev = pUrbLnx;
    1735             pDevLnx->pInFlightHead = pUrbLnx;
    1736         }
    1737         RTCritSectLeave(&pDevLnx->CritSect);
    1738     }
    1739     if (!pUrbLnx)
    1740     {
    1741         /*
    1742          * Don't block if nothing is in the air.
    1743          */
    1744         if (!pDevLnx->pInFlightHead)
    1745             return NULL;
    1746 
    1747         /*
    1748          * Block for requested period.
    1749          *
    1750          * It seems to me that the path of poll() is shorter and
    1751          * involves less semaphores than ioctl() on usbfs. So, we'll
    1752          * do a poll regardless of whether cMillies == 0 or not.
    1753          */
    1754         if (cMillies)
    1755         {
    1756 
    1757             for (;;)
    1758             {
    1759                 struct pollfd pfd;
    1760                 int rc;
    1761 
    1762                 pfd.fd = pDevLnx->File;
    1763                 pfd.events = POLLOUT | POLLWRNORM /* completed async */
    1764                            | POLLERR | POLLHUP    /* disconnected */;
    1765                 pfd.revents = 0;
    1766                 rc = poll(&pfd, 1, cMillies);
    1767                 Log(("usbProxyLinuxUrbReap: poll rc = %d\n", rc));
    1768                 if (rc >= 1)
    1769                     break;
    1770                 if (rc >= 0 /*|| errno == ETIMEOUT*/)
    1771                 {
    1772                     vusbProxyLinuxUrbDoTimeouts(pProxyDev, pDevLnx);
    1773                     return NULL;
    1774                 }
    1775                 if (errno != EAGAIN)
    1776                 {
    1777                     Log(("usb-linux: Reap URB - poll -> %d errno=%d pProxyDev=%s\n", rc, errno, usbProxyGetName(pProxyDev)));
    1778                     return NULL;
    1779                 }
    1780                 Log(("usbProxyLinuxUrbReap: poll again - weird!!!\n"));
    1781             }
    1782         }
    1783 
    1784         /*
    1785          * Reap URBs, non-blocking.
    1786          */
    1787         for (;;)
    1788         {
    1789             struct usbdevfs_urb *pKUrb;
    1790             while (ioctl(pDevLnx->File, USBDEVFS_REAPURBNDELAY, &pKUrb))
    1791                 if (errno != EINTR)
    1792                 {
    1793                     if (errno == ENODEV)
    1794                         usbProxLinuxUrbUnplugged(pProxyDev);
    1795                     else if (errno == EAGAIN)
    1796                         vusbProxyLinuxUrbDoTimeouts(pProxyDev, pDevLnx);
    1797                     else
    1798                         Log(("usb-linux: Reap URB. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1799                     return NULL;
    1800                 }
    1801             pUrbLnx = (PUSBPROXYURBLNX)pKUrb;
    1802 
    1803             /* split list: Is the entire split list done yet? */
    1804             if (pUrbLnx->pSplitHead)
    1805             {
    1806                 pUrbLnx->fSplitElementReaped = true;
    1807 
    1808                 /* for variable size URBs, we may need to queue more if the just-reaped URB was completely filled */
    1809                 if (pUrbLnx->cbSplitRemaining && (pKUrb->actual_length == pKUrb->buffer_length) && !pUrbLnx->pSplitNext)
    1810                 {
    1811                     bool fUnplugged = false;
    1812                     bool fSucceeded;
    1813 
    1814                     Assert(pUrbLnx->pSplitHead);
    1815                     Assert((pKUrb->endpoint & 0x80) && (!pKUrb->flags & USBDEVFS_URB_SHORT_NOT_OK));
    1816                     PUSBPROXYURBLNX pNew = usbProxyLinuxSplitURBFragment(pProxyDev, pUrbLnx->pSplitHead, pUrbLnx);
    1817                     if (!pNew)
    1818                     {
    1819                         Log(("usb-linux: Allocating URB fragment failed. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
    1820                         return NULL;
    1821                     }
    1822                     PVUSBURB pUrb = (PVUSBURB)pUrbLnx->KUrb.usercontext;
    1823                     fSucceeded = usbProxyLinuxSubmitURB(pProxyDev, pNew, pUrb, &fUnplugged);
    1824                     if (fUnplugged)
    1825                         usbProxLinuxUrbUnplugged(pProxyDev);
    1826                     if (!fSucceeded)
    1827                         return NULL;
    1828                     continue;   /* try reaping another URB */
    1829                 }
    1830                 PUSBPROXYURBLNX pCur;
    1831                 for (pCur = pUrbLnx->pSplitHead; pCur; pCur = pCur->pSplitNext)
    1832                     if (!pCur->fSplitElementReaped)
    1833                     {
    1834                         pUrbLnx = NULL;
    1835                         break;
    1836                     }
    1837                 if (!pUrbLnx)
    1838                     continue;
    1839                 pUrbLnx = pUrbLnx->pSplitHead;
    1840             }
    1841             break;
    1842         }
    1843     }
    1844 
    1845     /*
    1846      * Ok, we got one!
    1847      */
    1848     PVUSBURB pUrb = (PVUSBURB)pUrbLnx->KUrb.usercontext;
    1849     if (    pUrb
    1850         &&  !pUrbLnx->fCanceledBySubmit)
    1851     {
    1852         if (pUrbLnx->pSplitHead)
    1853         {
    1854             /* split - find the end byte and the first error status. */
    1855             Assert(pUrbLnx == pUrbLnx->pSplitHead);
    1856             uint8_t *pbEnd = &pUrb->abData[0];
    1857             pUrb->enmStatus = VUSBSTATUS_OK;
    1858             PUSBPROXYURBLNX pCur;
    1859             for (pCur = pUrbLnx; pCur; pCur = pCur->pSplitNext)
    1860             {
    1861                 if (pCur->KUrb.actual_length)
    1862                     pbEnd = (uint8_t *)pCur->KUrb.buffer + pCur->KUrb.actual_length;
    1863                 if (pUrb->enmStatus == VUSBSTATUS_OK)
    1864                     pUrb->enmStatus = vusbProxyLinuxUrbGetStatus(pCur);
    1865             }
    1866             pUrb->cbData = pbEnd - &pUrb->abData[0];
    1867             usbProxyLinuxUrbFreeSplitList(pProxyDev, pUrbLnx);
    1868         }
    1869         else
    1870         {
    1871             /* unsplit. */
    1872             pUrb->enmStatus = vusbProxyLinuxUrbGetStatus(pUrbLnx);
    1873             pUrb->cbData = pUrbLnx->KUrb.actual_length;
    1874             if (pUrb->enmType == VUSBXFERTYPE_ISOC)
    1875             {
    1876                 unsigned i, off;
    1877                 for (i = 0, off = 0; i < pUrb->cIsocPkts; i++)
    1878                 {
    1879                     pUrb->aIsocPkts[i].enmStatus = vusbProxyLinuxStatusToVUsbStatus(pUrbLnx->KUrb.iso_frame_desc[i].status);
    1880                     Assert(pUrb->aIsocPkts[i].off == off);
    1881                     pUrb->aIsocPkts[i].cb = pUrbLnx->KUrb.iso_frame_desc[i].actual_length;
    1882                     off += pUrbLnx->KUrb.iso_frame_desc[i].length;
    1883                 }
    1884             }
    1885             usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
    1886         }
    1887         pUrb->Dev.pvPrivate = NULL;
    1888 
    1889         /* some adjustments for message transfers. */
    1890         if (pUrb->enmType == VUSBXFERTYPE_MSG)
    1891         {
    1892             pUrb->cbData += sizeof(VUSBSETUP);
    1893             usbProxyLinuxUrbSwapSetup((PVUSBSETUP)pUrb->abData);
    1894         }
    1895     }
    1896     else
    1897     {
    1898         usbProxyLinuxUrbFree(pProxyDev, pUrbLnx);
    1899         pUrb = NULL;
    1900     }
    1901 
    1902     LogFlow(("usbProxyLinuxUrbReap: pProxyDev=%s returns %p\n", usbProxyGetName(pProxyDev), pUrb));
    1903     return pUrb;
    1904 }
    1905 
    1906 
    1907 /**
    1908  * Cancels the URB.
    1909  * The URB requires reaping, so we don't change its state.
    1910  */
    1911 static void usbProxyLinuxUrbCancel(PVUSBURB pUrb)
    1912 {
    1913 #ifndef RDESKTOP
    1914     PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
    1915 #else
    1916     PUSBPROXYDEV pProxyDev = usbProxyFromVusbDev(pUrb->pDev);
    1917 #endif
    1918     PUSBPROXYURBLNX pUrbLnx = (PUSBPROXYURBLNX)pUrb->Dev.pvPrivate;
    1919     if (pUrbLnx->pSplitHead)
    1920     {
    1921         /* split */
    1922         Assert(pUrbLnx == pUrbLnx->pSplitHead);
    1923         PUSBPROXYURBLNX pCur;
    1924         for (pCur = pUrbLnx; pCur; pCur = pCur->pSplitNext)
    1925         {
    1926             if (pCur->fSplitElementReaped)
    1927                 continue;
    1928             if (    !usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pCur->KUrb, true, UINT32_MAX)
    1929                 ||  errno == ENOENT)
    1930                 continue;
    1931             if (errno == ENODEV)
    1932                 break;
    1933             Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!! (split)\n",
    1934                  pUrb, errno, usbProxyGetName(pProxyDev)));
    1935         }
    1936     }
    1937     else
    1938     {
    1939         /* unsplit */
    1940         if (    usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_DISCARDURB, &pUrbLnx->KUrb, true, UINT32_MAX)
    1941             &&  errno != ENODEV /* deal with elsewhere. */
    1942             &&  errno != ENOENT)
    1943             Log(("usb-linux: Discard URB %p failed, errno=%d. pProxyDev=%s!!!\n",
    1944                  pUrb, errno, usbProxyGetName(pProxyDev)));
    1945     }
    1946 }
    1947 
    1948 
    1949 /**
    1950  * The Linux USB Proxy Backend.
    1951  */
    1952 const USBPROXYBACK g_USBProxyDeviceHost =
    1953 {
    1954     "host",
    1955     usbProxyLinuxOpen,
    1956     usbProxyLinuxInit,
    1957     usbProxyLinuxClose,
    1958     usbProxyLinuxReset,
    1959     usbProxyLinuxSetConfig,
    1960     usbProxyLinuxClaimInterface,
    1961     usbProxyLinuxReleaseInterface,
    1962     usbProxyLinuxSetInterface,
    1963     usbProxyLinuxClearHaltedEp,
    1964     usbProxyLinuxUrbQueue,
    1965     usbProxyLinuxUrbCancel,
    1966     usbProxyLinuxUrbReap,
    1967     0
    1968 };
    1969 
    1970 
    1971 /*
    1972  * Local Variables:
    1973  *  mode: c
    1974  *  c-file-style: "bsd"
    1975  *  c-basic-offset: 4
    1976  *  tab-width: 4
    1977  *  indent-tabs-mode: s
    1978  * End:
    1979  */
    1980 
     18#include "../../../Devices/USB/linux/USBProxyDevice-linux.cpp"
  • trunk/src/VBox/RDP/client/vrdp/runtime.h

    r31354 r31557  
    4848
    4949#define OPSTATIC
    50 // #define RDPUSB_DEBUG
     50#define RDPUSB_DEBUG
    5151#ifdef RDPUSB_DEBUG
    5252#define DoLog(a) do { \
    53         printf("Time %llu: ", RTTimeMilliTS()); \
     53        printf("Time %llu: ", (long long unsigned) RTTimeMilliTS()); \
    5454        printf a; \
    5555} while(0)
     
    8989#define VINF_SUCCESS 0
    9090#define VERR_NO_MEMORY        (-8)
     91#define VERR_INVALID_POINTER  (-6)
    9192#define VERR_UNRESOLVED_ERROR (-35)
    9293#define VERR_NOT_SUPPORTED    (-37)
    9394#define VERR_ACCESS_DENIED    (-38)
    9495#define VERR_VUSB_USBFS_PERMISSION (-2005)
     96
     97static inline const char *RTErrGetShort(int iErr)
     98{
     99    return   iErr == VINF_SUCCESS               ? "VINF_SUCCESS"
     100           : iErr == VERR_NO_MEMORY             ? "VERR_NO_MEMORY"
     101           : iErr == VERR_INVALID_POINTER       ? "VERR_INVALID_POINTER"
     102           : iErr == VERR_UNRESOLVED_ERROR      ? "VERR_UNRESOLVED_ERROR"
     103           : iErr == VERR_NOT_SUPPORTED         ? "VERR_NOT_SUPPORTED"
     104           : iErr == VERR_ACCESS_DENIED         ? "VERR_ACCESS_DENIED"
     105           : iErr == VERR_VUSB_USBFS_PERMISSION ? "VERR_VUSB_USBFS_PERMISSION"
     106           : "Unknown error";
     107}
    95108
    96109static inline int RTErrConvertFromErrno(int iErrno)
     
    136149#define NOREF(_a) ((void)_a)
    137150
     151#define VALID_PTR(ptr) ((ptr) != NULL)
     152
    138153#define RT_C_DECLS_BEGIN
    139154#define RT_C_DECLS_END
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette