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