diff options
-rw-r--r-- | config/config-backends.h | 1 | ||||
-rw-r--r-- | config/config.c | 56 | ||||
-rw-r--r-- | config/udev.c | 69 | ||||
-rw-r--r-- | configure.ac | 20 | ||||
-rw-r--r-- | hw/xfree86/common/Makefile.am | 8 | ||||
-rw-r--r-- | hw/xfree86/common/xf86.h | 5 | ||||
-rw-r--r-- | hw/xfree86/common/xf86AutoConfig.c | 9 | ||||
-rw-r--r-- | hw/xfree86/common/xf86Bus.c | 18 | ||||
-rw-r--r-- | hw/xfree86/common/xf86Bus.h | 1 | ||||
-rw-r--r-- | hw/xfree86/common/xf86fbBus.c | 4 | ||||
-rw-r--r-- | hw/xfree86/common/xf86pciBus.c | 41 | ||||
-rw-r--r-- | hw/xfree86/common/xf86pciBus.h | 10 | ||||
-rw-r--r-- | hw/xfree86/common/xf86platformBus.c | 379 | ||||
-rw-r--r-- | hw/xfree86/common/xf86platformBus.h | 59 | ||||
-rw-r--r-- | hw/xfree86/common/xf86str.h | 11 | ||||
-rw-r--r-- | hw/xfree86/os-support/linux/Makefile.am | 2 | ||||
-rw-r--r-- | hw/xfree86/os-support/linux/lnx_platform.c | 130 | ||||
-rw-r--r-- | hw/xfree86/os-support/shared/platform_noop.c | 23 | ||||
-rw-r--r-- | hw/xfree86/os-support/xf86_OSproc.h | 6 | ||||
-rw-r--r-- | include/dix-config.h.in | 3 | ||||
-rw-r--r-- | include/hotplug.h | 35 | ||||
-rw-r--r-- | include/xorg-config.h.in | 3 | ||||
-rw-r--r-- | include/xorg-server.h.in | 3 |
23 files changed, 877 insertions, 19 deletions
diff --git a/config/config-backends.h b/config/config-backends.h index 62abc0a5f..6423701fc 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 24e7ba7a0..d0889a394 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,51 @@ 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; +} + +void +config_odev_free_attribute_list(struct OdevAttributes *attribs) +{ + config_odev_free_attributes(attribs); + free(attribs); +} + +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 1995184f3..efa8d3257 100644 --- a/config/udev.c +++ b/config/udev.c @@ -366,3 +366,72 @@ 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, + 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 == FALSE) + goto fail; + + ret = config_odev_add_attribute(attribs, ODEV_ATTRIB_SYSPATH, syspath); + if (ret == FALSE) + 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") != 0) + goto no_probe; + else if (strncmp(sysname, "card", 4) != 0) + goto no_probe; + + config_udev_odev_setup_attribs(path, syspath, probe_callback); + + no_probe: + udev_device_unref(udev_device); + } + udev_enumerate_unref(enumerate); + return; +} +#endif + diff --git a/configure.ac b/configure.ac index d5ddf6e10..d1358a224 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) @@ -1650,7 +1658,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]) @@ -1668,6 +1676,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 =================================================================== @@ -1856,7 +1868,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 27921777d..65d98e694 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 129660d81..88a219c7f 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/xf86AutoConfig.c b/hw/xfree86/common/xf86AutoConfig.c index d0eb0affb..271ce86b6 100644 --- a/hw/xfree86/common/xf86AutoConfig.c +++ b/hw/xfree86/common/xf86AutoConfig.c @@ -198,10 +198,13 @@ listPossibleVideoDrivers(char *matches[], int nmatches) } i = 0; +#ifdef XSERVER_PLATFORM_BUS + i = xf86PlatformMatchDriver(matches, nmatches); +#endif #ifdef sun /* Check for driver type based on /dev/fb type and if valid, use it instead of PCI bus probe results */ - if (xf86Info.consoleFd >= 0) { + if (xf86Info.consoleFd >= 0 && (i < (nmatches - 1))) { struct vis_identifier visid; const char *cp; extern char xf86SolarisFbDev[PATH_MAX]; @@ -251,6 +254,7 @@ listPossibleVideoDrivers(char *matches[], int nmatches) } #endif #ifdef __sparc__ + if (i < (nmatches - 1)) { char *sbusDriver = sparcDriverName(); @@ -259,7 +263,8 @@ listPossibleVideoDrivers(char *matches[], int nmatches) } #endif #ifdef XSERVER_LIBPCIACCESS - i = xf86PciMatchDriver(matches, nmatches); + if (i < (nmatches - 1)) + i = xf86PciMatchDriver(matches, nmatches); #endif /* Fallback to platform default hardware */ if (i < (nmatches - 1)) { diff --git a/hw/xfree86/common/xf86Bus.c b/hw/xfree86/common/xf86Bus.c index 6c86f5e26..d0cfb2b3e 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 @@ -238,6 +247,8 @@ StringToBusType(const char *busID, const char **retID) ret = BUS_PCI; if (!xf86NameCmp(p, "sbus")) ret = BUS_SBUS; + if (!xf86NameCmp(p, "platform")) + ret = BUS_PLATFORM; if (ret != BUS_NONE) if (retID) *retID = busID + strlen(p) + 1; @@ -270,6 +281,8 @@ xf86IsEntityPrimary(int entityIndex) return pEnt->bus.id.pci == primaryBus.id.pci; case BUS_SBUS: return pEnt->bus.id.sbus.fbNum == primaryBus.id.sbus.fbNum; + case BUS_PLATFORM: + return pEnt->bus.id.plat == primaryBus.id.plat; default: return FALSE; } @@ -541,6 +554,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 abf2efd1a..e83ba780a 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 1e5162332..303b9c2f5 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 d758260b6..a2c18ebf2 100644 --- a/hw/xfree86/common/xf86pciBus.c +++ b/hw/xfree86/common/xf86pciBus.c @@ -110,7 +110,7 @@ xf86PciProbe(void) xf86PciVideoInfo[num - 1] = info; pci_device_probe(info); - if (pci_device_is_boot_vga(info)) { + if (primaryBus.type == BUS_NONE && pci_device_is_boot_vga(info)) { primaryBus.type = BUS_PCI; primaryBus.id.pci = info; } @@ -352,7 +352,15 @@ xf86ComparePciBusString(const char *busID, int bus, int device, int func) Bool xf86IsPrimaryPci(struct pci_device *pPci) { - return ((primaryBus.type == BUS_PCI) && (pPci == primaryBus.id.pci)); + if (primaryBus.type == BUS_PCI) + return pPci == primaryBus.id.pci; +#ifdef XSERVER_PLATFORM_BUS + if (primaryBus.type == BUS_PLATFORM) + if (primaryBus.id.plat->pdev) + if (MATCH_PCI_DEVICES(primaryBus.id.plat->pdev, pPci)) + return TRUE; +#endif + return FALSE; } /* @@ -367,7 +375,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 +416,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; } @@ -1065,8 +1088,8 @@ xf86ConfigActivePciEntity(ScrnInfoPtr pScrn, int entityIndex, return TRUE; } -static int -videoPtrToDriverList(struct pci_device *dev, +int +xf86VideoPtrToDriverList(struct pci_device *dev, char *returnList[], int returnListMax) { int i; @@ -1249,8 +1272,8 @@ xchomp(char *line) * don't export their PCI ID's properly. If distros don't end up using this * feature it can and should be removed because the symbol-based resolution * scheme should be the primary one */ -static void -matchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_chip) +void +xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_chip) { DIR *idsdir; FILE *fp; @@ -1379,7 +1402,7 @@ xf86PciMatchDriver(char *matches[], int nmatches) pci_iterator_destroy(iter); #ifdef __linux__ if (info) - matchDriverFromFiles(matches, info->vendor_id, info->device_id); + xf86MatchDriverFromFiles(matches, info->vendor_id, info->device_id); #endif for (i = 0; (i < nmatches) && (matches[i]); i++) { @@ -1387,7 +1410,7 @@ xf86PciMatchDriver(char *matches[], int nmatches) } if ((info != NULL) && (i < nmatches)) { - i += videoPtrToDriverList(info, &(matches[i]), nmatches - i); + i += xf86VideoPtrToDriverList(info, &(matches[i]), nmatches - i); } return i; diff --git a/hw/xfree86/common/xf86pciBus.h b/hw/xfree86/common/xf86pciBus.h index 56ec6e9e7..4972c3688 100644 --- a/hw/xfree86/common/xf86pciBus.h +++ b/hw/xfree86/common/xf86pciBus.h @@ -42,4 +42,14 @@ 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)) + +void +xf86MatchDriverFromFiles(char **matches, uint16_t match_vendor, uint16_t match_chip); +int +xf86VideoPtrToDriverList(struct pci_device *dev, + char *returnList[], int returnListMax); #endif /* _XF86_PCI_BUS_H */ diff --git a/hw/xfree86/common/xf86platformBus.c b/hw/xfree86/common/xf86platformBus.c new file mode 100644 index 000000000..50b7636ea --- /dev/null +++ b/hw/xfree86/common/xf86platformBus.c @@ -0,0 +1,379 @@ +/* + * 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@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_platform_devices[xf86_num_platform_devices].pdev = NULL; + + xf86_num_platform_devices++; + return 0; +} + +int +xf86_remove_platform_device(int dev_index) +{ + int j; + + config_odev_free_attribute_list(xf86_platform_devices[dev_index].attribs); + + for (j = dev_index; j < xf86_num_platform_devices - 1; j++) + memcpy(&xf86_platform_devices[j], &xf86_platform_devices[j + 1], sizeof(struct xf86_platform_device)); + 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]; + 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; +} + +char * +xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_id) +{ + 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; +} + + +/* + * xf86IsPrimaryPlatform() -- return TRUE if primary device + * is a platform device and it matches this one. + */ + +static Bool +xf86IsPrimaryPlatform(struct xf86_platform_device *plat) +{ + return ((primaryBus.type == BUS_PLATFORM) && (plat == primaryBus.id.plat)); +} + +static void +platform_find_pci_info(struct xf86_platform_device *pd, char *busid) +{ + struct pci_slot_match devmatch; + struct pci_device *info; + struct pci_device_iterator *iter; + int ret; + + 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) { + pd->pdev = info; + pci_device_probe(info); + if (pci_device_is_boot_vga(info)) { + primaryBus.type = BUS_PLATFORM; + primaryBus.id.plat = pd; + } + } + 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 (pd->pdev && u->bus.type == BUS_PCI) + return !MATCH_PCI_DEVICES(pd->pdev, u->bus.id.pci); + if ((u->bus.type == BUS_PLATFORM) && (pd == u->bus.id.plat)) { + return FALSE; + } + } + return TRUE; +} + +/** + * @return The numbers of found devices that match with the current system + * drivers. + */ +int +xf86PlatformMatchDriver(char *matches[], int nmatches) +{ + int i, j = 0; + struct pci_device *info = NULL; + int pass = 0; + + for (pass = 0; pass < 2; pass++) { + for (i = 0; i < xf86_num_platform_devices; i++) { + + if (xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 1)) + continue; + else if (!xf86IsPrimaryPlatform(&xf86_platform_devices[i]) && (pass == 0)) + continue; + + info = xf86_platform_devices[i].pdev; +#ifdef __linux__ + if (info) + xf86MatchDriverFromFiles(matches, info->vendor_id, info->device_id); +#endif + + for (j = 0; (j < nmatches) && (matches[j]); j++) { + /* find end of matches list */ + } + + if ((info != NULL) && (j < nmatches)) { + j += xf86VideoPtrToDriverList(info, &(matches[j]), nmatches - j); + } + } + } + return j; +} + +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) == 0)) { + platform_find_pci_info(&xf86_platform_devices[i], busid); + } + } + return 0; +} + +static int +xf86ClaimPlatformSlot(struct xf86_platform_device * d, DriverPtr drvp, + int chipset, GDevPtr dev, Bool active) +{ + EntityPtr p = NULL; + int num; + + if (xf86_check_platform_slot(d)) { + 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; + } + else + return -1; +} + +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)) + +static Bool doPlatformProbe(struct xf86_platform_device *dev, DriverPtr drvp, + GDevPtr gdev, int flags, intptr_t match_data) +{ + Bool foundScreen = FALSE; + int entity; + + if (gdev->screen == 0 && !xf86_check_platform_slot(dev)) + return FALSE; + + entity = xf86ClaimPlatformSlot(dev, drvp, 0, + gdev, gdev->active); + + if ((entity == -1) && (gdev->screen > 0)) { + unsigned nent; + + for (nent = 0; nent < xf86NumEntities; nent++) { + EntityPtr pEnt = xf86Entities[nent]; + + if (pEnt->bus.type != BUS_PLATFORM) + continue; + if (pEnt->bus.id.plat == dev) { + entity = nent; + xf86AddDevToEntity(nent, gdev); + break; + } + } + } + if (entity != -1) { + if (drvp->platformProbe(drvp, entity, flags, dev, match_data)) + foundScreen = TRUE; + else + xf86UnclaimPlatformSlot(dev, gdev); + } + return foundScreen; +} + +static Bool +probeSingleDevice(struct xf86_platform_device *dev, DriverPtr drvp, GDevPtr gdev, int flags) +{ + int k; + Bool foundScreen = FALSE; + struct pci_device *pPci; + const struct pci_id_match *const devices = drvp->supported_devices; + + if (dev->pdev && devices) { + int device_id = dev->pdev->device_id; + pPci = dev->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)) { + foundScreen = doPlatformProbe(dev, drvp, gdev, flags, devices[k].match_data); + if (foundScreen) + break; + } + } + } + else if (dev->pdev && !devices) + return FALSE; + else + foundScreen = doPlatformProbe(dev, drvp, gdev, flags, 0); + return foundScreen; +} + +int +xf86platformProbeDev(DriverPtr drvp) +{ + Bool foundScreen = FALSE; + GDevPtr *devList; + const unsigned numDevs = xf86MatchDevice(drvp->driverName, &devList); + int i, j; + + /* find the main device or any device specificed in xorg.conf */ + for (i = 0; i < numDevs; i++) { + for (j = 0; j < xf86_num_platform_devices; j++) { + if (devList[i]->busID && *devList[i]->busID) { + if (xf86PlatformDeviceCheckBusID(&xf86_platform_devices[j], devList[i]->busID)) + break; + } + else { + if (xf86_platform_devices[j].pdev) { + if (xf86IsPrimaryPlatform(&xf86_platform_devices[j])) + break; + } + } + } + + if (j == xf86_num_platform_devices) + continue; + + foundScreen = probeSingleDevice(&xf86_platform_devices[j], drvp, devList[i], 0); + if (!foundScreen) + continue; + } + + return foundScreen; +} + +#endif diff --git a/hw/xfree86/common/xf86platformBus.h b/hw/xfree86/common/xf86platformBus.h new file mode 100644 index 000000000..15a3022ac --- /dev/null +++ b/hw/xfree86/common/xf86platformBus.h @@ -0,0 +1,59 @@ +/* + * 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@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 int +xf86_remove_platform_device(int dev_index); +extern Bool +xf86_add_platform_device_attrib(int index, int attrib_id, char *attrib_str); + +extern _X_EXPORT char * +xf86_get_platform_device_attrib(struct xf86_platform_device *device, int attrib_id); +extern _X_EXPORT Bool +xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *busid); + +extern _X_EXPORT int +xf86PlatformMatchDriver(char *matches[], int nmatches); +#endif + +#endif diff --git a/hw/xfree86/common/xf86str.h b/hw/xfree86/common/xf86str.h index a1404c3aa..e12dcc4ce 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,16 @@ 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); + Bool (*platformProbe) (struct _DriverRec * drv, int entity_num, int flags, + struct xf86_platform_device * dev, intptr_t match_data); } 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 +351,7 @@ typedef struct _DriverRec { #undef BUS_NONE #undef BUS_PCI #undef BUS_SBUS +#undef BUS_PLATFORM #undef BUS_last #endif @@ -350,6 +359,7 @@ typedef enum { BUS_NONE, BUS_PCI, BUS_SBUS, + BUS_PLATFORM, BUS_last /* Keep last */ } BusType; @@ -362,6 +372,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 36748df2c..61175b386 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 000000000..9c63ee543 --- /dev/null +++ b/hw/xfree86/os-support/linux/lnx_platform.c @@ -0,0 +1,130 @@ +#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" +#include "xf86Bus.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; +} + +Bool +xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *busid) +{ + struct OdevAttribute *attrib; + const char *syspath = NULL; + BusType bustype; + const char *id; + xorg_list_for_each_entry(attrib, &device->attribs->list, member) { + if (attrib->attrib_id == ODEV_ATTRIB_SYSPATH) { + syspath = attrib->attrib_name; + break; + } + } + + if (!syspath) + return FALSE; + + bustype = StringToBusType(busid, &id); + if (bustype == BUS_PCI) { + struct pci_device *pPci = device->pdev; + if (xf86ComparePciBusString(busid, + ((pPci->domain << 8) + | pPci->bus), + pPci->dev, pPci->func)) { + return TRUE; + } + } + else if (bustype == BUS_PLATFORM) { + /* match on the minimum string */ + int len = strlen(id); + + if (strlen(syspath) < strlen(id)) + len = strlen(syspath); + + if (strncmp(id, syspath, len)) + return FALSE; + return TRUE; + } + return FALSE; +} + +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_attribute_list(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 000000000..199ae5e8e --- /dev/null +++ b/hw/xfree86/os-support/shared/platform_noop.c @@ -0,0 +1,23 @@ + +#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" + +Bool +xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *busid) +{ + return FALSE; +} + +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 e171146dd..2f0172e15 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 3c9bbafeb..77681a953 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 f3eeea21d..50007624a 100644 --- a/include/hotplug.h +++ b/include/hotplug.h @@ -26,8 +26,43 @@ #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; +}; + +struct OdevAttributes * +config_odev_allocate_attribute_list(void); + +void +config_odev_free_attribute_list(struct OdevAttributes *attribs); + +Bool +config_odev_add_attribute(struct OdevAttributes *attribs, int attrib, + const char *attrib_name); + +void +config_odev_free_attributes(struct OdevAttributes *attribs); + +/* path to kernel device node - Linux e.g. /dev/dri/card0 */ +#define ODEV_ATTRIB_PATH 1 +/* system device path - Linux e.g. /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/drm/card1 */ +#define ODEV_ATTRIB_SYSPATH 2 +/* DRI-style bus id */ +#define ODEV_ATTRIB_BUSID 3 + +typedef void (*config_odev_probe_proc_ptr)(struct OdevAttributes *attribs); +void config_odev_probe(config_odev_probe_proc_ptr probe_callback); + #endif /* HOTPLUG_H */ diff --git a/include/xorg-config.h.in b/include/xorg-config.h.in index 2cc416ae7..a71b25d72 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 8086f32ae..c0761f78a 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 |