HostHardwareLinux.cpp revision 5d739caa9796f66de8eca19c78ea5e411529b60d
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * Classes for handling hardware detection under Linux. Please feel free to
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * expand these to work for other systems (Solaris!) or to add new ones for
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * other systems.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * available from http://www.virtualbox.org. This file is free software;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * you can redistribute it and/or modify it under the terms of the GNU
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * General Public License (GPL) as published by the Free Software
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * additional information or have any questions.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Header Files *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/* bird: This is a hack to work around conflicts between these linux kernel headers
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * and the GLIBC tcpip headers. They have different declarations of the 4
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * standard byte order functions. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync// # define _LINUX_BYTEORDER_GENERIC_H
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#endif /* RT_OS_LINUX */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Global Variables *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic bool testing() { return true; }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic bool fNoProbe = false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic void setNoProbe(bool val) { fNoProbe = val; }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic bool testing() { return false; }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic bool noProbe() { return false; }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Typedefs and Defines *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** When waiting for hotplug events, we currently restart the wait after at
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * most this many milliseconds. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int getDriveInfoFromEnv(const char *pcszVar, DriveInfoList *pList,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int getDriveInfoFromDev(DriveInfoList *pList, bool isDVD,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int getDriveInfoFromSysfs(DriveInfoList *pList, bool isDVD,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/* These must be extern to be usable in the RTMemAutoPtr template */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncextern void VBoxHalShutdown (DBusConnection *pConnection);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncextern void VBoxHalShutdownPrivate (DBusConnection *pConnection);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncextern void VBoxDBusConnectionUnref(DBusConnection *pConnection);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncextern void VBoxDBusConnectionCloseAndUnref(DBusConnection *pConnection);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncextern void VBoxDBusMessageUnref(DBusMessage *pMessage);
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncstatic int halInit(RTMemAutoPtr <DBusConnection, VBoxHalShutdown> *pConnection);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int halInitPrivate(RTMemAutoPtr <DBusConnection, VBoxHalShutdownPrivate> *pConnection);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int halFindDeviceStringMatch (DBusConnection *pConnection,
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int halFindDeviceStringMatchVector (DBusConnection *pConnection,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync const char *pszKey,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync const char *pszValue,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync std::vector<iprt::MiniString> *pMatches);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int halGetPropertyStrings (DBusConnection *pConnection,
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync RTMemAutoPtr <DBusMessage, VBoxDBusMessageUnref> *pMessage);
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsyncstatic int halGetPropertyStringsVector (DBusConnection *pConnection,
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync const char *pszUdi, size_t cProps,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync const char **papszKeys,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync std::vector<iprt::MiniString> *pMatches,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync bool *pfMatches, bool *pfSuccess);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int getUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int getOldUSBDeviceInfoFromHal(USBDeviceInfoList *pList, bool *pfSuccess);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int getUSBInterfacesFromHal(std::vector <iprt::MiniString> *pList,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic DBusHandlerResult dbusFilterFunction (DBusConnection *pConnection,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#endif /* VBOX_WITH_DBUS */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** Find the length of a string, ignoring trailing non-ascii or control
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * characters */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Get the name of a floppy drive according to the Linux floppy driver.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns true on success, false if the name was not available (i.e. the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * device was not readible, or the file name wasn't a PC floppy
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pcszNode the path to the device node for the device
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param Number the Linux floppy driver number for the drive. Required.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszName where to store the name retreived
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic bool floppyGetName(const char *pcszNode, unsigned Number,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync int rc = RTFileOpen(&File, pcszNode, RTFILE_O_READ | RTFILE_O_NON_BLOCK);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** @todo The next line can produce a warning, as the ioctl request
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * field is defined as signed, but the Linux ioctl definition macros
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * produce unsigned constants. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rc = RTFileIoCtl(File, FDGETDRVTYP, pszName, 0, &rcIoCtl);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Create a UDI and a description for a floppy drive based on a number and the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * driver's name for it. We deliberately return an ugly sequence of
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * characters as the description rather than an English language string to
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * avoid translation issues.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns true if we know the device to be valid, false otherwise
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pcszName the floppy driver name for the device (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param Number the number of the floppy (0 to 3 on FDC 0, 4 to 7 on
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszDesc where to store the device description (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param cchDesc the size of the buffer in @a pszDesc
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszUdi where to store the device UDI (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param cchUdi the size of the buffer in @a pszUdi
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic void floppyCreateDeviceStrings(const floppy_drive_name pcszName,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync const char *pcszSize;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTStrPrintf(pszDesc, cchDesc, "%s %s K%s", pcszSize, &pcszName[1],
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTStrPrintf(pszDesc, cchDesc, "FDD %d%s", (Number & 4) + 1,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync "/org/freedesktop/Hal/devices/platform_floppy_%u_storage",
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Check whether a device number might correspond to a CD-ROM device according
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * to Documentation/devices.txt in the Linux kernel source.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns true if it might, false otherwise
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param Number the device number (major and minor combination)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (major == 30 /* CM205_CDROM_MAJOR */) /* no #define for some reason */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (major == 46 /* Parallel port ATAPI CD-ROM */) /* no #define */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Send an SCSI INQUIRY command to a device and return selected information.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns iprt status code
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns VERR_TRY_AGAIN if the query failed but might succeed next time
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pcszNode the full path to the device node
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pu8Type where to store the SCSI device type on success (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pchVendor where to store the vendor id string on success (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param cchVendor the size of the @a pchVendor buffer
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pchModel where to store the product id string on success (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param cchModel the size of the @a pchModel buffer
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @note check documentation on the SCSI INQUIRY command and the Linux kernel
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * SCSI headers included above if you want to understand what is going
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * on in this method.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int cdromDoInquiry(const char *pcszNode, uint8_t *pu8Type,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync LogRelFlowFunc(("pcszNode=%s, pu8Type=%p, pchVendor=%p, cchVendor=%llu, pchModel=%p, cchModel=%llu\n",
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync AssertPtrNullReturn(pu8Type, VERR_INVALID_POINTER);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync AssertPtrNullReturn(pchVendor, VERR_INVALID_POINTER);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync AssertPtrNullReturn(pchModel, VERR_INVALID_POINTER);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync { { INQUIRY, 0, 0, 0, sizeof(u8Response), 0 } /* INQUIRY */ };
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rc = RTFileOpen(&file, pcszNode, RTFILE_O_READ | RTFILE_O_NON_BLOCK);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rc = RTFileIoCtl(file, CDROM_SEND_PACKET, &CdromCommandReq, 0,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync LogRelFlowFunc((" type=%u, vendor=%.8s, product=%.16s\n",
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Initialise the device strings (description and UDI) for a DVD drive based on
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * vendor and model name strings.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pcszVendor the vendor ID string
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pcszModel the product ID string
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszDesc where to store the description string (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param cchDesc the size of the buffer in @pszDesc
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszUdi where to store the UDI string (optional)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param cchUdi the size of the buffer in @pszUdi
if (pszDesc)
if (cchVendor > 0)
if (pszUdi)
if (cchModel > 0)
"/org/freedesktop/Hal/devices/storage_model_%s",
if (pDevice)
if (isDVD)
unsigned Number;
cchUdi);
&success);
setNoProbe(false);
setNoProbe(true);
return rc;
setNoProbe(false);
&success);
setNoProbe(true);
&success);
return rc;
bool success = false;
if (pcszNext)
success = true;
return rc;
class sysfsBlockDev
misValid(false)
if (findDeviceNode())
if (mwantDVD)
const char *mpcszName;
bool mwantDVD;
bool misConsistent;
bool misValid;
bool findDeviceNode()
if (dev == 0)
misConsistent = false;
void validateAndInitForDVD()
if (cchVendor >= 0)
if (cchModel >= 0)
misValid = true;
if (!noProbe())
void probeAndInitForDVD()
sizeof(szModel));
misValid = true;
void validateAndInitForFloppy()
bool haveName = false;
if (!noProbe())
else if (!haveName)
misValid = true;
bool isConsistent()
return misConsistent;
bool isValid()
return misValid;
const char *getDesc()
return mszDesc;
const char *getUdi()
return mszUdi;
const char *getNode()
return mszNode;
int rc;
bool fSuccess = false;
unsigned cFound = 0;
return VINF_SUCCESS;
fSuccess = true;
++cFound;
for (unsigned i = 0; i < cFound; ++i)
if (pfSuccess)
return rc;
struct deviceNodeInfo
for (i = 0; i < MAX_DEVICE_NODES; ++i)
pfSuccess));
bool success = false;
for (unsigned i = 0; i < MAX_DEVICE_NODES; ++i)
success = true;
return rc;
bool halSuccess = false;
#if defined(RT_OS_LINUX)
#ifdef VBOX_WITH_DBUS
if (!success)
return rc;
volatile bool mTriggered;
volatile bool mInterrupt;
delete mContext;
bool connected = true;
unsigned cRealMillies;
if (!connected)
return rc;
class autoDBusError
~autoDBusError ()
if (IsSet())
bool IsSet ()
void FlowLog ()
if (IsSet ())
bool halSuccess = true;
if (!dbusConnection)
halSuccess = false;
if (halSuccess)
if (halSuccess)
"path='/org/freedesktop/Hal/Manager'",
if (halSuccess)
return rc;
bool halSuccess = true;
if (!dbusConnection)
halSuccess = false;
if (halSuccess)
if (halSuccess)
"path='/org/freedesktop/Hal/Manager'",
if (halSuccess)
return rc;
"path='/org/freedesktop/Hal/Manager'",
"path='/org/freedesktop/Hal/Manager'",
const char *pszValue,
"/org/freedesktop/Hal/Manager",
if (!message)
if (!reply)
halSuccess = false;
return rc;
bool *pfSuccess)
&replyFind);
if (!replyFind)
halSuccess = false;
halSuccess = false;
const char *pszUdi;
return rc;
char **papszValues,
LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, papszValues=%p, pMessage=%p\n",
if (!message)
if (!reply)
halSuccess = false;
halSuccess = false;
const char *pszKey;
return rc;
const char **papszKeys,
LogFlowFunc (("pConnection=%p, pszUdi=%s, cProps=%llu, papszKeys=%p, pMatches=%p, pfMatches=%p, pfSuccess=%p\n",
bool halSuccess = true;
if (!message)
halSuccess = false;
|| (pfMatches[j] == true)
return rc;
if (!dbusConnection)
halSuccess = false;
if (!replyFind)
halSuccess = false;
halSuccess = false;
const char *pszUdi;
return rc;
if (!dbusConnection)
halSuccess = false;
if (!replyFind)
halSuccess = false;
halSuccess = false;
const char *pszUdi;
&ifaceSuccess);
return rc;
pfSuccess));
if (!dbusConnection)
halSuccess = false;
if (!replyFind)
halSuccess = false;
halSuccess = false;
const char *pszUdi;
"linux.subsystem" };
if (!replyGet)
halSuccess = false;
halSuccess = false;
return rc;
*pTriggered = true;