USBProxyServiceLinux.cpp revision b52c24239bed9dc9f284d829b6059073afcb1894
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * VirtualBox USB Proxy Service, Linux Specialization.
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * Copyright (C) 2006-2010 Oracle Corporation
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * This file is part of VirtualBox Open Source Edition (OSE), as
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * available from http://www.virtualbox.org. This file is free software;
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * you can redistribute it and/or modify it under the terms of the GNU
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * General Public License (GPL) as published by the Free Software
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * Foundation, in version 2 as it comes in the "COPYING" file of the
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac/*******************************************************************************
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac* Header Files *
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac*******************************************************************************/
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac/*******************************************************************************
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac* Structures and Typedefs *
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac*******************************************************************************/
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac/** Suffix translation. */
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignactypedef struct USBSUFF
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac/*******************************************************************************
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac* Global Variables *
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac*******************************************************************************/
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * Suffixes for the endpoint polling interval.
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * Initialize data members.
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignacUSBProxyServiceLinux::USBProxyServiceLinux(Host *aHost, const char *aUsbfsRoot /* = "/proc/bus/usb" */)
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac : USBProxyService(aHost), mFile(NIL_RTFILE), mStream(NULL), mWakeupPipeR(NIL_RTFILE),
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac mWakeupPipeW(NIL_RTFILE), mUsbfsRoot(aUsbfsRoot), mUsingUsbfsDevices(true /* see init */), mUdevPolls(0)
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac LogFlowThisFunc(("aHost=%p aUsbfsRoot=%p:{%s}\n", aHost, aUsbfsRoot, aUsbfsRoot));
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * Initializes the object (called right after construction).
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * @returns S_OK on success and non-fatal failures, some COM error otherwise.
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * Call the superclass method first.
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * We have two methods available for getting host USB device data - using
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * USBFS and using sysfs/hal. The default choice depends on build-time
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * settings and an environment variable; if the default is not available
4aaed10df2638854f4cc50150e47f4f57ed5ea48JnRouvignac * we fall back to the second.
#ifdef VBOX_WITH_SYSFS_BY_DEFAULT
mUsingUsbfsDevices = false;
mUsingUsbfsDevices = true;
if (pszUsbFromEnv)
mUsingUsbfsDevices = true;
mUsingUsbfsDevices = false;
return S_OK;
int rc;
char *pszDevices;
if (pszDevices)
if (mStream)
return VINF_SUCCESS;
Log(("USBProxyServiceLinux::USBProxyServiceLinux: StFS.f_type=%d expected=%d\n", StFS.f_type, USBDEVICE_SUPER_MAGIC));
return rc;
#ifdef VBOX_USB_WITH_SYSFS
return VERR_NO_MEMORY;
return rc;
return VERR_NOT_IMPLEMENTED;
if (isActive())
stop();
if (mStream)
return VINF_SUCCESS;
return VINF_SUCCESS;
bool USBProxyServiceLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
void USBProxyServiceLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice)
LogRel(("USBProxy: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
int rc;
if (mUsingUsbfsDevices)
return rc;
mUdevPolls--;
if (rc == 0)
return VERR_TIMEOUT;
if (rc > 0)
return VINF_SUCCESS;
#ifdef VBOX_USB_WITH_SYSFS
return rc;
#ifdef VBOX_USB_WITH_SYSFS
if (!mUsingUsbfsDevices)
return VINF_SUCCESS;
return rc;
if (!pszNext++)
return VERR_PARSE_ERROR;
return VERR_PARSE_ERROR;
return VINF_SUCCESS;
static int usbReadNum(const char *pszValue, unsigned uBase, uint32_t u32Mask, PCUSBSUFF paSuffs, void *pvNum, char **ppszNext)
switch (u32Mask)
if (*pszValue)
char *pszNext;
return VERR_NO_DATA;
return VERR_OUT_OF_RANGE;
if (paSuffs)
return rc;
switch (u32Mask)
return VINF_SUCCESS;
static int usbRead16Suff(const char *pszValue, unsigned uBase, PCUSBSUFF paSuffs, uint16_t *pu16, char **ppszNext)
* The returned number contains the integer part in the high byte and the decimal part in the low byte.
*pu16 = 0;
if (*pszValue)
char *pszNext;
return VERR_NO_DATA;
return VERR_OUT_OF_RANGE;
return VERR_PARSE_ERROR;
return VERR_NO_DATA;
return VERR_OUT_OF_RANGE;
return rc;
return VINF_SUCCESS;
if (*ppsz)
if (*ppsz)
return VINF_SUCCESS;
return VERR_NO_MEMORY;
if (psz)
if (!psz)
psz--;
return psz;
pszValue++;
return VINF_SUCCESS;
return NULL;
return USBDEVICESTATE_UNSUPPORTED;
return USBDEVICESTATE_UNSUPPORTED;
#ifndef VBOX_USB_WITH_SYSFS
return USBDEVICESTATE_UNSUPPORTED;
return USBDEVICESTATE_USED_BY_HOST;
#ifdef VBOX_USB_WITH_SYSFS
return enmState;
int USBProxyServiceLinux::addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, int rc)
if (pDevNew)
RTStrAPrintf((char **)&pDevNew->pszAddress, "%s/%03d/%03d", mUsbfsRoot.c_str(), pDevNew->bBus, pDevNew->bDevNum);
if (*pppNext)
return rc;
if (mStream)
int cHits = 0;
char *psz;
char *pszValue;
if (!*psz)
switch (ch)
cHits++;
cHits++;
if ( !pszDriver
|| !*pszDriver
while (pFirst)
return pFirst;
#ifdef VBOX_USB_WITH_SYSFS
if (!pszLastComp)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
return VERR_NOT_SUPPORTED;
return VERR_INVALID_PARAMETER;
if (*pu8Port == 0)
return VERR_INVALID_PARAMETER;
return VINF_SUCCESS;
char *pszNext;
|| i32 < 0)
return VERR_NUMBER_TOO_BIG;
return VERR_NUMBER_TOO_BIG;
|| i32Lo < 0)
return VERR_NUMBER_TOO_BIG;
return VERR_NUMBER_TOO_BIG;
return VINF_SUCCESS;
#ifdef VBOX_USB_WITH_SYSFS
if (!Dev)
sizeof(szDeviceClean)))
sizeof(szSysfsClean)))
while (pFirst)
return pFirst;
return NULL;
if (mUsingUsbfsDevices)
return pDevices;