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