[PATCH 2/2] xfree86: use udev to provide device enumeration for kms devices

Dave Airlie airlied at gmail.com
Tue May 8 06:40:19 PDT 2012


From: Dave Airlie <airlied at redhat.com>

On Linux in order for future hotplug work, we are required to interface
to udev to detect device creation/removal. In order to try and get
some earlier testing on this, this patch adds the ability to use
udev for device enumeration on Linux.

At startup the list of drm/kms devices is probed and this info is
used to load drivers.

A new driver probing method is introduced that passes the udev
device info to the driver for probing.

The probing integrates with the pci probing code and will fallback
to the pci probe and old school probe functions in turn.

The flags parameter to the probe function will be used later
to provide hotplug and gpu screen flags for the driver to behave
in a different way.

This patch changes the driver ABI, all drivers should at least
be set with a NULL udev probe function after this commit.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 config/udev.c                  |   29 ++++
 configure.ac                   |   18 ++-
 hw/xfree86/common/Makefile.am  |   10 +-
 hw/xfree86/common/xf86.h       |    5 +
 hw/xfree86/common/xf86Bus.c    |   28 +++-
 hw/xfree86/common/xf86Bus.h    |    1 +
 hw/xfree86/common/xf86fbBus.c  |    4 +
 hw/xfree86/common/xf86pciBus.c |   20 +++-
 hw/xfree86/common/xf86str.h    |   15 ++
 hw/xfree86/common/xf86udev.c   |  304 ++++++++++++++++++++++++++++++++++++++++
 hw/xfree86/common/xf86udev.h   |   42 ++++++
 include/dix-config.h.in        |    3 +
 include/hotplug.h              |    4 +
 include/xorg-config.h.in       |    3 +
 include/xorg-server.h.in       |    3 +
 15 files changed, 478 insertions(+), 11 deletions(-)
 create mode 100644 hw/xfree86/common/xf86udev.c
 create mode 100644 hw/xfree86/common/xf86udev.h

diff --git a/config/udev.c b/config/udev.c
index 1995184..700cc8b 100644
--- a/config/udev.c
+++ b/config/udev.c
@@ -366,3 +366,32 @@ config_udev_fini(void)
     udev_monitor = NULL;
     udev_unref(udev);
 }
+
+#ifdef CONFIG_UDEV_KMS
+int
+config_udev_probe_kms_outputs(config_udev_kms_probe_proc_ptr probe_callback)
+{
+    struct udev *udev;
+    struct udev_enumerate *enumerate;
+    struct udev_list_entry *devices, *device;
+
+    udev = udev_monitor_get_udev(udev_monitor);
+    enumerate = udev_enumerate_new(udev);
+    if (!enumerate)
+        return 0;
+
+    udev_enumerate_add_match_subsystem(enumerate, "drm");
+    udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
+    udev_enumerate_scan_devices(enumerate);
+    devices = udev_enumerate_get_list_entry(enumerate);
+    udev_list_entry_foreach(device, devices) {
+        const char *syspath = udev_list_entry_get_name(device);
+        struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
+        probe_callback(udev_device);
+        udev_device_unref(udev_device);
+    }
+    udev_enumerate_unref(enumerate);
+    return 0;
+}
+#endif
+
diff --git a/configure.ac b/configure.ac
index 97ceab1..610cae9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -615,6 +615,7 @@ AC_ARG_ENABLE(dbe,            AS_HELP_STRING([--disable-dbe], [Build DBE extensi
 AC_ARG_ENABLE(xf86bigfont,    AS_HELP_STRING([--enable-xf86bigfont], [Build XF86 Big Font extension (default: disabled)]), [XF86BIGFONT=$enableval], [XF86BIGFONT=no])
 AC_ARG_ENABLE(dpms,           AS_HELP_STRING([--disable-dpms], [Build DPMS extension (default: enabled)]), [DPMSExtension=$enableval], [DPMSExtension=yes])
 AC_ARG_ENABLE(config-udev,    AS_HELP_STRING([--enable-config-udev], [Build udev support (default: auto)]), [CONFIG_UDEV=$enableval], [CONFIG_UDEV=auto])
+AC_ARG_ENABLE(config-udev-kms,    AS_HELP_STRING([--enable-config-udev-kms], [Build udev kms support (default: auto)]), [CONFIG_UDEV_KMS=$enableval], [CONFIG_UDEV_KMS=auto])
 AC_ARG_ENABLE(config-dbus,    AS_HELP_STRING([--enable-config-dbus], [Build D-BUS API support (default: no)]), [CONFIG_DBUS_API=$enableval], [CONFIG_DBUS_API=no])
 AC_ARG_ENABLE(config-hal,     AS_HELP_STRING([--disable-config-hal], [Build HAL support (default: auto)]), [CONFIG_HAL=$enableval], [CONFIG_HAL=auto])
 AC_ARG_ENABLE(config-wscons,  AS_HELP_STRING([--enable-config-wscons], [Build wscons config support (default: auto)]), [CONFIG_WSCONS=$enableval], [CONFIG_WSCONS=auto])
@@ -704,6 +705,7 @@ case $host_os in
 		CONFIG_DBUS_API=no
 		CONFIG_HAL=no
 		CONFIG_UDEV=no
+		CONFIG_UDEV_KMS=no
 		DGA=no
 		DRI2=no
 		INT10MODULE=no
@@ -838,11 +840,16 @@ AM_CONDITIONAL(CONFIG_UDEV, [test "x$CONFIG_UDEV" = xyes])
 if test "x$CONFIG_UDEV" = xyes; then
 	CONFIG_DBUS_API=no
 	CONFIG_HAL=no
+	if test "x$CONFIG_UDEV_KMS" = xauto; then
+		CONFIG_UDEV_KMS="$HAVE_LIBUDEV"
+	fi
 	if ! test "x$HAVE_LIBUDEV" = xyes; then
 		AC_MSG_ERROR([udev configuration API requested, but libudev is not installed])
 	fi
 	AC_DEFINE(CONFIG_UDEV, 1, [Use libudev for input hotplug])
-
+	if test "x$CONFIG_UDEV_KMS" = xyes; then
+		AC_DEFINE(CONFIG_UDEV_KMS, 1, [Use libudev for kms enumeration])
+	fi
 	SAVE_LIBS=$LIBS
 	SAVE_CFLAGS=$CFLAGS
 	CFLAGS=$UDEV_CFLAGS
@@ -852,6 +859,7 @@ if test "x$CONFIG_UDEV" = xyes; then
 	LIBS=$SAVE_LIBS
 	CFLAGS=$SAVE_CFLAGS
 fi
+AM_CONDITIONAL(CONFIG_UDEV_KMS, [test "x$CONFIG_UDEV_KMS" = xyes])
 
 dnl HAVE_DBUS is true if we actually have the D-Bus library, whereas
 dnl CONFIG_DBUS_API is true if we want to enable the D-Bus config
@@ -1099,7 +1107,7 @@ case "$DRI2,$HAVE_DRI2PROTO" in
 esac
 AM_CONDITIONAL(DRI2, test "x$DRI2" = xyes)
 
-if test "x$DRI" = xyes || test "x$DRI2" = xyes; then
+if test "x$DRI" = xyes || test "x$DRI2" = xyes || test "x$CONFIG_UDEV_KMS" = xyes; then
 	if test "x$DRM" = xyes; then
 		AC_DEFINE(WITH_LIBDRM, 1, [Building with libdrm support])
 		PKG_CHECK_MODULES([LIBDRM], $LIBDRM)
@@ -1630,7 +1638,7 @@ if test "x$XORG" = xyes; then
 
 	PKG_CHECK_MODULES([PCIACCESS], $LIBPCIACCESS)
 	SDK_REQUIRED_MODULES="$SDK_REQUIRED_MODULES $LIBPCIACCESS"
-	XORG_SYS_LIBS="$XORG_SYS_LIBS $PCIACCESS_LIBS $GLX_SYS_LIBS"
+	XORG_SYS_LIBS="$XORG_SYS_LIBS $PCIACCESS_LIBS $GLX_SYS_LIBS $LIBDRM_LIBS"
 	XORG_CFLAGS="$XORG_CFLAGS $PCIACCESS_CFLAGS"
 
 	AC_DEFINE(XSERVER_LIBPCIACCESS, 1, [Use libpciaccess for all pci manipulation])
@@ -1648,6 +1656,10 @@ if test "x$XORG" = xyes; then
 	fi
 	AC_MSG_RESULT([$PCI])
 
+	if test "x$CONFIG_UDEV_KMS" = xyes; then
+		AC_DEFINE(XSERVER_UDEV_KMS, 1, [X server supports using libudev for kms enumeration])
+	fi
+	AC_MSG_RESULT([$CONFIG_UDEV_KMS])
 	dnl ===================================================================
 	dnl ==================== end of PCI configuration =====================
 	dnl ===================================================================
diff --git a/hw/xfree86/common/Makefile.am b/hw/xfree86/common/Makefile.am
index 2792177..e0eec80 100644
--- a/hw/xfree86/common/Makefile.am
+++ b/hw/xfree86/common/Makefile.am
@@ -22,9 +22,13 @@ if DGA
 DGASOURCES = xf86DGA.c
 endif
 
+if CONFIG_UDEV_KMS
+UDEVSOURCES = xf86udev.c
+endif
+
 RANDRSOURCES = xf86RandR.c
 
-BUSSOURCES = xf86fbBus.c xf86noBus.c $(PCI_SOURCES) $(SBUS_SOURCES)
+BUSSOURCES = xf86fbBus.c xf86noBus.c $(PCI_SOURCES) $(SBUS_SOURCES) $(UDEVSOURCES)
 
 MODEDEFSOURCES = $(srcdir)/vesamodes $(srcdir)/extramodes
 
@@ -50,13 +54,13 @@ INCLUDES = $(XORG_INCS) -I$(srcdir)/../ddc -I$(srcdir)/../i2c \
 	   -I$(srcdir)/../loader -I$(srcdir)/../parser \
            -I$(srcdir)/../vbe -I$(srcdir)/../int10 \
 	   -I$(srcdir)/../vgahw -I$(srcdir)/../dixmods/extmod \
-	   -I$(srcdir)/../modes -I$(srcdir)/../ramdac
+	   -I$(srcdir)/../modes -I$(srcdir)/../ramdac @LIBDRM_CFLAGS@
 
 sdk_HEADERS = compiler.h fourcc.h xf86.h xf86Module.h xf86Opt.h \
               xf86PciInfo.h xf86Priv.h xf86Privstr.h \
               xf86cmap.h xf86fbman.h xf86str.h xf86Xinput.h xisb.h \
               $(XVSDKINCS) $(XF86VMODE_SDK) xorgVersion.h \
-              xf86sbusBus.h xf86VGAarbiter.h xf86Optionstr.h
+              xf86sbusBus.h xf86VGAarbiter.h xf86Optionstr.h xf86udev.h
 
 DISTCLEANFILES = xf86Build.h
 CLEANFILES = $(BUILT_SOURCES)
diff --git a/hw/xfree86/common/xf86.h b/hw/xfree86/common/xf86.h
index e6d41d6..a9d5210 100644
--- a/hw/xfree86/common/xf86.h
+++ b/hw/xfree86/common/xf86.h
@@ -71,6 +71,11 @@ extern _X_EXPORT Bool fbSlotClaimed;
 #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
 extern _X_EXPORT Bool sbusSlotClaimed;
 #endif
+
+#if defined(XSERVER_UDEV_KMS)
+extern _X_EXPORT int udevSlotClaimed;
+#endif
+
 extern _X_EXPORT confDRIRec xf86ConfigDRI;
 extern _X_EXPORT Bool xf86DRI2Enabled(void);
 
diff --git a/hw/xfree86/common/xf86Bus.c b/hw/xfree86/common/xf86Bus.c
index b876434..3ca6029 100644
--- a/hw/xfree86/common/xf86Bus.c
+++ b/hw/xfree86/common/xf86Bus.c
@@ -77,8 +77,14 @@ xf86CallDriverProbe(DriverPtr drv, Bool detect_only)
 {
     Bool foundScreen = FALSE;
 
+#ifdef XSERVER_UDEV_KMS
+    if (drv->udevProbe != NULL) {
+        foundScreen = xf86udevProbeDev(drv);
+    }
+#endif
+
 #ifdef XSERVER_LIBPCIACCESS
-    if (drv->PciProbe != NULL) {
+    if (!foundScreen && (drv->PciProbe != NULL)) {
         if (xf86DoConfigure && xf86DoConfigurePass1) {
             assert(detect_only);
             foundScreen = xf86PciAddMatchingDev(drv);
@@ -202,6 +208,9 @@ xf86BusConfig(void)
 void
 xf86BusProbe(void)
 {
+#ifdef CONFIG_UDEV_KMS
+    xf86udevProbe();
+#endif
 #ifdef XSERVER_LIBPCIACCESS
     xf86PciProbe();
 #endif
@@ -262,14 +271,22 @@ xf86IsEntityPrimary(int entityIndex)
 {
     EntityPtr pEnt = xf86Entities[entityIndex];
 
-    if (primaryBus.type != pEnt->bus.type)
-        return FALSE;
-
     switch (pEnt->bus.type) {
     case BUS_PCI:
+        if (primaryBus.type != pEnt->bus.type)
+            return FALSE;
         return pEnt->bus.id.pci == primaryBus.id.pci;
     case BUS_SBUS:
+        if (primaryBus.type != pEnt->bus.type)
+            return FALSE;
         return pEnt->bus.id.sbus.fbNum == primaryBus.id.sbus.fbNum;
+    case BUS_UDEV:
+        if (!pEnt->bus.id.udev->pdev)
+            return FALSE;
+        return ((pEnt->bus.id.udev->pdev->domain == primaryBus.id.pci->domain) &&
+                (pEnt->bus.id.udev->pdev->bus == primaryBus.id.pci->bus) &&
+                (pEnt->bus.id.udev->pdev->dev == primaryBus.id.pci->dev) &&
+                (pEnt->bus.id.udev->pdev->func == primaryBus.id.pci->func));
     default:
         return FALSE;
     }
@@ -542,6 +559,9 @@ xf86PostProbe(void)
 #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
                              sbusSlotClaimed ||
 #endif
+#ifdef XSERVER_UDEV_KMS
+                             udevSlotClaimed ||
+#endif
 #ifdef XSERVER_LIBPCIACCESS
                              pciSlotClaimed
 #else
diff --git a/hw/xfree86/common/xf86Bus.h b/hw/xfree86/common/xf86Bus.h
index abf2efd..a5e147c 100644
--- a/hw/xfree86/common/xf86Bus.h
+++ b/hw/xfree86/common/xf86Bus.h
@@ -42,6 +42,7 @@
 #if defined(__sparc__) || defined(__sparc)
 #include "xf86sbusBus.h"
 #endif
+#include "xf86udev.h"
 
 typedef struct {
     DriverPtr driver;
diff --git a/hw/xfree86/common/xf86fbBus.c b/hw/xfree86/common/xf86fbBus.c
index 1e51623..9c984f6 100644
--- a/hw/xfree86/common/xf86fbBus.c
+++ b/hw/xfree86/common/xf86fbBus.c
@@ -54,6 +54,10 @@ xf86ClaimFbSlot(DriverPtr drvp, int chipset, GDevPtr dev, Bool active)
     EntityPtr p;
     int num;
 
+#ifdef XSERVER_UDEV_KMS
+    if (udevSlotClaimed)
+        return -1;
+#endif
 #ifdef XSERVER_LIBPCIACCESS
     if (pciSlotClaimed)
         return -1;
diff --git a/hw/xfree86/common/xf86pciBus.c b/hw/xfree86/common/xf86pciBus.c
index d758260..e5f1388 100644
--- a/hw/xfree86/common/xf86pciBus.c
+++ b/hw/xfree86/common/xf86pciBus.c
@@ -367,7 +367,15 @@ xf86GetPciInfoForEntity(int entityIndex)
         return NULL;
 
     p = xf86Entities[entityIndex];
-    return (p->bus.type == BUS_PCI) ? p->bus.id.pci : NULL;
+    switch (p->bus.type) {
+    case BUS_PCI:
+        return p->bus.id.pci;
+    case BUS_UDEV:
+        return p->bus.id.udev->pdev;
+    default:
+        break;
+    }
+    return NULL;
 }
 
 /*
@@ -400,6 +408,16 @@ xf86CheckPciSlot(const struct pci_device *d)
         if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
             return FALSE;
         }
+#ifdef CONFIG_UDEV_KMS
+        if ((p->bus.type == BUS_UDEV) && (p->bus.id.udev->pdev)) {
+            struct pci_device *ud = p->bus.id.udev->pdev;
+            if (ud->domain == d->domain &&
+                ud->bus == d->bus &&
+                ud->dev == d->dev &&
+                ud->func == d->func)
+                return FALSE;
+        }
+#endif
     }
     return TRUE;
 }
diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h
index 6294845..01aabe9 100644
--- a/hw/xfree86/common/xf86str.h
+++ b/hw/xfree86/common/xf86str.h
@@ -311,6 +311,7 @@ struct _SymTabRec;
 struct _PciChipsets;
 
 struct pci_device;
+struct xf86_udev_device;
 
 typedef struct _DriverRec {
     int driverVersion;
@@ -325,9 +326,20 @@ typedef struct _DriverRec {
     const struct pci_id_match *supported_devices;
     Bool (*PciProbe) (struct _DriverRec * drv, int entity_num,
                       struct pci_device * dev, intptr_t match_data);
+#ifdef XSERVER_UDEV_KMS
+    Bool (*udevProbe) (struct _DriverRec * drv, int entity_num, int flags,
+                       struct xf86_udev_device * dev, intptr_t match_data);
+#else
+    void *udevProbe; /* place holder to non udev-kms support so struct is right size */
+#endif
 } DriverRec, *DriverPtr;
 
 /*
+ * udevprobe flags
+ * no flags are defined yet - but drivers should fail to load if a flag they
+ * don't understand is passed. 
+ */
+/*
  *  AddDriver flags
  */
 #define HaveDriverFuncs 1
@@ -343,6 +355,7 @@ typedef struct _DriverRec {
 #undef BUS_NONE
 #undef BUS_PCI
 #undef BUS_SBUS
+#undef BUS_UDEV
 #undef BUS_last
 #endif
 
@@ -350,6 +363,7 @@ typedef enum {
     BUS_NONE,
     BUS_PCI,
     BUS_SBUS,
+    BUS_UDEV,
     BUS_last                    /* Keep last */
 } BusType;
 
@@ -362,6 +376,7 @@ typedef struct _bus {
     union {
         struct pci_device *pci;
         SbusBusId sbus;
+        struct xf86_udev_device *udev;
     } id;
 } BusRec, *BusPtr;
 
diff --git a/hw/xfree86/common/xf86udev.c b/hw/xfree86/common/xf86udev.c
new file mode 100644
index 0000000..554552f
--- /dev/null
+++ b/hw/xfree86/common/xf86udev.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright © 2012 Red Hat.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Dave Airlie <airlied at redhat.com>
+ */
+
+/*
+ * This file contains the interfaces to the bus-specific code
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#ifdef XSERVER_UDEV_KMS
+#include <errno.h>
+#ifdef WITH_LIBDRM
+#include <xf86drm.h>
+#endif
+#include <pciaccess.h>
+#include <libudev.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "os.h"
+#include "hotplug.h"
+
+#include "xf86.h"
+#include "xf86Priv.h"
+#include "xf86str.h"
+#include "xf86Bus.h"
+#include "Pci.h"
+#include "xf86udev.h"
+
+int udevSlotClaimed;
+
+static int num_udev_devices;
+
+static struct xf86_udev_device *xf86_udev_devices;
+
+static int
+xf86_add_udev_device(const char *path, char *busid, const char *syspath)
+{
+    xf86_udev_devices = xnfrealloc(xf86_udev_devices,
+                                   (sizeof(struct xf86_udev_device)
+                                    * (num_udev_devices + 1)));
+    xf86_udev_devices[num_udev_devices].path = strdup(path);
+    xf86_udev_devices[num_udev_devices].busid = strdup(busid);
+    xf86_udev_devices[num_udev_devices].syspath = strdup(syspath);
+    num_udev_devices++;
+    return 0;
+}
+
+static void
+get_drm_info(const char *path, const char *syspath)
+{
+    drmSetVersion sv;
+    char *buf;
+    int fd;
+
+    fd = open(path, O_RDWR, O_CLOEXEC);
+    if (fd == -1)
+        return;
+
+    sv.drm_di_major = 1;
+    sv.drm_di_minor = 4;
+    sv.drm_dd_major = -1;       /* Don't care */
+    sv.drm_dd_minor = -1;       /* Don't care */
+    if (drmSetInterfaceVersion(fd, &sv)) {
+        ErrorF("setversion 1.4 failed\n");
+        return;
+    }
+
+    buf = drmGetBusid(fd);
+    xf86_add_udev_device(path, buf, syspath);
+    drmFreeBusid(buf);
+    close(fd);
+
+}
+
+static void
+kms_device_test(struct udev_device *udev_device)
+{
+    const char *path;
+    const char *syspath;
+    int i;
+
+    path = udev_device_get_devnode(udev_device);
+    syspath = udev_device_get_syspath(udev_device);
+
+    if (!path || !syspath)
+        return;
+
+    if (!strcmp(udev_device_get_subsystem(udev_device), "drm")) {
+        const char *sysname = udev_device_get_sysname(udev_device);
+
+        if (strncmp(sysname, "card", 4))
+            return;
+
+        for (i = 0; i < num_udev_devices; i++)
+            if (!strcmp(path, xf86_udev_devices[i].path))
+                break;
+
+        if (i != num_udev_devices)
+            return;
+
+        LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n",
+                   path);
+
+        get_drm_info(path, syspath);
+        return;
+    }
+}
+
+static int
+config_udev_output_probe(void)
+{
+    config_udev_probe_kms_outputs(&kms_device_test);
+    return 0;
+}
+
+static void
+udev_find_pci_info(int idx)
+{
+    struct pci_slot_match devmatch;
+    struct pci_device *info;
+    struct pci_device_iterator *iter;
+    int ret;
+
+    ret = sscanf(xf86_udev_devices[idx].busid, "pci:%04x:%02x:%02x.%u",
+                 &devmatch.domain, &devmatch.bus, &devmatch.dev,
+                 &devmatch.func);
+    if (ret != 4)
+        return;
+
+    iter = pci_slot_match_iterator_create(&devmatch);
+    info = pci_device_next(iter);
+    if (info) {
+        xf86_udev_devices[idx].pdev = info;
+        pci_device_probe(info);
+    }
+    pci_iterator_destroy(iter);
+
+}
+
+static Bool
+xf86_check_udev_slot(const struct xf86_udev_device *ud)
+{
+    int i;
+
+    for (i = 0; i < xf86NumEntities; i++) {
+        const EntityPtr u = xf86Entities[i];
+
+        if ((u->bus.type == BUS_UDEV) && (ud == u->bus.id.udev)) {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+int
+xf86udevProbe(void)
+{
+    int ret;
+    int i;
+    Bool pci = TRUE;
+
+    if (!xf86scanpci()) {
+        pci = FALSE;
+    }
+
+    ret = config_udev_output_probe();
+    for (i = 0; i < num_udev_devices; i++) {
+        xf86Msg(X_INFO, "udev: found output device %s %s %s\n", xf86_udev_devices[i].path,
+                xf86_udev_devices[i].busid, xf86_udev_devices[i].syspath);
+        if (pci && !strncmp(xf86_udev_devices[i].busid, "pci:", 4)) {
+            udev_find_pci_info(i);
+        }
+        else if (!strncmp(xf86_udev_devices[i].busid, "usb:", 4)) {
+            /* place holder */
+        }
+    }
+    return ret;
+}
+
+static int
+xf86ClaimUdevSlot(struct xf86_udev_device * d, DriverPtr drvp,
+                  int chipset, GDevPtr dev, Bool active)
+{
+    EntityPtr p = NULL;
+    int num;
+
+    num = xf86AllocateEntity();
+    p = xf86Entities[num];
+    p->driver = drvp;
+    p->chipset = chipset;
+    p->bus.type = BUS_UDEV;
+    p->bus.id.udev = d;
+    p->active = active;
+    p->inUse = FALSE;
+    if (dev)
+        xf86AddDevToEntity(num, dev);
+
+    udevSlotClaimed++;
+    return num;
+}
+
+static int
+xf86UnclaimUdevSlot(struct xf86_udev_device *d, GDevPtr dev)
+{
+    int i;
+
+    for (i = 0; i < xf86NumEntities; i++) {
+        const EntityPtr p = xf86Entities[i];
+
+        if ((p->bus.type == BUS_UDEV) && (p->bus.id.udev == d)) {
+            if (dev)
+                xf86RemoveDevFromEntity(i, dev);
+            udevSlotClaimed--;
+            p->bus.type = BUS_NONE;
+            return 0;
+        }
+    }
+    return 0;
+}
+
+#define END_OF_MATCHES(m)                                               \
+    (((m).vendor_id == 0) && ((m).device_id == 0) && ((m).subvendor_id == 0))
+
+int
+xf86udevProbeDev(DriverPtr drvp)
+{
+    Bool foundScreen = FALSE;
+    GDevPtr *devList;
+    const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList);
+    int i, j, k;
+    int  entity;
+    const struct pci_id_match *const devices = drvp->supported_devices;
+    struct pci_device *pPci;
+
+    for (i = 0; i < numDevs; i++) {
+        for (j = 0; j < num_udev_devices; j++) {
+            /* overload PCI match loading if we can use it */
+            if (xf86_udev_devices[j].pdev && devices) {
+                int device_id = xf86_udev_devices[j].pdev->device_id;
+                pPci = xf86_udev_devices[j].pdev;
+                for (k = 0; !END_OF_MATCHES(devices[k]); k++) {
+                    if (PCI_ID_COMPARE(devices[k].vendor_id, pPci->vendor_id)
+                        && PCI_ID_COMPARE(devices[k].device_id, device_id)
+                        && ((devices[k].device_class_mask & pPci->device_class)
+                            ==  devices[k].device_class)) {
+                        if (xf86_check_udev_slot(&xf86_udev_devices[j])) {
+                            entity = xf86ClaimUdevSlot(&xf86_udev_devices[j],
+                                                       drvp, 0, devList[i], devList[i]->active);
+                            if (entity != -1) {
+                                if (!drvp->udevProbe(drvp, entity, 0, &xf86_udev_devices[j], devices[k].match_data)) {
+                                    xf86UnclaimUdevSlot(&xf86_udev_devices[j], devList[i]);
+                                    continue;
+                                }
+                                foundScreen = TRUE;
+                                break;
+                            }
+                            else
+                                xf86UnclaimUdevSlot(&xf86_udev_devices[j], devList[i]);
+                        }
+                    }
+                }
+            }
+            else if (xf86_udev_devices[j].pdev && !devices)
+                continue;
+            else {
+                if (xf86_check_udev_slot(&xf86_udev_devices[j])) {
+                    entity = xf86ClaimUdevSlot(&xf86_udev_devices[j],
+                                               drvp, 0, devList[i], devList[i]->active);
+                    if (!drvp->udevProbe(drvp, entity, 0, &xf86_udev_devices[j], 0)) {
+                        xf86UnclaimUdevSlot(&xf86_udev_devices[j], devList[i]);
+                        continue;
+                    }
+                    foundScreen = TRUE;
+                }
+            }
+        }
+    }
+    return foundScreen;
+}
+
+#endif
diff --git a/hw/xfree86/common/xf86udev.h b/hw/xfree86/common/xf86udev.h
new file mode 100644
index 0000000..37ea1e7
--- /dev/null
+++ b/hw/xfree86/common/xf86udev.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2012 Red Hat.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Dave Airlie <airlied at redhat.com>
+ */
+#ifndef XF86_UDEV_H
+#define XF86_UDEV_H
+
+
+struct xf86_udev_device {
+    char *path;
+    char *busid;
+    char *syspath;
+    int dev_type;
+    /* for PCI devices */
+    struct pci_device *pdev;
+};
+
+#ifdef CONFIG_UDEV_KMS
+int xf86udevProbe(void);
+int xf86udevProbeDev(DriverPtr drvp);
+#endif
+
+#endif
diff --git a/include/dix-config.h.in b/include/dix-config.h.in
index 3c9bbaf..77681a9 100644
--- a/include/dix-config.h.in
+++ b/include/dix-config.h.in
@@ -390,6 +390,9 @@
 /* Use libudev for input hotplug */
 #undef CONFIG_UDEV
 
+/* Use libudev for kms enumeration */
+#undef CONFIG_UDEV_KMS
+
 /* Use udev_monitor_filter_add_match_tag() */
 #undef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
 
diff --git a/include/hotplug.h b/include/hotplug.h
index f3eeea2..e80bb56 100644
--- a/include/hotplug.h
+++ b/include/hotplug.h
@@ -30,4 +30,8 @@ extern _X_EXPORT void config_pre_init(void);
 extern _X_EXPORT void config_init(void);
 extern _X_EXPORT void config_fini(void);
 
+#ifdef CONFIG_UDEV_KMS
+typedef void (*config_udev_kms_probe_proc_ptr)(struct udev_device *device);
+int config_udev_probe_kms_outputs(config_udev_kms_probe_proc_ptr probe_callback);
+#endif
 #endif                          /* HOTPLUG_H */
diff --git a/include/xorg-config.h.in b/include/xorg-config.h.in
index 2cc416a..65e32ed 100644
--- a/include/xorg-config.h.in
+++ b/include/xorg-config.h.in
@@ -136,4 +136,7 @@
 /* Have getresuid */
 #undef HAVE_GETRESUID
 
+/* Use udev kms enumeration */
+#undef XSERVER_UDEV_KMS
+
 #endif /* _XORG_CONFIG_H_ */
diff --git a/include/xorg-server.h.in b/include/xorg-server.h.in
index 8086f32..c087742 100644
--- a/include/xorg-server.h.in
+++ b/include/xorg-server.h.in
@@ -205,6 +205,9 @@
 /* X Access Control Extension */
 #undef XACE
 
+/* X server udev kms enumeration */
+#undef XSERVER_UDEV_KMS
+
 #ifdef _LP64
 #define _XSERVER64 1
 #endif
-- 
1.7.6



More information about the xorg-devel mailing list