[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