USBProxyDevice-linux.cpp revision 8484c4787af17f5d59803f389274826754bfc23b
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * USB device proxy - the Linux backend.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Copyright (C) 2006-2010 Oracle Corporation
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * available from http://www.virtualbox.org. This file is free software;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * General Public License (GPL) as published by the Free Software
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/*******************************************************************************
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync* Defined Constants And Macros *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync*******************************************************************************/
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/** Define NO_PORT_RESET to skip the slow and broken linux port reset.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Resetting will break PalmOne. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/** Define NO_LOGICAL_RECONNECT to skip the broken logical reconnect handling. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/*******************************************************************************
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync* Header Files *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync*******************************************************************************/
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Backlevel 2.4 headers doesn't have these two defines.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * They were added some time between 2.4.21 and 2.4.26, probably in 2.4.23.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync# define USBDEVFS_URB_SHORT_NOT_OK 0 /* rhel3 doesn't have this. darn! */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/* FedoraCore 4 does not have the bit defined by default. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync# define RTCRITSECT void *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic inline int rtcsNoop() { return VINF_SUCCESS; }
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#if defined(NO_PORT_RESET) && !defined(NO_LOGICAL_RECONNECT)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/*******************************************************************************
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync* Structures and Typedefs *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync*******************************************************************************/
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Wrapper around the linux urb request structure.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This is required to track in-flight and landed URBs.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The kernel URB data */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Space filler for the isochronous packets. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync struct usbdevfs_iso_packet_desc aIsocPktsDonUseTheseUseTheOnesInKUrb[8];
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The millisecond timestamp when this URB was submitted. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Pointer to the next linux URB. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Pointer to the previous linux URB. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** If we've split the VUSBURB up into multiple linux URBs, this is points to the head. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The next linux URB if split up. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Whether it has timed out and should be shot down on the next failing reap call. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Indicates that this URB has been canceled by timeout and should return an CRC error. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /** Don't report these back. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /** This split element is reaped. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /** Size to transfer in remaining fragments of a split URB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Data for the linux usb proxy backend.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The open file. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Critical section protecting the two lists. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The list of free linux URBs. Singly linked. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The list of active linux URBs. Doubly linked.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * We must maintain this so we can properly reap URBs of a detached device.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Only the split head will appear in this list. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The list of landed linux URBs. Doubly linked.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Only the split head will appear in this list. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The tail of the landed linux URBs. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Are we using sysfs to find the active configuration? */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The device node/sysfs path of the device.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Used to figure out the configuration after a reset. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/*******************************************************************************
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync* Internal Functions *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync*******************************************************************************/
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxLinuxUrbUnplugged(PUSBPROXYDEV pProxyDev);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxyLinuxSetConnected(PUSBPROXYDEV pProyxDev, int iIf, bool fConnect, bool fQuiet);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pSplitHead);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Wrapper for the ioctl call.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This wrapper will repeate the call if we get an EINTR or EAGAIN. It can also
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * handle ENODEV (detached device) errors.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns whatever ioctl returns.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pProxyDev The proxy device.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param iCmd The ioctl command / function.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pvArg The ioctl argument / data.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param fHandleNoDev Whether to handle ENODEV.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param cTries The number of retries. Use UINT32_MAX for (kind of) indefinite retries.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @internal
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync Log(("usb-linux: ENODEV -> unplugged. pProxyDev=%s\n", usbProxyGetName(pProxyDev)));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync } while (cTries-- > 0);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * The device has been unplugged.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Cancel all in-flight URBs and put them up for reaping.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxLinuxUrbUnplugged(PUSBPROXYDEV pProxyDev)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Shoot down all flying URBs.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync ioctl(pDevLnx->File, USBDEVFS_DISCARDURB, &pCur->KUrb); /* not sure if this is required.. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* insert into the taxing list. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* Append the URBs we shot down to the taxing queue. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pDevLnx->pTaxingTail = pDevLnx->pTaxingHead = pUrbTaxing;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Set the connect state seen by kernel drivers
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @internal
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxyLinuxSetConnected(PUSBPROXYDEV pProxyDev, int iIf, bool fConnect, bool fQuiet)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync LogFlow(("usbProxyLinuxSetConnected: pProxyDev=%s iIf=%#x fConnect=%s\n",
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync usbProxyGetName(pProxyDev), iIf, fConnect ? "true" : "false"));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync IoCtl.ioctl_code = fConnect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync if ( usbProxyLinuxDoIoCtl(pProxyDev, USBDEVFS_IOCTL, &IoCtl, true, UINT32_MAX)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync Log(("usbProxyLinuxSetConnected: failure, errno=%d. pProxyDev=%s\n",
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Allocates a linux URB request structure.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns Pointer to an active URB request.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns NULL on failure.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pProxyDev The proxy device instance.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pSplitHead The split list head if allocating for a split list.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic PUSBPROXYURBLNX usbProxyLinuxUrbAlloc(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pSplitHead)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Try remove a linux URB from the free list, if none there allocate a new one.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pUrbLnx = (PUSBPROXYURBLNX)RTMemAlloc(sizeof(*pUrbLnx));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Link it into the active list
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pUrbLnx->pPrev = pUrbLnx->pNext = (PUSBPROXYURBLNX)0xdead;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Frees a linux URB request structure.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pProxyDev The proxy device instance.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pUrbLnx The linux URB to free.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxyLinuxUrbFree(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Remove from the active list.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Link it into the free list.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Frees split list of a linux URB request structure.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pProxyDev The proxy device instance.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pUrbLnx A linux URB to in the split list to be freed.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void usbProxyLinuxUrbFreeSplitList(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx)
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This finds the device in the /proc/bus/usb/bus/addr file and finds
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * the config with an asterix.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns The Cfg#.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns -1 if no active config.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pszDevNode The path to the device. We infere the location of
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * the devices file, which bus and device number we're
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * looking for.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param iFirstCfg The first configuration. (optional)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @internal
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxFindActiveConfigUsbfs(PUSBPROXYDEV pProxyDev, const char *pszDevNode, int *piFirstCfg)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Set return defaults.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Parse the usbfs device node path and turn it into a path to the "devices" file,
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * picking up the device number and bus along the way.
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync char *pszDevices = (char *)RTMemDupEx(pszDevNode, cchDevNode, sizeof("devices"));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* the device number */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync int rc = RTStrToUInt32Ex(psz + 1, NULL, 10, &uDev);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* the bus number */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Open and scan the devices file.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * We're ASSUMING that each device starts off with a 'T:' line.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (RT_SUCCESS(RTStrmGetLine(pFile, szLine, sizeof(szLine))))
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* we're only interested in 'T:' lines. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* Skip ahead to 'Bus' and compare */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync psz = RTStrStripL(psz + 2); Assert(!strncmp(psz, "Bus=", 4));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u); AssertRC(rc);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* Skip ahead to 'Dev#' and compare */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u); AssertRC(rc);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Ok, we've found the device.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Scan until we find a selected configuration, the next device, or EOF.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (RT_SUCCESS(RTStrmGetLine(pFile, szLine, sizeof(szLine))))
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* Get the 'Cfg#' value. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = RTStrToUInt32Ex(psz, &pszNext, 10, &u); AssertRC(rc);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This finds the active configuration from sysfs.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns The Cfg#.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns -1 if no active config.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pszPath The sysfs path for the device.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param piFirstCfg The first configuration. (optional)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @internal
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxFindActiveConfigSysfs(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync ? pProxyDev->paCfgDescs[0].Core.bConfigurationValue
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync return RTLinuxSysFsReadIntFile(10, "%s/bConfigurationValue", pszPath); /* returns -1 on failure */
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync#else /* !VBOX_USB_WITH_SYSFS */
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync#endif /* !VBOX_USB_WITH_SYSFS */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * This finds the active configuration.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns The Cfg#.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns -1 if no active config.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pszPath The sysfs path for the device, or the usbfs device
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * node path.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param iFirstCfg The first configuration. (optional)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @internal
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxFindActiveConfig(PUSBPROXYDEV pProxyDev, const char *pszPath, int *piFirstCfg)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync return usbProxyLinuxFindActiveConfigSysfs(pProxyDev, pszPath, piFirstCfg);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync return usbProxyLinuxFindActiveConfigUsbfs(pProxyDev, pszPath, piFirstCfg);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Extracts the Linux file descriptor associated with the kernel USB device.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This is used by rdesktop-vrdp for polling for events.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns the FD, or asserts and returns -1 on error
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pProxyDev The device instance
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncRTDECL(int) USBProxyDeviceLinuxGetFD(PUSBPROXYDEV pProxyDev)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)pProxyDev->Backend.pv;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Opens the device file.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns VBox status code.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pProxyDev The device instance.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pszAddress If we are using usbfs, this is the path to the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * device. If we are using sysfs, this is a string of
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * the form "sysfs:<sysfs path>//device:<device node>".
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * In the second case, the two paths are guaranteed
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * not to contain the substring "//".
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pvBackend Backend specific pointer, unused for the linux backend.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int usbProxyLinuxOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync LogFlow(("usbProxyLinuxOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync const char *pszPath;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Are we using sysfs or usbfs?
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync fUsingSysfs = strncmp(pszAddress, "sysfs:", sizeof("sysfs:") - 1) == 0;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync LogRel(("usbProxyLinuxOpen: Invalid device address: '%s'\n", pszAddress));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#endif /* VBOX_USB_WITH_SYSFS */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Try open the device node.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync int rc = RTFileOpen(&File, pszDevNode, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Allocate and initialize the linux backend data.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PUSBPROXYDEVLNX pDevLnx = (PUSBPROXYDEVLNX)RTMemAllocZVar(sizeof(*pDevLnx) + cchPath);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync LogFlow(("usbProxyLinuxOpen(%p, %s): returns successfully File=%d iActiveCfg=%d\n",
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pProxyDev, pszAddress, pDevLnx->File, pProxyDev->iActiveCfg));
return rc;
unsigned iIf;
int iFirstCfg;
Log(("usbProxyLinuxInit: No active config! Tried to set %d: iActiveCfg=%d\n", iFirstCfg, pProxyDev->iActiveCfg));
return VINF_SUCCESS;
if (!pDevLnx)
unsigned iIf;
while (pCur)
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",
pDev, pDev->Info.bBus, pDev->Info.bDevNum, pDev->Info.idVendor, pDev->Info.idProduct, pDev->Info.bcdDevice,
if (!RTThreadYield())
if (!pFile)
return VERR_FILE_NOT_FOUND;
int rc;
int got = 0;
switch ( buf[0] ) {
Log2(("usb_reset_logical_reconnect: {.bBus=%#x, .bDevNum=%#x, .idVendor=%#x, .idProduct=%#x, .bcdDevice=%#x, .u64SerialHash=%#llx, .bDevNumParent=%#x, .bPort=%#x, .bLevel=%#x}\n",
id.bBus, id.bDevNum, id.idVendor, id.idProduct, id.bcdDevice, id.u64SerialHash, id.bDevNumParent, id.bPort, id.bLevel));
goto l_found;
got = 0;
psz++;
got++;
got++;
return VINF_SUCCESS;
if (rc < 0) {
return VERR_GENERAL_FAILURE;
#ifdef NO_PORT_RESET
if ( !fResetOnLinux
# ifndef NO_LOGICAL_RECONNECT
# ifndef NO_LOGICAL_RECONNECT
return VINF_SUCCESS;
# ifndef NO_LOGICAL_RECONNECT
return VINF_SUCCESS;
LogFlow(("usbProxyLinuxClaimInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
LogFlow(("usbProxyLinuxReleaseInterface: pProxyDev=%s ifnum=%#x\n", usbProxyGetName(pProxyDev), iIf));
LogFlow(("usbProxyLinuxClearHaltedEp: pProxyDev=%s EndPt=%u\n", usbProxyGetName(pProxyDev), EndPt));
static void usbProxyLinuxCleanupFailedSubmit(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx, PUSBPROXYURBLNX pCur, PVUSBURB pUrb, bool *pfUnplugged)
*pfUnplugged = true;
LogRel(("USB: Failed to discard %p! errno=%d (pUrb=%p)\n", pUrbLnx->KUrb.usercontext, errno, pUrb)); /* serious! */
while (pCur)
if (*pfUnplugged)
static bool usbProxyLinuxSubmitURB(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pCur, PVUSBURB pUrb, bool *pfUnplugged)
unsigned cTries = 0;
*pfUnplugged = true;
static PUSBPROXYURBLNX usbProxyLinuxSplitURBFragment(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pHead, PUSBPROXYURBLNX pCur)
if (!pNew)
return NULL;
return pNew;
static int usbProxyLinuxUrbQueueSplit(PUSBPROXYDEV pProxyDev, PUSBPROXYURBLNX pUrbLnx, PVUSBURB pUrb)
case VUSBXFERTYPE_ISOC:
bool fSucceeded = false;
bool fUnplugged = false;
fSucceeded = true;
if (!pCur)
if (!fSucceeded)
if (fSucceeded)
unsigned cTries;
#ifndef RDESKTOP
if (!pUrbLnx)
case VUSBXFERTYPE_MSG:
case VUSBXFERTYPE_BULK:
case VUSBXFERTYPE_ISOC:
case VUSBXFERTYPE_INTR:
goto l_err;
cTries = 0;
pCur;
unsigned cFailures = 0;
Log(("vusbProxyLinuxUrbDoTimeouts: pUrb=%p failed errno=%d (!!split!!)\n", pCur2->KUrb.usercontext, errno));
LogRel(("USB: Cancelled URB (%p) after %llums!!\n", pCur->KUrb.usercontext, (long long unsigned) u64MilliTS - pCur->u64SubmitTS));
/* Disabled for the time beeing as some USB devices have URBs pending for an unknown amount of time.
else if (u64MilliTS - pCur->u64SubmitTS >= 200*1000 /* 200 sec (180 sec has been observed with XP) */)
* sitd_complete+itd_complete in ehci-sched.c, and qtd_copy_status in
* ehci-q.c.
switch (iStatus)
return VUSBSTATUS_OK;
case -EILSEQ:
return VUSBSTATUS_CRC;
return VUSBSTATUS_DATA_UNDERRUN;
case -EOVERFLOW:
return VUSBSTATUS_DATA_OVERRUN;
case -ETIME:
case -ENODEV:
return VUSBSTATUS_DNR;
case -EPIPE:
return VUSBSTATUS_STALL;
case -ESHUTDOWN:
return VUSBSTATUS_STALL;
return VUSBSTATUS_STALL;
return VUSBSTATUS_CRC;
if (pUrbLnx)
if (!pUrbLnx)
return NULL;
if (cMillies)
int rc;
return NULL;
Log(("usb-linux: Reap URB - poll -> %d errno=%d pProxyDev=%s\n", rc, errno, usbProxyGetName(pProxyDev)));
return NULL;
return NULL;
/* for variable size URBs, we may need to queue more if the just-reaped URB was completely filled */
if (pUrbLnx->cbSplitRemaining && (pKUrb->actual_length == pKUrb->buffer_length) && !pUrbLnx->pSplitNext)
bool fUnplugged = false;
bool fSucceeded;
if (!pNew)
Log(("usb-linux: Allocating URB fragment failed. errno=%d pProxyDev=%s\n", errno, usbProxyGetName(pProxyDev)));
return NULL;
if (fUnplugged)
if (!fSucceeded)
return NULL;
if (!pUrbLnx)
if ( pUrb
unsigned i, off;
pUrb->aIsocPkts[i].enmStatus = vusbProxyLinuxStatusToVUsbStatus(pUrbLnx->KUrb.iso_frame_desc[i].status);
return pUrb;
#ifndef RDESKTOP