diff options
-rw-r--r-- | libkms/Makefile.am | 7 | ||||
-rw-r--r-- | libkms/api.c | 28 | ||||
-rw-r--r-- | libkms/internal.h | 2 | ||||
-rw-r--r-- | libkms/linux.c | 129 |
4 files changed, 135 insertions, 31 deletions
diff --git a/libkms/Makefile.am b/libkms/Makefile.am index 23f78e08..293045c2 100644 --- a/libkms/Makefile.am +++ b/libkms/Makefile.am @@ -5,8 +5,11 @@ AM_CFLAGS = \ libkms_la_LTLIBRARIES = libkms.la libkms_ladir = $(libdir) libkms_la_LDFLAGS = -version-number 1:0:0 -no-undefined -libkms_la_LIBADD = \ - $(LIBUDEV_LIBS) +libkms_la_LIBADD = + +#if HAVE_LIBUDEV +#libkms_la_LIBADD += $(LIBUDEV_LIBS) +#endif libkms_la_SOURCES = \ linux.c \ diff --git a/libkms/api.c b/libkms/api.c index 12dcd9a1..7696918a 100644 --- a/libkms/api.c +++ b/libkms/api.c @@ -32,35 +32,9 @@ #include <string.h> #include "internal.h" -struct create_record -{ - unsigned vendor; - unsigned chip; - int (*func)(int fd, struct kms_driver **out); -}; - -static struct create_record table[] = { - { 0x8086, 0x2a42, intel_create }, /* i965 */ -#ifdef HAVE_VMWGFX - { 0x15ad, 0x0405, vmwgfx_create }, /* VMware vGPU */ -#endif - { 0, 0, NULL }, -}; - int kms_create(int fd, struct kms_driver **out) { - unsigned vendor_id, chip_id; - int ret, i; - - ret = linux_get_pciid_from_fd(fd, &vendor_id, &chip_id); - if (ret) - return ret; - - for (i = 0; table[i].func; i++) - if (table[i].vendor == vendor_id && table[i].chip == chip_id) - return table[i].func(fd, out); - - return -ENOSYS; + return linux_create(fd, out); } int kms_get_prop(struct kms_driver *kms, unsigned key, unsigned *out) diff --git a/libkms/internal.h b/libkms/internal.h index a441266b..9d1c5f7c 100644 --- a/libkms/internal.h +++ b/libkms/internal.h @@ -62,7 +62,7 @@ struct kms_bo unsigned handle; }; -int linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id); +int linux_create(int fd, struct kms_driver **out); int vmwgfx_create(int fd, struct kms_driver **out); diff --git a/libkms/linux.c b/libkms/linux.c index 2b08b854..94e1b526 100644 --- a/libkms/linux.c +++ b/libkms/linux.c @@ -30,17 +30,111 @@ */ +#include "config.h" #include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <xf86drm.h> +#include <string.h> +#include <unistd.h> + #include <sys/stat.h> #include "internal.h" +#define PATH_SIZE 512 + +static int +linux_name_from_sysfs(int fd, char **out) +{ + char path[PATH_SIZE+1] = ""; /* initialize to please valgrind */ + char link[PATH_SIZE+1] = ""; + struct stat buffer; + unsigned maj, min; + char* slash_name; + int ret; + + /* + * Inside the sysfs directory for the device there is a symlink + * to the directory representing the driver module, that path + * happens to hold the name of the driver. + * + * So lets get the symlink for the drm device. Then read the link + * and filter out the last directory which happens to be the name + * of the driver, which we can use to load the correct interface. + * + * Thanks to Ray Strode of Plymouth for the code. + */ + + ret = fstat(fd, &buffer); + if (ret) + return ret; + + if (!S_ISCHR(buffer.st_mode)) + return -EINVAL; + + maj = major(buffer.st_rdev); + min = minor(buffer.st_rdev); + + snprintf(path, PATH_SIZE, "/sys/dev/char/%d:%d/device/driver", maj, min); + + if (readlink(path, link, PATH_SIZE) < 0) + return -EINVAL; + + /* link looks something like this: ../../../bus/pci/drivers/intel */ + slash_name = strrchr(link, '/'); + if (!slash_name) + return -EINVAL; + + /* copy name and at the same time remove the slash */ + *out = strdup(slash_name + 1); + return 0; +} + +static int +linux_from_sysfs(int fd, struct kms_driver **out) +{ + char *name; + int ret; + + ret = linux_name_from_sysfs(fd, &name); + if (ret) + return ret; + + if (!strcmp(name, "intel")) + ret = intel_create(fd, out); +#ifdef HAVE_VMWGFX + else if (!strcmp(name, "vmwgfx")) + ret = vmwgfx_create(fd, out); +#endif + else + ret = -ENOSYS; + + free(name); + return ret; +} + +#if 0 #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE #include <libudev.h> -int linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id) +struct create_record +{ + unsigned vendor; + unsigned chip; + int (*func)(int fd, struct kms_driver **out); +}; + +static struct create_record table[] = { + { 0x8086, 0x2a42, intel_create }, /* i965 */ +#ifdef HAVE_VMWGFX + { 0x15ad, 0x0405, vmwgfx_create }, /* VMware vGPU */ +#endif + { 0, 0, NULL }, +}; + +static int +linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id) { struct udev *udev; struct udev_device *device; @@ -86,3 +180,36 @@ err_free_udev: udev_unref(udev); return -EINVAL; } + +static int +linux_from_udev(int fd, struct kms_driver **out) +{ + unsigned vendor_id, chip_id; + int ret, i; + + ret = linux_get_pciid_from_fd(fd, &vendor_id, &chip_id); + if (ret) + return ret; + + for (i = 0; table[i].func; i++) + if (table[i].vendor == vendor_id && table[i].chip == chip_id) + return table[i].func(fd, out); + + return -ENOSYS; +} +#else +static int +linux_from_udev(int fd, struct kms_driver **out) +{ + return -ENOSYS; +} +#endif + +int +linux_create(int fd, struct kms_driver **out) +{ + if (!linux_from_udev(fd, out)) + return 0; + + return linux_from_sysfs(fd, out); +} |