[Mesa-dev] [PATCH] loader: allow alternative methods for PCI identification.
Gary Wong
gtw at gnu.org
Wed May 14 21:39:05 PDT 2014
loader_get_pci_id_for_fd() and loader_get_device_name_for_fd() now attempt
all available strategies to identify the hardware, instead of conditionally
compiling in a single test. The existing libudev and DRM approaches have
been retained, and another simple alternative of looking up the answer in
the /sys filesystem (available on Linux) is added.
This should assist Linux systems that mount /sys but do not include
libudev (Android?), give Mesa a fighting chance of running on systems
where libudev is uninstalled/inaccessible/broken at runtime, and provides
a hook where non-Linux systems (BSD?) could implement their own PCI
identification.
Signed-off-by: Gary Wong <gtw at gnu.org>
---
configure.ac | 51 ++++++++++++----
src/loader/loader.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 195 insertions(+), 29 deletions(-)
diff --git a/configure.ac b/configure.ac
index d3e96de..fe572cd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -818,13 +818,31 @@ fi
case "$host_os" in
linux*)
- need_libudev=yes ;;
+ need_pci_id=yes ;;
*)
- need_libudev=no ;;
+ need_pci_id=no ;;
esac
-PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED],
- have_libudev=yes, have_libudev=no)
+AC_ARG_ENABLE([libudev],
+ [AS_HELP_STRING([--disable-libudev],
+ [disable libudev PCI identification @<:@default=enabled on supported platforms@:>@])],
+ [attempt_libudev="$enableval"],
+ [attempt_libudev=yes]
+)
+
+if test "x$attempt_libudev" = "xyes"; then
+ PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED],
+ have_libudev=yes, have_libudev=no)
+else
+ have_libudev=no
+fi
+
+AC_ARG_ENABLE([sysfs],
+ [AS_HELP_STRING([--disable-sysfs],
+ [disable /sys PCI identification @<:@default=enabled on supported platforms@:>@])],
+ [have_sysfs="$enableval"],
+ [have_sysfs=yes]
+)
if test "x$enable_dri" = xyes; then
if test "$enable_static" = yes; then
@@ -910,8 +928,15 @@ xyesno)
;;
esac
+have_pci_id=no
if test "$have_libudev" = yes; then
DEFINES="$DEFINES -DHAVE_LIBUDEV"
+ have_pci_id=yes
+fi
+
+if test "$have_sysfs" = yes; then
+ DEFINES="$DEFINES -DHAVE_SYSFS"
+ have_pci_id=yes
fi
# This is outside the case (above) so that it is invoked even for non-GLX
@@ -1013,8 +1038,8 @@ if test "x$enable_dri" = xyes; then
DEFINES="$DEFINES -DHAVE_DRI3"
fi
- if test "x$have_libudev" != xyes; then
- AC_MSG_ERROR([libudev-dev required for building DRI])
+ if test "x$have_pci_id" != xyes; then
+ AC_MSG_ERROR([libudev-dev or sysfs required for building DRI])
fi
case "$host_cpu" in
@@ -1183,8 +1208,8 @@ if test "x$enable_gbm" = xauto; then
esac
fi
if test "x$enable_gbm" = xyes; then
- if test "x$need_libudev$have_libudev" = xyesno; then
- AC_MSG_ERROR([gbm requires udev >= $LIBUDEV_REQUIRED])
+ if test "x$need_pci_id$have_pci_id" = xyesno; then
+ AC_MSG_ERROR([gbm requires udev >= $LIBUDEV_REQUIRED or sysfs])
fi
if test "x$enable_dri" = xyes; then
@@ -1202,7 +1227,7 @@ if test "x$enable_gbm" = xyes; then
fi
fi
AM_CONDITIONAL(HAVE_GBM, test "x$enable_gbm" = xyes)
-if test "x$need_libudev" = xyes; then
+if test "x$need_pci_id$have_libudev" = xyesyes; then
GBM_PC_REQ_PRIV="libudev >= $LIBUDEV_REQUIRED"
else
GBM_PC_REQ_PRIV=""
@@ -1491,9 +1516,9 @@ for plat in $egl_platforms; do
;;
esac
- case "$plat$need_libudev$have_libudev" in
+ case "$plat$need_pci_id$have_pci_id" in
waylandyesno|drmyesno)
- AC_MSG_ERROR([cannot build $plat platform without udev >= $LIBUDEV_REQUIRED]) ;;
+ AC_MSG_ERROR([cannot build $plat platform without udev >= $LIBUDEV_REQUIRED or sysfs]) ;;
esac
done
@@ -1766,8 +1791,8 @@ gallium_require_llvm() {
gallium_require_drm_loader() {
if test "x$enable_gallium_loader" = xyes; then
- if test "x$need_libudev$have_libudev" = xyesno; then
- AC_MSG_ERROR([Gallium drm loader requires libudev >= $LIBUDEV_REQUIRED])
+ if test "x$need_pci_id$have_pci_id" = xyesno; then
+ AC_MSG_ERROR([Gallium drm loader requires libudev >= $LIBUDEV_REQUIRED or sysfs])
fi
if test "x$have_libdrm" != xyes; then
AC_MSG_ERROR([Gallium drm loader requires libdrm >= $LIBDRM_REQUIRED])
diff --git a/src/loader/loader.c b/src/loader/loader.c
index 666d015..33e77b3 100644
--- a/src/loader/loader.c
+++ b/src/loader/loader.c
@@ -71,6 +71,10 @@
#include <assert.h>
#include <dlfcn.h>
#endif
+#ifdef HAVE_SYSFS
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
#include "loader.h"
#ifndef __NOT_HAVE_DRM_H
@@ -113,8 +117,8 @@ udev_dlopen_handle(void)
udev_handle = dlopen("libudev.so.0", RTLD_LOCAL | RTLD_LAZY);
if (!udev_handle) {
- log_(_LOADER_FATAL, "Couldn't dlopen libudev.so.1 or libudev.so.0, "
- "driver detection may be broken.\n");
+ log_(_LOADER_WARNING, "Couldn't dlopen libudev.so.1 or "
+ "libudev.so.0, driver detection may be broken.\n");
}
}
}
@@ -122,16 +126,19 @@ udev_dlopen_handle(void)
return udev_handle;
}
+static int dlcheck_failed;
+
static void *
-asserted_dlsym(void *dlopen_handle, const char *name)
+checked_dlsym(void *dlopen_handle, const char *name)
{
void *result = dlsym(dlopen_handle, name);
- assert(result);
+ if (!result)
+ dlcheck_failed = 1;
return result;
}
#define UDEV_SYMBOL(ret, name, args) \
- ret (*name) args = asserted_dlsym(udev_dlopen_handle(), #name);
+ ret (*name) args = checked_dlsym(udev_dlopen_handle(), #name);
static inline struct udev_device *
@@ -142,6 +149,9 @@ udev_device_new_from_fd(struct udev *udev, int fd)
UDEV_SYMBOL(struct udev_device *, udev_device_new_from_devnum,
(struct udev *udev, char type, dev_t devnum));
+ if (dlcheck_failed)
+ return NULL;
+
if (fstat(fd, &buf) < 0) {
log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d\n", fd);
return NULL;
@@ -157,8 +167,8 @@ udev_device_new_from_fd(struct udev *udev, int fd)
return device;
}
-int
-loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
+static int
+libudev_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
{
struct udev *udev = NULL;
struct udev_device *device = NULL, *parent;
@@ -174,6 +184,9 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
*chip_id = -1;
+ if (dlcheck_failed)
+ return 0;
+
udev = udev_new();
device = udev_device_new_from_fd(udev, fd);
if (!device)
@@ -201,16 +214,76 @@ out:
return (*chip_id >= 0);
}
+#endif
+
+#if defined(HAVE_SYSFS)
+static int
+dev_node_from_fd(int fd, unsigned int *maj, unsigned int *min)
+{
+ struct stat buf;
+
+ if (fstat(fd, &buf) < 0) {
+ log_(_LOADER_WARNING, "MESA-LOADER: failed to stat fd %d\n", fd);
+ return -1;
+ }
-#elif !defined(__NOT_HAVE_DRM_H)
+ if (!S_ISCHR(buf.st_mode)) {
+ log_(_LOADER_WARNING, "MESA-LOADER: fd %d not a character device\n", fd);
+ return -1;
+ }
+
+ *maj = major(buf.st_rdev);
+ *min = minor(buf.st_rdev);
+
+ return 0;
+}
+static int
+sysfs_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
+{
+ unsigned int maj, min;
+ FILE *f;
+ char buf[ 0x40 ];
+
+ if (dev_node_from_fd(fd, &maj, &min) < 0) {
+ *chip_id = -1;
+ return 0;
+ }
+
+ snprintf( buf, sizeof buf, "/sys/dev/char/%d:%d/device/vendor", maj, min );
+ if (!(f = fopen(buf, "r"))) {
+ *chip_id = -1;
+ return 0;
+ }
+ if (fscanf(f, "%x", vendor_id) != 1) {
+ *chip_id = -1;
+ fclose(f);
+ return 0;
+ }
+ fclose(f);
+ snprintf( buf, sizeof buf, "/sys/dev/char/%d:%d/device/device", maj, min );
+ if (!(f = fopen(buf, "r"))) {
+ *chip_id = -1;
+ return 0;
+ }
+ if (fscanf(f, "%x", chip_id) != 1) {
+ *chip_id = -1;
+ fclose(f);
+ return 0;
+ }
+ fclose(f);
+ return 1;
+}
+#endif
+
+#if !defined(__NOT_HAVE_DRM_H)
/* for i915 */
#include <i915_drm.h>
/* for radeon */
#include <radeon_drm.h>
-int
-loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
+static int
+drm_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
{
drmVersionPtr version;
@@ -272,23 +345,33 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
return (*chip_id >= 0);
}
+#endif
-#else
int
loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
{
+#if HAVE_LIBUDEV
+ if (libudev_get_pci_id_for_fd(fd, vendor_id, chip_id))
+ return 1;
+#endif
+#if HAVE_SYSFS
+ if (sysfs_get_pci_id_for_fd(fd, vendor_id, chip_id))
+ return 1;
+#endif
+#if !defined(__NOT_HAVE_DRM_H)
+ if (drm_get_pci_id_for_fd(fd, vendor_id, chip_id))
+ return 1;
+#endif
return 0;
}
-#endif
-
-char *
-loader_get_device_name_for_fd(int fd)
+#ifdef HAVE_LIBUDEV
+static char *
+libudev_get_device_name_for_fd(int fd)
{
char *device_name = NULL;
-#ifdef HAVE_LIBUDEV
struct udev *udev;
struct udev_device *device;
const char *const_device_name;
@@ -312,9 +395,67 @@ loader_get_device_name_for_fd(int fd)
out:
udev_device_unref(device);
udev_unref(udev);
+ return device_name;
+}
#endif
+
+
+#if HAVE_SYSFS
+static char *
+sysfs_get_device_name_for_fd(int fd)
+{
+ char *device_name = NULL;
+ unsigned int maj, min;
+ FILE *f;
+ char buf[ 0x40 ];
+ static const char match[ 9 ] = "\0DEVNAME=";
+ int expected = 1;
+
+ if (dev_node_from_fd(fd, &maj, &min) < 0)
+ return NULL;
+
+ snprintf( buf, sizeof buf, "/sys/dev/char/%d:%d/uevent", maj, min );
+ if (!(f = fopen(buf, "r")))
+ return NULL;
+
+ while( expected < sizeof match ) {
+ int c = getc(f);
+
+ if (c == EOF) {
+ fclose(f);
+ return NULL;
+ } else if (c == match[expected] )
+ expected++;
+ else
+ expected = 0;
+ }
+
+ if (!fgets(buf, sizeof buf, f))
+ device_name = NULL;
+ else
+ device_name = strdup(buf);
+
+ fclose(f);
return device_name;
}
+#endif
+
+
+char *
+loader_get_device_name_for_fd(int fd)
+{
+ char *result;
+
+#if HAVE_LIBUDEV
+ if ((result = libudev_get_device_name_for_fd(fd)))
+ return result;
+#endif
+#if HAVE_SYSFS
+ if ((result = sysfs_get_device_name_for_fd(fd)))
+ return result;
+#endif
+ return NULL;
+}
char *
loader_get_driver_for_fd(int fd, unsigned driver_types)
--
1.9.2
More information about the mesa-dev
mailing list