VirtualBox

Changeset 28574 in vbox for trunk/src/VBox/Main/linux


Ignore:
Timestamp:
Apr 21, 2010 8:50:48 PM (15 years ago)
Author:
vboxsync
Message:

Main: add support for polling for USB devices on Linux hosts without usbfs or hal - fixes

File:
1 edited

Legend:

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

    r28553 r28574  
    3030#include <HostHardwareLinux.h>
    3131
     32#include <VBox/err.h>
    3233#include <VBox/log.h>
    33 # ifdef VBOX_WITH_DBUS
    34 #  include <VBox/dbus.h>
    35 # endif
     34
     35#ifdef VBOX_WITH_DBUS
     36# include <VBox/dbus.h>
     37#endif
    3638
    3739#include <iprt/dir.h>
     
    4749#include <iprt/thread.h>  /* for RTThreadSleep() */
    4850
    49 #ifdef RT_OS_LINUX
    50 # include <sys/types.h>
    51 # include <sys/stat.h>
    52 # include <unistd.h>
    53 # include <fcntl.h>
    54 /* bird: This is a hack to work around conflicts between these linux kernel headers
    55  *       and the GLIBC tcpip headers. They have different declarations of the 4
    56  *       standard byte order functions. */
    57 // # define _LINUX_BYTEORDER_GENERIC_H
    58 # define _LINUX_BYTEORDER_SWABB_H
    59 # include <linux/cdrom.h>
    60 # include <linux/fd.h>
    61 # include <linux/major.h>
    62 # include <errno.h>
    63 # include <scsi/scsi.h>
    64 
    65 # include <iprt/linux/sysfs.h>
    66 #endif /* RT_OS_LINUX */
    67 
    68 #include <fam.h>
     51#include <linux/cdrom.h>
     52#include <linux/fd.h>
     53#include <linux/major.h>
     54#include <scsi/scsi.h>
     55
     56#include <iprt/linux/sysfs.h>
     57
     58#ifdef VBOX_USB_WITH_SYSFS
     59# include <fam.h>
     60#endif
    6961
    7062#include <vector>
     63
     64#include <errno.h>
    7165
    7266/******************************************************************************
     
    9993static int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD,
    10094                                 bool *pfSuccess);
     95#ifdef VBOX_USB_WITH_SYSFS
    10196static int getUSBDeviceInfoFromSysfs(USBDeviceInfoList *pList, bool *pfSuccess);
    102 #ifdef VBOX_WITH_DBUS
     97# ifdef VBOX_WITH_DBUS
    10398/* These must be extern to be usable in the RTMemAutoPtr template */
    10499extern void VBoxHalShutdown (DBusConnection *pConnection);
     
    136131static DBusHandlerResult dbusFilterFunction (DBusConnection *pConnection,
    137132                                             DBusMessage *pMessage, void *pvUser);
    138 #endif  /* VBOX_WITH_DBUS */
     133# endif  /* VBOX_WITH_DBUS */
     134#endif /* VBOX_USB_WITH_SYSFS */
    139135
    140136
     
    10311027    try
    10321028    {
     1029        mDeviceList.clear();
     1030#ifdef VBOX_USB_WITH_SYSFS
     1031# ifdef VBOX_WITH_DBUS
    10331032        bool halSuccess = false;
    1034         mDeviceList.clear();
    1035 #if defined(RT_OS_LINUX)
    1036 #ifdef VBOX_WITH_DBUS
    10371033        if (   RT_SUCCESS(rc)
    10381034            && RT_SUCCESS(RTDBusLoadLib())
     
    10451041        if (!success)
    10461042            success = halSuccess;
    1047 #endif /* VBOX_WITH_DBUS defined */
     1043# endif /* VBOX_WITH_DBUS */
    10481044        if (   RT_SUCCESS(rc)
    10491045            && (!success || testing()))
    1050             rc = getUSBDeviceInfoFromSysfs(&mDeviceList, &halSuccess);
    1051 #endif /* RT_OS_LINUX */
     1046            rc = getUSBDeviceInfoFromSysfs(&mDeviceList, &success);
     1047#else /* !VBOX_USB_WITH_SYSFS */
     1048        NOREF(success);
     1049#endif /* !VBOX_USB_WITH_SYSFS */
    10521050    }
    10531051    catch(std::bad_alloc &e)
     
    10591057}
    10601058
    1061 #if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
     1059#if defined VBOX_USB_WITH_SYSFS && defined VBOX_WITH_DBUS
    10621060class hotplugDBusImpl : public VBoxMainHotplugWaiterImpl
    10631061{
     
    11661164    mInterrupt = true;
    11671165}
    1168 #endif  /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
     1166#endif  /* VBOX_USB_WITH_SYSFS && VBOX_WITH_DBUS */
    11691167
    11701168class hotplugNullImpl : public VBoxMainHotplugWaiterImpl
     
    11831181
    11841182#ifdef VBOX_USB_WITH_SYSFS
    1185 
    1186 /** @todo move these elsewhere, but wait for words of wisdom from the iprt
    1187  * maintainer first :)
    1188  * The ideas behind the macros are on the one hand to increase code readability
    1189  * by reducing the space taken by the error handling (exceptions using pure C
    1190  * if you like, where a do {} while(0) block replaces the try {} catch() and a
    1191  * variable at a higher scope remembers the success or failure); and on the
    1192  * other to reduce duplication in error handling code, hopefully thereby
    1193  * raising the chances that error paths will actually work.
    1194  */
    1195 
    1196 /**
    1197  * Store an iprt status code (expected to be a function call with the status
    1198  * code as its return value) in a variable and execute a break statement if
    1199  * the status is unsuccessful.
    1200  * @param  rc    where to store the value
    1201  * @param  expr  the expression returning the status.  @a expr will only be
    1202  *               evaluated once by the macro call
    1203  */
    1204 #define SETRCBREAK(rc, expr) \
    1205     if (RT_FAILURE(((rc) = (expr)))) \
    1206         break; \
    1207     else do {} while (0)
    1208 
    1209 /**
    1210  * Store an iprt status code (expected to be a function call with the status
    1211  * code as its return value) in a variable and execute a return statement if
    1212  * the status is unsuccessful.
    1213  * @param  rc    where to store the value
    1214  * @param  expr  the expression returning the status.  @a expr will only be
    1215  *               evaluated once by the macro call
    1216  */
    1217 #define SETRCRETURN(rc, expr) \
    1218     do \
    1219     { \
    1220         (rc) = (expr); \
    1221         if (RT_FAILURE(rc)) \
    1222             return (rc); \
    1223     } while (0)
    1224 
    1225 static void testSetRCBreak(void)
    1226 {
    1227     int rc = VINF_SUCCESS;
    1228     do {
    1229         SETRCBREAK(rc, VERR_WRONG_ORDER);
    1230         rc = VINF_SUCCESS;
    1231     } while(0);
    1232     Assert(rc == VERR_WRONG_ORDER);
    1233     rc = VERR_GENERAL_FAILURE;
    1234     do {
    1235         SETRCBREAK(rc, VINF_BUFFER_OVERFLOW);
    1236         Assert(rc == VINF_BUFFER_OVERFLOW);
    1237         rc = VERR_WRONG_ORDER;
    1238     } while(0);
    1239     Assert(rc == VERR_WRONG_ORDER);
    1240 }
    1241 
    1242 static int testSetRCReturnWorker(int rc)
    1243 {
    1244     int rc2 = VERR_WRONG_ORDER;
    1245     SETRCRETURN(rc2, rc);
    1246     Assert(rc == rc2);
    1247     return VINF_SUCCESS;
    1248 }
    1249 
    1250 static void testSetRCReturn(void)
    1251 {
    1252     Assert(testSetRCReturnWorker(VERR_GENERAL_FAILURE) == VERR_GENERAL_FAILURE);
    1253     AssertRCSuccess(testSetRCReturnWorker(VINF_BUFFER_OVERFLOW));
    1254 }
    12551183
    12561184#define SYSFS_USB_DEVICE_PATH "/dev/bus/usb"
     
    12941222    {
    12951223        if (FAMOpen(&mFAMConnection) < 0)
    1296             return VERR_UNRESOLVED_ERROR;  /* VERR_FAM_OPEN_FAILED */
     1224            return VERR_FAM_OPEN_FAILED;
    12971225        mfFAMInitialised = true;
    12981226        return VINF_SUCCESS;
     
    13051233        FAMRequest dummyReq;
    13061234        if (FAMMonitorDirectory(&mFAMConnection, pszName, &dummyReq, NULL) < 0)
    1307             return VERR_UNRESOLVED_ERROR;  /* VERR_FAM_MONITOR_FILE_FAILED */
     1235            return VERR_FAM_MONITOR_DIRECTORY_FAILED;
    13081236        return VINF_SUCCESS;
    13091237    }
     
    13151243        int oldFD = FAMCONNECTION_GETFD(&mFAMConnection);
    13161244        FAMCONNECTION_GETFD(&mFAMConnection) = -1;
    1317         Assert(monitorDirectoryFAM(NULL) == VERR_UNRESOLVED_ERROR);
     1245        Assert(monitorDirectoryFAM(NULL) == VERR_FAM_MONITOR_DIRECTORY_FAILED);
    13181246        FAMCONNECTION_GETFD(&mFAMConnection) = oldFD;
    13191247    }
     
    13281256        mfFAMInitialised = false;
    13291257    }
     1258
     1259    /** Read the wakeup string from the wakeup pipe */
     1260    int drainWakeupPipe(void);
    13301261public:
    13311262    hotplugSysfsFAMImpl(void);
     
    13611292     * no-op. */
    13621293    term();
    1363     /** Unit test our macros above */
    1364     testSetRCBreak();
    1365     testSetRCReturn();
     1294    /* For now this probing method should only be used if nothing else is
     1295     * available */
     1296    if (!testing())
     1297    {
     1298#ifndef VBOX_USB_WITH_SYSFS_BY_DEFAULT
     1299        Assert(!RTFileExists("/proc/bus/usb/devices"));
     1300#endif
     1301#ifdef VBOX_WITH_DBUS
     1302        Assert(!hotplugDBusImpl::HalAvailable());
     1303#endif
     1304    }
    13661305#endif
    13671306    int rc;
    13681307    do {
    1369         SETRCBREAK(rc, RTPipeCreate(&mhWakeupPipeR, &mhWakeupPipeW, 0));
    1370         SETRCBREAK(rc, openFAM());
    1371         SETRCBREAK(rc, RTSocketFromNative
    1372                            (&mhFAMFD, FAMCONNECTION_GETFD(&mFAMConnection)));
    1373         SETRCBREAK(rc, monitorDirectoryFAM(SYSFS_USB_DEVICE_PATH));
    1374         SETRCBREAK(rc, RTPollSetCreate(&mhPollSet));
    1375         SETRCBREAK(rc, RTPollSetAddSocket
    1376                            (mhPollSet, mhFAMFD, RTPOLL_EVT_READ, FAMFD_ID));
    1377         SETRCBREAK(rc, RTPollSetAddPipe
    1378                            (mhPollSet, mhWakeupPipeR, RTPOLL_EVT_READ, RPIPE_ID));
     1308        if (RT_FAILURE(rc = RTPipeCreate(&mhWakeupPipeR, &mhWakeupPipeW, 0)))
     1309            break;
     1310        if (RT_FAILURE(rc = openFAM()))
     1311            break;
     1312        if (RT_FAILURE(rc = RTSocketFromNative
     1313                                (&mhFAMFD, FAMCONNECTION_GETFD(&mFAMConnection))))
     1314            break;
     1315        if (RT_FAILURE(rc = monitorDirectoryFAM(SYSFS_USB_DEVICE_PATH)))
     1316            break;
     1317        if (RT_FAILURE(rc = RTPollSetCreate(&mhPollSet)))
     1318            break;
     1319        if (RT_FAILURE(rc = RTPollSetAddSocket
     1320                                (mhPollSet, mhFAMFD, RTPOLL_EVT_READ, FAMFD_ID)))
     1321            break;
     1322        if (RT_FAILURE(rc = RTPollSetAddPipe
     1323                                (mhPollSet, mhWakeupPipeR, RTPOLL_EVT_READ, RPIPE_ID)))
     1324            break;
    13791325#ifdef DEBUG
    13801326        /** Other tests */
     
    13991345}
    14001346
     1347/** Does a FAM event code mean that the available devices have (probably)
     1348 * changed? */
     1349static int sysfsGetStatusForFAMCode(enum FAMCodes enmCode)
     1350{
     1351    if (enmCode == FAMExists || enmCode == FAMEndExist)
     1352        return VERR_TRY_AGAIN;
     1353    return VINF_SUCCESS;
     1354}
     1355
     1356int hotplugSysfsFAMImpl::drainWakeupPipe(void)
     1357{
     1358    char szBuf[sizeof(SYSFS_WAKEUP_STRING)];
     1359    int rc = RTPipeRead(mhWakeupPipeR, szBuf, sizeof(szBuf), NULL);
     1360    AssertRC(rc);
     1361    return VINF_SUCCESS;
     1362}
     1363
    14011364int hotplugSysfsFAMImpl::Wait(RTMSINTERVAL aMillies)
    14021365{
     
    14081371        return VERR_NOT_SUPPORTED;
    14091372    /* timeout returns */
    1410     SETRCRETURN(rc, RTPoll(mhPollSet, aMillies, NULL, &id));
     1373    if (RT_FAILURE(rc = RTPoll(mhPollSet, aMillies, NULL, &id)))
     1374        return rc;
    14111375    if (id == RPIPE_ID)
    1412     {
    1413         /* drain the pipe */
    1414         char szBuf[sizeof(SYSFS_WAKEUP_STRING)];
    1415         rc = RTPipeRead(mhWakeupPipeR, szBuf, sizeof(szBuf), NULL);
    1416         AssertRC(rc);
    1417         return VINF_SUCCESS;
    1418     }
     1376        return drainWakeupPipe();
    14191377    AssertReturn(id == FAMFD_ID, VERR_NOT_SUPPORTED);
    14201378    /* Samba re-opens the connection to FAM if this happens. */
    14211379    AssertReturn(FAMNextEvent(&mFAMConnection, &ev) == 1,
    14221380                 VERR_NOT_SUPPORTED);
    1423     switch(ev.code)
    1424     {
    1425         case FAMExists:
    1426         case FAMEndExist:
    1427             return VERR_TRY_AGAIN;
    1428         default:
    1429             break;
    1430     }
    1431     return VINF_SUCCESS;
     1381    return sysfsGetStatusForFAMCode(ev.code);
    14321382}
    14331383
     
    14451395VBoxMainHotplugWaiter::VBoxMainHotplugWaiter(void)
    14461396{
    1447 #if defined RT_OS_LINUX && defined VBOX_WITH_DBUS
     1397#ifdef VBOX_USB_WITH_SYSFS
     1398# ifdef VBOX_WITH_DBUS
    14481399    if (hotplugDBusImpl::HalAvailable())
    14491400    {
     
    14511402        return;
    14521403    }
    1453 #endif  /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
    1454 #if defined VBOX_USB_WITH_SYSFS
     1404# endif  /* VBOX_WITH_DBUS */
    14551405    if (hotplugSysfsFAMImpl::SysfsAvailable())
    14561406    {
     
    14581408        return;
    14591409    }
    1460 #endif  /* !(defined RT_OS_LINUX && defined VBOX_WITH_DBUS) */
     1410#endif  /* VBOX_USB_WITH_SYSFS */
    14611411    mImpl = new hotplugNullImpl;
    14621412}
    14631413
     1414#ifdef VBOX_USB_WITH_SYSFS
    14641415class sysfsPathHandler
    14651416{
     
    16721623    return rc;
    16731624}
    1674 
    1675 
    1676 #if defined(RT_OS_LINUX) && defined(VBOX_WITH_DBUS)
     1625#endif /* VBOX_USB_WITH_SYSFS */
     1626
     1627#if defined VBOX_USB_WITH_SYSFS && defined VBOX_WITH_DBUS
    16771628/** Wrapper class around DBusError for automatic cleanup */
    16781629class autoDBusError
     
    24432394    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    24442395}
    2445 #endif  /* RT_OS_LINUX && VBOX_WITH_DBUS */
    2446 
     2396#endif  /* VBOX_USB_WITH_SYSFS && VBOX_WITH_DBUS */
     2397
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