VirtualBox

Changeset 31581 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Aug 11, 2010 9:02:13 PM (14 years ago)
Author:
vboxsync
Message:

Main/HostHardwareLinux: convert USB enumeration to C, first part

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/linux/HostHardwareLinux.cpp

    r31564 r31581  
    9090
    9191/** Function object to be invoked on filenames from a directory. */
    92 class pathHandler
     92typedef struct pathHandler
    9393{
    9494    /** Called on each element of the sysfs directory.  Can e.g. store
    9595     * interesting entries in a list. */
    96     virtual bool handle(const char *pcszNode) = 0;
    97 public:
    98     bool doHandle(const char *pcszNode)
    99     {
    100         AssertPtr(pcszNode);
    101         Assert(pcszNode[0] == '/');
    102         return handle(pcszNode);
    103     }
    104 };
     96    bool (*handle)(pathHandler *pHandle, const char *pcszNode);
     97} pathHandler;
     98
     99static bool phDoHandle(pathHandler *pHandler, const char *pcszNode)
     100{
     101    AssertPtr(pHandler);
     102    AssertPtr(pHandler->handle);
     103    AssertPtr(pcszNode);
     104    Assert(pcszNode[0] == '/');
     105    return pHandler->handle(pHandler, pcszNode);
     106}
    105107
    106108static int walkDirectory(const char *pcszPath, pathHandler *pHandler,
     
    10431045 * Inherits from pathHandler so that it can be passed to walkDirectory() to
    10441046 * easily add all files from a directory. */
    1045 class inotifyWatch : public pathHandler
    1046 {
     1047typedef struct inotifyWatch
     1048{
     1049    /** The pathHandler we inherit from - this must be the first structure
     1050     * member */
     1051    pathHandler mParent;
    10471052    /** Pointer to the inotify_add_watch() glibc function/Linux API */
    10481053    int (*inotify_add_watch)(int, const char *, uint32_t);
    10491054    /** The native handle of the inotify fd. */
    10501055    int mhInotify;
    1051     /** Object initialisation status, to save us throwing an exception from
    1052      * the constructor if we can't initialise */
    1053     int mStatus;
    1054 
    1055     /** Object initialistation */
    1056     int initInotify(void);
    1057 
    1058 public:
    1059     /** Add @a pcszPath to the list of files and directories to be monitored */
    1060     virtual bool handle(const char *pcszPath);
    1061 
    1062     inotifyWatch(void) : mhInotify(-1)
    1063     {
    1064         mStatus = initInotify();
    1065     }
    1066 
    1067     ~inotifyWatch(void)
    1068     {
    1069         if (mhInotify != -1)
    1070         {
    1071             close(mhInotify);
    1072             mhInotify = -1;
    1073         }
    1074     }
    1075 
    1076     int getStatus(void)
    1077     {
    1078         return mStatus;
    1079     }
    1080 
    1081     int getFD(void)
    1082     {
    1083         AssertRCReturn(mStatus, -1);
    1084         return mhInotify;
    1085     }
    1086 };
    1087 
    1088 int inotifyWatch::initInotify(void)
     1056} inotifyWatch;
     1057
     1058/** The flags we pass to inotify - modify, create, delete, change permissions
     1059 */
     1060#define IN_FLAGS 0x306
     1061
     1062static bool iwHandle(pathHandler *pParent, const char *pcszPath)
     1063{
     1064    AssertPtrReturn(pParent, false);
     1065    AssertReturn(pParent->handle == iwHandle, false);
     1066    inotifyWatch *pSelf = (inotifyWatch *)pParent;
     1067    errno = 0;
     1068    if (  pSelf->inotify_add_watch(pSelf->mhInotify, pcszPath, IN_FLAGS) >= 0
     1069        || (errno == EACCES))
     1070        return true;
     1071    /* Other errors listed in the manpage can be treated as fatal */
     1072    return false;
     1073}
     1074
     1075/** Object initialisation */
     1076static int iwInit(inotifyWatch *pSelf)
    10891077{
    10901078    int (*inotify_init)(void);
    10911079    int fd, flags;
    1092 
     1080    int rc = VINF_SUCCESS;
     1081
     1082    AssertPtr(pSelf);
     1083    pSelf->mParent.handle = iwHandle;
     1084    pSelf->mhInotify = -1;
    10931085    errno = 0;
    10941086    *(void **)(&inotify_init) = dlsym(RTLD_DEFAULT, "inotify_init");
    10951087    if (!inotify_init)
    10961088        return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
    1097     *(void **)(&inotify_add_watch) = dlsym(RTLD_DEFAULT, "inotify_add_watch");
    1098     if (!inotify_add_watch)
     1089    *(void **)(&pSelf->inotify_add_watch)
     1090                    = dlsym(RTLD_DEFAULT, "inotify_add_watch");
     1091    if (!pSelf->inotify_add_watch)
    10991092        return VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
    11001093    fd = inotify_init();
     
    11061099    Assert(errno == 0);
    11071100
    1108     int rc = VINF_SUCCESS;
    1109 
    11101101    flags = fcntl(fd, F_GETFL, NULL);
    11111102    if (   flags < 0
     
    11201111    {
    11211112        Assert(errno == 0);
    1122         mhInotify = fd;
     1113        pSelf->mhInotify = fd;
    11231114    }
    11241115    return rc;
    11251116}
    11261117
    1127 /** The flags we pass to inotify - modify, create, delete, change permissions
    1128  */
    1129 #define IN_FLAGS 0x306
    1130 
    1131 bool inotifyWatch::handle(const char *pcszPath)
    1132 {
    1133     AssertRCReturn(mStatus, false);
    1134     errno = 0;
    1135     if (  inotify_add_watch(mhInotify, pcszPath, IN_FLAGS) >= 0
    1136         || (errno == EACCES))
    1137         return true;
    1138     /* Other errors listed in the manpage can be treated as fatal */
    1139     return false;
     1118static void iwTerm(inotifyWatch *pSelf)
     1119{
     1120    AssertPtrReturnVoid(pSelf);
     1121    if (pSelf->mhInotify != -1)
     1122    {
     1123        close(pSelf->mhInotify);
     1124        pSelf->mhInotify = -1;
     1125    }
     1126}
     1127
     1128static int iwGetFD(inotifyWatch *pSelf)
     1129{
     1130    AssertPtrReturn(pSelf, -1);
     1131    return pSelf->mhInotify;
    11401132}
    11411133
     
    12431235    int rc;
    12441236    do {
    1245         if (RT_FAILURE(rc = mWatches.getStatus()))
     1237        if (RT_FAILURE(rc = iwInit(&mWatches)))
    12461238            break;
    1247         mWatches.doHandle(SYSFS_USB_DEVICE_PATH);
     1239        phDoHandle(&mWatches.mParent, SYSFS_USB_DEVICE_PATH);
    12481240        if (RT_FAILURE(rc = pipeCreateSimple(&mhWakeupPipeR, &mhWakeupPipeW)))
    12491241            break;
     
    12681260        mhWakeupPipeW = -1;
    12691261    }
     1262    iwTerm(&mWatches);
    12701263}
    12711264
     
    12781271    errno = 0;
    12791272    do {
    1280         cchRead = read(mWatches.getFD(), chBuf, sizeof(chBuf));
     1273        cchRead = read(iwGetFD(&mWatches), chBuf, sizeof(chBuf));
    12811274    } while (cchRead > 0);
    12821275    if (cchRead == 0)
     
    13091302        struct pollfd pollFD[MAX_POLLID];
    13101303
    1311         if (RT_FAILURE(rc = walkDirectory(SYSFS_USB_DEVICE_PATH, &mWatches,
     1304        if (RT_FAILURE(rc = walkDirectory(SYSFS_USB_DEVICE_PATH, &mWatches.mParent,
    13121305                                          false)))
    13131306            break;
    13141307        pollFD[RPIPE_ID].fd = mhWakeupPipeR;
    13151308        pollFD[RPIPE_ID].events = POLLIN;
    1316         pollFD[INOTIFY_ID].fd = mWatches.getFD();
     1309        pollFD[INOTIFY_ID].fd = iwGetFD(&mWatches);
    13171310        pollFD[INOTIFY_ID].events = POLLIN | POLLERR | POLLHUP;
    13181311        errno = 0;
     
    14241417            if (RT_FAILURE(rc))
    14251418                break;  /* The file can vanish if a device is unplugged. */
    1426             if (!pHandler->doHandle(szAbsPath))
     1419            if (!phDoHandle(pHandler, szAbsPath))
    14271420                break;
    14281421        }
    14291422        else
    1430             if (!pHandler->doHandle(szPath))
     1423            if (!phDoHandle(pHandler, szPath))
    14311424                break;
    14321425    }
     
    14821475 * interface.  To be used with getDeviceInfoFromSysfs().
    14831476 */
    1484 class matchUSBDevice : public pathHandler
    1485 {
     1477typedef struct matchUSBDevice
     1478{
     1479    /** The pathHandler object we inherit from - must come first */
     1480    pathHandler mParent;
    14861481    USBDeviceInfoList *mList;
    1487 public:
    1488     matchUSBDevice(USBDeviceInfoList *pList) : mList(pList) {}
    1489 private:
    1490     virtual bool handle(const char *pcszNode)
    1491     {
    1492         const char *pcszFile = strrchr(pcszNode, '/');
    1493         if (strchr(pcszFile, ':'))
    1494             return true;
    1495         dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode);
    1496         /* Sanity test of our static helpers */
    1497         Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5);
    1498         Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6);
    1499         AssertReturn (devnum, true);
    1500         char szDevPath[RTPATH_MAX];
    1501         ssize_t cchDevPath;
    1502         cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR,
    1503                                            szDevPath, sizeof(szDevPath),
    1504                                            "/dev/bus/usb/%.3d/%.3d",
    1505                                            usbBusFromDevNum(devnum),
    1506                                            usbDeviceFromDevNum(devnum));
    1507         if (cchDevPath < 0)
    1508             return true;
    1509         try
    1510         {
    1511             mList->push_back(USBDeviceInfo(szDevPath, pcszNode));
    1512         }
    1513         catch(std::bad_alloc &e)
    1514         {
    1515             return false;
    1516         }
    1517         return true;
    1518     }
    1519 };
     1482} matchUSBDevice;
     1483
     1484static bool mudHandle(pathHandler *pParent, const char *pcszNode)
     1485{
     1486    AssertPtrReturn(pParent, false);
     1487    AssertReturn(pParent->handle = mudHandle, false);
     1488    matchUSBDevice *pSelf = (matchUSBDevice *)pParent;
     1489    const char *pcszFile = strrchr(pcszNode, '/');
     1490    if (strchr(pcszFile, ':'))
     1491        return true;
     1492    dev_t devnum = RTLinuxSysFsReadDevNumFile("%s/dev", pcszNode);
     1493    /* Sanity test of our static helpers */
     1494    Assert(usbBusFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 5);
     1495    Assert(usbDeviceFromDevNum(makedev(USBDEVICE_MAJOR, 517)) == 6);
     1496    AssertReturn (devnum, true);
     1497    char szDevPath[RTPATH_MAX];
     1498    ssize_t cchDevPath;
     1499    cchDevPath = RTLinuxFindDevicePath(devnum, RTFS_TYPE_DEV_CHAR,
     1500                                       szDevPath, sizeof(szDevPath),
     1501                                       "/dev/bus/usb/%.3d/%.3d",
     1502                                       usbBusFromDevNum(devnum),
     1503                                       usbDeviceFromDevNum(devnum));
     1504    if (cchDevPath < 0)
     1505        return true;
     1506    try
     1507    {
     1508        pSelf->mList->push_back(USBDeviceInfo(szDevPath, pcszNode));
     1509    }
     1510    catch(std::bad_alloc &e)
     1511    {
     1512        return false;
     1513    }
     1514    return true;
     1515}
     1516
     1517static void mudInit(matchUSBDevice *pSelf, USBDeviceInfoList *pList)
     1518{
     1519    AssertPtrReturnVoid(pSelf);
     1520    pSelf->mParent.handle = mudHandle;
     1521    pSelf->mList = pList;
     1522}
     1523
    15201524
    15211525/**
     
    15231527 * device.  To be used with getDeviceInfoFromSysfs().
    15241528 */
    1525 class matchUSBInterface : public pathHandler
    1526 {
     1529typedef struct matchUSBInterface
     1530{
     1531    /** The pathHandler class we inherit from - must be the first member. */
     1532    pathHandler mParent;
    15271533    USBDeviceInfo *mInfo;
    1528 public:
    1529     /** This constructor is currently used to unit test the class logic in
    1530      * debug builds.  Since no access is made to anything outside the class,
    1531      * this shouldn't cause any slowdown worth mentioning. */
    1532     matchUSBInterface(USBDeviceInfo *pInfo) : mInfo(pInfo)
    1533     {
    1534         Assert(isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0",
    1535                "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
    1536         Assert(!isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1",
    1537                "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
    1538         Assert(!isAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver",
    1539                "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
    1540     }
    1541 private:
    1542     /** The logic for testing whether a sysfs address corresponds to an
    1543      * interface of a device.  Both must be referenced by their canonical
    1544      * sysfs paths.  This is not tested, as the test requires file-system
    1545      * interaction. */
    1546     bool isAnInterfaceOf(const char *pcszIface, const char *pcszDev)
    1547     {
    1548         size_t cchDev = strlen(pcszDev);
    1549 
    1550         AssertPtr(pcszIface);
    1551         AssertPtr(pcszDev);
    1552         Assert(pcszIface[0] == '/');
    1553         Assert(pcszDev[0] == '/');
    1554         Assert(pcszDev[cchDev - 1] != '/');
    1555         /* If this passes, pcszIface is at least cchDev long */
    1556         if (strncmp(pcszIface, pcszDev, cchDev))
    1557             return false;
    1558         /* If this passes, pcszIface is longer than cchDev */
    1559         if (pcszIface[cchDev] != '/')
    1560             return false;
    1561         /* In sysfs an interface is an immediate subdirectory of the device */
    1562         if (strchr(pcszIface + cchDev + 1, '/'))
    1563             return false;
    1564         /* And it always has a colon in its name */
    1565         if (!strchr(pcszIface + cchDev + 1, ':'))
    1566             return false;
    1567         /* And hopefully we have now elimitated everything else */
    1568         return true;
    1569     }
    1570 
    1571     virtual bool handle(const char *pcszNode)
    1572     {
    1573         if (!isAnInterfaceOf(pcszNode, mInfo->mSysfsPath.c_str()))
    1574             return true;
    1575         try
    1576         {
    1577             mInfo->mInterfaces.push_back(pcszNode);
    1578         }
    1579         catch(std::bad_alloc &e)
    1580         {
    1581             return false;
    1582         }
    1583         return true;
    1584     }
    1585 };
     1534} matchUSBInterface;
     1535
     1536/** The logic for testing whether a sysfs address corresponds to an
     1537 * interface of a device.  Both must be referenced by their canonical
     1538 * sysfs paths.  This is not tested, as the test requires file-system
     1539 * interaction. */
     1540static bool muiIsAnInterfaceOf(const char *pcszIface, const char *pcszDev)
     1541{
     1542    size_t cchDev = strlen(pcszDev);
     1543
     1544    AssertPtr(pcszIface);
     1545    AssertPtr(pcszDev);
     1546    Assert(pcszIface[0] == '/');
     1547    Assert(pcszDev[0] == '/');
     1548    Assert(pcszDev[cchDev - 1] != '/');
     1549    /* If this passes, pcszIface is at least cchDev long */
     1550    if (strncmp(pcszIface, pcszDev, cchDev))
     1551        return false;
     1552    /* If this passes, pcszIface is longer than cchDev */
     1553    if (pcszIface[cchDev] != '/')
     1554        return false;
     1555    /* In sysfs an interface is an immediate subdirectory of the device */
     1556    if (strchr(pcszIface + cchDev + 1, '/'))
     1557        return false;
     1558    /* And it always has a colon in its name */
     1559    if (!strchr(pcszIface + cchDev + 1, ':'))
     1560        return false;
     1561    /* And hopefully we have now elimitated everything else */
     1562    return true;
     1563}
     1564
     1565static bool muiHandle(pathHandler *pParent, const char *pcszNode)
     1566{
     1567    AssertPtrReturn(pParent, false);
     1568    AssertReturn(pParent->handle == muiHandle, false);
     1569    matchUSBInterface *pSelf = (matchUSBInterface *)pParent;
     1570    if (!muiIsAnInterfaceOf(pcszNode, pSelf->mInfo->mSysfsPath.c_str()))
     1571        return true;
     1572    try
     1573    {
     1574        pSelf->mInfo->mInterfaces.push_back(pcszNode);
     1575    }
     1576    catch(std::bad_alloc &e)
     1577    {
     1578        return false;
     1579    }
     1580    return true;
     1581}
     1582
     1583/** This constructor is currently used to unit test the class logic in
     1584 * debug builds.  Since no access is made to anything outside the class,
     1585 * this shouldn't cause any slowdown worth mentioning. */
     1586static void muiInit(matchUSBInterface *pSelf, USBDeviceInfo *pInfo)
     1587{
     1588    Assert(muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0",
     1589           "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
     1590    Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-1",
     1591           "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
     1592    Assert(!muiIsAnInterfaceOf("/sys/devices/pci0000:00/0000:00:1a.0/usb3/3-0:1.0/driver",
     1593           "/sys/devices/pci0000:00/0000:00:1a.0/usb3"));
     1594    AssertPtrReturnVoid(pSelf);
     1595    pSelf->mInfo = pInfo;
     1596    pSelf->mParent.handle = muiHandle;
     1597}
    15861598
    15871599/**
     
    16021614                  pList, pfSuccess));
    16031615    size_t cDevices = pList->size();
    1604     matchUSBDevice devHandler(pList);
    1605     int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler);
     1616    matchUSBDevice devHandler;
     1617    mudInit(&devHandler, pList);
     1618    int rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &devHandler.mParent);
    16061619    do {
    16071620        if (RT_FAILURE(rc))
     
    16101623             pInfo != pList->end(); ++pInfo)
    16111624        {
    1612             matchUSBInterface ifaceHandler(&*pInfo);
    1613             rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices", &ifaceHandler);
     1625            matchUSBInterface ifaceHandler;
     1626            muiInit(&ifaceHandler, &*pInfo);
     1627            rc = getDeviceInfoFromSysfs("/sys/bus/usb/devices",
     1628                                        &ifaceHandler.mParent);
    16141629            if (RT_FAILURE(rc))
    16151630                break;
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