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