VirtualBox

Changeset 32324 in vbox for trunk


Ignore:
Timestamp:
Sep 8, 2010 3:43:32 PM (14 years ago)
Author:
vboxsync
Message:

Main/USBProxyServiceLinux: split out USB enumeration from USBProxyServiceLinux.cpp and HostHardwareLinux.cpp into a separate file

Location:
trunk/src/VBox/Main
Files:
1 added
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r32312 r32324  
    361361 VBoxSVC_SOURCES.darwin  +=  darwin/USBProxyServiceDarwin.cpp
    362362 VBoxSVC_SOURCES.linux   +=   linux/USBProxyServiceLinux.cpp
     363 VBoxSVC_SOURCES.linux   +=   linux/USBGetDevices.cpp
    363364 VBoxSVC_SOURCES.os2     +=     os2/USBProxyServiceOs2.cpp
    364365 VBoxSVC_SOURCES.solaris += solaris/USBProxyServiceSolaris.cpp
  • trunk/src/VBox/Main/include/HostHardwareLinux.h

    r32299 r32324  
    110110typedef VBoxMainDriveInfo::DriveInfo DriveInfo;
    111111
    112 
    113 /** Structure describing a host USB device */
    114 typedef struct USBDeviceInfo
    115 {
    116     /** The device node of the device. */
    117     char *mDevice;
    118     /** The system identifier of the device.  Specific to the probing
    119      * method. */
    120     char *mSysfsPath;
    121     /** List of interfaces as sysfs paths */
    122     VECTOR_PTR(char *) mvecpszInterfaces;
    123 } USBDeviceInfo;
    124 
    125 /** Destructor. */
    126 void USBDevInfoCleanup(USBDeviceInfo *pSelf);
    127 
    128 /** Constructor - the strings will be duplicated. */
    129 int USBDevInfoInit(USBDeviceInfo *pSelf, const char *aDevice,
    130                    const char *aSystemID);
    131 
    132 /**
    133  * Enumerate USB devices attached to the host using sysfs and return them as a
    134  * vector
    135  * @returns iprt status code
    136  * @param pvecDevInfo  vector to add the devices onto the end of.  Should be
    137  *                     initialised and empty.
    138  */
    139 int USBSysfsEnumerateHostDevices(VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo);
    140 
    141 
    142112/** Implementation of the hotplug waiter class below */
    143113class VBoxMainHotplugWaiterImpl
  • trunk/src/VBox/Main/include/vector.h

    r32262 r32324  
    2727# define MAIN_VECTOR_H
    2828
    29 /*** Helper macros and deinitions ***/
     29/*******************************************************************************
     30*   Header Files                                                               *
     31*******************************************************************************/
     32
     33#include <stdlib.h>
     34
     35/*******************************************************************************
     36*   Helper macros and definitions                                              *
     37*******************************************************************************/
    3038
    3139/** The unit by which the vector capacity is increased */
     
    208216}
    209217
    210 /*** Public interface macros ***/
     218/*******************************************************************************
     219*   Public interface macros                                                    *
     220*******************************************************************************/
    211221
    212222/**
  • trunk/src/VBox/Main/linux/HostHardwareLinux.cpp

    r32299 r32324  
    14011401    { }
    14021402}
    1403 
    1404 void USBDevInfoCleanup(USBDeviceInfo *pSelf)
    1405 {
    1406     RTStrFree(pSelf->mDevice);
    1407     RTStrFree(pSelf->mSysfsPath);
    1408     pSelf->mDevice = pSelf->mSysfsPath = NULL;
    1409     VEC_CLEANUP_PTR(&pSelf->mvecpszInterfaces);
    1410 }
    1411 
    1412 int USBDevInfoInit(USBDeviceInfo *pSelf, const char *aDevice,
    1413                    const char *aSystemID)
    1414 {
    1415     pSelf->mDevice = aDevice ? RTStrDup(aDevice) : NULL;
    1416     pSelf->mSysfsPath = aSystemID ? RTStrDup(aSystemID) : NULL;
    1417     VEC_INIT_PTR(&pSelf->mvecpszInterfaces, char *, RTStrFree);
    1418     if ((aDevice && !pSelf->mDevice) || (aSystemID && ! pSelf->mSysfsPath))
    1419     {
    1420         USBDevInfoCleanup(pSelf);
    1421         return 0;
    1422     }
    1423     return 1;
    1424 }
    1425 
    1426 #ifdef VBOX_USB_WITH_SYSFS
    1427 # ifdef VBOX_USB_WITH_INOTIFY
    1428 
    1429 #define USBDEVICE_MAJOR 189
    1430 
    1431 /** Deduce the bus that a USB device is plugged into from the device node
    1432  * number.  See drivers/usb/core/hub.c:usb_new_device as of Linux 2.6.20. */
    1433 static unsigned usbBusFromDevNum(dev_t devNum)
    1434 {
    1435     AssertReturn(devNum, 0);
    1436     AssertReturn(major(devNum) == USBDEVICE_MAJOR, 0);
    1437     return (minor(devNum) >> 7) + 1;
    1438 }
    1439 
    1440 
    1441 /** Deduce the device number of a USB device on the bus from the device node
    1442  * number.  See drivers/usb/core/hub.c:usb_new_device as of Linux 2.6.20. */
    1443 static unsigned usbDeviceFromDevNum(dev_t devNum)
    1444 {
    1445     AssertReturn(devNum, 0);
    1446     AssertReturn(major(devNum) == USBDEVICE_MAJOR, 0);
    1447     return (minor(devNum) & 127) + 1;
    1448 }
    1449 
    1450 
    1451 /**
    1452  * If a file @a pcszNode from /sys/bus/usb/devices is a device rather than an
    1453  * interface add an element for the device to @a pvecDevInfo.
    1454  */
    1455 static int addIfDevice(const char *pcszNode,
    1456                        VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo)
    1457 {
    1458     const char *pcszFile = strrchr(pcszNode, '/');
    1459     if (strchr(pcszFile, ':'))
    1460         return VINF_SUCCESS;
    1461     dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode);
    1462     /* Sanity test of our static helpers */
    1463     Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5);
    1464     Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6);
    1465     if (!devnum)
    1466         return VINF_SUCCESS;
    1467     char szDevPath[RTPATH_MAX];
    1468     ssize_t cchDevPath;
    1469     cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR,
    1470                                        szDevPath, sizeof(szDevPath),
    1471                                        "/dev/bus/usb/%.3d/%.3d",
    1472                                        usbBusFromDevNum(devnum),
    1473                                        usbDeviceFromDevNum(devnum));
    1474     if (cchDevPath < 0)
    1475         return VINF_SUCCESS;
    1476    
    1477     USBDeviceInfo info;
    1478     if (USBDevInfoInit(&info, szDevPath, pcszNode))
    1479         if (RT_SUCCESS(VEC_PUSH_BACK_OBJ(pvecDevInfo, USBDeviceInfo,
    1480                                          &info)))
    1481             return VINF_SUCCESS;
    1482     USBDevInfoCleanup(&info);
    1483     return VERR_NO_MEMORY;
    1484 }
    1485 
    1486 /** The logic for testing whether a sysfs address corresponds to an
    1487  * interface of a device.  Both must be referenced by their canonical
    1488  * sysfs paths.  This is not tested, as the test requires file-system
    1489  * interaction. */
    1490 static bool muiIsAnInterfaceOf(const char *pcszIface, const char *pcszDev)
    1491 {
    1492     size_t cchDev = strlen(pcszDev);
    1493 
    1494     AssertPtr(pcszIface);
    1495     AssertPtr(pcszDev);
    1496     Assert(pcszIface[0] == '/');
    1497     Assert(pcszDev[0] == '/');
    1498     Assert(pcszDev[cchDev - 1] != '/');
    1499     /* If this passes, pcszIface is at least cchDev long */
    1500     if (strncmp(pcszIface, pcszDev, cchDev))
    1501         return false;
    1502     /* If this passes, pcszIface is longer than cchDev */
    1503     if (pcszIface[cchDev] != '/')
    1504         return false;
    1505     /* In sysfs an interface is an immediate subdirectory of the device */
    1506     if (strchr(pcszIface + cchDev + 1, '/'))
    1507         return false;
    1508     /* And it always has a colon in its name */
    1509     if (!strchr(pcszIface + cchDev + 1, ':'))
    1510         return false;
    1511     /* And hopefully we have now elimitated everything else */
    1512     return true;
    1513 }
    1514 
    1515 #ifdef DEBUG
    1516 /** Unit test the logic in muiIsAnInterfaceOf in debug builds. */
    1517 class testIsAnInterfaceOf
    1518 {
    1519 public:
    1520     testIsAnInterfaceOf()
    1521     {
    1522         Assert(muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0",
    1523                "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
    1524         Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1",
    1525                "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
    1526         Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver",
    1527                "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
    1528     }
    1529 };
    1530 static testIsAnInterfaceOf testIsAnInterfaceOfInst;
    1531 #endif
    1532 
    1533 /**
    1534  * Tell whether a file in /sys/bus/usb/devices is an interface rather than a
    1535  * device.  To be used with getDeviceInfoFromSysfs().
    1536  */
    1537 static int addIfInterfaceOf(const char *pcszNode, USBDeviceInfo *pInfo)
    1538 {
    1539     if (!muiIsAnInterfaceOf(pcszNode, pInfo->mSysfsPath))
    1540         return VINF_SUCCESS;
    1541     char *pszDup = (char *)RTStrDup(pcszNode);
    1542     if (pszDup)
    1543         if (RT_SUCCESS(VEC_PUSH_BACK_PTR(&pInfo->mvecpszInterfaces,
    1544                                          char *, pszDup)))
    1545             return VINF_SUCCESS;
    1546     RTStrFree(pszDup);
    1547     return VERR_NO_MEMORY;
    1548 }
    1549 
    1550 /**
    1551  * Logic for USBSysfsEnumerateHostDevices.
    1552  * @param pvecDevInfo  vector of device information structures to add device
    1553  *                     information to
    1554  * @param pvecpchDevs  empty scratch vector which will be freed by the caller
    1555  */
    1556 static int doSysfsEnumerateHostDevices(VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo,
    1557                               VECTOR_PTR(char *) *pvecpchDevs)
    1558 {
    1559     char **ppszEntry;
    1560     USBDeviceInfo *pInfo;
    1561     int rc;
    1562 
    1563     AssertPtrReturn(pvecDevInfo, VERR_INVALID_POINTER);
    1564     LogFlowFunc (("pvecDevInfo=%p\n", pvecDevInfo));
    1565 
    1566     rc = readFilePaths("/sys/bus/usb/devices", pvecpchDevs, true);
    1567     if (RT_FAILURE(rc))
    1568         return rc;
    1569     VEC_FOR_EACH(pvecpchDevs, char *, ppszEntry)
    1570         if (RT_FAILURE(rc = addIfDevice(*ppszEntry, pvecDevInfo)))
    1571             return rc;
    1572     VEC_FOR_EACH(pvecDevInfo, USBDeviceInfo, pInfo)
    1573         VEC_FOR_EACH(pvecpchDevs, char *, ppszEntry)
    1574             if (RT_FAILURE(rc = addIfInterfaceOf(*ppszEntry, pInfo)))
    1575                 return rc;
    1576     return VINF_SUCCESS;
    1577 }
    1578 # endif /* VBOX_USB_WITH_INOTIFY */
    1579 #endif /* VBOX_USB_WITH_SYSFS */
    1580 
    1581 int USBSysfsEnumerateHostDevices(VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo)
    1582 {
    1583     VECTOR_PTR(char *) vecpchDevs;
    1584     int rc = VERR_NOT_IMPLEMENTED;
    1585 
    1586     AssertReturn(VEC_SIZE_OBJ(pvecDevInfo) == 0, VERR_INVALID_PARAMETER);
    1587     LogFlowFunc(("entered\n"));
    1588     VEC_INIT_PTR(&vecpchDevs, char *, RTStrFree);
    1589 #ifdef VBOX_USB_WITH_SYSFS
    1590 # ifdef VBOX_USB_WITH_INOTIFY
    1591     rc = doSysfsEnumerateHostDevices(pvecDevInfo, &vecpchDevs);
    1592 # endif
    1593 #endif /* !VBOX_USB_WITH_SYSFS */
    1594     VEC_CLEANUP_PTR(&vecpchDevs);
    1595     LogFlowFunc(("rc=%Rrc\n", rc));
    1596     return rc;
    1597 }
  • trunk/src/VBox/Main/linux/USBGetDevices.cpp

    r32301 r32324  
    11/* $Id$ */
    22/** @file
    3  * VirtualBox USB Proxy Service, Linux Specialization.
     3 * VirtualBox Linux host USB device enumeration.
    44 */
    55
     
    2020*   Header Files                                                               *
    2121*******************************************************************************/
    22 #include "USBProxyService.h"
    23 #include "Logging.h"
     22
     23#include "USBGetDevices.h"
    2424
    2525#include <VBox/usb.h>
    2626#include <VBox/usblib.h>
    27 #include <VBox/err.h>
    28 
    29 #include <iprt/string.h>
    30 #include <iprt/alloc.h>
    31 #include <iprt/assert.h>
     27
     28#include <iprt/linux/sysfs.h>
     29#include <iprt/cdefs.h>
    3230#include <iprt/ctype.h>
    33 #include <iprt/env.h>
    34 #include <iprt/file.h>
    3531#include <iprt/err.h>
     32#include <iprt/fs.h>
     33#include <iprt/log.h>
    3634#include <iprt/mem.h>
    3735#include <iprt/param.h>
    38 #include <iprt/path.h>
    39 #include <iprt/stream.h>
    40 #include <iprt/linux/sysfs.h>
    41 
    42 #include <stdlib.h>
     36#include <iprt/string.h>
     37#include "vector.h"
     38
     39#include <linux/usbdevice_fs.h>
     40
     41#include <sys/types.h>
     42#include <sys/stat.h>
     43#include <sys/vfs.h>
     44
     45#include <dirent.h>
     46#include <errno.h>
     47#include <fcntl.h>
     48#include <stdio.h>
    4349#include <string.h>
    44 #include <stdio.h>
    45 #include <errno.h>
    4650#include <unistd.h>
    47 #include <sys/statfs.h>
    48 #include <sys/poll.h>
    49 #ifdef VBOX_WITH_LINUX_COMPILER_H
    50 # include <linux/compiler.h>
    51 #endif
    52 #include <linux/usbdevice_fs.h>
    53 
    5451
    5552/*******************************************************************************
     
    6663typedef const USBSUFF *PCUSBSUFF;
    6764
     65/** Structure describing a host USB device */
     66typedef struct USBDeviceInfo
     67{
     68    /** The device node of the device. */
     69    char *mDevice;
     70    /** The system identifier of the device.  Specific to the probing
     71     * method. */
     72    char *mSysfsPath;
     73    /** List of interfaces as sysfs paths */
     74    VECTOR_PTR(char *) mvecpszInterfaces;
     75} USBDeviceInfo;
    6876
    6977/*******************************************************************************
     
    8391
    8492
    85 /**
    86  * Initialize data members.
    87  */
    88 USBProxyServiceLinux::USBProxyServiceLinux(Host *aHost, const char *aUsbfsRoot /* = "/proc/bus/usb" */)
    89     : USBProxyService(aHost), mFile(NIL_RTFILE), mWakeupPipeR(NIL_RTFILE),
    90       mWakeupPipeW(NIL_RTFILE), mUsbfsRoot(aUsbfsRoot), mUsingUsbfsDevices(true /* see init */), mUdevPolls(0)
    91 {
    92     LogFlowThisFunc(("aHost=%p aUsbfsRoot=%p:{%s}\n", aHost, aUsbfsRoot, aUsbfsRoot));
    93 }
    94 
    95 
    96 /**
    97  * Initializes the object (called right after construction).
    98  *
    99  * @returns S_OK on success and non-fatal failures, some COM error otherwise.
    100  */
    101 HRESULT USBProxyServiceLinux::init(void)
    102 {
    103     /*
    104      * Call the superclass method first.
    105      */
    106     HRESULT hrc = USBProxyService::init();
    107     AssertComRCReturn(hrc, hrc);
    108 
    109     /*
    110      * We have two methods available for getting host USB device data - using
    111      * USBFS and using sysfs/hal.  The default choice depends on build-time
    112      * settings and an environment variable; if the default is not available
    113      * we fall back to the second.
    114      * In the event of both failing, the error from the second method tried
    115      * will be presented to the user.
    116      */
    117 #ifdef VBOX_WITH_SYSFS_BY_DEFAULT
    118     mUsingUsbfsDevices = false;
    119 #else
    120     mUsingUsbfsDevices = true;
    121 #endif
    122     const char *pszUsbFromEnv = RTEnvGet("VBOX_USB");
    123     if (pszUsbFromEnv)
    124     {
    125         if (!RTStrICmp(pszUsbFromEnv, "USBFS"))
    126         {
    127             LogRel(("Default USB access method set to \"usbfs\" from environment\n"));
    128             mUsingUsbfsDevices = true;
    129         }
    130         else if (!RTStrICmp(pszUsbFromEnv, "SYSFS"))
    131         {
    132             LogRel(("Default USB method set to \"sysfs\" from environment\n"));
    133             mUsingUsbfsDevices = false;
    134         }
    135         else
    136             LogRel(("Invalid VBOX_USB environment variable setting \"%s\"\n",
    137                     pszUsbFromEnv));
    138     }
    139     int rc = mUsingUsbfsDevices ? initUsbfs() : initSysfs();
    140     if (RT_FAILURE(rc))
    141     {
    142         /* For the day when we have VBoxSVC release logging... */
    143         LogRel(("Failed to initialise host USB using %s\n",
    144                 mUsingUsbfsDevices ? "USBFS" : "sysfs/hal"));
    145         mUsingUsbfsDevices = !mUsingUsbfsDevices;
    146         rc = mUsingUsbfsDevices ? initUsbfs() : initSysfs();
    147     }
    148     LogRel((RT_SUCCESS(rc) ? "Successfully initialised host USB using %s\n"
    149                            : "Failed to initialise host USB using %s\n",
    150             mUsingUsbfsDevices ? "USBFS" : "sysfs/hal"));
    151     mLastError = rc;
    152     return S_OK;
    153 }
    154 
    155 
    156 static int USBProxyLinuxCheckForUsbfs(const char *pcszDevices)
    157 {
    158     RTFILE File;
    159     int rc;
    160 
    161     rc = RTFileOpen(&File, pcszDevices, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    162     if (RT_SUCCESS(rc))
     93int USBProxyLinuxCheckForUsbfs(const char *pcszDevices)
     94{
     95    int fd;
     96
     97    fd = open(pcszDevices, O_RDONLY, 00600);
     98    if (fd)
    16399    {
    164100        /*
     
    166102         */
    167103        struct statfs StFS;
    168         if (!fstatfs(File, &StFS))
     104        if (!fstatfs(fd, &StFS))
    169105        {
    170106            if (StFS.f_type == USBDEVICE_SUPER_MAGIC)
     
    176112            return RTErrConvertFromErrno(errno);
    177113    }
    178     return rc;
    179 }
    180 
    181 
    182 /**
    183  * Initializiation routine for the usbfs based operation.
    184  *
    185  * @returns iprt status code.
    186  */
    187 int USBProxyServiceLinux::initUsbfs(void)
    188 {
    189     Assert(mUsingUsbfsDevices);
    190 
    191     /*
    192      * Open the devices file.
    193      */
    194     int rc;
    195     char *pszDevices;
    196     RTStrAPrintf(&pszDevices, "%s/devices", mUsbfsRoot.c_str());
    197     if (pszDevices)
    198     {
    199         rc = USBProxyLinuxCheckForUsbfs(pszDevices);
    200         if (RT_SUCCESS(rc))
    201         {
    202             rc = RTFileOpen(&mFile, pszDevices, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    203             if (RT_SUCCESS(rc))
    204             {
    205                 int pipes[2];
    206                 if (!pipe(pipes))
    207                 {
    208                     mWakeupPipeR = pipes[0];
    209                     mWakeupPipeW = pipes[1];
    210                     /*
    211                      * Start the poller thread.
    212                      */
    213                     rc = start();
    214                     if (RT_SUCCESS(rc))
    215                     {
    216                         RTStrFree(pszDevices);
    217                         LogFlowThisFunc(("returns successfully - mWakeupPipeR/W=%d/%d\n",
    218                                          mWakeupPipeR, mWakeupPipeW));
    219                         return VINF_SUCCESS;
    220                     }
    221 
    222                     RTFileClose(mWakeupPipeR);
    223                     RTFileClose(mWakeupPipeW);
    224                     mWakeupPipeW = mWakeupPipeR = NIL_RTFILE;
    225                 }
    226                 else
    227                 {
    228                     rc = RTErrConvertFromErrno(errno);
    229                     Log(("USBProxyServiceLinux::USBProxyServiceLinux: pipe failed, errno=%d\n", errno));
    230                 }
    231                 RTFileClose(mFile);
    232             }
    233            
    234         }
    235         RTStrFree(pszDevices);
    236     }
    237114    else
    238     {
    239         rc = VERR_NO_MEMORY;
    240         Log(("USBProxyServiceLinux::USBProxyServiceLinux: out of memory!\n"));
    241     }
    242 
    243     LogFlowThisFunc(("returns failure!!! (rc=%Rrc)\n", rc));
    244     return rc;
    245 }
    246 
    247 
    248 /**
    249  * Initializiation routine for the sysfs based operation.
    250  *
    251  * @returns iprt status code
    252  */
    253 int USBProxyServiceLinux::initSysfs(void)
    254 {
    255     Assert(!mUsingUsbfsDevices);
    256 
    257 #ifdef VBOX_USB_WITH_SYSFS
    258     int rc = mWaiter.getStatus();
    259     if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT || rc == VERR_TRY_AGAIN)
    260         rc = start();
    261     else if (rc == VERR_NOT_SUPPORTED)
    262         /* This can legitimately happen if hal or DBus are not running, but of
    263          * course we can't start in this case. */
    264         rc = VINF_SUCCESS;
    265     return rc;
    266 
    267 #else  /* !VBOX_USB_WITH_SYSFS */
    268     return VERR_NOT_IMPLEMENTED;
    269 #endif /* !VBOX_USB_WITH_SYSFS */
    270 }
    271 
    272 
    273 /**
    274  * Stop all service threads and free the device chain.
    275  */
    276 USBProxyServiceLinux::~USBProxyServiceLinux()
    277 {
    278     LogFlowThisFunc(("\n"));
    279 
    280     /*
    281      * Stop the service.
    282      */
    283     if (isActive())
    284         stop();
    285 
    286     /*
    287      * Free resources.
    288      */
    289     doUsbfsCleanupAsNeeded();
    290 
    291     /* (No extra work for !mUsingUsbfsDevices.) */
    292 }
    293 
    294 
    295 /**
    296  * If any Usbfs-releated resources are currently allocated, then free them
    297  * and mark them as freed.
    298  */
    299 void USBProxyServiceLinux::doUsbfsCleanupAsNeeded()
    300 {
    301     /*
    302      * Free resources.
    303      */
    304     if (mFile != NIL_RTFILE)
    305     {
    306         RTFileClose(mFile);
    307         mFile = NIL_RTFILE;
    308     }
    309 
    310     if (mWakeupPipeR != NIL_RTFILE)
    311         RTFileClose(mWakeupPipeR);
    312     if (mWakeupPipeW != NIL_RTFILE)
    313         RTFileClose(mWakeupPipeW);
    314     mWakeupPipeW = mWakeupPipeR = NIL_RTFILE;
    315 }
    316 
    317 
    318 int USBProxyServiceLinux::captureDevice(HostUSBDevice *aDevice)
    319 {
    320     Log(("USBProxyServiceLinux::captureDevice: %p {%s}\n", aDevice, aDevice->getName().c_str()));
    321     AssertReturn(aDevice, VERR_GENERAL_FAILURE);
    322     AssertReturn(aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
    323 
    324     /*
    325      * Don't think we need to do anything when the device is held... fake it.
    326      */
    327     Assert(aDevice->getUnistate() == kHostUSBDeviceState_Capturing);
    328     interruptWait();
    329 
    330     return VINF_SUCCESS;
    331 }
    332 
    333 
    334 int USBProxyServiceLinux::releaseDevice(HostUSBDevice *aDevice)
    335 {
    336     Log(("USBProxyServiceLinux::releaseDevice: %p\n", aDevice));
    337     AssertReturn(aDevice, VERR_GENERAL_FAILURE);
    338     AssertReturn(aDevice->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
    339 
    340     /*
    341      * We're not really holding it atm., just fake it.
    342      */
    343     Assert(aDevice->getUnistate() == kHostUSBDeviceState_ReleasingToHost);
    344     interruptWait();
    345 
    346     return VINF_SUCCESS;
    347 }
    348 
    349 
    350 bool USBProxyServiceLinux::updateDeviceState(HostUSBDevice *aDevice, PUSBDEVICE aUSBDevice, bool *aRunFilters, SessionMachine **aIgnoreMachine)
    351 {
    352     if (    aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE
    353         &&  aDevice->mUsb->enmState == USBDEVICESTATE_USED_BY_HOST)
    354         LogRel(("USBProxy: Device %04x:%04x (%s) has become accessible.\n",
    355                 aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
    356     return updateDeviceStateFake(aDevice, aUSBDevice, aRunFilters, aIgnoreMachine);
    357 }
    358 
    359 
    360 /**
    361  * A device was added, we need to adjust mUdevPolls.
    362  *
    363  * See USBProxyService::deviceAdded for details.
    364  */
    365 void USBProxyServiceLinux::deviceAdded(ComObjPtr<HostUSBDevice> &aDevice, SessionMachinesList &llOpenedMachines, PUSBDEVICE aUSBDevice)
    366 {
    367     if (aUSBDevice->enmState == USBDEVICESTATE_USED_BY_HOST)
    368     {
    369         LogRel(("USBProxy: Device %04x:%04x (%s) isn't accessible. giving udev a few seconds to fix this...\n",
    370                 aUSBDevice->idVendor, aUSBDevice->idProduct, aUSBDevice->pszAddress));
    371         mUdevPolls = 10; /* (10 * 500ms = 5s) */
    372     }
    373 
    374     USBProxyService::deviceAdded(aDevice, llOpenedMachines, aUSBDevice);
    375 }
    376 
    377 
    378 int USBProxyServiceLinux::wait(RTMSINTERVAL aMillies)
    379 {
    380     int rc;
    381     if (mUsingUsbfsDevices)
    382         rc = waitUsbfs(aMillies);
    383     else
    384         rc = waitSysfs(aMillies);
    385     return rc;
    386 }
    387 
    388 
    389 /** String written to the wakeup pipe. */
    390 #define WAKE_UP_STRING      "WakeUp!"
    391 /** Length of the string written. */
    392 #define WAKE_UP_STRING_LEN  ( sizeof(WAKE_UP_STRING) - 1 )
    393 
    394 int USBProxyServiceLinux::waitUsbfs(RTMSINTERVAL aMillies)
    395 {
    396     struct pollfd PollFds[2];
    397 
    398     /* Cap the wait interval if we're polling for udevd changing device permissions. */
    399     if (aMillies > 500 && mUdevPolls > 0)
    400     {
    401         mUdevPolls--;
    402         aMillies = 500;
    403     }
    404 
    405     memset(&PollFds, 0, sizeof(PollFds));
    406     PollFds[0].fd        = mFile;
    407     PollFds[0].events    = POLLIN;
    408     PollFds[1].fd        = mWakeupPipeR;
    409     PollFds[1].events    = POLLIN | POLLERR | POLLHUP;
    410 
    411     int rc = poll(&PollFds[0], 2, aMillies);
    412     if (rc == 0)
    413         return VERR_TIMEOUT;
    414     if (rc > 0)
    415     {
    416         /* drain the pipe */
    417         if (PollFds[1].revents & POLLIN)
    418         {
    419             char szBuf[WAKE_UP_STRING_LEN];
    420             rc = RTFileRead(mWakeupPipeR, szBuf, sizeof(szBuf), NULL);
    421             AssertRC(rc);
    422         }
    423         return VINF_SUCCESS;
    424     }
    425     return RTErrConvertFromErrno(errno);
    426 }
    427 
    428 
    429 int USBProxyServiceLinux::waitSysfs(RTMSINTERVAL aMillies)
    430 {
    431 #ifdef VBOX_USB_WITH_SYSFS
    432     int rc = mWaiter.Wait(aMillies);
    433     if (rc == VERR_TRY_AGAIN)
    434     {
    435         RTThreadYield();
    436         rc = VINF_SUCCESS;
    437     }
    438     return rc;
    439 #else  /* !VBOX_USB_WITH_SYSFS */
    440     return USBProxyService::wait(aMillies);
    441 #endif /* !VBOX_USB_WITH_SYSFS */
    442 }
    443 
    444 
    445 int USBProxyServiceLinux::interruptWait(void)
    446 {
    447 #ifdef VBOX_USB_WITH_SYSFS
    448     LogFlowFunc(("mUsingUsbfsDevices=%d\n", mUsingUsbfsDevices));
    449     if (!mUsingUsbfsDevices)
    450     {
    451         mWaiter.Interrupt();
    452         LogFlowFunc(("Returning VINF_SUCCESS\n"));
    453         return VINF_SUCCESS;
    454     }
    455 #endif /* VBOX_USB_WITH_SYSFS */
    456     int rc = RTFileWrite(mWakeupPipeW, WAKE_UP_STRING, WAKE_UP_STRING_LEN, NULL);
    457     if (RT_SUCCESS(rc))
    458         RTFileFlush(mWakeupPipeW);
    459     LogFlowFunc(("returning %Rrc\n", rc));
    460     return rc;
    461 }
    462 
    463 /**
    464  * Free all the members of a USB device created by the Linux enumeration code.
    465  * @note this duplicates a USBProxyService method which we needed access too
    466  *       without pulling in the rest of the proxy service code.
    467  *
    468  * @param   pDevice     Pointer to the device.
    469  */
    470 static void deviceFreeMembers(PUSBDEVICE pDevice)
    471 {
    472     RTStrFree((char *)pDevice->pszManufacturer);
    473     pDevice->pszManufacturer = NULL;
    474     RTStrFree((char *)pDevice->pszProduct);
    475     pDevice->pszProduct = NULL;
    476     RTStrFree((char *)pDevice->pszSerialNumber);
    477     pDevice->pszSerialNumber = NULL;
    478 
    479     RTStrFree((char *)pDevice->pszAddress);
    480     pDevice->pszAddress = NULL;
    481 }
    482 
    483 /**
    484  * Free one USB device created by the Linux enumeration code.
    485  * @note this duplicates a USBProxyService method which we needed access too
    486  *       without pulling in the rest of the proxy service code.
    487  *
    488  * @param   pDevice     Pointer to the device.
    489  */
    490 static void deviceFree(PUSBDEVICE pDevice)
    491 {
    492     deviceFreeMembers(pDevice);
    493     RTMemFree(pDevice);
    494 }
     115        return RTErrConvertFromErrno(errno);
     116    return 0;
     117}
     118
    495119
    496120/**
     
    1185809#ifdef VBOX_USB_WITH_SYSFS
    1186810
     811static void USBDevInfoCleanup(USBDeviceInfo *pSelf)
     812{
     813    RTStrFree(pSelf->mDevice);
     814    RTStrFree(pSelf->mSysfsPath);
     815    pSelf->mDevice = pSelf->mSysfsPath = NULL;
     816    VEC_CLEANUP_PTR(&pSelf->mvecpszInterfaces);
     817}
     818
     819static int USBDevInfoInit(USBDeviceInfo *pSelf, const char *aDevice,
     820                   const char *aSystemID)
     821{
     822    pSelf->mDevice = aDevice ? RTStrDup(aDevice) : NULL;
     823    pSelf->mSysfsPath = aSystemID ? RTStrDup(aSystemID) : NULL;
     824    VEC_INIT_PTR(&pSelf->mvecpszInterfaces, char *, RTStrFree);
     825    if ((aDevice && !pSelf->mDevice) || (aSystemID && ! pSelf->mSysfsPath))
     826    {
     827        USBDevInfoCleanup(pSelf);
     828        return 0;
     829    }
     830    return 1;
     831}
     832
     833#define USBDEVICE_MAJOR 189
     834
     835/** Deduce the bus that a USB device is plugged into from the device node
     836 * number.  See drivers/usb/core/hub.c:usb_new_device as of Linux 2.6.20. */
     837static unsigned usbBusFromDevNum(dev_t devNum)
     838{
     839    AssertReturn(devNum, 0);
     840    AssertReturn(major(devNum) == USBDEVICE_MAJOR, 0);
     841    return (minor(devNum) >> 7) + 1;
     842}
     843
     844
     845/** Deduce the device number of a USB device on the bus from the device node
     846 * number.  See drivers/usb/core/hub.c:usb_new_device as of Linux 2.6.20. */
     847static unsigned usbDeviceFromDevNum(dev_t devNum)
     848{
     849    AssertReturn(devNum, 0);
     850    AssertReturn(major(devNum) == USBDEVICE_MAJOR, 0);
     851    return (minor(devNum) & 127) + 1;
     852}
     853
     854
     855/**
     856 * If a file @a pcszNode from /sys/bus/usb/devices is a device rather than an
     857 * interface add an element for the device to @a pvecDevInfo.
     858 */
     859static int addIfDevice(const char *pcszNode,
     860                       VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo)
     861{
     862    const char *pcszFile = strrchr(pcszNode, '/');
     863    if (strchr(pcszFile, ':'))
     864        return VINF_SUCCESS;
     865    dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode);
     866    /* Sanity test of our static helpers */
     867    Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5);
     868    Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6);
     869    if (!devnum)
     870        return VINF_SUCCESS;
     871    char szDevPath[RTPATH_MAX];
     872    ssize_t cchDevPath;
     873    cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR,
     874                                       szDevPath, sizeof(szDevPath),
     875                                       "/dev/bus/usb/%.3d/%.3d",
     876                                       usbBusFromDevNum(devnum),
     877                                       usbDeviceFromDevNum(devnum));
     878    if (cchDevPath < 0)
     879        return VINF_SUCCESS;
     880   
     881    USBDeviceInfo info;
     882    if (USBDevInfoInit(&info, szDevPath, pcszNode))
     883        if (RT_SUCCESS(VEC_PUSH_BACK_OBJ(pvecDevInfo, USBDeviceInfo,
     884                                         &info)))
     885            return VINF_SUCCESS;
     886    USBDevInfoCleanup(&info);
     887    return VERR_NO_MEMORY;
     888}
     889
     890/** The logic for testing whether a sysfs address corresponds to an
     891 * interface of a device.  Both must be referenced by their canonical
     892 * sysfs paths.  This is not tested, as the test requires file-system
     893 * interaction. */
     894static bool muiIsAnInterfaceOf(const char *pcszIface, const char *pcszDev)
     895{
     896    size_t cchDev = strlen(pcszDev);
     897
     898    AssertPtr(pcszIface);
     899    AssertPtr(pcszDev);
     900    Assert(pcszIface[0] == '/');
     901    Assert(pcszDev[0] == '/');
     902    Assert(pcszDev[cchDev - 1] != '/');
     903    /* If this passes, pcszIface is at least cchDev long */
     904    if (strncmp(pcszIface, pcszDev, cchDev))
     905        return false;
     906    /* If this passes, pcszIface is longer than cchDev */
     907    if (pcszIface[cchDev] != '/')
     908        return false;
     909    /* In sysfs an interface is an immediate subdirectory of the device */
     910    if (strchr(pcszIface + cchDev + 1, '/'))
     911        return false;
     912    /* And it always has a colon in its name */
     913    if (!strchr(pcszIface + cchDev + 1, ':'))
     914        return false;
     915    /* And hopefully we have now elimitated everything else */
     916    return true;
     917}
     918
     919#ifdef DEBUG
     920# ifdef __cplusplus
     921/** Unit test the logic in muiIsAnInterfaceOf in debug builds. */
     922class testIsAnInterfaceOf
     923{
     924public:
     925    testIsAnInterfaceOf()
     926    {
     927        Assert(muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0",
     928               "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
     929        Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1",
     930               "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
     931        Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver",
     932               "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
     933    }
     934};
     935static testIsAnInterfaceOf testIsAnInterfaceOfInst;
     936# endif /* __cplusplus */
     937#endif /* DEBUG */
     938
     939/**
     940 * Tell whether a file in /sys/bus/usb/devices is an interface rather than a
     941 * device.  To be used with getDeviceInfoFromSysfs().
     942 */
     943static int addIfInterfaceOf(const char *pcszNode, USBDeviceInfo *pInfo)
     944{
     945    if (!muiIsAnInterfaceOf(pcszNode, pInfo->mSysfsPath))
     946        return VINF_SUCCESS;
     947    char *pszDup = (char *)RTStrDup(pcszNode);
     948    if (pszDup)
     949        if (RT_SUCCESS(VEC_PUSH_BACK_PTR(&pInfo->mvecpszInterfaces,
     950                                         char *, pszDup)))
     951            return VINF_SUCCESS;
     952    RTStrFree(pszDup);
     953    return VERR_NO_MEMORY;
     954}
     955
     956/** Helper for readFilePaths().  Adds the entries from the open directory
     957 * @a pDir to the vector @a pvecpchDevs using either the full path or the
     958 * realpath() and skipping hidden files and files on which realpath() fails. */
     959static int readFilePathsFromDir(const char *pcszPath, DIR *pDir,
     960                                VECTOR_PTR(char *) *pvecpchDevs)
     961{
     962    struct dirent entry, *pResult;
     963    int err, rc;
     964
     965    for (err = readdir_r(pDir, &entry, &pResult); pResult;
     966         err = readdir_r(pDir, &entry, &pResult))
     967    {
     968        char szPath[RTPATH_MAX + 1], szRealPath[RTPATH_MAX + 1], *pszPath;
     969        if (entry.d_name[0] == '.')
     970            continue;
     971        if (snprintf(szPath, sizeof(szPath), "%s/%s", pcszPath,
     972                     entry.d_name) < 0)
     973            return RTErrConvertFromErrno(errno);
     974        pszPath = RTStrDup(realpath(szPath, szRealPath));
     975        if (!pszPath)
     976            return VERR_NO_MEMORY;
     977        if (RT_FAILURE(rc = VEC_PUSH_BACK_PTR(pvecpchDevs, char *, pszPath)))
     978            return rc;
     979    }
     980    return RTErrConvertFromErrno(err);
     981}
     982
     983/**
     984 * Dump the names of a directory's entries into a vector of char pointers.
     985 *
     986 * @returns zero on success or (positive) posix error value.
     987 * @param   pcszPath      the path to dump. 
     988 * @param   pvecpchDevs   an empty vector of char pointers - must be cleaned up
     989 *                        by the caller even on failure.
     990 * @param   withRealPath  whether to canonicalise the filename with realpath
     991 */
     992static int readFilePaths(const char *pcszPath, VECTOR_PTR(char *) *pvecpchDevs)
     993{
     994    DIR *pDir;
     995    int rc;
     996
     997    AssertPtrReturn(pvecpchDevs, EINVAL);
     998    AssertReturn(VEC_SIZE_PTR(pvecpchDevs) == 0, EINVAL);
     999    AssertPtrReturn(pcszPath, EINVAL);
     1000
     1001    pDir = opendir(pcszPath);
     1002    if (!pDir)
     1003        return RTErrConvertFromErrno(errno);
     1004    rc = readFilePathsFromDir(pcszPath, pDir, pvecpchDevs);
     1005    if (closedir(pDir) < 0 && RT_SUCCESS(rc))
     1006        rc = RTErrConvertFromErrno(errno);
     1007    return rc;
     1008}
     1009
     1010/**
     1011 * Logic for USBSysfsEnumerateHostDevices.
     1012 * @param pvecDevInfo  vector of device information structures to add device
     1013 *                     information to
     1014 * @param pvecpchDevs  empty scratch vector which will be freed by the caller
     1015 */
     1016static int doSysfsEnumerateHostDevices(VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo,
     1017                              VECTOR_PTR(char *) *pvecpchDevs)
     1018{
     1019    char **ppszEntry;
     1020    USBDeviceInfo *pInfo;
     1021    int rc;
     1022
     1023    AssertPtrReturn(pvecDevInfo, VERR_INVALID_POINTER);
     1024    LogFlowFunc (("pvecDevInfo=%p\n", pvecDevInfo));
     1025
     1026    rc = readFilePaths("/sys/bus/usb/devices", pvecpchDevs);
     1027    if (RT_FAILURE(rc))
     1028        return rc;
     1029    VEC_FOR_EACH(pvecpchDevs, char *, ppszEntry)
     1030        if (RT_FAILURE(rc = addIfDevice(*ppszEntry, pvecDevInfo)))
     1031            return rc;
     1032    VEC_FOR_EACH(pvecDevInfo, USBDeviceInfo, pInfo)
     1033        VEC_FOR_EACH(pvecpchDevs, char *, ppszEntry)
     1034            if (RT_FAILURE(rc = addIfInterfaceOf(*ppszEntry, pInfo)))
     1035                return rc;
     1036    return VINF_SUCCESS;
     1037}
     1038
     1039static int USBSysfsEnumerateHostDevices(VECTOR_OBJ(USBDeviceInfo) *pvecDevInfo)
     1040{
     1041    VECTOR_PTR(char *) vecpchDevs;
     1042    int rc = VERR_NOT_IMPLEMENTED;
     1043
     1044    AssertReturn(VEC_SIZE_OBJ(pvecDevInfo) == 0, VERR_INVALID_PARAMETER);
     1045    LogFlowFunc(("entered\n"));
     1046    VEC_INIT_PTR(&vecpchDevs, char *, RTStrFree);
     1047    rc = doSysfsEnumerateHostDevices(pvecDevInfo, &vecpchDevs);
     1048    VEC_CLEANUP_PTR(&vecpchDevs);
     1049    LogFlowFunc(("rc=%Rrc\n", rc));
     1050    return rc;
     1051}
     1052
    11871053/**
    11881054 * Helper function for extracting the port number on the parent device from
     
    14551321    }
    14561322
    1457     /* We want a copy of the device node and sysfs paths guaranteed not to
    1458      * contain double slashes, since we use a double slash as a separator in
    1459      * the pszAddress field. */
    1460     char szDeviceClean[RTPATH_MAX];
    1461     char szSysfsClean[RTPATH_MAX];
     1323    /* We use a double slash as a separator in the pszAddress field.  This is
     1324     * alright as the two paths can't contain a slash due to the way we build
     1325     * them. */
    14621326    char *pszAddress = NULL;
    1463     if (   RT_SUCCESS(RTPathReal(pInfo->mDevice, szDeviceClean,
    1464                                  sizeof(szDeviceClean)))
    1465         && RT_SUCCESS(RTPathReal(pszSysfsPath, szSysfsClean,
    1466                                  sizeof(szSysfsClean)))
    1467        )
    1468         RTStrAPrintf(&pszAddress, "sysfs:%s//device:%s", szSysfsClean,
    1469                      szDeviceClean);
     1327    RTStrAPrintf(&pszAddress, "sysfs:%s//device:%s", pszSysfsPath,
     1328                 pInfo->mDevice);
    14701329    Dev->pszAddress = pszAddress;
    14711330
     
    15341393}
    15351394
    1536 static PUSBDEVICE USBProxyLinuxGetDevices(const char *pcszUsbfsRoot)
     1395PUSBDEVICE USBProxyLinuxGetDevices(const char *pcszUsbfsRoot)
    15371396{
    15381397    if (pcszUsbfsRoot)
     
    15411400        return getDevicesFromSysfs();
    15421401}
    1543 
    1544 PUSBDEVICE USBProxyServiceLinux::getDevices(void)
    1545 {
    1546     if (mUsingUsbfsDevices)
    1547         return USBProxyLinuxGetDevices(mUsbfsRoot.c_str());
    1548     else
    1549         return USBProxyLinuxGetDevices(NULL);
    1550 }
    1551 
  • trunk/src/VBox/Main/linux/USBProxyServiceLinux.cpp

    r32301 r32324  
    2121*******************************************************************************/
    2222#include "USBProxyService.h"
     23#include "USBGetDevices.h"
    2324#include "Logging.h"
    2425
     
    151152    mLastError = rc;
    152153    return S_OK;
    153 }
    154 
    155 
    156 static int USBProxyLinuxCheckForUsbfs(const char *pcszDevices)
    157 {
    158     RTFILE File;
    159     int rc;
    160 
    161     rc = RTFileOpen(&File, pcszDevices, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    162     if (RT_SUCCESS(rc))
    163     {
    164         /*
    165          * Check that we're actually on the usbfs.
    166          */
    167         struct statfs StFS;
    168         if (!fstatfs(File, &StFS))
    169         {
    170             if (StFS.f_type == USBDEVICE_SUPER_MAGIC)
    171                 return VINF_SUCCESS;
    172             else
    173                 return VERR_NOT_FOUND;
    174         }
    175         else
    176             return RTErrConvertFromErrno(errno);
    177     }
    178     return rc;
    179154}
    180155
     
    461436}
    462437
    463 /**
    464  * Free all the members of a USB device created by the Linux enumeration code.
    465  * @note this duplicates a USBProxyService method which we needed access too
    466  *       without pulling in the rest of the proxy service code.
    467  *
    468  * @param   pDevice     Pointer to the device.
    469  */
    470 static void deviceFreeMembers(PUSBDEVICE pDevice)
    471 {
    472     RTStrFree((char *)pDevice->pszManufacturer);
    473     pDevice->pszManufacturer = NULL;
    474     RTStrFree((char *)pDevice->pszProduct);
    475     pDevice->pszProduct = NULL;
    476     RTStrFree((char *)pDevice->pszSerialNumber);
    477     pDevice->pszSerialNumber = NULL;
    478 
    479     RTStrFree((char *)pDevice->pszAddress);
    480     pDevice->pszAddress = NULL;
    481 }
    482 
    483 /**
    484  * Free one USB device created by the Linux enumeration code.
    485  * @note this duplicates a USBProxyService method which we needed access too
    486  *       without pulling in the rest of the proxy service code.
    487  *
    488  * @param   pDevice     Pointer to the device.
    489  */
    490 static void deviceFree(PUSBDEVICE pDevice)
    491 {
    492     deviceFreeMembers(pDevice);
    493     RTMemFree(pDevice);
    494 }
    495 
    496 /**
    497  * "reads" the number suffix. It's more like validating it and
    498  * skipping the necessary number of chars.
    499  */
    500 static int usbReadSkipSuffix(char **ppszNext)
    501 {
    502     char *pszNext = *ppszNext;
    503     if (!RT_C_IS_SPACE(*pszNext) && *pszNext)
    504     {
    505         /* skip unit */
    506         if (pszNext[0] == 'm' && pszNext[1] == 's')
    507             pszNext += 2;
    508         else if (pszNext[0] == 'm' && pszNext[1] == 'A')
    509             pszNext += 2;
    510 
    511         /* skip parenthesis */
    512         if (*pszNext == '(')
    513         {
    514             pszNext = strchr(pszNext, ')');
    515             if (!pszNext++)
    516             {
    517                 AssertMsgFailed(("*ppszNext=%s\n", *ppszNext));
    518                 return VERR_PARSE_ERROR;
    519             }
    520         }
    521 
    522         /* blank or end of the line. */
    523         if (!RT_C_IS_SPACE(*pszNext) && *pszNext)
    524         {
    525             AssertMsgFailed(("pszNext=%s\n", pszNext));
    526             return VERR_PARSE_ERROR;
    527         }
    528 
    529         /* it's ok. */
    530         *ppszNext = pszNext;
    531     }
    532 
    533     return VINF_SUCCESS;
    534 }
    535 
    536 
    537 /**
    538  * Reads a USB number returning the number and the position of the next character to parse.
    539  */
    540 static int usbReadNum(const char *pszValue, unsigned uBase, uint32_t u32Mask, PCUSBSUFF paSuffs, void *pvNum, char **ppszNext)
    541 {
    542     /*
    543      * Initialize return value to zero and strip leading spaces.
    544      */
    545     switch (u32Mask)
    546     {
    547         case 0xff: *(uint8_t *)pvNum = 0; break;
    548         case 0xffff: *(uint16_t *)pvNum = 0; break;
    549         case 0xffffffff: *(uint32_t *)pvNum = 0; break;
    550     }
    551     pszValue = RTStrStripL(pszValue);
    552     if (*pszValue)
    553     {
    554         /*
    555          * Try convert the number.
    556          */
    557         char *pszNext;
    558         uint32_t u32 = 0;
    559         RTStrToUInt32Ex(pszValue, &pszNext, uBase, &u32);
    560         if (pszNext == pszValue)
    561         {
    562             AssertMsgFailed(("pszValue=%d\n", pszValue));
    563             return VERR_NO_DATA;
    564         }
    565 
    566         /*
    567          * Check the range.
    568          */
    569         if (u32 & ~u32Mask)
    570         {
    571             AssertMsgFailed(("pszValue=%d u32=%#x lMask=%#x\n", pszValue, u32, u32Mask));
    572             return VERR_OUT_OF_RANGE;
    573         }
    574 
    575         /*
    576          * Validate and skip stuff following the number.
    577          */
    578         if (paSuffs)
    579         {
    580             if (!RT_C_IS_SPACE(*pszNext) && *pszNext)
    581             {
    582                 for (PCUSBSUFF pSuff = paSuffs; pSuff->szSuff[0]; pSuff++)
    583                 {
    584                     if (    !strncmp(pSuff->szSuff, pszNext, pSuff->cchSuff)
    585                         &&  (!pszNext[pSuff->cchSuff] || RT_C_IS_SPACE(pszNext[pSuff->cchSuff])))
    586                     {
    587                         if (pSuff->uDiv)
    588                             u32 /= pSuff->uDiv;
    589                         else
    590                             u32 *= pSuff->uMul;
    591                         break;
    592                     }
    593                 }
    594             }
    595         }
    596         else
    597         {
    598             int rc = usbReadSkipSuffix(&pszNext);
    599             if (RT_FAILURE(rc))
    600                 return rc;
    601         }
    602 
    603         *ppszNext = pszNext;
    604 
    605         /*
    606          * Set the value.
    607          */
    608         switch (u32Mask)
    609         {
    610             case 0xff: *(uint8_t *)pvNum = (uint8_t)u32; break;
    611             case 0xffff: *(uint16_t *)pvNum = (uint16_t)u32; break;
    612             case 0xffffffff: *(uint32_t *)pvNum = (uint32_t)u32; break;
    613         }
    614     }
    615     return VINF_SUCCESS;
    616 }
    617 
    618 
    619 static int usbRead8(const char *pszValue, unsigned uBase, uint8_t *pu8, char **ppszNext)
    620 {
    621     return usbReadNum(pszValue, uBase, 0xff, NULL, pu8, ppszNext);
    622 }
    623 
    624 
    625 static int usbRead16(const char *pszValue, unsigned uBase, uint16_t *pu16, char **ppszNext)
    626 {
    627     return usbReadNum(pszValue, uBase, 0xffff, NULL, pu16, ppszNext);
    628 }
    629 
    630 
    631 #if 0
    632 static int usbRead16Suff(const char *pszValue, unsigned uBase, PCUSBSUFF paSuffs, uint16_t *pu16,  char **ppszNext)
    633 {
    634     return usbReadNum(pszValue, uBase, 0xffff, paSuffs, pu16, ppszNext);
    635 }
    636 #endif
    637 
    638 
    639 /**
    640  * Reads a USB BCD number returning the number and the position of the next character to parse.
    641  * The returned number contains the integer part in the high byte and the decimal part in the low byte.
    642  */
    643 static int usbReadBCD(const char *pszValue, unsigned uBase, uint16_t *pu16, char **ppszNext)
    644 {
    645     /*
    646      * Initialize return value to zero and strip leading spaces.
    647      */
    648     *pu16 = 0;
    649     pszValue = RTStrStripL(pszValue);
    650     if (*pszValue)
    651     {
    652         /*
    653          * Try convert the number.
    654          */
    655         /* integer part */
    656         char *pszNext;
    657         uint32_t u32Int = 0;
    658         RTStrToUInt32Ex(pszValue, &pszNext, uBase, &u32Int);
    659         if (pszNext == pszValue)
    660         {
    661             AssertMsgFailed(("pszValue=%s\n", pszValue));
    662             return VERR_NO_DATA;
    663         }
    664         if (u32Int & ~0xff)
    665         {
    666             AssertMsgFailed(("pszValue=%s u32Int=%#x (int)\n", pszValue, u32Int));
    667             return VERR_OUT_OF_RANGE;
    668         }
    669 
    670         /* skip dot and read decimal part */
    671         if (*pszNext != '.')
    672         {
    673             AssertMsgFailed(("pszValue=%s pszNext=%s (int)\n", pszValue, pszNext));
    674             return VERR_PARSE_ERROR;
    675         }
    676         char *pszValue2 = RTStrStripL(pszNext + 1);
    677         uint32_t u32Dec = 0;
    678         RTStrToUInt32Ex(pszValue2, &pszNext, uBase, &u32Dec);
    679         if (pszNext == pszValue)
    680         {
    681             AssertMsgFailed(("pszValue=%s\n", pszValue));
    682             return VERR_NO_DATA;
    683         }
    684         if (u32Dec & ~0xff)
    685         {
    686             AssertMsgFailed(("pszValue=%s u32Dec=%#x\n", pszValue, u32Dec));
    687             return VERR_OUT_OF_RANGE;
    688         }
    689 
    690         /*
    691          * Validate and skip stuff following the number.
    692          */
    693         int rc = usbReadSkipSuffix(&pszNext);
    694         if (RT_FAILURE(rc))
    695             return rc;
    696         *ppszNext = pszNext;
    697 
    698         /*
    699          * Set the value.
    700          */
    701         *pu16 = (uint16_t)u32Int << 8 | (uint16_t)u32Dec;
    702     }
    703     return VINF_SUCCESS;
    704 }
    705 
    706 
    707 /**
    708  * Reads a string, i.e. allocates memory and copies it.
    709  *
    710  * We assume that a string is pure ASCII, if that's not the case
    711  * tell me how to figure out the codeset please.
    712  */
    713 static int usbReadStr(const char *pszValue, const char **ppsz)
    714 {
    715     if (*ppsz)
    716         RTStrFree((char *)*ppsz);
    717     *ppsz = RTStrDup(pszValue);
    718     if (*ppsz)
    719         return VINF_SUCCESS;
    720     return VERR_NO_MEMORY;
    721 }
    722 
    723 
    724 /**
    725  * Skips the current property.
    726  */
    727 static char *usbReadSkip(char *pszValue)
    728 {
    729     char *psz = strchr(pszValue, '=');
    730     if (psz)
    731         psz = strchr(psz + 1, '=');
    732     if (!psz)
    733         return strchr(pszValue,  '\0');
    734     while (psz > pszValue && !RT_C_IS_SPACE(psz[-1]))
    735         psz--;
    736     Assert(psz > pszValue);
    737     return psz;
    738 }
    739 
    740 
    741 /**
    742  * Determine the USB speed.
    743  */
    744 static int usbReadSpeed(const char *pszValue, USBDEVICESPEED *pSpd, char **ppszNext)
    745 {
    746     pszValue = RTStrStripL(pszValue);
    747     /* verified with Linux 2.4.0 ... Linux 2.6.25 */
    748     if (!strncmp(pszValue, "1.5", 3))
    749         *pSpd = USBDEVICESPEED_LOW;
    750     else if (!strncmp(pszValue, "12 ", 3))
    751         *pSpd = USBDEVICESPEED_FULL;
    752     else if (!strncmp(pszValue, "480", 3))
    753         *pSpd = USBDEVICESPEED_HIGH;
    754     else
    755         *pSpd = USBDEVICESPEED_UNKNOWN;
    756     while (pszValue[0] != '\0' && !RT_C_IS_SPACE(pszValue[0]))
    757         pszValue++;
    758     *ppszNext = (char *)pszValue;
    759     return VINF_SUCCESS;
    760 }
    761 
    762 
    763 /**
    764  * Compare a prefix and returns pointer to the char following it if it matches.
    765  */
    766 static char *usbPrefix(char *psz, const char *pszPref, size_t cchPref)
    767 {
    768     if (strncmp(psz, pszPref, cchPref))
    769         return NULL;
    770     return psz + cchPref;
    771 }
    772 
    773 
    774 /**
    775  * Does some extra checks to improve the detected device state.
    776  *
    777  * We cannot distinguish between USED_BY_HOST_CAPTURABLE and
    778  * USED_BY_GUEST, HELD_BY_PROXY all that well and it shouldn't be
    779  * necessary either.
    780  *
    781  * We will however, distinguish between the device we have permissions
    782  * to open and those we don't. This is necessary for two reasons.
    783  *
    784  * Firstly, because it's futile to even attempt opening a device which we
    785  * don't have access to, it only serves to confuse the user. (That said,
    786  * it might also be a bit confusing for the user to see that a USB device
    787  * is grayed out with no further explanation, and no way of generating an
    788  * error hinting at why this is the case.)
    789  *
    790  * Secondly and more importantly, we're racing against udevd with respect
    791  * to permissions and group settings on newly plugged devices. When we
    792  * detect a new device that we cannot access we will poll on it for a few
    793  * seconds to give udevd time to fix it. The polling is actually triggered
    794  * in the 'new device' case in the compare loop.
    795  *
    796  * The USBDEVICESTATE_USED_BY_HOST state is only used for this no-access
    797  * case, while USBDEVICESTATE_UNSUPPORTED is only used in the 'hub' case.
    798  * When it's neither of these, we set USBDEVICESTATE_UNUSED or
    799  * USBDEVICESTATE_USED_BY_HOST_CAPTURABLE depending on whether there is
    800  * a driver associated with any of the interfaces.
    801  *
    802  * All except the access check and a special idVendor == 0 precaution
    803  * is handled at parse time.
    804  *
    805  * @returns The adjusted state.
    806  * @param   pDevice     The device.
    807  */
    808 static USBDEVICESTATE usbDeterminState(PCUSBDEVICE pDevice)
    809 {
    810     /*
    811      * If it's already flagged as unsupported, there is nothing to do.
    812      */
    813     USBDEVICESTATE enmState = pDevice->enmState;
    814     if (enmState == USBDEVICESTATE_UNSUPPORTED)
    815         return USBDEVICESTATE_UNSUPPORTED;
    816 
    817     /*
    818      * Root hubs and similar doesn't have any vendor id, just
    819      * refuse these device.
    820      */
    821     if (!pDevice->idVendor)
    822         return USBDEVICESTATE_UNSUPPORTED;
    823 
    824     /*
    825      * Check if we've got access to the device, if we haven't flag
    826      * it as used-by-host.
    827      */
    828 #ifndef VBOX_USB_WITH_SYSFS
    829     const char *pszAddress = pDevice->pszAddress;
    830 #else
    831     if (pDevice->pszAddress == NULL)
    832         /* We can't do much with the device without an address. */
    833         return USBDEVICESTATE_UNSUPPORTED;
    834     const char *pszAddress = strstr(pDevice->pszAddress, "//device:");
    835     pszAddress = pszAddress != NULL
    836                ? pszAddress + sizeof("//device:") - 1
    837                : pDevice->pszAddress;
    838 #endif
    839     if (    access(pszAddress, R_OK | W_OK) != 0
    840         &&  errno == EACCES)
    841         return USBDEVICESTATE_USED_BY_HOST;
    842 
    843 #ifdef VBOX_USB_WITH_SYSFS
    844     /**
    845      * @todo Check that any other essential fields are present and mark as
    846      * invalid if not.  Particularly to catch the case where the device was
    847      * unplugged while we were reading in its properties.
    848      */
    849 #endif
    850 
    851     return enmState;
    852 }
    853 
    854 
    855 /** Just a worker for USBProxyServiceLinux::getDevices that avoids some code duplication. */
    856 static int addDeviceToChain(PUSBDEVICE pDev, PUSBDEVICE *ppFirst, PUSBDEVICE **pppNext, const char *pcszUsbfsRoot, int rc)
    857 {
    858     /* usbDeterminState requires the address. */
    859     PUSBDEVICE pDevNew = (PUSBDEVICE)RTMemDup(pDev, sizeof(*pDev));
    860     if (pDevNew)
    861     {
    862         RTStrAPrintf((char **)&pDevNew->pszAddress, "%s/%03d/%03d", pcszUsbfsRoot, pDevNew->bBus, pDevNew->bDevNum);
    863         if (pDevNew->pszAddress)
    864         {
    865             pDevNew->enmState = usbDeterminState(pDevNew);
    866             if (pDevNew->enmState != USBDEVICESTATE_UNSUPPORTED)
    867             {
    868                 if (*pppNext)
    869                     **pppNext = pDevNew;
    870                 else
    871                     *ppFirst = pDevNew;
    872                 *pppNext = &pDevNew->pNext;
    873             }
    874             else
    875                 deviceFree(pDevNew);
    876         }
    877         else
    878         {
    879             deviceFree(pDevNew);
    880             rc = VERR_NO_MEMORY;
    881         }
    882     }
    883     else
    884     {
    885         rc = VERR_NO_MEMORY;
    886         deviceFreeMembers(pDev);
    887     }
    888 
    889     return rc;
    890 }
    891 
    892 
    893 static int openDevicesFile(const char *pcszUsbfsRoot, FILE **ppFile)
    894 {
    895     char *pszPath;
    896     FILE *pFile;
    897     RTStrAPrintf(&pszPath, "%s/devices", pcszUsbfsRoot);
    898     if (!pszPath)
    899         return VERR_NO_MEMORY;
    900     pFile = fopen(pszPath, "r");
    901     RTStrFree(pszPath);
    902     if (!pFile)
    903         return RTErrConvertFromErrno(errno);
    904     *ppFile = pFile;
    905     return VINF_SUCCESS;
    906 }
    907 
    908 /**
    909  * USBProxyService::getDevices() implementation for usbfs.
    910  */
    911 static PUSBDEVICE getDevicesFromUsbfs(const char *pcszUsbfsRoot)
    912 {
    913     PUSBDEVICE pFirst = NULL;
    914     FILE *pFile;
    915     int rc;
    916     rc = openDevicesFile(pcszUsbfsRoot, &pFile);
    917     if (RT_SUCCESS(rc))
    918     {
    919         PUSBDEVICE     *ppNext = NULL;
    920         int             cHits = 0;
    921         char            szLine[1024];
    922         USBDEVICE       Dev;
    923         RT_ZERO(Dev);
    924         Dev.enmState = USBDEVICESTATE_UNUSED;
    925 
    926         rc = VINF_SUCCESS;
    927         while (     RT_SUCCESS(rc)
    928                &&   fgets(szLine, sizeof(szLine), pFile))
    929         {
    930             char   *psz;
    931             char   *pszValue;
    932 
    933             /* validate and remove the trailing newline. */
    934             psz = strchr(szLine, '\0');
    935             if (psz[-1] != '\n' && !feof(pFile))
    936             {
    937                 AssertMsgFailed(("Line too long. (cch=%d)\n", strlen(szLine)));
    938                 continue;
    939             }
    940 
    941             /* strip */
    942             psz = RTStrStrip(szLine);
    943             if (!*psz)
    944                 continue;
    945 
    946             /*
    947              * Interpret the line.
    948              * (Ordered by normal occurence.)
    949              */
    950             char ch = psz[0];
    951             if (psz[1] != ':')
    952                 continue;
    953             psz = RTStrStripL(psz + 3);
    954 #define PREFIX(str) ( (pszValue = usbPrefix(psz, str, sizeof(str) - 1)) != NULL )
    955             switch (ch)
    956             {
    957                 /*
    958                  * T:  Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd
    959                  * |   |      |      |       |       |      |        |       |__MaxChildren
    960                  * |   |      |      |       |       |      |        |__Device Speed in Mbps
    961                  * |   |      |      |       |       |      |__DeviceNumber
    962                  * |   |      |      |       |       |__Count of devices at this level
    963                  * |   |      |      |       |__Connector/Port on Parent for this device
    964                  * |   |      |      |__Parent DeviceNumber
    965                  * |   |      |__Level in topology for this bus
    966                  * |   |__Bus number
    967                  * |__Topology info tag
    968                  */
    969                 case 'T':
    970                     /* add */
    971                     AssertMsg(cHits >= 3 || cHits == 0, ("cHits=%d\n", cHits));
    972                     if (cHits >= 3)
    973                         rc = addDeviceToChain(&Dev, &pFirst, &ppNext, pcszUsbfsRoot, rc);
    974                     else
    975                         deviceFreeMembers(&Dev);
    976 
    977                     /* Reset device state */
    978                     memset(&Dev, 0, sizeof (Dev));
    979                     Dev.enmState = USBDEVICESTATE_UNUSED;
    980                     cHits = 1;
    981 
    982                     /* parse the line. */
    983                     while (*psz && RT_SUCCESS(rc))
    984                     {
    985                         if (PREFIX("Bus="))
    986                             rc = usbRead8(pszValue, 10, &Dev.bBus, &psz);
    987                         else if (PREFIX("Port="))
    988                             rc = usbRead8(pszValue, 10, &Dev.bPort, &psz);
    989                         else if (PREFIX("Spd="))
    990                             rc = usbReadSpeed(pszValue, &Dev.enmSpeed, &psz);
    991                         else if (PREFIX("Dev#="))
    992                             rc = usbRead8(pszValue, 10, &Dev.bDevNum, &psz);
    993                         else
    994                             psz = usbReadSkip(psz);
    995                         psz = RTStrStripL(psz);
    996                     }
    997                     break;
    998 
    999                 /*
    1000                  * Bandwidth info:
    1001                  * B:  Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd
    1002                  * |   |                       |         |__Number of isochronous requests
    1003                  * |   |                       |__Number of interrupt requests
    1004                  * |   |__Total Bandwidth allocated to this bus
    1005                  * |__Bandwidth info tag
    1006                  */
    1007                 case 'B':
    1008                     break;
    1009 
    1010                 /*
    1011                  * D:  Ver=x.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd
    1012                  * |   |        |             |      |       |       |__NumberConfigurations
    1013                  * |   |        |             |      |       |__MaxPacketSize of Default Endpoint
    1014                  * |   |        |             |      |__DeviceProtocol
    1015                  * |   |        |             |__DeviceSubClass
    1016                  * |   |        |__DeviceClass
    1017                  * |   |__Device USB version
    1018                  * |__Device info tag #1
    1019                  */
    1020                 case 'D':
    1021                     while (*psz && RT_SUCCESS(rc))
    1022                     {
    1023                         if (PREFIX("Ver="))
    1024                             rc = usbReadBCD(pszValue, 16, &Dev.bcdUSB, &psz);
    1025                         else if (PREFIX("Cls="))
    1026                         {
    1027                             rc = usbRead8(pszValue, 16, &Dev.bDeviceClass, &psz);
    1028                             if (RT_SUCCESS(rc) && Dev.bDeviceClass == 9 /* HUB */)
    1029                                 Dev.enmState = USBDEVICESTATE_UNSUPPORTED;
    1030                         }
    1031                         else if (PREFIX("Sub="))
    1032                             rc = usbRead8(pszValue, 16, &Dev.bDeviceSubClass, &psz);
    1033                         else if (PREFIX("Prot="))
    1034                             rc = usbRead8(pszValue, 16, &Dev.bDeviceProtocol, &psz);
    1035                         //else if (PREFIX("MxPS="))
    1036                         //    rc = usbRead16(pszValue, 10, &Dev.wMaxPacketSize, &psz);
    1037                         else if (PREFIX("#Cfgs="))
    1038                             rc = usbRead8(pszValue, 10, &Dev.bNumConfigurations, &psz);
    1039                         else
    1040                             psz = usbReadSkip(psz);
    1041                         psz = RTStrStripL(psz);
    1042                     }
    1043                     cHits++;
    1044                     break;
    1045 
    1046                 /*
    1047                  * P:  Vendor=xxxx ProdID=xxxx Rev=xx.xx
    1048                  * |   |           |           |__Product revision number
    1049                  * |   |           |__Product ID code
    1050                  * |   |__Vendor ID code
    1051                  * |__Device info tag #2
    1052                  */
    1053                 case 'P':
    1054                     while (*psz && RT_SUCCESS(rc))
    1055                     {
    1056                         if (PREFIX("Vendor="))
    1057                             rc = usbRead16(pszValue, 16, &Dev.idVendor, &psz);
    1058                         else if (PREFIX("ProdID="))
    1059                             rc = usbRead16(pszValue, 16, &Dev.idProduct, &psz);
    1060                         else if (PREFIX("Rev="))
    1061                             rc = usbReadBCD(pszValue, 16, &Dev.bcdDevice, &psz);
    1062                         else
    1063                             psz = usbReadSkip(psz);
    1064                         psz = RTStrStripL(psz);
    1065                     }
    1066                     cHits++;
    1067                     break;
    1068 
    1069                 /*
    1070                  * String.
    1071                  */
    1072                 case 'S':
    1073                     if (PREFIX("Manufacturer="))
    1074                         rc = usbReadStr(pszValue, &Dev.pszManufacturer);
    1075                     else if (PREFIX("Product="))
    1076                         rc = usbReadStr(pszValue, &Dev.pszProduct);
    1077                     else if (PREFIX("SerialNumber="))
    1078                     {
    1079                         rc = usbReadStr(pszValue, &Dev.pszSerialNumber);
    1080                         if (RT_SUCCESS(rc))
    1081                             Dev.u64SerialHash = USBLibHashSerial(pszValue);
    1082                     }
    1083                     break;
    1084 
    1085                 /*
    1086                  * C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
    1087                  * | | |       |       |      |__MaxPower in mA
    1088                  * | | |       |       |__Attributes
    1089                  * | | |       |__ConfiguratioNumber
    1090                  * | | |__NumberOfInterfaces
    1091                  * | |__ "*" indicates the active configuration (others are " ")
    1092                  * |__Config info tag
    1093                  */
    1094                 case 'C':
    1095                     break;
    1096 
    1097                 /*
    1098                  * I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
    1099                  * |   |      |      |       |             |      |       |__Driver name
    1100                  * |   |      |      |       |             |      |          or "(none)"
    1101                  * |   |      |      |       |             |      |__InterfaceProtocol
    1102                  * |   |      |      |       |             |__InterfaceSubClass
    1103                  * |   |      |      |       |__InterfaceClass
    1104                  * |   |      |      |__NumberOfEndpoints
    1105                  * |   |      |__AlternateSettingNumber
    1106                  * |   |__InterfaceNumber
    1107                  * |__Interface info tag
    1108                  */
    1109                 case 'I':
    1110                 {
    1111                     /* Check for thing we don't support.  */
    1112                     while (*psz && RT_SUCCESS(rc))
    1113                     {
    1114                         if (PREFIX("Driver="))
    1115                         {
    1116                             const char *pszDriver = NULL;
    1117                             rc = usbReadStr(pszValue, &pszDriver);
    1118                             if (   !pszDriver
    1119                                 || !*pszDriver
    1120                                 || !strcmp(pszDriver, "(none)")
    1121                                 || !strcmp(pszDriver, "(no driver)"))
    1122                                 /* no driver */;
    1123                             else if (!strcmp(pszDriver, "hub"))
    1124                                 Dev.enmState = USBDEVICESTATE_UNSUPPORTED;
    1125                             else if (Dev.enmState == USBDEVICESTATE_UNUSED)
    1126                                 Dev.enmState = USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
    1127                             RTStrFree((char *)pszDriver);
    1128                             break; /* last attrib */
    1129                         }
    1130                         else if (PREFIX("Cls="))
    1131                         {
    1132                             uint8_t bInterfaceClass;
    1133                             rc = usbRead8(pszValue, 16, &bInterfaceClass, &psz);
    1134                             if (RT_SUCCESS(rc) && bInterfaceClass == 9 /* HUB */)
    1135                                 Dev.enmState = USBDEVICESTATE_UNSUPPORTED;
    1136                         }
    1137                         else
    1138                             psz = usbReadSkip(psz);
    1139                         psz = RTStrStripL(psz);
    1140                     }
    1141                     break;
    1142                 }
    1143 
    1144 
    1145                 /*
    1146                  * E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=dddms
    1147                  * |   |        |            |         |__Interval (max) between transfers
    1148                  * |   |        |            |__EndpointMaxPacketSize
    1149                  * |   |        |__Attributes(EndpointType)
    1150                  * |   |__EndpointAddress(I=In,O=Out)
    1151                  * |__Endpoint info tag
    1152                  */
    1153                 case 'E':
    1154                     break;
    1155 
    1156             }
    1157 #undef PREFIX
    1158         } /* parse loop */
    1159 
    1160         /*
    1161          * Add the current entry.
    1162          */
    1163         AssertMsg(cHits >= 3 || cHits == 0, ("cHits=%d\n", cHits));
    1164         if (cHits >= 3)
    1165             rc = addDeviceToChain(&Dev, &pFirst, &ppNext, pcszUsbfsRoot, rc);
    1166 
    1167         /*
    1168          * Success?
    1169          */
    1170         if (RT_FAILURE(rc))
    1171         {
    1172             while (pFirst)
    1173             {
    1174                 PUSBDEVICE pFree = pFirst;
    1175                 pFirst = pFirst->pNext;
    1176                 deviceFree(pFree);
    1177             }
    1178         }
    1179     }
    1180     if (RT_FAILURE(rc))
    1181         LogFlow(("USBProxyServiceLinux::getDevices: rc=%Rrc\n", rc));
    1182     return pFirst;
    1183 }
    1184 
    1185 #ifdef VBOX_USB_WITH_SYSFS
    1186 
    1187 /**
    1188  * Helper function for extracting the port number on the parent device from
    1189  * the sysfs path value.
    1190  *
    1191  * The sysfs path is a chain of elements separated by forward slashes, and for
    1192  * USB devices, the last element in the chain takes the form
    1193  *   <port>-<port>.[...].<port>[:<config>.<interface>]
    1194  * where the first <port> is the port number on the root hub, and the following
    1195  * (optional) ones are the port numbers on any other hubs between the device
    1196  * and the root hub.  The last part (:<config.interface>) is only present for
    1197  * interfaces, not for devices.  This API should only be called for devices.
    1198  * For compatibility with usbfs, which enumerates from zero up, we subtract one
    1199  * from the port number.
    1200  *
    1201  * For root hubs, the last element in the chain takes the form
    1202  *   usb<hub number>
    1203  * and usbfs always returns port number zero.
    1204  *
    1205  * @returns VBox status. pu8Port is set on success.
    1206  * @param   pszPath     The sysfs path to parse.
    1207  * @param   pu8Port     Where to store the port number.
    1208  */
    1209 static int usbGetPortFromSysfsPath(const char *pszPath, uint8_t *pu8Port)
    1210 {
    1211     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    1212     AssertPtrReturn(pu8Port, VERR_INVALID_POINTER);
    1213 
    1214     /*
    1215      * This should not be possible until we get PCs with USB as their primary bus.
    1216      * Note: We don't assert this, as we don't expect the caller to validate the
    1217      *       sysfs path.
    1218      */
    1219     const char *pszLastComp = strrchr(pszPath, '/');
    1220     if (!pszLastComp)
    1221     {
    1222         Log(("usbGetPortFromSysfsPath(%s): failed [1]\n", pszPath));
    1223         return VERR_INVALID_PARAMETER;
    1224     }
    1225     pszLastComp++; /* skip the slash */
    1226 
    1227     /*
    1228      * This API should not be called for interfaces, so the last component
    1229      * of the path should not contain a colon.  We *do* assert this, as it
    1230      * might indicate a caller bug.
    1231      */
    1232     AssertMsgReturn(strchr(pszLastComp, ':') == NULL, ("%s\n", pszPath), VERR_INVALID_PARAMETER);
    1233 
    1234     /*
    1235      * Look for the start of the last number.
    1236      */
    1237     const char *pchDash = strrchr(pszLastComp, '-');
    1238     const char *pchDot  = strrchr(pszLastComp, '.');
    1239     if (!pchDash && !pchDot)
    1240     {
    1241         /* No -/. so it must be a root hub. Check that it's usb<something>. */
    1242         if (strncmp(pszLastComp, "usb", sizeof("usb") - 1) != 0)
    1243         {
    1244             Log(("usbGetPortFromSysfsPath(%s): failed [2]\n", pszPath));
    1245             return VERR_INVALID_PARAMETER;
    1246         }
    1247         return VERR_NOT_SUPPORTED;
    1248     }
    1249     else
    1250     {
    1251         const char *pszLastPort = pchDot != NULL
    1252                                 ? pchDot  + 1
    1253                                 : pchDash + 1;
    1254         int rc = RTStrToUInt8Full(pszLastPort, 10, pu8Port);
    1255         if (rc != VINF_SUCCESS)
    1256         {
    1257             Log(("usbGetPortFromSysfsPath(%s): failed [3], rc=%Rrc\n", pszPath, rc));
    1258             return VERR_INVALID_PARAMETER;
    1259         }
    1260         if (*pu8Port == 0)
    1261         {
    1262             Log(("usbGetPortFromSysfsPath(%s): failed [4]\n", pszPath));
    1263             return VERR_INVALID_PARAMETER;
    1264         }
    1265 
    1266         /* usbfs compatibility, 0-based port number. */
    1267         *pu8Port -= 1;
    1268     }
    1269     return VINF_SUCCESS;
    1270 }
    1271 
    1272 
    1273 /**
    1274  * Dumps a USBDEVICE structure to the log using LogLevel 3.
    1275  * @param   pDev        The structure to log.
    1276  * @todo    This is really common code.
    1277  */
    1278 DECLINLINE(void) usbLogDevice(PUSBDEVICE pDev)
    1279 {
    1280     NOREF(pDev);
    1281 
    1282     Log3(("USB device:\n"));
    1283     Log3(("Product: %s (%x)\n", pDev->pszProduct, pDev->idProduct));
    1284     Log3(("Manufacturer: %s (Vendor ID %x)\n", pDev->pszManufacturer, pDev->idVendor));
    1285     Log3(("Serial number: %s (%llx)\n", pDev->pszSerialNumber, pDev->u64SerialHash));
    1286     Log3(("Device revision: %d\n", pDev->bcdDevice));
    1287     Log3(("Device class: %x\n", pDev->bDeviceClass));
    1288     Log3(("Device subclass: %x\n", pDev->bDeviceSubClass));
    1289     Log3(("Device protocol: %x\n", pDev->bDeviceProtocol));
    1290     Log3(("USB version number: %d\n", pDev->bcdUSB));
    1291     Log3(("Device speed: %s\n",
    1292             pDev->enmSpeed == USBDEVICESPEED_UNKNOWN  ? "unknown"
    1293           : pDev->enmSpeed == USBDEVICESPEED_LOW      ? "1.5 MBit/s"
    1294           : pDev->enmSpeed == USBDEVICESPEED_FULL     ? "12 MBit/s"
    1295           : pDev->enmSpeed == USBDEVICESPEED_HIGH     ? "480 MBit/s"
    1296           : pDev->enmSpeed == USBDEVICESPEED_VARIABLE ? "variable"
    1297           :                                             "invalid"));
    1298     Log3(("Number of configurations: %d\n", pDev->bNumConfigurations));
    1299     Log3(("Bus number: %d\n", pDev->bBus));
    1300     Log3(("Port number: %d\n", pDev->bPort));
    1301     Log3(("Device number: %d\n", pDev->bDevNum));
    1302     Log3(("Device state: %s\n",
    1303             pDev->enmState == USBDEVICESTATE_UNSUPPORTED   ? "unsupported"
    1304           : pDev->enmState == USBDEVICESTATE_USED_BY_HOST  ? "in use by host"
    1305           : pDev->enmState == USBDEVICESTATE_USED_BY_HOST_CAPTURABLE ? "in use by host, possibly capturable"
    1306           : pDev->enmState == USBDEVICESTATE_UNUSED        ? "not in use"
    1307           : pDev->enmState == USBDEVICESTATE_HELD_BY_PROXY ? "held by proxy"
    1308           : pDev->enmState == USBDEVICESTATE_USED_BY_GUEST ? "used by guest"
    1309           :                                                  "invalid"));
    1310     Log3(("OS device address: %s\n", pDev->pszAddress));
    1311 }
    1312 
    1313 /**
    1314  * In contrast to usbReadBCD() this function can handle BCD values without
    1315  * a decimal separator. This is necessary for parsing bcdDevice.
    1316  * @param   pszBuf      Pointer to the string buffer.
    1317  * @param   pu15        Pointer to the return value.
    1318  * @returns IPRT status code.
    1319  */
    1320 static int convertSysfsStrToBCD(const char *pszBuf, uint16_t *pu16)
    1321 {
    1322     char *pszNext;
    1323     int32_t i32;
    1324 
    1325     pszBuf = RTStrStripL(pszBuf);
    1326     int rc = RTStrToInt32Ex(pszBuf, &pszNext, 16, &i32);
    1327     if (   RT_FAILURE(rc)
    1328         || rc == VWRN_NUMBER_TOO_BIG
    1329         || i32 < 0)
    1330         return VERR_NUMBER_TOO_BIG;
    1331     if (*pszNext == '.')
    1332     {
    1333         if (i32 > 255)
    1334             return VERR_NUMBER_TOO_BIG;
    1335         int32_t i32Lo;
    1336         rc = RTStrToInt32Ex(pszNext+1, &pszNext, 16, &i32Lo);
    1337         if (   RT_FAILURE(rc)
    1338             || rc == VWRN_NUMBER_TOO_BIG
    1339             || i32Lo > 255
    1340             || i32Lo < 0)
    1341             return VERR_NUMBER_TOO_BIG;
    1342         i32 = (i32 << 8) | i32Lo;
    1343     }
    1344     if (   i32 > 65535
    1345         || (*pszNext != '\0' && *pszNext != ' '))
    1346         return VERR_NUMBER_TOO_BIG;
    1347 
    1348     *pu16 = (uint16_t)i32;
    1349     return VINF_SUCCESS;
    1350 }
    1351 
    1352 #endif  /* VBOX_USB_WITH_SYSFS */
    1353 
    1354 static void fillInDeviceFromSysfs(USBDEVICE *Dev, USBDeviceInfo *pInfo)
    1355 {
    1356     int rc;
    1357     const char *pszSysfsPath = pInfo->mSysfsPath;
    1358 
    1359     /* Fill in the simple fields */
    1360     Dev->enmState           = USBDEVICESTATE_UNUSED;
    1361     Dev->bBus               = RTLinuxSysFsReadIntFile(10, "%s/busnum", pszSysfsPath);
    1362     Dev->bDeviceClass       = RTLinuxSysFsReadIntFile(16, "%s/bDeviceClass", pszSysfsPath);
    1363     Dev->bDeviceSubClass    = RTLinuxSysFsReadIntFile(16, "%s/bDeviceSubClass", pszSysfsPath);
    1364     Dev->bDeviceProtocol    = RTLinuxSysFsReadIntFile(16, "%s/bDeviceProtocol", pszSysfsPath);
    1365     Dev->bNumConfigurations = RTLinuxSysFsReadIntFile(10, "%s/bNumConfigurations", pszSysfsPath);
    1366     Dev->idVendor           = RTLinuxSysFsReadIntFile(16, "%s/idVendor", pszSysfsPath);
    1367     Dev->idProduct          = RTLinuxSysFsReadIntFile(16, "%s/idProduct", pszSysfsPath);
    1368     Dev->bDevNum            = RTLinuxSysFsReadIntFile(10, "%s/devnum", pszSysfsPath);
    1369 
    1370     /* Now deal with the non-numeric bits. */
    1371     char szBuf[1024];  /* Should be larger than anything a sane device
    1372                         * will need, and insane devices can be unsupported
    1373                         * until further notice. */
    1374     ssize_t cchRead;
    1375 
    1376     /* For simplicity, we just do strcmps on the next one. */
    1377     cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/speed",
    1378                                       pszSysfsPath);
    1379     if (cchRead <= 0 || (size_t) cchRead == sizeof(szBuf))
    1380         Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
    1381     else
    1382         Dev->enmSpeed =   !strcmp(szBuf, "1.5") ? USBDEVICESPEED_LOW
    1383                         : !strcmp(szBuf, "12")  ? USBDEVICESPEED_FULL
    1384                         : !strcmp(szBuf, "480") ? USBDEVICESPEED_HIGH
    1385                         : USBDEVICESPEED_UNKNOWN;
    1386 
    1387     cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/version",
    1388                                       pszSysfsPath);
    1389     if (cchRead <= 0 || (size_t) cchRead == sizeof(szBuf))
    1390         Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
    1391     else
    1392     {
    1393         rc = convertSysfsStrToBCD(szBuf, &Dev->bcdUSB);
    1394         if (RT_FAILURE(rc))
    1395         {
    1396             Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
    1397             Dev->bcdUSB = (uint16_t)-1;
    1398         }
    1399     }
    1400 
    1401     cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/bcdDevice",
    1402                                       pszSysfsPath);
    1403     if (cchRead <= 0 || (size_t) cchRead == sizeof(szBuf))
    1404         Dev->bcdDevice = (uint16_t)-1;
    1405     else
    1406     {
    1407         rc = convertSysfsStrToBCD(szBuf, &Dev->bcdDevice);
    1408         if (RT_FAILURE(rc))
    1409             Dev->bcdDevice = (uint16_t)-1;
    1410     }
    1411 
    1412     /* Now do things that need string duplication */
    1413     cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/product",
    1414                                       pszSysfsPath);
    1415     if (cchRead > 0 && (size_t) cchRead < sizeof(szBuf))
    1416     {
    1417         RTStrPurgeEncoding(szBuf);
    1418         Dev->pszProduct = RTStrDup(szBuf);
    1419     }
    1420 
    1421     cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/serial",
    1422                                       pszSysfsPath);
    1423     if (cchRead > 0 && (size_t) cchRead < sizeof(szBuf))
    1424     {
    1425         RTStrPurgeEncoding(szBuf);
    1426         Dev->pszSerialNumber = RTStrDup(szBuf);
    1427         Dev->u64SerialHash = USBLibHashSerial(szBuf);
    1428     }
    1429 
    1430     cchRead = RTLinuxSysFsReadStrFile(szBuf, sizeof(szBuf), "%s/manufacturer",
    1431                                       pszSysfsPath);
    1432     if (cchRead > 0 && (size_t) cchRead < sizeof(szBuf))
    1433     {
    1434         RTStrPurgeEncoding(szBuf);
    1435         Dev->pszManufacturer = RTStrDup(szBuf);
    1436     }
    1437 
    1438     /* Work out the port number */
    1439     if (RT_FAILURE(usbGetPortFromSysfsPath(pszSysfsPath, &Dev->bPort)))
    1440         Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
    1441 
    1442     /* Check the interfaces to see if we can support the device. */
    1443     char **ppszIf;
    1444     VEC_FOR_EACH(&pInfo->mvecpszInterfaces, char *, ppszIf)
    1445     {
    1446         ssize_t cb = RTLinuxSysFsGetLinkDest(szBuf, sizeof(szBuf), "%s/driver",
    1447                                              *ppszIf);
    1448         if (cb > 0 && Dev->enmState != USBDEVICESTATE_UNSUPPORTED)
    1449             Dev->enmState = (strcmp(szBuf, "hub") == 0)
    1450                           ? USBDEVICESTATE_UNSUPPORTED
    1451                           : USBDEVICESTATE_USED_BY_HOST_CAPTURABLE;
    1452         if (RTLinuxSysFsReadIntFile(16, "%s/bInterfaceClass",
    1453                                     *ppszIf) == 9 /* hub */)
    1454             Dev->enmState = USBDEVICESTATE_UNSUPPORTED;
    1455     }
    1456 
    1457     /* We want a copy of the device node and sysfs paths guaranteed not to
    1458      * contain double slashes, since we use a double slash as a separator in
    1459      * the pszAddress field. */
    1460     char szDeviceClean[RTPATH_MAX];
    1461     char szSysfsClean[RTPATH_MAX];
    1462     char *pszAddress = NULL;
    1463     if (   RT_SUCCESS(RTPathReal(pInfo->mDevice, szDeviceClean,
    1464                                  sizeof(szDeviceClean)))
    1465         && RT_SUCCESS(RTPathReal(pszSysfsPath, szSysfsClean,
    1466                                  sizeof(szSysfsClean)))
    1467        )
    1468         RTStrAPrintf(&pszAddress, "sysfs:%s//device:%s", szSysfsClean,
    1469                      szDeviceClean);
    1470     Dev->pszAddress = pszAddress;
    1471 
    1472     /* Work out from the data collected whether we can support this device. */
    1473     Dev->enmState = usbDeterminState(Dev);
    1474     usbLogDevice(Dev);
    1475 }
    1476 
    1477 /**
    1478  * USBProxyService::getDevices() implementation for sysfs.
    1479  */
    1480 static PUSBDEVICE getDevicesFromSysfs(void)
    1481 {
    1482 #ifdef VBOX_USB_WITH_SYSFS
    1483     /* Add each of the devices found to the chain. */
    1484     PUSBDEVICE pFirst = NULL;
    1485     PUSBDEVICE pLast  = NULL;
    1486     VECTOR_OBJ(USBDeviceInfo) vecDevInfo;
    1487     USBDeviceInfo *pInfo;
    1488     int rc;
    1489 
    1490     VEC_INIT_OBJ(&vecDevInfo, USBDeviceInfo, USBDevInfoCleanup);
    1491     rc = USBSysfsEnumerateHostDevices(&vecDevInfo);
    1492     if (RT_FAILURE(rc))
    1493         return NULL;
    1494     VEC_FOR_EACH(&vecDevInfo, USBDeviceInfo, pInfo)
    1495     {
    1496         USBDEVICE *Dev = (USBDEVICE *)RTMemAllocZ(sizeof(USBDEVICE));
    1497         if (!Dev)
    1498             rc = VERR_NO_MEMORY;
    1499         if (RT_SUCCESS(rc))
    1500         {
    1501             fillInDeviceFromSysfs(Dev, pInfo);
    1502         }
    1503         if (   RT_SUCCESS(rc)
    1504             && Dev->enmState != USBDEVICESTATE_UNSUPPORTED
    1505             && Dev->pszAddress != NULL
    1506            )
    1507         {
    1508             if (pLast != NULL)
    1509             {
    1510                 pLast->pNext = Dev;
    1511                 pLast = pLast->pNext;
    1512             }
    1513             else
    1514                 pFirst = pLast = Dev;
    1515         }
    1516         else
    1517             deviceFree(Dev);
    1518         if (RT_FAILURE(rc))
    1519             break;
    1520     }
    1521     if (RT_FAILURE(rc))
    1522         while (pFirst)
    1523         {
    1524             PUSBDEVICE pNext = pFirst->pNext;
    1525             deviceFree(pFirst);
    1526             pFirst = pNext;
    1527         }
    1528 
    1529     VEC_CLEANUP_OBJ(&vecDevInfo);
    1530     return pFirst;
    1531 #else  /* !VBOX_USB_WITH_SYSFS */
    1532     return NULL;
    1533 #endif  /* !VBOX_USB_WITH_SYSFS */
    1534 }
    1535 
    1536 static PUSBDEVICE USBProxyLinuxGetDevices(const char *pcszUsbfsRoot)
    1537 {
    1538     if (pcszUsbfsRoot)
    1539         return getDevicesFromUsbfs(pcszUsbfsRoot);
    1540     else
    1541         return getDevicesFromSysfs();
    1542 }
    1543438
    1544439PUSBDEVICE USBProxyServiceLinux::getDevices(void)
  • trunk/src/VBox/Main/testcase/Makefile.kmk

    r30931 r32324  
    151151tstHostHardwareLinux_SOURCES   = \
    152152        tstHostHardwareLinux.cpp \
    153         ../linux/HostHardwareLinux.cpp
     153        ../linux/HostHardwareLinux.cpp \
     154        ../linux/USBGetDevices.cpp
    154155tstHostHardwareLinux_INCS      = . ../include
    155156tstHostHardwareLinux_DEFS      = \
  • trunk/src/VBox/Main/testcase/tstHostHardwareLinux.cpp

    r32299 r32324  
    1919
    2020#include <HostHardwareLinux.h>
     21#include <USBGetDevices.h>
    2122
    2223#include <VBox/err.h>
     
    5253    }
    5354    return rc;
     55}
     56
     57void printDevices(PUSBDEVICE pDevices, const char *pcszAccess)
     58{
     59    PUSBDEVICE pDevice = pDevices;
     60
     61    RTPrintf("Enumerating usb devices using %s\n", pcszAccess);
     62    while (pDevice)
     63    {
     64        RTPrintf("  Manufacturer: %s, product: %s, serial number string: %s\n",
     65                    pDevice->pszManufacturer, pDevice->pszProduct,
     66                    pDevice->pszSerialNumber);
     67        RTPrintf("    Device address: %s\n", pDevice->pszAddress);
     68        pDevice = pDevice->pNext;
     69    }
     70}
     71
     72void freeDevices(PUSBDEVICE pDevices)
     73{
     74    PUSBDEVICE pDevice = pDevices, pDeviceNext;
     75
     76    while (pDevice)
     77    {
     78        pDeviceNext = pDevice->pNext;
     79        deviceFree(pDevice);
     80        pDevice = pDeviceNext;
     81    }
    5482}
    5583
     
    91119    }
    92120#ifdef VBOX_USB_WITH_SYSFS
    93     VECTOR_OBJ(USBDeviceInfo) vecDevInfo;
    94     VEC_INIT_OBJ(&vecDevInfo, USBDeviceInfo, USBDevInfoCleanup);
    95     rc = USBSysfsEnumerateHostDevices(&vecDevInfo);
    96     if (RT_FAILURE(rc))
     121    PUSBDEVICE pDevice = USBProxyLinuxGetDevices(NULL);
     122    printDevices(pDevice, "sysfs");
     123    freeDevices(pDevice);
     124    if (USBProxyLinuxCheckForUsbfs("/proc/bus/usb/devices"))
    97125    {
    98         RTPrintf ("Failed to update the host USB device information, error %Rrc\n",
    99                  rc);
    100         return 1;
     126        pDevice = USBProxyLinuxGetDevices("/proc/bus/usb");
     127        printDevices(pDevice, "/proc/bus/usb");
     128        freeDevices(pDevice);
    101129    }
    102     RTPrintf ("Listing USB devices detected:\n");
    103     USBDeviceInfo *pInfo;
    104     VEC_FOR_EACH(&vecDevInfo, USBDeviceInfo, pInfo)
     130    if (USBProxyLinuxCheckForUsbfs("/dev/bus/usb/devices"))
    105131    {
    106         char szProduct[1024];
    107         if (RTLinuxSysFsReadStrFile(szProduct, sizeof(szProduct),
    108                                     "%s/product", pInfo->mSysfsPath) == -1)
    109         {
    110             if (errno != ENOENT)
    111             {
    112                 RTPrintf ("Failed to get the product name for device %s: error %s\n",
    113                           pInfo->mDevice, strerror(errno));
    114                 return 1;
    115             }
    116             else
    117                 szProduct[0] = '\0';
    118         }
    119         RTPrintf ("  device: %s (%s), sysfs path: %s\n", szProduct, pInfo->mDevice,
    120                   pInfo->mSysfsPath);
    121         RTPrintf ("    interfaces:\n");
    122         char **ppszIf;
    123         VEC_FOR_EACH(&pInfo->mvecpszInterfaces, char *, ppszIf)
    124         {
    125             char szDriver[RTPATH_MAX];
    126             strcpy(szDriver, "none");
    127             ssize_t size = RTLinuxSysFsGetLinkDest(szDriver, sizeof(szDriver),
    128                                                    "%s/driver", *ppszIf);
    129             if (size == -1 && errno != ENOENT)
    130             {
    131                 RTPrintf ("Failed to get the driver for interface %s of device %s: error %s\n",
    132                           *ppszIf, pInfo->mDevice, strerror(errno));
    133                 return 1;
    134             }
    135             if (RTLinuxSysFsExists("%s/driver", *ppszIf) != (size != -1))
    136             {
    137                 RTPrintf ("RTLinuxSysFsExists did not return the expected value for the driver link of interface %s of device %s.\n",
    138                           *ppszIf, pInfo->mDevice);
    139                 return 1;
    140             }
    141             uint64_t u64InterfaceClass;
    142             u64InterfaceClass = RTLinuxSysFsReadIntFile(16, "%s/bInterfaceClass",
    143                                                         *ppszIf);
    144             RTPrintf ("      sysfs path: %s, driver: %s, interface class: 0x%x\n",
    145                       *ppszIf, szDriver, u64InterfaceClass);
    146         }
     132        pDevice = USBProxyLinuxGetDevices("/dev/bus/usb");
     133        printDevices(pDevice, "/dev/bus/usb");
     134        freeDevices(pDevice);
    147135    }
    148     VEC_CLEANUP_OBJ(&vecDevInfo);
    149136    VBoxMainHotplugWaiter waiter;
    150137    RTPrintf ("Waiting for a hotplug event for five seconds...\n");
Note: See TracChangeset for help on using the changeset viewer.

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