VirtualBox

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

Last change on this file since 52254 was 52254, checked in by vboxsync, 11 years ago

Devices/USB: Several fixes and misc cleanups, the VM crash when detaching a USB device while transfering data should be fixed, likewise several assertions in debug builds should be fixed now. Removed a bit dead code in the linux backend (timeout handling which wasn't active)

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

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