1 #ifdef HAVE_XORG_CONFIG_H
2 #include <xorg-config.h>
3 #endif
4
5 #ifdef XSERVER_PLATFORM_BUS
6
7 #include <xf86drm.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <string.h>
12
13 /* Linux platform device support */
14 #include "xf86_OSproc.h"
15
16 #include "xf86.h"
17 #include "xf86platformBus.h"
18 #include "xf86Bus.h"
19
20 #include "hotplug.h"
21 #include "systemd-logind.h"
22
23 static Bool
get_drm_info(struct OdevAttributes * attribs,char * path,int delayed_index)24 get_drm_info(struct OdevAttributes *attribs, char *path, int delayed_index)
25 {
26 drmSetVersion sv;
27 drmVersionPtr v;
28 char *buf;
29 int fd;
30 int err = 0;
31 Bool paused, server_fd = FALSE;
32
33 fd = systemd_logind_take_fd(attribs->major, attribs->minor, path, &paused);
34 if (fd != -1) {
35 if (paused) {
36 LogMessage(X_ERROR,
37 "Error systemd-logind returned paused fd for drm node\n");
38 systemd_logind_release_fd(attribs->major, attribs->minor, -1);
39 return FALSE;
40 }
41 attribs->fd = fd;
42 server_fd = TRUE;
43 }
44
45 if (fd == -1)
46 fd = open(path, O_RDWR | O_CLOEXEC, 0);
47
48 if (fd == -1)
49 return FALSE;
50
51 sv.drm_di_major = 1;
52 sv.drm_di_minor = 4;
53 sv.drm_dd_major = -1; /* Don't care */
54 sv.drm_dd_minor = -1; /* Don't care */
55
56 err = drmSetInterfaceVersion(fd, &sv);
57 if (err) {
58 xf86Msg(X_ERROR, "%s: failed to set DRM interface version 1.4: %s\n",
59 path, strerror(-err));
60 goto out;
61 }
62
63 /* for a delayed probe we've already added the device */
64 if (delayed_index == -1) {
65 xf86_add_platform_device(attribs, FALSE);
66 delayed_index = xf86_num_platform_devices - 1;
67 }
68
69 if (server_fd)
70 xf86_platform_devices[delayed_index].flags |= XF86_PDEV_SERVER_FD;
71
72 buf = drmGetBusid(fd);
73 xf86_platform_odev_attributes(delayed_index)->busid = XNFstrdup(buf);
74 drmFreeBusid(buf);
75
76 v = drmGetVersion(fd);
77 if (!v) {
78 xf86Msg(X_ERROR, "%s: failed to query DRM version\n", path);
79 goto out;
80 }
81
82 xf86_platform_odev_attributes(delayed_index)->driver = XNFstrdup(v->name);
83 drmFreeVersion(v);
84
85 out:
86 if (!server_fd)
87 close(fd);
88 return (err == 0);
89 }
90
91 Bool
xf86PlatformDeviceCheckBusID(struct xf86_platform_device * device,const char * busid)92 xf86PlatformDeviceCheckBusID(struct xf86_platform_device *device, const char *busid)
93 {
94 const char *syspath = device->attribs->syspath;
95 BusType bustype;
96 const char *id;
97
98 if (!syspath)
99 return FALSE;
100
101 bustype = StringToBusType(busid, &id);
102 if (bustype == BUS_PCI) {
103 struct pci_device *pPci = device->pdev;
104 if (xf86ComparePciBusString(busid,
105 ((pPci->domain << 8)
106 | pPci->bus),
107 pPci->dev, pPci->func)) {
108 return TRUE;
109 }
110 }
111 else if (bustype == BUS_PLATFORM) {
112 /* match on the minimum string */
113 int len = strlen(id);
114
115 if (strlen(syspath) < strlen(id))
116 len = strlen(syspath);
117
118 if (strncmp(id, syspath, len))
119 return FALSE;
120 return TRUE;
121 }
122 return FALSE;
123 }
124
125 void
xf86PlatformReprobeDevice(int index,struct OdevAttributes * attribs)126 xf86PlatformReprobeDevice(int index, struct OdevAttributes *attribs)
127 {
128 Bool ret;
129 char *dpath = attribs->path;
130
131 ret = get_drm_info(attribs, dpath, index);
132 if (ret == FALSE) {
133 xf86_remove_platform_device(index);
134 return;
135 }
136 ret = xf86platformAddDevice(index);
137 if (ret == -1)
138 xf86_remove_platform_device(index);
139 }
140
141 void
xf86PlatformDeviceProbe(struct OdevAttributes * attribs)142 xf86PlatformDeviceProbe(struct OdevAttributes *attribs)
143 {
144 int i;
145 char *path = attribs->path;
146 Bool ret;
147
148 if (!path)
149 goto out_free;
150
151 for (i = 0; i < xf86_num_platform_devices; i++) {
152 char *dpath = xf86_platform_odev_attributes(i)->path;
153
154 if (dpath && !strcmp(path, dpath))
155 break;
156 }
157
158 if (i != xf86_num_platform_devices)
159 goto out_free;
160
161 LogMessage(X_INFO, "xfree86: Adding drm device (%s)\n", path);
162
163 if (!xf86VTOwner()) {
164 /* if we don't currently own the VT then don't probe the device,
165 just mark it as unowned for later use */
166 xf86_add_platform_device(attribs, TRUE);
167 return;
168 }
169
170 ret = get_drm_info(attribs, path, -1);
171 if (ret == FALSE)
172 goto out_free;
173
174 return;
175
176 out_free:
177 config_odev_free_attributes(attribs);
178 }
179
NewGPUDeviceRequest(struct OdevAttributes * attribs)180 void NewGPUDeviceRequest(struct OdevAttributes *attribs)
181 {
182 int old_num = xf86_num_platform_devices;
183 int ret;
184 xf86PlatformDeviceProbe(attribs);
185
186 if (old_num == xf86_num_platform_devices)
187 return;
188
189 if (xf86_get_platform_device_unowned(xf86_num_platform_devices - 1) == TRUE)
190 return;
191
192 ret = xf86platformAddDevice(xf86_num_platform_devices-1);
193 if (ret == -1)
194 xf86_remove_platform_device(xf86_num_platform_devices-1);
195
196 ErrorF("xf86: found device %d\n", xf86_num_platform_devices);
197 return;
198 }
199
DeleteGPUDeviceRequest(struct OdevAttributes * attribs)200 void DeleteGPUDeviceRequest(struct OdevAttributes *attribs)
201 {
202 int index;
203 char *syspath = attribs->syspath;
204
205 if (!syspath)
206 goto out;
207
208 for (index = 0; index < xf86_num_platform_devices; index++) {
209 char *dspath = xf86_platform_odev_attributes(index)->syspath;
210 if (dspath && !strcmp(syspath, dspath))
211 break;
212 }
213
214 if (index == xf86_num_platform_devices)
215 goto out;
216
217 ErrorF("xf86: remove device %d %s\n", index, syspath);
218
219 if (xf86_get_platform_device_unowned(index) == TRUE)
220 xf86_remove_platform_device(index);
221 else
222 xf86platformRemoveDevice(index);
223 out:
224 config_odev_free_attributes(attribs);
225 }
226
227 #endif
228