1 /*
2 * Copyright © 2009 Julien Cristau
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Author: Julien Cristau <jcristau@debian.org>
24 */
25
26 #ifdef HAVE_DIX_CONFIG_H
27 #include <dix-config.h>
28 #endif
29
30 #include <libudev.h>
31 #include <ctype.h>
32 #include <unistd.h>
33
34 #include "input.h"
35 #include "inputstr.h"
36 #include "hotplug.h"
37 #include "config-backends.h"
38 #include "os.h"
39 #include "globals.h"
40 #include "systemd-logind.h"
41
42 #define UDEV_XKB_PROP_KEY "xkb"
43
44 #define LOG_PROPERTY(path, prop, val) \
45 LogMessageVerb(X_INFO, 10, \
46 "config/udev: getting property %s on %s " \
47 "returned \"%s\"\n", \
48 (prop), (path), (val) ? (val) : "(null)")
49 #define LOG_SYSATTR(path, attr, val) \
50 LogMessageVerb(X_INFO, 10, \
51 "config/udev: getting attribute %s on %s " \
52 "returned \"%s\"\n", \
53 (attr), (path), (val) ? (val) : "(null)")
54
55 static struct udev_monitor *udev_monitor;
56
57 #ifdef CONFIG_UDEV_KMS
58 static void
59 config_udev_odev_setup_attribs(const char *path, const char *syspath,
60 int major, int minor,
61 config_odev_probe_proc_ptr probe_callback);
62 #endif
63
64 static char itoa_buf[16];
65
itoa(int i)66 static const char *itoa(int i)
67 {
68 snprintf(itoa_buf, sizeof(itoa_buf), "%d", i);
69 return itoa_buf;
70 }
71
72 static Bool
check_seat(struct udev_device * udev_device)73 check_seat(struct udev_device *udev_device)
74 {
75 const char *dev_seat;
76
77 dev_seat = udev_device_get_property_value(udev_device, "ID_SEAT");
78 if (!dev_seat)
79 dev_seat = "seat0";
80
81 if (SeatId && strcmp(dev_seat, SeatId))
82 return FALSE;
83
84 if (!SeatId && strcmp(dev_seat, "seat0"))
85 return FALSE;
86
87 return TRUE;
88 }
89
90 static void
device_added(struct udev_device * udev_device)91 device_added(struct udev_device *udev_device)
92 {
93 const char *path, *name = NULL;
94 char *config_info = NULL;
95 const char *syspath;
96 const char *tags_prop;
97 const char *key, *value, *tmp;
98 InputOption *input_options;
99 InputAttributes attrs = { };
100 DeviceIntPtr dev = NULL;
101 struct udev_list_entry *set, *entry;
102 struct udev_device *parent;
103 int rc;
104 dev_t devnum;
105
106 path = udev_device_get_devnode(udev_device);
107
108 syspath = udev_device_get_syspath(udev_device);
109
110 if (!path || !syspath)
111 return;
112
113 if (!check_seat(udev_device))
114 return;
115
116 devnum = udev_device_get_devnum(udev_device);
117
118 #ifdef CONFIG_UDEV_KMS
119 if (!strcmp(udev_device_get_subsystem(udev_device), "drm")) {
120 const char *sysname = udev_device_get_sysname(udev_device);
121
122 if (strncmp(sysname, "card", 4) != 0)
123 return;
124
125 /* Check for devices already added through xf86platformProbe() */
126 if (xf86_find_platform_device_by_devnum(major(devnum), minor(devnum)))
127 return;
128
129 LogMessage(X_INFO, "config/udev: Adding drm device (%s)\n", path);
130
131 config_udev_odev_setup_attribs(path, syspath, major(devnum),
132 minor(devnum), NewGPUDeviceRequest);
133 return;
134 }
135 #endif
136
137 value = udev_device_get_property_value(udev_device, "ID_INPUT");
138 if (!value || !strcmp(value, "0")) {
139 LogMessageVerb(X_INFO, 10,
140 "config/udev: ignoring device %s without "
141 "property ID_INPUT set\n", path);
142 return;
143 }
144
145 input_options = input_option_new(NULL, "_source", "server/udev");
146 if (!input_options)
147 return;
148
149 parent = udev_device_get_parent(udev_device);
150 if (parent) {
151 const char *ppath = udev_device_get_devnode(parent);
152 const char *product = udev_device_get_property_value(parent, "PRODUCT");
153 const char *pnp_id = udev_device_get_sysattr_value(parent, "id");
154 unsigned int usb_vendor, usb_model;
155
156 name = udev_device_get_sysattr_value(parent, "name");
157 LOG_SYSATTR(ppath, "name", name);
158 if (!name) {
159 name = udev_device_get_property_value(parent, "NAME");
160 LOG_PROPERTY(ppath, "NAME", name);
161 }
162
163 /* construct USB ID in lowercase hex - "0000:ffff" */
164 if (product &&
165 sscanf(product, "%*x/%4x/%4x/%*x", &usb_vendor, &usb_model) == 2) {
166 char *usb_id;
167 if (asprintf(&usb_id, "%04x:%04x", usb_vendor, usb_model)
168 == -1)
169 usb_id = NULL;
170 else
171 LOG_PROPERTY(ppath, "PRODUCT", product);
172 attrs.usb_id = usb_id;
173 }
174
175 while (!pnp_id && (parent = udev_device_get_parent(parent))) {
176 pnp_id = udev_device_get_sysattr_value(parent, "id");
177 if (!pnp_id)
178 continue;
179
180 attrs.pnp_id = strdup(pnp_id);
181 ppath = udev_device_get_devnode(parent);
182 LOG_SYSATTR(ppath, "id", pnp_id);
183 }
184
185 }
186 if (!name)
187 name = "(unnamed)";
188 else
189 attrs.product = strdup(name);
190 input_options = input_option_new(input_options, "name", name);
191 input_options = input_option_new(input_options, "path", path);
192 input_options = input_option_new(input_options, "device", path);
193 input_options = input_option_new(input_options, "major", itoa(major(devnum)));
194 input_options = input_option_new(input_options, "minor", itoa(minor(devnum)));
195 if (path)
196 attrs.device = strdup(path);
197
198 tags_prop = udev_device_get_property_value(udev_device, "ID_INPUT.tags");
199 LOG_PROPERTY(path, "ID_INPUT.tags", tags_prop);
200 attrs.tags = xstrtokenize(tags_prop, ",");
201
202 if (asprintf(&config_info, "udev:%s", syspath) == -1) {
203 config_info = NULL;
204 goto unwind;
205 }
206
207 if (device_is_duplicate(config_info)) {
208 LogMessage(X_WARNING, "config/udev: device %s already added. "
209 "Ignoring.\n", name);
210 goto unwind;
211 }
212
213 set = udev_device_get_properties_list_entry(udev_device);
214 udev_list_entry_foreach(entry, set) {
215 key = udev_list_entry_get_name(entry);
216 if (!key)
217 continue;
218 value = udev_list_entry_get_value(entry);
219 if (!strncasecmp(key, UDEV_XKB_PROP_KEY, sizeof(UDEV_XKB_PROP_KEY) - 1)) {
220 LOG_PROPERTY(path, key, value);
221 tmp = key + sizeof(UDEV_XKB_PROP_KEY) - 1;
222 if (!strcasecmp(tmp, "rules"))
223 input_options =
224 input_option_new(input_options, "xkb_rules", value);
225 else if (!strcasecmp(tmp, "layout"))
226 input_options =
227 input_option_new(input_options, "xkb_layout", value);
228 else if (!strcasecmp(tmp, "variant"))
229 input_options =
230 input_option_new(input_options, "xkb_variant", value);
231 else if (!strcasecmp(tmp, "model"))
232 input_options =
233 input_option_new(input_options, "xkb_model", value);
234 else if (!strcasecmp(tmp, "options"))
235 input_options =
236 input_option_new(input_options, "xkb_options", value);
237 }
238 else if (!strcmp(key, "ID_VENDOR")) {
239 LOG_PROPERTY(path, key, value);
240 attrs.vendor = strdup(value);
241 } else if (!strncmp(key, "ID_INPUT_", 9)) {
242 const struct pfmap {
243 const char *property;
244 unsigned int flag;
245 } map[] = {
246 { "ID_INPUT_KEY", ATTR_KEY },
247 { "ID_INPUT_KEYBOARD", ATTR_KEYBOARD },
248 { "ID_INPUT_MOUSE", ATTR_POINTER },
249 { "ID_INPUT_JOYSTICK", ATTR_JOYSTICK },
250 { "ID_INPUT_TABLET", ATTR_TABLET },
251 { "ID_INPUT_TABLET_PAD", ATTR_TABLET_PAD },
252 { "ID_INPUT_TOUCHPAD", ATTR_TOUCHPAD },
253 { "ID_INPUT_TOUCHSCREEN", ATTR_TOUCHSCREEN },
254 { NULL, 0 },
255 };
256
257 /* Anything but the literal string "0" is considered a
258 * boolean true. The empty string isn't a thing with udev
259 * properties anyway */
260 if (value && strcmp(value, "0")) {
261 const struct pfmap *m = map;
262
263 while (m->property != NULL) {
264 if (!strcmp(m->property, key)) {
265 LOG_PROPERTY(path, key, value);
266 attrs.flags |= m->flag;
267 }
268 m++;
269 }
270 }
271 }
272 }
273
274 input_options = input_option_new(input_options, "config_info", config_info);
275
276 /* Default setting needed for non-seat0 seats */
277 if (ServerIsNotSeat0())
278 input_options = input_option_new(input_options, "GrabDevice", "on");
279
280 LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
281 name, path);
282 rc = NewInputDeviceRequest(input_options, &attrs, &dev);
283 if (rc != Success)
284 goto unwind;
285
286 unwind:
287 free(config_info);
288 input_option_free_list(&input_options);
289
290 free(attrs.usb_id);
291 free(attrs.pnp_id);
292 free(attrs.product);
293 free(attrs.device);
294 free(attrs.vendor);
295 if (attrs.tags) {
296 char **tag = attrs.tags;
297
298 while (*tag) {
299 free(*tag);
300 tag++;
301 }
302 free(attrs.tags);
303 }
304
305 return;
306 }
307
308 static void
device_removed(struct udev_device * device)309 device_removed(struct udev_device *device)
310 {
311 char *value;
312 const char *syspath = udev_device_get_syspath(device);
313
314 #ifdef CONFIG_UDEV_KMS
315 if (!strcmp(udev_device_get_subsystem(device), "drm")) {
316 const char *sysname = udev_device_get_sysname(device);
317 const char *path = udev_device_get_devnode(device);
318 dev_t devnum = udev_device_get_devnum(device);
319
320 if ((strncmp(sysname,"card", 4) != 0) || (path == NULL))
321 return;
322
323 LogMessage(X_INFO, "config/udev: removing GPU device %s %s\n",
324 syspath, path);
325 config_udev_odev_setup_attribs(path, syspath, major(devnum),
326 minor(devnum), DeleteGPUDeviceRequest);
327 /* Retry vtenter after a drm node removal */
328 systemd_logind_vtenter();
329 return;
330 }
331 #endif
332
333 if (asprintf(&value, "udev:%s", syspath) == -1)
334 return;
335
336 remove_devices("udev", value);
337
338 free(value);
339 }
340
341 static void
socket_handler(int fd,int ready,void * data)342 socket_handler(int fd, int ready, void *data)
343 {
344 struct udev_device *udev_device;
345 const char *action;
346
347 input_lock();
348 udev_device = udev_monitor_receive_device(udev_monitor);
349 if (!udev_device) {
350 input_unlock();
351 return;
352 }
353 action = udev_device_get_action(udev_device);
354 if (action) {
355 if (!strcmp(action, "add")) {
356 device_removed(udev_device);
357 device_added(udev_device);
358 } else if (!strcmp(action, "change")) {
359 /* ignore change for the drm devices */
360 if (strcmp(udev_device_get_subsystem(udev_device), "drm")) {
361 device_removed(udev_device);
362 device_added(udev_device);
363 }
364 }
365 else if (!strcmp(action, "remove"))
366 device_removed(udev_device);
367 }
368 udev_device_unref(udev_device);
369 input_unlock();
370 }
371
372 int
config_udev_pre_init(void)373 config_udev_pre_init(void)
374 {
375 struct udev *udev;
376
377 udev = udev_new();
378 if (!udev)
379 return 0;
380
381 udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
382 if (!udev_monitor)
383 return 0;
384
385 udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input",
386 NULL);
387 /* For Wacom serial devices */
388 udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL);
389 #ifdef CONFIG_UDEV_KMS
390 /* For output GPU devices */
391 udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "drm", NULL);
392 #endif
393
394 #ifdef HAVE_UDEV_MONITOR_FILTER_ADD_MATCH_TAG
395 if (ServerIsNotSeat0())
396 udev_monitor_filter_add_match_tag(udev_monitor, SeatId);
397 #endif
398 if (udev_monitor_enable_receiving(udev_monitor)) {
399 ErrorF("config/udev: failed to bind the udev monitor\n");
400 return 0;
401 }
402 return 1;
403 }
404
405 int
config_udev_init(void)406 config_udev_init(void)
407 {
408 struct udev *udev;
409 struct udev_enumerate *enumerate;
410 struct udev_list_entry *devices, *device;
411
412 udev = udev_monitor_get_udev(udev_monitor);
413 enumerate = udev_enumerate_new(udev);
414 if (!enumerate)
415 return 0;
416
417 udev_enumerate_add_match_subsystem(enumerate, "input");
418 udev_enumerate_add_match_subsystem(enumerate, "tty");
419 #ifdef CONFIG_UDEV_KMS
420 udev_enumerate_add_match_subsystem(enumerate, "drm");
421 #endif
422
423 #ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
424 if (ServerIsNotSeat0())
425 udev_enumerate_add_match_tag(enumerate, SeatId);
426 #endif
427
428 udev_enumerate_scan_devices(enumerate);
429 devices = udev_enumerate_get_list_entry(enumerate);
430 udev_list_entry_foreach(device, devices) {
431 const char *syspath = udev_list_entry_get_name(device);
432 struct udev_device *udev_device =
433 udev_device_new_from_syspath(udev, syspath);
434
435 /* Device might be gone by the time we try to open it */
436 if (!udev_device)
437 continue;
438
439 device_added(udev_device);
440 udev_device_unref(udev_device);
441 }
442 udev_enumerate_unref(enumerate);
443
444 SetNotifyFd(udev_monitor_get_fd(udev_monitor), socket_handler, X_NOTIFY_READ, NULL);
445
446 return 1;
447 }
448
449 void
config_udev_fini(void)450 config_udev_fini(void)
451 {
452 struct udev *udev;
453
454 if (!udev_monitor)
455 return;
456
457 udev = udev_monitor_get_udev(udev_monitor);
458
459 RemoveNotifyFd(udev_monitor_get_fd(udev_monitor));
460 udev_monitor_unref(udev_monitor);
461 udev_monitor = NULL;
462 udev_unref(udev);
463 }
464
465 #ifdef CONFIG_UDEV_KMS
466
467 static void
config_udev_odev_setup_attribs(const char * path,const char * syspath,int major,int minor,config_odev_probe_proc_ptr probe_callback)468 config_udev_odev_setup_attribs(const char *path, const char *syspath,
469 int major, int minor,
470 config_odev_probe_proc_ptr probe_callback)
471 {
472 struct OdevAttributes *attribs = config_odev_allocate_attributes();
473
474 attribs->path = XNFstrdup(path);
475 attribs->syspath = XNFstrdup(syspath);
476 attribs->major = major;
477 attribs->minor = minor;
478
479 /* ownership of attribs is passed to probe layer */
480 probe_callback(attribs);
481 }
482
483 void
config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)484 config_udev_odev_probe(config_odev_probe_proc_ptr probe_callback)
485 {
486 struct udev *udev;
487 struct udev_enumerate *enumerate;
488 struct udev_list_entry *devices, *device;
489
490 udev = udev_monitor_get_udev(udev_monitor);
491 enumerate = udev_enumerate_new(udev);
492 if (!enumerate)
493 return;
494
495 udev_enumerate_add_match_subsystem(enumerate, "drm");
496 udev_enumerate_add_match_sysname(enumerate, "card[0-9]*");
497 #ifdef HAVE_UDEV_ENUMERATE_ADD_MATCH_TAG
498 if (ServerIsNotSeat0())
499 udev_enumerate_add_match_tag(enumerate, SeatId);
500 #endif
501 udev_enumerate_scan_devices(enumerate);
502 devices = udev_enumerate_get_list_entry(enumerate);
503 udev_list_entry_foreach(device, devices) {
504 const char *syspath = udev_list_entry_get_name(device);
505 struct udev_device *udev_device = udev_device_new_from_syspath(udev, syspath);
506 const char *path = udev_device_get_devnode(udev_device);
507 const char *sysname = udev_device_get_sysname(udev_device);
508 dev_t devnum = udev_device_get_devnum(udev_device);
509
510 if (!path || !syspath)
511 goto no_probe;
512 else if (strcmp(udev_device_get_subsystem(udev_device), "drm") != 0)
513 goto no_probe;
514 else if (strncmp(sysname, "card", 4) != 0)
515 goto no_probe;
516 else if (!check_seat(udev_device))
517 goto no_probe;
518
519 config_udev_odev_setup_attribs(path, syspath, major(devnum),
520 minor(devnum), probe_callback);
521 no_probe:
522 udev_device_unref(udev_device);
523 }
524 udev_enumerate_unref(enumerate);
525 return;
526 }
527 #endif
528
529