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