VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/linux/USBProxyDevice-linux.cpp@ 31558

Last change on this file since 31558 was 31558, checked in by vboxsync, 14 years ago

Devices/USB and RDP/client: things that should not have been in r64661

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

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