diff options
author | Jakob Bornecrantz | 2010-01-12 11:53:49 -0600 |
---|---|---|
committer | Jakob Bornecrantz | 2010-01-12 15:10:12 -0600 |
commit | d920fa9d0b54873d53f03a006d0fe3df11136b74 (patch) | |
tree | 43178c3fb49a55920ebbfb66ae111d5e1b735491 /libkms/linux.c | |
parent | d207a38701d664ac818829249d4d2566349bb359 (diff) | |
download | external-libdrm-d920fa9d0b54873d53f03a006d0fe3df11136b74.tar.gz external-libdrm-d920fa9d0b54873d53f03a006d0fe3df11136b74.tar.xz external-libdrm-d920fa9d0b54873d53f03a006d0fe3df11136b74.zip |
libkms: Use sysfs instead of udev to find driver
Udev code is still there just commented out.
Diffstat (limited to 'libkms/linux.c')
-rw-r--r-- | libkms/linux.c | 129 |
1 files changed, 128 insertions, 1 deletions
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 @@ | |||
30 | */ | 30 | */ |
31 | 31 | ||
32 | 32 | ||
33 | #include "config.h" | ||
33 | #include <errno.h> | 34 | #include <errno.h> |
34 | #include <stdio.h> | 35 | #include <stdio.h> |
36 | #include <stdlib.h> | ||
35 | #include <xf86drm.h> | 37 | #include <xf86drm.h> |
38 | #include <string.h> | ||
39 | #include <unistd.h> | ||
40 | |||
36 | #include <sys/stat.h> | 41 | #include <sys/stat.h> |
37 | 42 | ||
38 | #include "internal.h" | 43 | #include "internal.h" |
39 | 44 | ||
45 | #define PATH_SIZE 512 | ||
46 | |||
47 | static int | ||
48 | linux_name_from_sysfs(int fd, char **out) | ||
49 | { | ||
50 | char path[PATH_SIZE+1] = ""; /* initialize to please valgrind */ | ||
51 | char link[PATH_SIZE+1] = ""; | ||
52 | struct stat buffer; | ||
53 | unsigned maj, min; | ||
54 | char* slash_name; | ||
55 | int ret; | ||
56 | |||
57 | /* | ||
58 | * Inside the sysfs directory for the device there is a symlink | ||
59 | * to the directory representing the driver module, that path | ||
60 | * happens to hold the name of the driver. | ||
61 | * | ||
62 | * So lets get the symlink for the drm device. Then read the link | ||
63 | * and filter out the last directory which happens to be the name | ||
64 | * of the driver, which we can use to load the correct interface. | ||
65 | * | ||
66 | * Thanks to Ray Strode of Plymouth for the code. | ||
67 | */ | ||
68 | |||
69 | ret = fstat(fd, &buffer); | ||
70 | if (ret) | ||
71 | return ret; | ||
72 | |||
73 | if (!S_ISCHR(buffer.st_mode)) | ||
74 | return -EINVAL; | ||
75 | |||
76 | maj = major(buffer.st_rdev); | ||
77 | min = minor(buffer.st_rdev); | ||
78 | |||
79 | snprintf(path, PATH_SIZE, "/sys/dev/char/%d:%d/device/driver", maj, min); | ||
80 | |||
81 | if (readlink(path, link, PATH_SIZE) < 0) | ||
82 | return -EINVAL; | ||
83 | |||
84 | /* link looks something like this: ../../../bus/pci/drivers/intel */ | ||
85 | slash_name = strrchr(link, '/'); | ||
86 | if (!slash_name) | ||
87 | return -EINVAL; | ||
88 | |||
89 | /* copy name and at the same time remove the slash */ | ||
90 | *out = strdup(slash_name + 1); | ||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static int | ||
95 | linux_from_sysfs(int fd, struct kms_driver **out) | ||
96 | { | ||
97 | char *name; | ||
98 | int ret; | ||
99 | |||
100 | ret = linux_name_from_sysfs(fd, &name); | ||
101 | if (ret) | ||
102 | return ret; | ||
103 | |||
104 | if (!strcmp(name, "intel")) | ||
105 | ret = intel_create(fd, out); | ||
106 | #ifdef HAVE_VMWGFX | ||
107 | else if (!strcmp(name, "vmwgfx")) | ||
108 | ret = vmwgfx_create(fd, out); | ||
109 | #endif | ||
110 | else | ||
111 | ret = -ENOSYS; | ||
112 | |||
113 | free(name); | ||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | #if 0 | ||
40 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE | 118 | #define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE |
41 | #include <libudev.h> | 119 | #include <libudev.h> |
42 | 120 | ||
43 | int linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id) | 121 | struct create_record |
122 | { | ||
123 | unsigned vendor; | ||
124 | unsigned chip; | ||
125 | int (*func)(int fd, struct kms_driver **out); | ||
126 | }; | ||
127 | |||
128 | static struct create_record table[] = { | ||
129 | { 0x8086, 0x2a42, intel_create }, /* i965 */ | ||
130 | #ifdef HAVE_VMWGFX | ||
131 | { 0x15ad, 0x0405, vmwgfx_create }, /* VMware vGPU */ | ||
132 | #endif | ||
133 | { 0, 0, NULL }, | ||
134 | }; | ||
135 | |||
136 | static int | ||
137 | linux_get_pciid_from_fd(int fd, unsigned *vendor_id, unsigned *chip_id) | ||
44 | { | 138 | { |
45 | struct udev *udev; | 139 | struct udev *udev; |
46 | struct udev_device *device; | 140 | struct udev_device *device; |
@@ -86,3 +180,36 @@ err_free_udev: | |||
86 | udev_unref(udev); | 180 | udev_unref(udev); |
87 | return -EINVAL; | 181 | return -EINVAL; |
88 | } | 182 | } |
183 | |||
184 | static int | ||
185 | linux_from_udev(int fd, struct kms_driver **out) | ||
186 | { | ||
187 | unsigned vendor_id, chip_id; | ||
188 | int ret, i; | ||
189 | |||
190 | ret = linux_get_pciid_from_fd(fd, &vendor_id, &chip_id); | ||
191 | if (ret) | ||
192 | return ret; | ||
193 | |||
194 | for (i = 0; table[i].func; i++) | ||
195 | if (table[i].vendor == vendor_id && table[i].chip == chip_id) | ||
196 | return table[i].func(fd, out); | ||
197 | |||
198 | return -ENOSYS; | ||
199 | } | ||
200 | #else | ||
201 | static int | ||
202 | linux_from_udev(int fd, struct kms_driver **out) | ||
203 | { | ||
204 | return -ENOSYS; | ||
205 | } | ||
206 | #endif | ||
207 | |||
208 | int | ||
209 | linux_create(int fd, struct kms_driver **out) | ||
210 | { | ||
211 | if (!linux_from_udev(fd, out)) | ||
212 | return 0; | ||
213 | |||
214 | return linux_from_sysfs(fd, out); | ||
215 | } | ||