[PATCH] xfree86: use udev to provide device enumeration for kms devices (v3)

Peter Hutterer peter.hutterer at who-t.net
Thu May 10 17:14:00 PDT 2012


On Thu, May 10, 2012 at 11:25:04AM +0100, Dave Airlie wrote:
> 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.
> 
> v2: rename to platform bus, now with 100% less udev specific,
> 
> this version passes config_odev_attribs around which are an array
> of id/string pairs, then the udev code can attach the set of attribs
> it understands, the OS specific code can attach its attrib, and then
> the core/drivers can lookup the required attribs.
> 
> also add MATCH_PCI_DEVICES macro.
> 
> This version is mainly to address concerns raised by ajax.
> 
> v3: Address comments from Peter.
> fix whitespace that snuck in.
> rework to use a linked list with some core functions that
> xf86 wraps.
> 
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
>  config/config-backends.h                     |    1 +
>  config/config.c                              |   49 +++++
>  config/udev.c                                |   73 ++++++++
>  configure.ac                                 |   20 ++-
>  hw/xfree86/common/Makefile.am                |    8 +-
>  hw/xfree86/common/xf86.h                     |    5 +
>  hw/xfree86/common/xf86Bus.c                  |   25 ++-
>  hw/xfree86/common/xf86Bus.h                  |    1 +
>  hw/xfree86/common/xf86fbBus.c                |    4 +
>  hw/xfree86/common/xf86pciBus.c               |   17 ++-
>  hw/xfree86/common/xf86pciBus.h               |    5 +
>  hw/xfree86/common/xf86platformBus.c          |  256 ++++++++++++++++++++++++++
>  hw/xfree86/common/xf86platformBus.h          |   51 +++++
>  hw/xfree86/common/xf86str.h                  |   15 ++
>  hw/xfree86/os-support/linux/Makefile.am      |    2 +-
>  hw/xfree86/os-support/linux/lnx_platform.c   |   89 +++++++++
>  hw/xfree86/os-support/shared/platform_noop.c |   17 ++
>  hw/xfree86/os-support/xf86_OSproc.h          |    6 +
>  include/dix-config.h.in                      |    3 +
>  include/hotplug.h                            |   33 ++++
>  include/xorg-config.h.in                     |    3 +
>  include/xorg-server.h.in                     |    3 +
>  22 files changed, 674 insertions(+), 12 deletions(-)
>  create mode 100644 hw/xfree86/common/xf86platformBus.c
>  create mode 100644 hw/xfree86/common/xf86platformBus.h
>  create mode 100644 hw/xfree86/os-support/linux/lnx_platform.c
>  create mode 100644 hw/xfree86/os-support/shared/platform_noop.c
> 
> diff --git a/config/config-backends.h b/config/config-backends.h
> index 62abc0a..6423701 100644
> --- a/config/config-backends.h
> +++ b/config/config-backends.h
> @@ -36,6 +36,7 @@ BOOL device_is_duplicate(const char *config_info);
>  int config_udev_pre_init(void);
>  int config_udev_init(void);
>  void config_udev_fini(void);
> +void config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback);
>  #else
>  
>  #ifdef CONFIG_NEED_DBUS
> diff --git a/config/config.c b/config/config.c
> index 24e7ba7..8d57b34 100644
> --- a/config/config.c
> +++ b/config/config.c
> @@ -85,6 +85,14 @@ config_fini(void)
>  #endif
>  }
>  
> +void
> +config_odev_probe(config_odev_probe_proc_ptr probe_callback)
> +{
> +#if defined(CONFIG_UDEV_KMS)
> +    config_udev_odev_probe(probe_callback);
> +#endif
> +}
> +
>  static void
>  remove_device(const char *backend, DeviceIntPtr dev)
>  {
> @@ -133,3 +141,44 @@ device_is_duplicate(const char *config_info)
>  
>      return FALSE;
>  }
> +
> +struct OdevAttributes *
> +config_odev_allocate_attribute_list(void)
> +{
> +    struct OdevAttributes *attriblist;
> +
> +    attriblist = malloc(sizeof(struct OdevAttributes));
> +    if (!attriblist)
> +        return NULL;
> +
> +    xorg_list_init(&attriblist->list);
> +    return attriblist;
> +}

there's no matching free_attribute_list()? would be useful, so you don't
have to fix all the callers if OdevAttributes ever changes.

> +
> +Bool
> +config_odev_add_attribute(struct OdevAttributes *attribs, int attrib,
> +                          const char *attrib_name)
> +{
> +    struct OdevAttribute *oa;
> +
> +    oa = malloc(sizeof(struct OdevAttribute));
> +    if (!oa)
> +        return FALSE;
> +
> +    oa->attrib_id = attrib;
> +    oa->attrib_name = strdup(attrib_name);
> +    xorg_list_append(&oa->member, &attribs->list);
> +    return TRUE;
> +}
> +
> +void
> +config_odev_free_attributes(struct OdevAttributes *attribs)
> +{
> +    struct OdevAttribute *iter, *safe;
> +
> +    xorg_list_for_each_entry_safe(iter, safe, &attribs->list, member) {
> +        xorg_list_del(&iter->member);
> +        free(iter->attrib_name);
> +        free(iter);
> +    }
> +}
> diff --git a/config/udev.c b/config/udev.c
> index 1995184..cb2a3e6 100644
> --- a/config/udev.c
> +++ b/config/udev.c
> @@ -366,3 +366,76 @@ config_udev_fini(void)
>      udev_monitor = NULL;
>      udev_unref(udev);
>  }
> +
> +#ifdef CONFIG_UDEV_KMS
> +
> +static Bool
> +config_udev_odev_setup_attribs(const char *path, const char *syspath, const char *sysname,
> +                               config_odev_probe_proc_ptr probe_callback)
> +{
> +    struct OdevAttributes *attribs = config_odev_allocate_attribute_list();
> +    int ret;
> +
> +    if (!attribs)
> +        return FALSE;
> +    
> +    ret = config_odev_add_attribute(attribs, ODEV_ATTRIB_PATH, path);
> +    if (ret)
> +        goto fail;
> +
> +    ret = config_odev_add_attribute(attribs, ODEV_ATTRIB_SYSPATH, syspath);
> +    if (ret)
> +        goto fail;
> +
> +    ret = config_odev_add_attribute(attribs, ODEV_ATTRIB_SYSNAME, sysname);
> +    if (ret)
> +        goto fail;
> +
> +    /* ownership of attribs is passed to probe layer */
> +    probe_callback(attribs);
> +    return TRUE;
> +fail:
> +    config_odev_free_attributes(attribs);
> +    free(attribs);
> +    return FALSE;
> +}
> +
> +void
> +config_udev_odev_probe(config_odev_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;
> +
> +    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);
> +        const char *path = udev_device_get_devnode(udev_device);
> +        const char *sysname = udev_device_get_sysname(udev_device);
> +
> +        if (!path || !syspath)
> +            goto no_probe;
> +        else if (strcmp(udev_device_get_subsystem(udev_device), "drm"))
> +            goto no_probe;
> +        else if (strncmp(sysname, "card", 4))
> +            goto no_probe;
> +
> +        config_udev_odev_setup_attribs(path, syspath, sysname, probe_callback);
> +
> +    no_probe:
> +        udev_device_unref(udev_device);
> +    }
> +    udev_enumerate_unref(enumerate);
> +    return;
> +}
> +#endif
> +
> diff --git a/configure.ac b/configure.ac
> index 97ceab1..19fae0e 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_PLATFORM_BUS, 1, [X server supports platform device enumeration])
> +	fi
> +	AC_MSG_RESULT([$XSERVER_PLATFORM_BUS])
>  	dnl ===================================================================
>  	dnl ==================== end of PCI configuration =====================
>  	dnl ===================================================================
> @@ -1836,7 +1848,7 @@ AM_CONDITIONAL([SOLARIS_ASM_INLINE], [test "x$solaris_asm_inline" = xyes])
>  AM_CONDITIONAL([SOLARIS_VT], [test "x$solaris_vt" = xyes])
>  AM_CONDITIONAL([DGA], [test "x$DGA" = xyes])
>  AM_CONDITIONAL([XF86VIDMODE], [test "x$XF86VIDMODE" = xyes])
> -
> +AM_CONDITIONAL([XORG_BUS_PLATFORM], [test "x$CONFIG_UDEV_KMS" = xyes])
>  dnl XWin DDX
>  
>  AC_MSG_CHECKING([whether to build XWin DDX])
> diff --git a/hw/xfree86/common/Makefile.am b/hw/xfree86/common/Makefile.am
> index 2792177..65d98e6 100644
> --- a/hw/xfree86/common/Makefile.am
> +++ b/hw/xfree86/common/Makefile.am
> @@ -22,9 +22,13 @@ if DGA
>  DGASOURCES = xf86DGA.c
>  endif
>  
> +if XORG_BUS_PLATFORM
> +PLATSOURCES = xf86platformBus.c
> +endif
> +
>  RANDRSOURCES = xf86RandR.c
>  
> -BUSSOURCES = xf86fbBus.c xf86noBus.c $(PCI_SOURCES) $(SBUS_SOURCES)
> +BUSSOURCES = xf86fbBus.c xf86noBus.c $(PCI_SOURCES) $(SBUS_SOURCES) $(PLATSOURCES)
>  
>  MODEDEFSOURCES = $(srcdir)/vesamodes $(srcdir)/extramodes
>  
> @@ -56,7 +60,7 @@ 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 xf86platformBus.h
>  
>  DISTCLEANFILES = xf86Build.h
>  CLEANFILES = $(BUILT_SOURCES)
> diff --git a/hw/xfree86/common/xf86.h b/hw/xfree86/common/xf86.h
> index e6d41d6..5f7badb 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_PLATFORM_BUS)
> +extern _X_EXPORT int platformSlotClaimed;
> +#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..733fe84 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_PLATFORM_BUS
> +    if (drv->platformProbe != NULL) {
> +        foundScreen = xf86platformProbeDev(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 XSERVER_PLATFORM_BUS
> +    xf86platformProbe();
> +#endif
>  #ifdef XSERVER_LIBPCIACCESS
>      xf86PciProbe();
>  #endif
> @@ -262,14 +271,19 @@ 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_PLATFORM:
> +        if (!pEnt->bus.id.plat->pdev)
> +            return FALSE;
> +        return (MATCH_PCI_DEVICES(pEnt->bus.id.plat->pdev, primaryBus.id.pci));
>      default:
>          return FALSE;
>      }
> @@ -542,6 +556,9 @@ xf86PostProbe(void)
>  #if (defined(__sparc__) || defined(__sparc)) && !defined(__OpenBSD__)
>                               sbusSlotClaimed ||
>  #endif
> +#ifdef XSERVER_PLATFORM_BUS
> +                             platformSlotClaimed ||
> +#endif
>  #ifdef XSERVER_LIBPCIACCESS
>                               pciSlotClaimed
>  #else
> diff --git a/hw/xfree86/common/xf86Bus.h b/hw/xfree86/common/xf86Bus.h
> index abf2efd..e83ba78 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 "xf86platformBus.h"
>  
>  typedef struct {
>      DriverPtr driver;
> diff --git a/hw/xfree86/common/xf86fbBus.c b/hw/xfree86/common/xf86fbBus.c
> index 1e51623..303b9c2 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_PLATFORM_BUS
> +    if (platformSlotClaimed)
> +        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..38ced15 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_PLATFORM:
> +        return p->bus.id.plat->pdev;
> +    default:
> +        break;
> +    }
> +    return NULL;
>  }
>  
>  /*
> @@ -400,6 +408,13 @@ xf86CheckPciSlot(const struct pci_device *d)
>          if ((p->bus.type == BUS_PCI) && (p->bus.id.pci == d)) {
>              return FALSE;
>          }
> +#ifdef XSERVER_PLATFORM_BUS
> +        if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat->pdev)) {
> +            struct pci_device *ud = p->bus.id.plat->pdev;
> +            if (MATCH_PCI_DEVICES(ud, d))
> +                return FALSE;
> +        }
> +#endif
>      }
>      return TRUE;
>  }
> diff --git a/hw/xfree86/common/xf86pciBus.h b/hw/xfree86/common/xf86pciBus.h
> index 56ec6e9..975da6c 100644
> --- a/hw/xfree86/common/xf86pciBus.h
> +++ b/hw/xfree86/common/xf86pciBus.h
> @@ -42,4 +42,9 @@ Bool xf86PciConfigure(void *busData, struct pci_device *pDev);
>  void xf86PciConfigureNewDev(void *busData, struct pci_device *pVideo,
>                              GDevRec * GDev, int *chipset);
>  
> +#define MATCH_PCI_DEVICES(x, y) (((x)->domain == (y)->domain) &&        \
> +                                 ((x)->bus == (y)->bus) &&              \
> +                                 ((x)->func == (y)->func) &&            \
> +                                 ((x)->dev == (y)->dev))
> +
>  #endif                          /* _XF86_PCI_BUS_H */
> diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c
> new file mode 100644
> index 0000000..af02622
> --- /dev/null
> +++ b/hw/xfree86/common/xf86platformBus.c
> @@ -0,0 +1,256 @@
> +/*
> + * 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_PLATFORM_BUS
> +#include <errno.h>
> +
> +#include <pciaccess.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include "os.h"
> +#include "hotplug.h"
> +
> +#include "xf86.h"
> +#include "xf86_OSproc.h"
> +#include "xf86Priv.h"
> +#include "xf86str.h"
> +#include "xf86Bus.h"
> +#include "Pci.h"
> +#include "xf86platformBus.h"
> +
> +int platformSlotClaimed;
> +
> +int xf86_num_platform_devices;
> +
> +static struct xf86_platform_device *xf86_platform_devices;
> +
> +int
> +xf86_add_platform_device(struct OdevAttributes *attribs)
> +{
> +    xf86_platform_devices = xnfrealloc(xf86_platform_devices,
> +                                   (sizeof(struct xf86_platform_device)
> +                                    * (xf86_num_platform_devices + 1)));
> +
> +    xf86_platform_devices[xf86_num_platform_devices].attribs = attribs;
> +    xf86_num_platform_devices++;
> +    return 0;
> +}
> +
> +Bool
> +xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_name)
> +{
> +    struct xf86_platform_device *device = &xf86_platform_devices[index];
> +
> +    return config_odev_add_attribute(device->attribs, attrib_id, attrib_name);
> +}
> +
> +char *
> +xf86_get_platform_attrib(int index, int attrib_id)
> +{
> +    struct xf86_platform_device *device = &xf86_platform_devices[index];
> +    int i;
> +    struct OdevAttribute *oa;
> +
> +    xorg_list_for_each_entry(oa, &device->attribs->list, member) {
> +        if (oa->attrib_id == attrib_id)
> +            return oa->attrib_name;
> +    }
> +    return NULL;
> +}
> +
> +static void
> +platform_find_pci_info(int idx)
> +{
> +    struct pci_slot_match devmatch;
> +    struct pci_device *info;
> +    struct pci_device_iterator *iter;
> +    int ret;
> +    char *busid;
> +
> +    busid = xf86_get_platform_attrib(idx, ODEV_ATTRIB_BUSID);
> +    ret = sscanf(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_platform_devices[idx].pdev = info;
> +        pci_device_probe(info);
> +    }
> +    pci_iterator_destroy(iter);
> +
> +}
> +
> +static Bool
> +xf86_check_platform_slot(const struct xf86_platform_device *pd)
> +{
> +    int i;
> +
> +    for (i = 0; i < xf86NumEntities; i++) {
> +        const EntityPtr u = xf86Entities[i];
> +
> +        if ((u->bus.type == BUS_PLATFORM) && (pd == u->bus.id.plat)) {
> +            return FALSE;
> +        }
> +    }
> +    return TRUE;
> +}
> +
> +int
> +xf86platformProbe(void)
> +{
> +    int i;
> +    Bool pci = TRUE;
> +
> +    if (!xf86scanpci()) {
> +        pci = FALSE;
> +    }
> +
> +    config_odev_probe(&xf86PlatformDeviceProbe);
> +    for (i = 0; i < xf86_num_platform_devices; i++) {
> +        char *busid = xf86_get_platform_attrib(i, ODEV_ATTRIB_BUSID);
> +
> +        if (pci && !strncmp(busid, "pci:", 4)) {
> +            platform_find_pci_info(i);
> +        }
> +        else if (!strncmp(busid, "usb:", 4)) {
> +            /* place holder */
> +        }
> +    }
> +    return 0;
> +}
> +
> +static int
> +xf86ClaimPlatformSlot(struct xf86_platform_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_PLATFORM;
> +    p->bus.id.plat = d;
> +    p->active = active;
> +    p->inUse = FALSE;
> +    if (dev)
> +        xf86AddDevToEntity(num, dev);
> +
> +    platformSlotClaimed++;
> +    return num;
> +}
> +
> +static int
> +xf86UnclaimPlatformSlot(struct xf86_platform_device *d, GDevPtr dev)
> +{
> +    int i;
> +
> +    for (i = 0; i < xf86NumEntities; i++) {
> +        const EntityPtr p = xf86Entities[i];
> +
> +        if ((p->bus.type == BUS_PLATFORM) && (p->bus.id.plat == d)) {
> +            if (dev)
> +                xf86RemoveDevFromEntity(i, dev);
> +            platformSlotClaimed--;
> +            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
> +xf86platformProbeDev(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 < xf86_num_platform_devices; j++) {
> +            /* overload PCI match loading if we can use it */
> +            if (xf86_platform_devices[j].pdev && devices) {
> +                int device_id = xf86_platform_devices[j].pdev->device_id;
> +                pPci = xf86_platform_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_platform_slot(&xf86_platform_devices[j])) {
> +                            entity = xf86ClaimPlatformSlot(&xf86_platform_devices[j],
> +                                                       drvp, 0, devList[i], devList[i]->active);
> +                            if (entity != -1) {
> +                                if (!drvp->platformProbe(drvp, entity, 0, &xf86_platform_devices[j], devices[k].match_data)) {
> +                                    xf86UnclaimPlatformSlot(&xf86_platform_devices[j], devList[i]);
> +                                    continue;
> +                                }
> +                                foundScreen = TRUE;
> +                                break;
> +                            }
> +                            else
> +                                xf86UnclaimPlatformSlot(&xf86_platform_devices[j], devList[i]);
> +                        }
> +                    }
> +                }
> +            }
> +            else if (xf86_platform_devices[j].pdev && !devices)
> +                continue;
> +            else {
> +                if (xf86_check_platform_slot(&xf86_platform_devices[j])) {
> +                    entity = xf86ClaimPlatformSlot(&xf86_platform_devices[j],
> +                                               drvp, 0, devList[i], devList[i]->active);
> +                    if (!drvp->platformProbe(drvp, entity, 0, &xf86_platform_devices[j], 0)) {
> +                        xf86UnclaimPlatformSlot(&xf86_platform_devices[j], devList[i]);
> +                        continue;
> +                    }
> +                    foundScreen = TRUE;
> +                }
> +            }
> +        }
> +    }
> +    return foundScreen;
> +}
> +
> +#endif
> diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h
> new file mode 100644
> index 0000000..f152af5
> --- /dev/null
> +++ b/hw/xfree86/common/xf86platformBus.h
> @@ -0,0 +1,51 @@
> +/*
> + * 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_PLATFORM_BUS_H
> +#define XF86_PLATFORM_BUS_H
> +
> +#include "hotplug.h"
> +
> +struct xf86_platform_device {
> +    struct OdevAttributes *attribs;
> +    /* for PCI devices */
> +    struct pci_device *pdev;
> +};
> +
> +#ifdef XSERVER_PLATFORM_BUS
> +int xf86platformProbe(void);
> +int xf86platformProbeDev(DriverPtr drvp);
> +
> +extern int xf86_num_platform_devices;
> +
> +extern char *
> +xf86_get_platform_attrib(int index, int attrib_id);
> +extern int
> +xf86_add_platform_device(struct OdevAttributes *attribs);
> +
> +extern Bool
> +xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_str);
> +
> +#endif
> +
> +#endif
> diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h
> index 6294845..ebfd7f7 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_platform_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_PLATFORM_BUS
> +    Bool (*platformProbe) (struct _DriverRec * drv, int entity_num, int flags,
> +                           struct xf86_platform_device * dev, intptr_t match_data);
> +#else
> +    void *platformProbe; /* place holder to non udev-kms support so struct is right size */
> +#endif
>  } DriverRec, *DriverPtr;
>  
>  /*
> + * platform probe 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_PLATFORM
>  #undef BUS_last
>  #endif
>  
> @@ -350,6 +363,7 @@ typedef enum {
>      BUS_NONE,
>      BUS_PCI,
>      BUS_SBUS,
> +    BUS_PLATFORM,
>      BUS_last                    /* Keep last */
>  } BusType;
>  
> @@ -362,6 +376,7 @@ typedef struct _bus {
>      union {
>          struct pci_device *pci;
>          SbusBusId sbus;
> +        struct xf86_platform_device *plat;
>      } id;
>  } BusRec, *BusPtr;
>  
> diff --git a/hw/xfree86/os-support/linux/Makefile.am b/hw/xfree86/os-support/linux/Makefile.am
> index 36748df..61175b3 100644
> --- a/hw/xfree86/os-support/linux/Makefile.am
> +++ b/hw/xfree86/os-support/linux/Makefile.am
> @@ -22,7 +22,7 @@ XORG_CFLAGS += -DHAVE_APM
>  endif
>  
>  liblinux_la_SOURCES = lnx_init.c lnx_video.c \
> -                     lnx_agp.c lnx_kmod.c lnx_bell.c \
> +                     lnx_agp.c lnx_kmod.c lnx_bell.c lnx_platform.c \
>                       $(srcdir)/../shared/bios_mmap.c \
>  		     $(srcdir)/../shared/VTsw_usl.c \
>  		     $(srcdir)/../shared/posix_tty.c \
> diff --git a/hw/xfree86/os-support/linux/lnx_platform.c b/hw/xfree86/os-support/linux/lnx_platform.c
> new file mode 100644
> index 0000000..4285a19
> --- /dev/null
> +++ b/hw/xfree86/os-support/linux/lnx_platform.c
> @@ -0,0 +1,89 @@
> +#ifdef HAVE_XORG_CONFIG_H
> +#include <xorg-config.h>
> +#endif
> +
> +#ifdef XSERVER_PLATFORM_BUS
> +
> +#include <xf86drm.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +
> +/* Linux platform device support */
> +#include "xf86_OSproc.h"
> +
> +#include "xf86.h"
> +#include "xf86platformBus.h"
> +
> +static Bool
> +get_drm_info(struct OdevAttributes *attribs, char *path)
> +{
> +    drmSetVersion sv;
> +    char *buf;
> +    int fd;
> +
> +    fd = open(path, O_RDWR, O_CLOEXEC);
> +    if (fd == -1)
> +        return FALSE;
> +
> +    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 FALSE;
> +    }
> +
> +    xf86_add_platform_device(attribs);
> +
> +    buf = drmGetBusid(fd);
> +    xf86_add_platform_device_attrib(xf86_num_platform_devices - 1,
> +                                    ODEV_ATTRIB_BUSID, buf);
> +    drmFreeBusid(buf);
> +    close(fd);
> +    return TRUE;
> +}
> +
> +void
> +xf86PlatformDeviceProbe(struct OdevAttributes *attribs)
> +{
> +    struct OdevAttribute *attrib;
> +    int i;
> +    char *path = NULL;
> +    Bool ret;
> +
> +    xorg_list_for_each_entry(attrib, &attribs->list, member) {
> +        if (attrib->attrib_id == ODEV_ATTRIB_PATH) {
> +            path = attrib->attrib_name;
> +            break;
> +        }
> +    }
> +    if (!path)
> +        goto out_free;
> +
> +    for (i = 0; i < xf86_num_platform_devices; i++) {
> +        char *dpath;
> +        dpath = xf86_get_platform_attrib(i, ODEV_ATTRIB_PATH);
> +
> +        if (!strcmp(path, dpath))
> +            break;
> +    }
> +
> +    if (i != xf86_num_platform_devices)
> +        goto out_free;
> +
> +    LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n",
> +               path);
> +
> +    ret = get_drm_info(attribs, path);
> +    if (ret == FALSE)
> +        goto out_free;
> +
> +    return;
> +
> +out_free:
> +    config_odev_free_attributes(attribs);
> +    free(attribs);
> +}
> +
> +#endif
> diff --git a/hw/xfree86/os-support/shared/platform_noop.c b/hw/xfree86/os-support/shared/platform_noop.c
> new file mode 100644
> index 0000000..2baf72a
> --- /dev/null
> +++ b/hw/xfree86/os-support/shared/platform_noop.c
> @@ -0,0 +1,17 @@
> +
> +#ifdef HAVE_XORG_CONFIG_H
> +#include <xorg-config.h>
> +#endif
> +
> +#ifdef XSERVER_PLATFORM_BUS
> +/* noop platform device support */
> +#include "xf86_OSproc.h"
> +
> +#include "xf86.h"
> +#include "xf86platformBus.h"
> +
> +void xf86PlatformDeviceProbe(struct OdevAttributes *attribs)
> +{
> +
> +}
> +#endif
> diff --git a/hw/xfree86/os-support/xf86_OSproc.h b/hw/xfree86/os-support/xf86_OSproc.h
> index e171146..2f0172e 100644
> --- a/hw/xfree86/os-support/xf86_OSproc.h
> +++ b/hw/xfree86/os-support/xf86_OSproc.h
> @@ -221,6 +221,12 @@ extern _X_EXPORT void xf86InitVidMem(void);
>  
>  #endif                          /* XF86_OS_PRIVS */
>  
> +#ifdef XSERVER_PLATFORM_BUS
> +#include "hotplug.h"
> +void
> +xf86PlatformDeviceProbe(struct OdevAttributes *attribs);
> +#endif
> +
>  _XFUNCPROTOEND
>  #endif                          /* NO_OSLIB_PROTOTYPES */
>  #endif                          /* _XF86_OSPROC_H */
> 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..6e3a193 100644
> --- a/include/hotplug.h
> +++ b/include/hotplug.h
> @@ -26,8 +26,41 @@
>  #ifndef HOTPLUG_H
>  #define HOTPLUG_H
>  
> +#include "list.h"
> +
>  extern _X_EXPORT void config_pre_init(void);
>  extern _X_EXPORT void config_init(void);
>  extern _X_EXPORT void config_fini(void);
>  
> +struct OdevAttribute
> +{
> +    struct xorg_list member;
> +    int attrib_id;
> +    char *attrib_name;
> +};
> +
> +struct OdevAttributes
> +{
> +    struct xorg_list list;
> +};

looks like the coding style now requires {  on the same line for structs.

Reviewed-by: Peter Hutterer <peter.hutterer at who-t.net> otherwise

Cheers,
  Peter

> +
> +struct OdevAttributes *
> +config_odev_allocate_attribute_list(void);
> +
> +Bool
> +config_odev_add_attribute(struct OdevAttributes *attribs, int attrib,
> +                          const char *attrib_name);
> +
> +void
> +config_odev_free_attributes(struct OdevAttributes *attribs);
> +
> +#define ODEV_ATTRIB_PATH 1
> +#define ODEV_ATTRIB_SYSPATH 2
> +#define ODEV_ATTRIB_SYSNAME 3
> +#define ODEV_ATTRIB_BUSID 4
> +
> +#ifdef CONFIG_UDEV_KMS
> +typedef void (*config_odev_probe_proc_ptr)(struct OdevAttributes *attribs);
> +void config_odev_probe(config_odev_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..a71b25d 100644
> --- a/include/xorg-config.h.in
> +++ b/include/xorg-config.h.in
> @@ -136,4 +136,7 @@
>  /* Have getresuid */
>  #undef HAVE_GETRESUID
>  
> +/* Have X server platform bus support */
> +#undef XSERVER_PLATFORM_BUS
> +
>  #endif /* _XORG_CONFIG_H_ */
> diff --git a/include/xorg-server.h.in b/include/xorg-server.h.in
> index 8086f32..c0761f7 100644
> --- a/include/xorg-server.h.in
> +++ b/include/xorg-server.h.in
> @@ -205,6 +205,9 @@
>  /* X Access Control Extension */
>  #undef XACE
>  
> +/* Have X server platform bus support */
> +#undef XSERVER_PLATFORM_BUS
> +
>  #ifdef _LP64
>  #define _XSERVER64 1
>  #endif
> -- 
> 1.7.6


More information about the xorg-devel mailing list