i965/rbc: Allow integer formats as advertised in isl_format.c
[mesa.git] / src / loader / loader.c
index 19d99d52ef2349b2e6b36503f61d51438d6825b3..3e60e4ccf1d1cc9eadef2e9a0b24b45e7452d715 100644 (file)
  *    Rob Clark <robclark@freedesktop.org>
  */
 
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
 #ifdef HAVE_LIBUDEV
 #include <assert.h>
 #include <dlfcn.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <stdlib.h>
-#include <errno.h>
+#ifdef USE_DRICONF
+#include "xmlconfig.h"
+#include "xmlpool.h"
 #endif
-#ifdef HAVE_SYSFS
-#include <sys/stat.h>
-#include <sys/types.h>
+#endif
+#ifdef MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif
+#ifdef MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
 #endif
 #include "loader.h"
 
-#ifndef __NOT_HAVE_DRM_H
+#ifdef HAVE_LIBDRM
 #include <xf86drm.h>
 #endif
 
@@ -100,6 +107,22 @@ static void default_logger(int level, const char *fmt, ...)
 
 static void (*log_)(int level, const char *fmt, ...) = default_logger;
 
+int
+loader_open_device(const char *device_name)
+{
+   int fd;
+#ifdef O_CLOEXEC
+   fd = open(device_name, O_RDWR | O_CLOEXEC);
+   if (fd == -1 && errno == EINVAL)
+#endif
+   {
+      fd = open(device_name, O_RDWR);
+      if (fd != -1)
+         fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+   }
+   return fd;
+}
+
 #ifdef HAVE_LIBUDEV
 #include <libudev.h>
 
@@ -108,26 +131,36 @@ static void *udev_handle = NULL;
 static void *
 udev_dlopen_handle(void)
 {
-   if (!udev_handle) {
-      udev_handle = dlopen("libudev.so.1", RTLD_LOCAL | RTLD_LAZY);
-
-      if (!udev_handle) {
-         /* libudev.so.1 changed the return types of the two unref functions
-          * from voids to pointers.  We don't use those return values, and the
-          * only ABI I've heard that cares about this kind of change (calling
-          * a function with a void * return that actually only returns void)
-          * might be ia64.
-          */
-         udev_handle = dlopen("libudev.so.0", RTLD_LOCAL | RTLD_LAZY);
-
-         if (!udev_handle) {
-            log_(_LOADER_WARNING, "Couldn't dlopen libudev.so.1 or "
-                 "libudev.so.0, driver detection may be broken.\n");
-         }
+   char name[80];
+   unsigned flags = RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY;
+   int version;
+
+   /* libudev.so.1 changed the return types of the two unref functions
+    * from voids to pointers.  We don't use those return values, and the
+    * only ABI I've heard that cares about this kind of change (calling
+    * a function with a void * return that actually only returns void)
+    * might be ia64.
+    */
+
+   /* First try opening an already linked libudev, then try loading one */
+   do {
+      for (version = 1; version >= 0; version--) {
+         snprintf(name, sizeof(name), "libudev.so.%d", version);
+         udev_handle = dlopen(name, flags);
+         if (udev_handle)
+            return udev_handle;
       }
-   }
 
-   return udev_handle;
+      if ((flags & RTLD_NOLOAD) == 0)
+         break;
+
+      flags &= ~RTLD_NOLOAD;
+   } while (1);
+
+   log_(_LOADER_WARNING,
+        "Couldn't dlopen libudev.so.1 or "
+        "libudev.so.0, driver detection may be broken.\n");
+   return NULL;
 }
 
 static int dlsym_failed = 0;
@@ -203,9 +236,12 @@ libudev_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
    }
 
    pci_id = udev_device_get_property_value(parent, "PCI_ID");
-   if (pci_id == NULL ||
-       sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2) {
-      log_(_LOADER_WARNING, "MESA-LOADER: malformed or no PCI ID\n");
+   if (pci_id == NULL) {
+      log_(_LOADER_INFO, "MESA-LOADER: no PCI ID\n");
+      *chip_id = -1;
+      goto out;
+   } else if (sscanf(pci_id, "%x:%x", vendor_id, chip_id) != 2) {
+      log_(_LOADER_WARNING, "MESA-LOADER: malformed PCI ID\n");
       *chip_id = -1;
       goto out;
    }
@@ -240,6 +276,8 @@ get_render_node_from_id_path_tag(struct udev *udev,
                (struct udev_enumerate *));
    UDEV_SYMBOL(struct udev_list_entry *, udev_enumerate_get_list_entry,
                (struct udev_enumerate *));
+   UDEV_SYMBOL(void, udev_enumerate_unref,
+               (struct udev_enumerate *));
    UDEV_SYMBOL(struct udev_list_entry *, udev_list_entry_get_next,
                (struct udev_list_entry *));
    UDEV_SYMBOL(const char *, udev_list_entry_get_name,
@@ -274,6 +312,8 @@ get_render_node_from_id_path_tag(struct udev *udev,
       udev_device_unref(device);
    }
 
+   udev_enumerate_unref(e);
+
    if (found) {
       path_res = strdup(udev_device_get_devnode(device));
       udev_device_unref(device);
@@ -307,25 +347,22 @@ get_id_path_tag_from_fd(struct udev *udev, int fd)
    return id_path_tag;
 }
 
-static int
-drm_open_device(const char *device_name)
-{
-   int fd;
-#ifdef O_CLOEXEC
-   fd = open(device_name, O_RDWR | O_CLOEXEC);
-   if (fd == -1 && errno == EINVAL)
+#ifdef USE_DRICONF
+const char __driConfigOptionsLoader[] =
+DRI_CONF_BEGIN
+    DRI_CONF_SECTION_INITIALIZATION
+        DRI_CONF_DEVICE_ID_PATH_TAG()
+    DRI_CONF_SECTION_END
+DRI_CONF_END;
 #endif
-   {
-      fd = open(device_name, O_RDWR);
-      if (fd != -1)
-         fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
-   }
-   return fd;
-}
 
 int loader_get_user_preferred_fd(int default_fd, int *different_device)
 {
    struct udev *udev;
+#ifdef USE_DRICONF
+   driOptionCache defaultInitOptions;
+   driOptionCache userInitOptions;
+#endif
    const char *dri_prime = getenv("DRI_PRIME");
    char *prime = NULL;
    int is_different_device = 0, fd = default_fd;
@@ -337,6 +374,16 @@ int loader_get_user_preferred_fd(int default_fd, int *different_device)
 
    if (dri_prime)
       prime = strdup(dri_prime);
+#ifdef USE_DRICONF
+   else {
+      driParseOptionInfo(&defaultInitOptions, __driConfigOptionsLoader);
+      driParseConfigFiles(&userInitOptions, &defaultInitOptions, 0, "loader");
+      if (driCheckOption(&userInitOptions, "device_id", DRI_STRING))
+         prime = strdup(driQueryOptionstr(&userInitOptions, "device_id"));
+      driDestroyOptionCache(&userInitOptions);
+      driDestroyOptionInfo(&defaultInitOptions);
+   }
+#endif
 
    if (prime == NULL) {
       *different_device = 0;
@@ -374,8 +421,8 @@ int loader_get_user_preferred_fd(int default_fd, int *different_device)
       goto default_device_clean;
    }
 
-   fd = drm_open_device(device_name);
-   if (fd > 0) {
+   fd = loader_open_device(device_name);
+   if (fd >= 0) {
       close(default_fd);
    } else {
       fd = default_fd;
@@ -401,7 +448,7 @@ int loader_get_user_preferred_fd(int default_fd, int *different_device)
 }
 #endif
 
-#if defined(HAVE_SYSFS)
+#if defined(HAVE_SYSFS) || defined(HAVE_LIBDRM)
 static int
 dev_node_from_fd(int fd, unsigned int *maj, unsigned int *min)
 {
@@ -422,7 +469,9 @@ dev_node_from_fd(int fd, unsigned int *maj, unsigned int *min)
 
    return 0;
 }
+#endif
 
+#if defined(HAVE_SYSFS)
 static int
 sysfs_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
 {
@@ -461,7 +510,7 @@ sysfs_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
 }
 #endif
 
-#if !defined(__NOT_HAVE_DRM_H)
+#if defined(HAVE_LIBDRM)
 /* for i915 */
 #include <i915_drm.h>
 /* for radeon */
@@ -544,7 +593,7 @@ loader_get_pci_id_for_fd(int fd, int *vendor_id, int *chip_id)
    if (sysfs_get_pci_id_for_fd(fd, vendor_id, chip_id))
       return 1;
 #endif
-#if !defined(__NOT_HAVE_DRM_H)
+#if HAVE_LIBDRM
    if (drm_get_pci_id_for_fd(fd, vendor_id, chip_id))
       return 1;
 #endif
@@ -567,6 +616,9 @@ libudev_get_device_name_for_fd(int fd)
                (struct udev_device *));
    UDEV_SYMBOL(struct udev *, udev_unref, (struct udev *));
 
+   if (dlsym_failed)
+      return NULL;
+
    udev = udev_new();
    device = udev_device_new_from_fd(udev, fd);
    if (device == NULL)
@@ -593,7 +645,7 @@ sysfs_get_device_name_for_fd(int fd)
    unsigned int maj, min;
    FILE *f;
    char buf[0x40];
-   static const char match[9] = "\0DEVNAME=";
+   static const char match[9] = "\nDEVNAME=";
    int expected = 1;
 
    if (dev_node_from_fd(fd, &maj, &min) < 0)
@@ -616,14 +668,34 @@ sysfs_get_device_name_for_fd(int fd)
    }
 
    strcpy(buf, "/dev/");
-   if (fgets(buf + 5, sizeof(buf) - 5, f))
+   if (fgets(buf + 5, sizeof(buf) - 5, f)) {
+      buf[strcspn(buf, "\n")] = '\0';
       device_name = strdup(buf);
+   }
 
    fclose(f);
    return device_name;
 }
 #endif
 
+#if defined(HAVE_LIBDRM)
+static char *
+drm_get_device_name_for_fd(int fd)
+{
+   unsigned int maj, min;
+   char buf[0x40];
+   int n;
+
+   if (dev_node_from_fd(fd, &maj, &min) < 0)
+      return NULL;
+
+   n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, min);
+   if (n == -1 || n >= sizeof(buf))
+      return NULL;
+
+   return strdup(buf);
+}
+#endif
 
 char *
 loader_get_device_name_for_fd(int fd)
@@ -637,6 +709,10 @@ loader_get_device_name_for_fd(int fd)
 #if HAVE_SYSFS
    if ((result = sysfs_get_device_name_for_fd(fd)))
       return result;
+#endif
+#if HAVE_LIBDRM
+   if ((result = drm_get_device_name_for_fd(fd)))
+      return result;
 #endif
    return result;
 }
@@ -652,7 +728,7 @@ loader_get_driver_for_fd(int fd, unsigned driver_types)
 
    if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) {
 
-#ifndef __NOT_HAVE_DRM_H
+#if HAVE_LIBDRM
       /* fallback to drmGetVersion(): */
       drmVersionPtr version = drmGetVersion(fd);