Changeset 31557 in vbox
- Timestamp:
- Aug 11, 2010 9:15:04 AM (15 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 4 added
- 2 deleted
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Makefile.kmk
r31551 r31557 1166 1166 1167 1167 # 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 from1171 # the first line of the files (svn keywords).1172 # If you are updating the code, build with VBOX_WITH_TESTCASES= as long as you1173 # 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.run1178 OTHERS += $(PATH_Drivers)/tstSameUSBProxyDevLinux.run1179 VBOX_PRX_DEV_LNX = $(PATH_ROOT)/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp1180 VRDP_PRX_DEV_LNX = $(PATH_ROOT)/src/VBox/RDP/client/vrdp/USBProxyDevice-linux.c1181 $$(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 + !SDK1187 endif1188 1189 1190 #1191 1168 # Internal Networking - Ring-3 Testcase for the Ring-0 code (a bit hackish). 1192 1169 # -
trunk/src/VBox/RDP/client/Makefile.kmk
r28800 r31557 21 21 # Globals 22 22 VBOX_PATH_RDESKTOP_SRC := $(PATH_SUB_CURRENT) 23 VBOX_PATH_DEVICES_USB := $(PATH_ROOT)/src/VBox/Devices/USB 23 24 VBOX_RDESKTOP_SRC_SUBDIR = rdesktop-1.6.0-vrdp 24 25 … … 92 93 vrdp/rdpusb.c \ 93 94 vrdp/USBProxyDevice-linux.c 95 rdesktop-vrdp_INCS += \ 96 $(VBOX_PATH_RDESKTOP_SRC) \ 97 $(VBOX_PATH_RDESKTOP_SRC)/vrdp \ 98 $(VBOX_PATH_DEVICES_USB) \ 99 $(PATH_ROOT)/include/VBox 94 100 # @todo implement usb proxy for Solaris 95 101 rdesktop-vrdp_SOURCES.solaris = \ … … 120 126 ## @todo change this to an INSTALLS target. 121 127 OTHERS += $(PATH_BIN)/rdesktop-vrdp.tar.gz 122 OTHER_CLEAN += $(OTHERS) $(PATH_TARGET)/$(VBOX_RDESKTOP_SRC_SUBDIR)128 OTHER_CLEAN += $(OTHERS) 123 129 124 130 125 131 include $(KBUILD_PATH)/subfooter.kmk 126 132 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 133 INSTALLS += rdesktop-bin 134 rdesktop-bin_INST = obj/$(VBOX_RDESKTOP_SRC_SUBDIR) 135 rdesktop-bin_MODE = a+rx,u+w 136 rdesktop-bin_SOURCES = \ 137 $(foreach i,configure \ 138 config.sub \ 139 config.guess \ 140 bootstrap \ 141 install-sh, \ 142 client/$i=>$i) 160 143 161 $(PATH_TARGET)/$(VBOX_RDESKTOP_SRC_SUBDIR): 162 $(MKDIR) -p $(@D) 163 $(LN_SYMLINK) $(abspath $(VBOX_PATH_RDESKTOP_SRC)) $@ 144 INSTALLS += rdesktop-nonbin 145 rdesktop-nonbin_INST = obj/$(VBOX_RDESKTOP_SRC_SUBDIR) 146 rdesktop-nonbin_MODE = a+r,u+w 147 rdesktop-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))) 164 179 165 180 $(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 168 183 $(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 16 16 */ 17 17 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 48 48 49 49 #define OPSTATIC 50 //#define RDPUSB_DEBUG50 #define RDPUSB_DEBUG 51 51 #ifdef RDPUSB_DEBUG 52 52 #define DoLog(a) do { \ 53 printf("Time %llu: ", RTTimeMilliTS()); \53 printf("Time %llu: ", (long long unsigned) RTTimeMilliTS()); \ 54 54 printf a; \ 55 55 } while(0) … … 89 89 #define VINF_SUCCESS 0 90 90 #define VERR_NO_MEMORY (-8) 91 #define VERR_INVALID_POINTER (-6) 91 92 #define VERR_UNRESOLVED_ERROR (-35) 92 93 #define VERR_NOT_SUPPORTED (-37) 93 94 #define VERR_ACCESS_DENIED (-38) 94 95 #define VERR_VUSB_USBFS_PERMISSION (-2005) 96 97 static 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 } 95 108 96 109 static inline int RTErrConvertFromErrno(int iErrno) … … 136 149 #define NOREF(_a) ((void)_a) 137 150 151 #define VALID_PTR(ptr) ((ptr) != NULL) 152 138 153 #define RT_C_DECLS_BEGIN 139 154 #define RT_C_DECLS_END
Note:
See TracChangeset
for help on using the changeset viewer.