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