1 /*
2 * Copyright (c) 2012 Baptiste Daroussin
3 * Copyright (c) 2013, 2014 Alex Kozlov
4 * Copyright (c) 2014 Robert Millan
5 * Copyright (c) 2014 Jean-Sebastien Pedron
6 * Copyright (c) 2015 Hans Petter Selasky
7 * Copyright (c) 2015-2017 Rozhuk Ivan
8 * Copyright (c) 2016, 2017 Vladimir Kondratyev
9 * Copyright (c) 2017 Matthew Rezny
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice (including the next
19 * paragraph) shall be included in all copies or substantial portions of the
20 * Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 *
30 * Author: Baptiste Daroussin <bapt@FreeBSD.org>
31 */
32
33 #ifdef HAVE_DIX_CONFIG_H
34 #include <dix-config.h>
35 #endif
36
37 #include <sys/types.h>
38 #include <sys/kbio.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/sysctl.h>
42 #include <sys/un.h>
43 #include <sys/mouse.h>
44 #include <sys/consio.h>
45 #include <sys/ioctl.h>
46 #include <dev/evdev/input.h>
47 #include <dev/usb/usb_ioctl.h>
48 #include <dev/usb/usbhid.h>
49
50 #include <ctype.h>
51 #include <dirent.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <stdbool.h>
57 #include <unistd.h>
58 #include <string.h>
59 #include <paths.h>
60 #include <usbhid.h>
61
62 #include "input.h"
63 #include "inputstr.h"
64 #include "hotplug.h"
65 #include "config-backends.h"
66 #include "os.h"
67
68 #define _IOC_READ IOC_OUT
69
70 #define ULONG_BITS (sizeof(unsigned long) * 8)
71 #define ULONG_CNT(__x) (((__x) + ULONG_BITS - 1) / ULONG_BITS)
72 #define ULONG_IS_BIT_SET(__x, __bit) (((const unsigned long*)(__x))[(__bit) / ULONG_BITS] & (1UL << (__bit % ULONG_BITS)))
73
74 /* from: <linux/joystick.h> */
75 #define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */
76
77 /* WebCamD specific. */
78 #define WEBCAMD_IOCTL_GET_USB_VENDOR_ID _IOR('q', 250, unsigned short)
79 #define WEBCAMD_IOCTL_GET_USB_PRODUCT_ID _IOR('q', 251, unsigned short)
80 #define WEBCAMD_IOCTL_GET_USB_SPEED _IOR('q', 252, unsigned int)
81
82 #ifdef COMPAT_32BIT
83 #define hid_pass_ptr(ptr) ((uint64_t)(uintptr_t)(ptr))
84 #else
85 #define hid_pass_ptr(ptr) (ptr)
86 #endif
87
88 #define _PATH_DEV_LEN (sizeof(_PATH_DEV) - 1)
89 #define DEVD_PATH_DEV "devd:" _PATH_DEV
90 #define DEVD_PATH_DEV_LEN (sizeof(DEVD_PATH_DEV) - 1)
91 #define DEVD_PATH_LEN (DEVD_PATH_DEV_LEN - _PATH_DEV_LEN)
92
93 #define DEVD_SOCK_PATH _PATH_VARRUN "devd.pipe"
94
95 #define DEVD_EVENT_ADD '+'
96 #define DEVD_EVENT_REMOVE '-'
97 #define DEVD_EVENT_NOTIFY '!'
98
99 #define RECONNECT_DELAY (5 * 1000)
100
101 #define is_meuqual(__v1, __v1sz, __v2, __v2sz) \
102 ((__v1sz) == (__v2sz) && NULL != (__v1) && NULL != (__v2) && \
103 0 == memcmp((__v1), (__v2), (__v1sz)))
104
105 #define is_meuqual_cstr(__cstr, __v, __vsz) \
106 is_meuqual(__cstr, (sizeof(__cstr) - 1), __v, __vsz)
107
108 #define is_de_euqual_cstr(__de, __cstr) \
109 (NULL != (__de) && \
110 is_meuqual((__de)->d_name, (__de)->d_namlen, __cstr, (sizeof(__cstr) - 1)))
111
112 #define devd_get_val_cstr(__cstr, __buf, __bufsz, __valsz) \
113 devd_get_val((__buf), (__bufsz), __cstr, (sizeof(__cstr) - 1), \
114 (__valsz))
115
116 static int devd_skt = 0;
117 static char devd_buf[4096];
118 static size_t devd_buf_used = 0;
119 static int is_kbdmux = 0;
120 static int evdev_support = 0;
121 static OsTimerPtr rtimer = NULL;
122
123 /* Input devices. */
124 typedef struct hw_type_s {
125 const char *dev_name;
126 size_t dev_name_size;
127 size_t path_offset;
128 int is_hybrid; /* has both evdev and traditional interfaces */
129 int flags;
130 const char *xdriver;
131 } hw_type_t, *hw_type_p;
132
133 /* xdriver can be set via config "InputClass" section.
134 * Do not set xdriver name if device have more than one
135 * xf86-input-* drivers.
136 * "input/event" can be handled by: xf86-input-libinput,
137 * xf86-input-evdev and xf86-input-wacom, let user choose.
138 */
139 static hw_type_t hw_types[] = {
140 { "uhid", 4, 0, 0, 0, NULL },
141 { "ukbd", 4, 0, 1, ATTR_KEY | ATTR_KEYBOARD, "kbd" },
142 { "atkbd", 5, 0, 1, ATTR_KEY | ATTR_KEYBOARD, "kbd" },
143 { "kbdmux", 6, 0, 1, ATTR_KEY | ATTR_KEYBOARD, "kbd" },
144 { "sysmouse", 8, 0, 1, ATTR_POINTER, "mouse" },
145 { "ums", 3, 0, 1, ATTR_POINTER, "mouse" },
146 { "psm", 3, 0, 1, ATTR_POINTER, "mouse" },
147 { "vboxguest", 9, 0, 0, ATTR_POINTER, "vboxmouse" },
148 { "joy", 3, 0, 0, ATTR_JOYSTICK, NULL },
149 { "atp", 3, 0, 0, ATTR_TOUCHPAD, NULL },
150 { "uep", 3, 0, 0, ATTR_TOUCHSCREEN, NULL },
151 { "input/event",5, 6, 0, 0, NULL },
152 { "input/js", 2, 6, 0, ATTR_JOYSTICK, NULL },
153 { NULL, 0, 0, 0, NULL },
154 };
155
156 /* Input devices paths. */
157 static hw_type_t hw_type_path[] = {
158 { "input/", 0, 6, 0, NULL },
159 { NULL, 0, 0, 0, NULL },
160 };
161
162 static size_t
bits_calc(const unsigned long * bits,size_t off_start,size_t off_stop)163 bits_calc(const unsigned long *bits, size_t off_start, size_t off_stop)
164 {
165 size_t count = 0;
166
167 for (size_t i = off_start; i < off_stop; ++i) {
168 if (ULONG_IS_BIT_SET(bits, i)) {
169 ++count;
170 }
171 }
172 return count;
173 }
174
175 static hw_type_p
get_dev_type_by_name(const char * dev_name,size_t dev_name_size)176 get_dev_type_by_name(const char *dev_name, size_t dev_name_size)
177 {
178 if (!dev_name || !dev_name_size)
179 return NULL;
180
181 for (size_t i = 0; hw_types[i].dev_name; ++i) {
182 if (dev_name_size >= (hw_types[i].dev_name_size + hw_types[i].path_offset) &&
183 !memcmp(dev_name, hw_types[i].dev_name, (hw_types[i].path_offset + hw_types[i].dev_name_size))) {
184 return &hw_types[i];
185 }
186 }
187 return NULL;
188 }
189
190 static hw_type_p
get_dev_type_by_path(const char * dev_name,size_t dev_name_size,hw_type_p hw_type_cust)191 get_dev_type_by_path(const char *dev_name, size_t dev_name_size, hw_type_p hw_type_cust)
192 {
193 if (!dev_name || !dev_name_size || !hw_type_cust)
194 return NULL;
195
196 for (size_t i = 0; hw_type_path[i].dev_name; ++i) {
197 if (dev_name_size <= hw_type_path[i].path_offset ||
198 memcmp(dev_name, hw_type_path[i].dev_name, hw_type_path[i].path_offset))
199 continue;
200 /* Path in white list. */
201 hw_type_cust->dev_name = dev_name;
202 hw_type_cust->flags = hw_type_path[i].flags;
203 hw_type_cust->xdriver = hw_type_path[i].xdriver;
204 hw_type_cust->path_offset = hw_type_path[i].path_offset;
205 size_t name_end = hw_type_cust->path_offset;
206 while (name_end < dev_name_size && !isdigit(dev_name[name_end]))
207 ++name_end;
208 hw_type_cust->dev_name_size = (name_end - hw_type_cust->path_offset);
209 return hw_type_cust;
210 }
211 return NULL;
212 }
213
214 static int
is_kbdmux_enabled(void)215 is_kbdmux_enabled(void)
216 {
217 /* Xorg uses /dev/ttyv0 as a console device */
218 /* const char device[]="/dev/console"; */
219 static const char *device = _PATH_TTY "v0";
220
221 int fd = open(device, O_RDONLY);
222 if (fd < 0)
223 return 0;
224
225 keyboard_info_t info;
226 int ret = (ioctl(fd, KDGKBINFO, &info) == -1 ||
227 memcmp(info.kb_name, "kbdmux", 6)) ? 0 : 1;
228 close(fd);
229 return ret;
230 }
231
232 /* Derived from EvdevProbe() function of xf86-input-evdev driver */
233 static int
get_evdev_flags(int fd)234 get_evdev_flags(int fd)
235 {
236 if (fd<0)
237 return 0;
238
239 unsigned long key_bits[ULONG_CNT(KEY_CNT)], rel_bits[ULONG_CNT(REL_CNT)], abs_bits[ULONG_CNT(ABS_CNT)];
240 size_t has_keys = 0, has_buttons = 0, has_lmr = 0, has_rel_axes = 0, has_abs_axes = 0, has_mt = 0;
241 if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) != -1) {
242 has_keys = bits_calc(key_bits, 0, BTN_MISC);
243 has_buttons = bits_calc(key_bits, BTN_MISC, BTN_JOYSTICK);
244 has_lmr = bits_calc(key_bits, BTN_LEFT, BTN_MIDDLE + 1);
245 }
246 if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) != -1) {
247 has_rel_axes = bits_calc(rel_bits, 0, REL_CNT);
248 }
249 if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits) != -1) {
250 has_abs_axes = bits_calc(abs_bits, 0, ABS_CNT);
251 has_mt = bits_calc(abs_bits, ABS_MT_SLOT, ABS_CNT);
252 }
253
254 int flags = 0;
255 if (has_abs_axes) {
256 if (has_mt) {
257 if (!has_buttons) {
258 /*
259 * XXX: I'm not sure that joystick detection is
260 * done right. xf86-input-evdev does not support them.
261 */
262 if (ULONG_IS_BIT_SET(key_bits, BTN_JOYSTICK))
263 flags = ATTR_JOYSTICK;
264 else
265 ++has_buttons;
266 }
267 }
268 if (!flags && ULONG_IS_BIT_SET(abs_bits, ABS_X) && ULONG_IS_BIT_SET(abs_bits, ABS_Y)) {
269 if (ULONG_IS_BIT_SET(key_bits, BTN_TOOL_PEN) ||
270 ULONG_IS_BIT_SET(key_bits, BTN_STYLUS) ||
271 ULONG_IS_BIT_SET(key_bits, BTN_STYLUS2))
272 flags = ATTR_TABLET;
273 else if (ULONG_IS_BIT_SET(abs_bits, ABS_PRESSURE) ||
274 ULONG_IS_BIT_SET(key_bits, BTN_TOUCH)) {
275 if (has_lmr || ULONG_IS_BIT_SET(key_bits, BTN_TOOL_FINGER))
276 flags = ATTR_TOUCHPAD;
277 else
278 flags = ATTR_TOUCHSCREEN;
279 } else if (!(ULONG_IS_BIT_SET(rel_bits, REL_X) &&
280 ULONG_IS_BIT_SET(rel_bits, REL_Y)) &&
281 has_lmr) /* some touchscreens use BTN_LEFT rather than BTN_TOUCH */
282 flags = ATTR_TOUCHSCREEN;
283 }
284 }
285 if (!flags) {
286 if (has_keys)
287 flags = ATTR_KEY | ATTR_KEYBOARD;
288 else if (has_rel_axes || has_abs_axes || has_buttons)
289 flags = ATTR_POINTER;
290 }
291 return flags;
292 }
293
294 /* From: sys/dev/usb/usb_hid.c */
295 static int
hid_is_collection(report_desc_t s,uint32_t usage)296 hid_is_collection(report_desc_t s, uint32_t usage)
297 {
298 struct hid_data* hd = hid_start_parse(s, ~0, -1);
299 if (!hd)
300 return 0;
301
302 struct hid_item hi;
303 int rc;
304 while ((rc = hid_get_item(hd, &hi))) {
305 if (hi.kind == hid_collection && hi.usage == usage)
306 break;
307 }
308 hid_end_parse(hd);
309 return rc;
310 }
311
312 static int
hid_is_mouse(report_desc_t s)313 hid_is_mouse(report_desc_t s)
314 {
315 struct hid_data* hd = hid_start_parse(s, (1 << hid_input), -1);
316 if (!hd)
317 return 0;
318
319 struct hid_item hi;
320 int found = 0, mdepth = 0;
321 while (hid_get_item(hd, &hi)) {
322 switch (hi.kind) {
323 case hid_collection:
324 if (mdepth != 0)
325 ++mdepth;
326 else if (hi.collection == 1 &&
327 hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
328 ++mdepth;
329 break;
330 case hid_endcollection:
331 if (mdepth)
332 --mdepth;
333 break;
334 case hid_input:
335 if (!mdepth)
336 break;
337 if (hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
338 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
339 ++found;
340 if (hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
341 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
342 ++found;
343 break;
344 default:
345 break;
346 }
347 }
348 hid_end_parse(hd);
349 return found;
350 }
351
352 static char *
sysctl_get_str(const char * sysctlname,size_t * size_ret)353 sysctl_get_str(const char *sysctlname, size_t *size_ret)
354 {
355 if (!sysctlname)
356 return NULL;
357
358 size_t len = 0;
359 if (sysctlbyname(sysctlname, NULL, &len, NULL, 0) || !len)
360 return NULL;
361
362 char* dest = malloc(len + 1);
363 if (!dest)
364 return NULL;
365
366 if (sysctlbyname(sysctlname, dest, &len, NULL, 0)) {
367 free(dest);
368 return NULL;
369 }
370 dest[len] = 0;
371 if (size_ret)
372 *size_ret = len;
373 return dest;
374 }
375
376 static char *
devd_get_val(char * buf,size_t buf_size,const char * val_name,size_t val_name_size,size_t * val_size)377 devd_get_val(char *buf, size_t buf_size, const char *val_name, size_t val_name_size, size_t *val_size)
378 {
379 if (!buf || !buf_size || !val_name || !val_name_size)
380 return NULL;
381
382 char *ret = buf, *buf_end = (buf + buf_size);
383 while (ret && ret < buf_end) {
384 ret = memmem(ret, (buf_end - ret), val_name, val_name_size);
385 if (!ret)
386 return NULL;
387 /* Found. */
388 /* Check: space before or buf+1. */
389 if ((buf + 1) < ret && ret[-1] != ' ') {
390 ret += val_name_size;
391 continue;
392 }
393 /* Check: = after name and size for value. */
394 ret += val_name_size;
395 if ((ret + 1) >= buf_end)
396 return NULL;
397 if (ret[0] != '=')
398 continue;
399 ++ret;
400 break;
401 }
402 if (!ret || !val_size)
403 return ret;
404 /* Calc value data size. */
405 char* ptr = memchr(ret, ' ', (buf_end - ret));
406 if (!ptr) /* End of string/last value. */
407 ptr = buf_end;
408 *val_size = (ptr - ret);
409 return ret;
410 }
411
412 static void
device_added(const char * dev_name,size_t dev_name_size,int allow_no_device)413 device_added(const char *dev_name, size_t dev_name_size, int allow_no_device)
414 {
415 if (!dev_name || !dev_name_size || dev_name_size > PATH_MAX)
416 return;
417
418 char config_info[PATH_MAX + 32];
419 /* Make dev_name null ended string. */
420 snprintf(config_info, sizeof(config_info), DEVD_PATH_DEV"%.*s", (int)dev_name_size, dev_name);
421 /* Set / update pointers to dev_name and dev_path. */
422 char* dev_path = (config_info + DEVD_PATH_LEN); /* Skip: "devd:" */
423 dev_name = (dev_path + _PATH_DEV_LEN); /* Skip: "/dev/" */
424
425 /* Is known input device or path? */
426 hw_type_t *hwtype = get_dev_type_by_name(dev_name, dev_name_size);
427 if (!hwtype) {
428 hw_type_t hwtype_cust;
429 hwtype = get_dev_type_by_path(dev_name, dev_name_size, &hwtype_cust);
430 }
431 if (!hwtype) /* Not found in white list. */
432 return;
433
434 /* Skip legacy interfaces if EVDEV_SUPPORT is compiled into kernel */
435 if (evdev_support && hwtype->is_hybrid) {
436 LogMessage(X_INFO, "config/devd: EVDEV_SUPPORT is enabled, ignoring device %s\n", dev_name);
437 return;
438 }
439 /* Skip keyboard devices if kbdmux is enabled */
440 if (is_kbdmux && !allow_no_device && (hwtype->flags & ATTR_KEYBOARD)) {
441 LogMessage(X_INFO, "config/devd: kbdmux is enabled, ignoring device %s\n", dev_name);
442 return;
443 }
444 /* Skip duplicate devices. */
445 if (device_is_duplicate(config_info)) {
446 LogMessage(X_WARNING, "config/devd: device %s already added. ignoring\n", dev_path);
447 return;
448 }
449
450 /* Init and set attributes. */
451 char pnp_usb_id[PATH_MAX], product[PATH_MAX], vendor[PATH_MAX];
452 InputAttributes attrs;
453 memset(&attrs, 0, sizeof(attrs));
454 attrs.device = dev_path;
455 attrs.flags = hwtype->flags;
456
457 /* Try to open device. */
458 int fd = open(dev_path, O_RDONLY);
459 if (fd < 0) {
460 if (!(hwtype->flags & (ATTR_KEY | ATTR_KEYBOARD))) {
461 /*
462 * Fail if cannot open device, it breaks AllowMouseOpenFail,
463 * but it should not matter when config/devd is enabled
464 */
465 LogMessage(X_WARNING, "config/devd: device %s already opened\n", dev_path);
466 return;
467 }
468 if (!allow_no_device) {
469 /*
470 * There can be only one keyboard attached to console and
471 * it is already added.
472 */
473 LogMessage(X_WARNING, "config/devd: console keyboard is already added, ignoring %s\n", dev_path);
474 return;
475 }
476 } else {
477 /* Try to get device info via ioctl(). */
478 keyboard_info_t kbdi;
479 mousehw_t mshw;
480 struct input_id iid;
481 report_desc_t rep_desc;
482
483 if (ioctl(fd, KDGKBINFO, &kbdi) != -1) { /* Is this keyboard? */
484 memcpy(product, kbdi.kb_name, sizeof(kbdi.kb_name));
485 attrs.product = product;
486 attrs.flags = ATTR_KEY | ATTR_KEYBOARD;
487 LogMessage(X_INFO, "config/devd: detected keyboard: %s, kb_index=%i, kb_unit=%i, kb_type=%i, kb_config=%i\n",
488 kbdi.kb_name, kbdi.kb_index, kbdi.kb_unit, kbdi.kb_type, kbdi.kb_config);
489 } else if (ioctl(fd, MOUSE_GETHWINFO, &mshw) != -1) { /* Is this mouse? */
490 /* FreeBSD mouse drivers does not return real vid+pid. */
491 /* construct USB ID in lowercase hex - "0000:ffff" */
492 if (mshw.iftype != MOUSE_IF_USB && mshw.model > 0) {
493 snprintf(pnp_usb_id, sizeof(pnp_usb_id), "%04x:%04x", mshw.hwid, mshw.model);
494 attrs.usb_id = pnp_usb_id;
495 }
496 if (mshw.type == MOUSE_PAD)
497 attrs.flags = ATTR_TOUCHPAD;
498 else
499 attrs.flags = ATTR_POINTER;
500 LogMessage(X_INFO, "config/devd: detected mouse: hwid=%04x, model=%04x, type=%04x, iftype=%04x, buttons=%d\n",
501 mshw.hwid, mshw.model, mshw.type, mshw.iftype, mshw.buttons);
502 } else if (ioctl(fd, JSIOCGNAME((sizeof(product) - 1)), product) != -1) { /* Is this joystick? */
503 attrs.product = product;
504 attrs.flags = ATTR_JOYSTICK;
505 LogMessage(X_INFO, "config/devd: detected joystick: %s\n", product);
506 } else if (ioctl(fd, EVIOCGID, &iid) != -1 &&
507 ioctl(fd, EVIOCGNAME((sizeof(product) - 1)), product) != -1) { /* Is this event? */
508 /* construct USB ID in lowercase hex - "0000:ffff" */
509 snprintf(pnp_usb_id, sizeof(pnp_usb_id), "%04x:%04x", iid.vendor, iid.product);
510 attrs.usb_id = pnp_usb_id;
511 attrs.product = product;
512 /* Detect device type. */
513 attrs.flags = get_evdev_flags(fd);
514 /* Skip keyboard devices if kbdmux is enabled and EVDEV_SUPPORT is not compiled into kernel*/
515 if (is_kbdmux && !evdev_support && (attrs.flags & ATTR_KEYBOARD)) {
516 close(fd);
517 LogMessage(X_INFO, "config/devd: kbdmux is enabled, ignoring device %s\n", dev_name);
518 return;
519 }
520 LogMessage(X_INFO, "config/devd: detected event input: %s, bustype=%04x, vendor=%04x, product=%04x, version=%04x\n",
521 product, iid.bustype, iid.vendor, iid.product, iid.version);
522 } else if ((rep_desc = hid_get_report_desc(fd))) { /* Is USB HID? */
523 if (hid_is_mouse(rep_desc)) {
524 attrs.flags = ATTR_POINTER;
525 LogMessage(X_INFO, "config/devd: detected USB HID mouse\n");
526 } else if (hid_is_collection(rep_desc, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) {
527 /* Skip keyboard devices if kbdmux is enabled */
528 if (is_kbdmux) {
529 hid_dispose_report_desc(rep_desc);
530 close(fd);
531 LogMessage(X_INFO, "config/devd: kbdmux is enabled, ignoring device %s\n", dev_name);
532 return;
533 }
534 attrs.flags = ATTR_KEY | ATTR_KEYBOARD;
535 LogMessage(X_INFO, "config/devd: detected USB HID keyboard\n");
536 } else if (hid_is_collection(rep_desc, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_JOYSTICK)) ||
537 hid_is_collection(rep_desc, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_GAME_PAD))) {
538 attrs.flags = ATTR_JOYSTICK;
539 LogMessage(X_INFO, "config/devd: detected USB HID joystick\n");
540 } else
541 LogMessage(X_INFO, "config/devd: detected USB HID of unknown type\n");
542 hid_dispose_report_desc(rep_desc);
543 }
544
545 if (!attrs.usb_id) { /* Is this webcamd device? */
546 unsigned short vid, pid;
547 if (ioctl(fd, WEBCAMD_IOCTL_GET_USB_VENDOR_ID, &vid) != -1 &&
548 ioctl(fd, WEBCAMD_IOCTL_GET_USB_PRODUCT_ID, &pid) != -1) {
549 snprintf(pnp_usb_id, sizeof(pnp_usb_id), "%04x:%04x", vid, pid);
550 attrs.usb_id = pnp_usb_id;
551 LogMessage(X_INFO, "config/devd: webcamd device: %s\n", pnp_usb_id);
552 }
553 }
554 }
555 close(fd);
556
557 /* Try to get device info via sysctl(). */
558 if (!attrs.usb_id && !attrs.pnp_id) {
559 char sysctlname[PATH_MAX];
560 snprintf(sysctlname, sizeof(sysctlname), "dev.%.*s.%s.%%pnpinfo",
561 (int)hwtype->dev_name_size,
562 (hwtype->dev_name + hwtype->path_offset),
563 (dev_name + hwtype->path_offset + hwtype->dev_name_size));
564 size_t sdata_size;
565 char* sdata = sysctl_get_str(sysctlname, &sdata_size);
566 if (sdata) {
567 size_t pid_size, vid_size;
568 char* ptr_vid = devd_get_val_cstr("vendor", sdata, sdata_size, &vid_size);
569 char* ptr_pid = devd_get_val_cstr("product", sdata, sdata_size, &pid_size);
570 if (ptr_vid && ptr_pid) { /* usb_id */
571 ptr_vid[vid_size] = 0;
572 ptr_pid[pid_size] = 0;
573 snprintf(pnp_usb_id, sizeof(pnp_usb_id), "%s:%s", ptr_vid, ptr_pid);
574 attrs.usb_id = pnp_usb_id;
575 LogMessage(X_INFO, "config/devd: [sysctl] usb_id: %s\n", pnp_usb_id);
576 } else { /* pnp_id */
577 strlcpy(pnp_usb_id, sdata, sizeof(pnp_usb_id));
578 attrs.pnp_id = pnp_usb_id;
579 }
580 free(sdata);
581 }
582 }
583 if (!attrs.vendor || !attrs.product) {
584 char sysctlname[PATH_MAX];
585 snprintf(sysctlname, sizeof(sysctlname), "dev.%.*s.%s.%%desc",
586 (int)hwtype->dev_name_size,
587 (hwtype->dev_name + hwtype->path_offset),
588 (dev_name + hwtype->path_offset + hwtype->dev_name_size));
589 size_t sdata_size;
590 char* sdata = sysctl_get_str(sysctlname, &sdata_size);
591 if (sdata) {
592 /* Vendor. */
593 char* ptr_pid = memchr(sdata, ' ', sdata_size);
594 if (ptr_pid)
595 ptr_pid[0] = 0;
596 strlcpy(vendor, sdata, sizeof(vendor));
597 attrs.vendor = vendor;
598 /* Product. */
599 if (!attrs.product && ptr_pid) {
600 ++ptr_pid;
601 char* ptr_vid = memchr(ptr_pid, ',', (sdata_size - (ptr_pid - sdata)));
602 if (ptr_vid)
603 ptr_vid[0] = 0;
604 strlcpy(product, ptr_pid, sizeof(product));
605 attrs.product = product;
606 } else
607 product[0] = 0;
608 free(sdata);
609 LogMessage(X_INFO, "config/devd: [sysctl] vendor: %s, product: %s\n", vendor, product);
610 }
611 }
612
613 /* Init options. */
614 InputOption *option = NULL, *options = NULL;
615 if ((option = input_option_new(options, "_source", "server/devd")))
616 options = option;
617 if (option && (option = input_option_new(options, "config_info", config_info)))
618 options = option;
619 if (option && (option = input_option_new(options, "name", (attrs.product ? attrs.product : dev_name))))
620 options = option;
621 if (option && hwtype->xdriver && (option = input_option_new(options, "driver", hwtype->xdriver)))
622 options = option;
623 /*
624 * Don't pass "device" option if the keyboard is already attached to the console (ie. open() failed)
625 * This would activate a special logic in xf86-input-keyboard. Prevent any other attached to console
626 * keyboards being processed. There can be only one such device.
627 */
628 if (option && fd >= 0 && (option = input_option_new(options, "device", dev_path)))
629 options = option;
630 /* Most drivers just use "device" but evdev also uses "path" so populate both */
631 if (option && (option = input_option_new(options, "path", dev_path)))
632 options = option;
633 if (option) {
634 LogMessage(X_INFO, "config/devd: adding input device %s\n", dev_path);
635 DeviceIntPtr dev_iptr = NULL;
636 int rc;
637 if ((rc = NewInputDeviceRequest(options, &attrs, &dev_iptr)) != Success)
638 LogMessage(X_ERROR, "config/devd: error %d adding device %s\n", rc, dev_path);
639 } else
640 LogMessage(X_ERROR, "config/devd: error adding device %s\n", dev_path);
641 if (options)
642 input_option_free_list(&options);
643 return;
644 }
645
646 static void
device_removed(const char * dev_name,size_t dev_name_size)647 device_removed(const char *dev_name, size_t dev_name_size)
648 {
649
650 if (!dev_name || !dev_name_size || dev_name_size > PATH_MAX)
651 return;
652
653 hw_type_t hwtype_cust;
654 if (!get_dev_type_by_name(dev_name, dev_name_size) &&
655 !get_dev_type_by_path(dev_name, dev_name_size, &hwtype_cust))
656 return; /* Device not in list - unknown. */
657
658 char config_info[PATH_MAX + 32];
659 snprintf(config_info, sizeof(config_info), DEVD_PATH_DEV"%.*s", (int)dev_name_size, dev_name);
660 if (device_is_duplicate(config_info))
661 LogMessage(X_INFO, "config/devd: removing input device %s\n", (config_info + DEVD_PATH_LEN));
662 else
663 LogMessage(X_INFO, "config/devd: removing nonexistent device %s\n", (config_info + DEVD_PATH_LEN));
664 remove_devices("devd", config_info);
665 return;
666 }
667
668 static void socket_handler(int fd, int ready, void *data);
669
670 static int
connect_devd(void)671 connect_devd(void)
672 {
673 int sock = socket(AF_UNIX, SOCK_STREAM, 0);
674 if (sock < 0) {
675 LogMessage(X_ERROR, "config/devd: failed opening stream socket: %s\n", strerror(errno));
676 return -1;
677 }
678
679 struct sockaddr_un devd;
680 devd.sun_family = AF_UNIX;
681 memcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(DEVD_SOCK_PATH));
682 if (connect(sock, (struct sockaddr*)&devd, sizeof(devd)) < 0) {
683 int error = errno;
684 close(sock);
685 LogMessage(X_ERROR, "config/devd: failed to connect to devd: %s)\n", strerror(error));
686 return -1;
687 }
688
689 SetNotifyFd(sock, socket_handler, X_NOTIFY_READ, NULL);
690 return sock;
691 }
692
693 static void
disconnect_devd(int sock)694 disconnect_devd(int sock)
695 {
696 if (sock < 0)
697 return;
698 RemoveNotifyFd(sock);
699 close(sock);
700 return;
701 }
702
703 static CARD32
reconnect_handler(OsTimerPtr timer,CARD32 time,void * arg)704 reconnect_handler(OsTimerPtr timer, CARD32 time, void *arg)
705 {
706 devd_buf_used = 0;
707 devd_skt = connect_devd();
708 if (devd_skt < 0) /* Try again after RECONNECT_DELAY */
709 return RECONNECT_DELAY;
710 TimerFree(rtimer);
711 rtimer = NULL;
712 LogMessage(X_INFO, "config/devd: reopened devd socket\n");
713 return 0;
714 }
715
716 static void
socket_handler(int fd,int ready,void * data)717 socket_handler(int fd, int ready, void *data)
718 {
719 /* Read new data. */
720 while (1) {
721 ssize_t ios = recv(devd_skt, (devd_buf + devd_buf_used), (sizeof(devd_buf) - devd_buf_used), MSG_DONTWAIT);
722 if (ios > 0) { /* Read OK. */
723 devd_buf_used += ios;
724 continue; /* Try to read more. */
725 }
726 /* Something wrong. */
727 int error = errno;
728 if (error == EAGAIN)
729 break; /* All available data read. */
730 if (error == EINTR)
731 continue;
732 if (devd_buf_used >= sizeof(devd_buf)) {
733 devd_buf_used = 0; /* Message too long, reset buf. */
734 continue;
735 }
736 /* devd socket is lost */
737 disconnect_devd(devd_skt);
738 rtimer = TimerSet(NULL, 0, 1, reconnect_handler, NULL);
739 LogMessage(X_WARNING, "config/devd: devd socket read error: %s\n", strerror(error));
740 return;
741 }
742
743 /* Process data. */
744 char *ptr, *line = (devd_buf + 1);
745 size_t line_size = 0;
746 while((ptr = memchr(line, '\n', (devd_buf_used - line_size)))) {
747 line_size = (ptr - line);
748 do {
749 if (*(line - 1) != DEVD_EVENT_NOTIFY)
750 break; /* Handle only notify. */
751 /* Check: is system=DEVFS. */
752 size_t val_size;
753 char* val = devd_get_val_cstr("system", line, line_size, &val_size);
754 if (!is_meuqual_cstr("DEVFS", val, val_size))
755 break;
756 /* Check: is subsystem=CDEV. */
757 val = devd_get_val_cstr("subsystem", line, line_size, &val_size);
758 if (!is_meuqual_cstr("CDEV", val, val_size))
759 break;
760 /* Get device name. */
761 size_t cdev_size;
762 char* cdev = devd_get_val_cstr("cdev", line, line_size, &cdev_size);
763 if (!cdev)
764 break;
765 /* Get event type. */
766 val = devd_get_val_cstr("type", line, line_size, &val_size);
767 if (is_meuqual_cstr("CREATE", val, val_size)) {
768 device_added(cdev, cdev_size, 0);
769 } else if (is_meuqual_cstr("DESTROY", val, val_size)) {
770 device_removed(cdev, cdev_size);
771 }
772 } while(0);
773
774 line += (line_size + 2); /* Skip '\n' and event type byte. */
775 line_size = (line - devd_buf);
776 if (devd_buf_used <= line_size) {
777 devd_buf_used = 0;
778 return;
779 }
780 }
781 /* Save line without end marker. */
782 if (line_size) {
783 devd_buf_used -= (line_size - 1);
784 memmove(devd_buf, (line - 1), devd_buf_used);
785 }
786 return;
787 }
788
789 int
config_devd_init(void)790 config_devd_init(void)
791 {
792 LogMessage(X_INFO, "config/devd: probing input devices...\n");
793
794 /* Check if kernel is compiled with evdev support in hybrid drivers */
795 evdev_support = feature_present("evdev_support");
796
797 /*
798 * Add fake keyboard and give up on keyboards management
799 * if kbdmux is enabled and not exported through evdev
800 */
801 is_kbdmux = is_kbdmux_enabled();
802 if (is_kbdmux && !evdev_support)
803 device_added("kbdmux0", 7, 1);
804
805 /* Scan /dev/ for devices. */
806 struct dirent** namelist;
807 size_t dir_cnt = scandir(_PATH_DEV, &namelist, 0, alphasort);
808 for (size_t i = 0; i < dir_cnt; ++i) {
809 struct dirent* de = namelist[i];
810 if (is_de_euqual_cstr(de, ".") ||
811 is_de_euqual_cstr(de, "..")) {
812 free(de);
813 continue;
814 }
815 if (de->d_type != DT_DIR) {
816 device_added(de->d_name, de->d_namlen, 0);
817 } else { /* Sub folder. */
818 char devicename[PATH_MAX];
819 snprintf(devicename, sizeof(devicename), _PATH_DEV "%s", de->d_name);
820 struct dirent** snamelist;
821 size_t sdir_cnt = scandir(devicename, &snamelist, 0, alphasort);
822 for (size_t j = 0; j < sdir_cnt; ++j) {
823 struct dirent* sde = snamelist[j];
824 if (!is_de_euqual_cstr(sde, ".") &&
825 !is_de_euqual_cstr(sde, "..") &&
826 sde->d_type != DT_DIR) {
827 size_t tm = snprintf(devicename, sizeof(devicename), "%s/%s", de->d_name, sde->d_name);
828 device_added(devicename, tm, 0);
829 }
830 free(sde);
831 }
832 free(snamelist);
833 }
834 free(de);
835 }
836 free(namelist);
837
838 devd_buf_used = 0;
839 devd_skt = connect_devd();
840 return (devd_skt < 0) ? 0 : 1;
841 }
842
843 void
config_devd_fini(void)844 config_devd_fini(void)
845 {
846 LogMessage(X_INFO, "config/devd: terminating backend...\n");
847
848 if (rtimer) {
849 TimerFree(rtimer);
850 rtimer = NULL;
851 }
852
853 disconnect_devd(devd_skt);
854 return;
855 }
856