View | Details | Raw Unified | Return to bug 196678 | Differences between
and this patch

Collapse All | Expand All

(-)config/devd.c (+885 lines)
Added Link Here
1
/*
2
 * Copyright (c) 2012 Baptiste Daroussin
3
 * Copyright (c) 2013, 2014 Alex Kozlov
4
 * Copyright (c) 2014 Robert Millan
5
 * Copyright (c) 2014 Jean-Sebastien Pedron
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice (including the next
15
 * paragraph) shall be included in all copies or substantial portions of the
16
 * Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
 * DEALINGS IN THE SOFTWARE.
25
 *
26
 * Author: Baptiste Daroussin <bapt@FreeBSD.org>
27
 */
28
29
#ifdef HAVE_DIX_CONFIG_H
30
#include <dix-config.h>
31
#endif
32
33
#include <sys/param.h>
34
#include <sys/ioccom.h>
35
#include <sys/kbio.h>
36
#include <sys/queue.h>
37
#include <sys/socket.h>
38
#include <sys/stat.h>
39
#include <sys/sysctl.h>
40
#include <sys/un.h>
41
42
#include <ctype.h>
43
#include <dirent.h>
44
#include <errno.h>
45
#include <fcntl.h>
46
#include <limits.h>
47
#include <stddef.h>
48
#include <stdlib.h>
49
#include <stdio.h>
50
#include <stdbool.h>
51
#include <string.h>
52
#include <unistd.h>
53
#include <paths.h>
54
55
#include "input.h"
56
#include "inputstr.h"
57
#include "hotplug.h"
58
#include "config-backends.h"
59
#include "os.h"
60
61
#define DEVD_SOCK_PATH "/var/run/devd.pipe"
62
63
#define RECONNECT_DELAY		(5 * 1000)
64
65
static int sock_devd;
66
static bool is_kbdmux = false;
67
static bool is_kernel_evdev = false;
68
OsTimerPtr rtimer;
69
70
struct hw_type {
71
	const char *driver;
72
	int flag;
73
	const char *xdriver;
74
	const char *sysctldesc;
75
};
76
77
static const struct hw_type hw_types0[] = {
78
	{ _PATH_DEV "sysmouse", ATTR_POINTER, "mouse", NULL },
79
	{ _PATH_DEV "vboxguest", ATTR_POINTER, "vboxmouse", NULL },
80
	{ NULL, 0, NULL, NULL },
81
};
82
83
static const struct hw_type hw_types1[] = {
84
	{ _PATH_DEV "ukbd%d", ATTR_KEYBOARD, "kbd", "ukbd" },
85
	{ _PATH_DEV "atkbd%d", ATTR_KEYBOARD, "kbd", "atkbd" },
86
	{ _PATH_DEV "kbdmux%d", ATTR_KEYBOARD, "kbd", NULL },
87
	{ _PATH_DEV "ums%d", ATTR_POINTER, "mouse", "ums" },
88
	{ _PATH_DEV "psm%d", ATTR_POINTER, "mouse", "psm" },
89
	{ _PATH_DEV "joy%d", ATTR_JOYSTICK, "mouse", "joy" },
90
	{ _PATH_DEV "atp%d", ATTR_TOUCHPAD, "mouse", "atp" },
91
	{ _PATH_DEV "wsp%d", ATTR_TOUCHPAD, "mouse", "wsp" },
92
	{ _PATH_DEV "uep%d", ATTR_TOUCHSCREEN, "mouse", "uep" },
93
	{ _PATH_DEV "input/event%d", 0, "evdev", NULL },
94
	{ NULL, 0, NULL, NULL },
95
};
96
97
/* like basename() but returns a pointer to incoming string */
98
static char *
99
bname(const char *path)
100
{
101
	char *bname = NULL;
102
103
	if (path != NULL)
104
		bname = strrchr(path, '/');
105
	return (bname == NULL) ? (char *)path : bname + 1;
106
}
107
108
struct dev_entry {
109
	SLIST_ENTRY(dev_entry) next;
110
	char name[];
111
};
112
SLIST_HEAD(dev_list, dev_entry);
113
114
#define	dev_list_init(dev_list)		SLIST_INIT(dev_list)
115
#define	dev_list_empty(dev_list)	SLIST_EMPTY(dev_list)
116
117
static void
118
dev_list_insert(struct dev_list *devs, const char *devname)
119
{
120
	struct dev_entry *dev;
121
122
	dev = malloc(offsetof(struct dev_entry, name) + strlen(devname) + 1);
123
	if (dev != NULL) {
124
		strcpy(dev->name, devname);
125
		SLIST_INSERT_HEAD(devs, dev, next);
126
	}
127
}
128
129
static void
130
dev_list_destroy(struct dev_list *devs)
131
{
132
	struct dev_entry *dev;
133
134
	while (!SLIST_EMPTY(devs)) {
135
		dev = SLIST_FIRST(devs);
136
		SLIST_REMOVE_HEAD(devs, next);
137
		free(dev);
138
	}
139
}
140
141
static bool
142
dev_list_search(struct dev_list *devs, const char *devname)
143
{
144
	struct dev_entry *dev;
145
146
	if (devname != NULL)
147
		SLIST_FOREACH(dev, devs, next)
148
			if (strcmp(devname, dev->name) == 0)
149
				return true;
150
	return false;
151
}
152
153
/* Some definitions from linux/input.h */
154
struct input_id {
155
	uint16_t bustype;
156
	uint16_t vendor;
157
	uint16_t product;
158
	uint16_t version;
159
};
160
161
#define	EVIOCGBIT(ev,len)	_IOC(IOC_OUT, 'E', 0x20 + (ev), len)
162
#define	EVIOCGID		_IOR('E', 0x02, struct input_id)
163
#define	EVIOCGNAME(len)		_IOC(IOC_OUT, 'E', 0x06, len)
164
#define	EVIOCGPHYS(len)		_IOC(IOC_OUT, 'E', 0x07, len)
165
166
#define	EV_KEY			0x01
167
#define	EV_REL			0x02
168
#define	EV_ABS			0x03
169
#define	BTN_MISC		0x100
170
#define	BTN_LEFT		0x110
171
#define	BTN_RIGHT		0x111
172
#define	BTN_MIDDLE		0x112
173
#define	BTN_JOYSTICK		0x120
174
#define	BTN_TOOL_PEN		0x140
175
#define	BTN_TOOL_FINGER		0x145
176
#define	BTN_TOUCH		0x14a
177
#define	BTN_STYLUS		0x14b
178
#define	BTN_STYLUS2		0x14c
179
#define	KEY_MAX			0x2ff
180
#define	KEY_CNT			(KEY_MAX+1)
181
#define	REL_X			0x00
182
#define	REL_Y			0x01
183
#define	REL_MAX			0x0f
184
#define	REL_CNT			(REL_MAX+1)
185
#define	ABS_X			0x00
186
#define	ABS_Y			0x01
187
#define	ABS_PRESSURE		0x18
188
#define	ABS_MT_SLOT		0x2f
189
#define	ABS_MAX			0x3f
190
#define	ABS_CNT			(ABS_MAX+1)
191
192
#define	LONG_BITS	(sizeof(long) * 8)
193
#define	NLONGS(x)	(((x) + LONG_BITS - 1) / LONG_BITS)
194
195
static inline bool
196
bit_is_set(const unsigned long *array, int bit)
197
{
198
	return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
199
}
200
201
static inline bool
202
bit_find(const unsigned long *array, int start, int stop)
203
{
204
	int i;
205
206
	for (i = start; i < stop; i++)
207
		if (bit_is_set(array, i))
208
			return true;
209
210
	return false;
211
}
212
213
/*
214
 * Event device type detection routine.
215
 * Derived from EvdevProbe() function of xf86-input-evdev driver
216
 */
217
static void
218
get_evdev_attrs(InputAttributes *attrs, const char *devicename)
219
{
220
	int fd, flags;
221
	bool has_keys, has_buttons, has_lmr;
222
	bool has_rel_axes, has_abs_axes, has_mt;
223
	unsigned long key_bits[NLONGS(KEY_CNT)];
224
	unsigned long rel_bits[NLONGS(REL_CNT)];
225
	unsigned long abs_bits[NLONGS(ABS_CNT)];
226
	struct input_id id;
227
	char name[80];
228
229
	flags = 0;
230
231
	fd = open(devicename, O_RDONLY | O_CLOEXEC);
232
	if (fd < 0)
233
		goto out;
234
	if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), name) < 0 ||
235
	    ioctl(fd, EVIOCGID, &id) < 0 ||
236
	    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) < 0 ||
237
	    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits) < 0 ||
238
	    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) {
239
		close(fd);
240
		goto out;
241
	}
242
	close(fd);
243
244
	*(strchrnul(name, ',')) = '\0'; /* strip name */
245
	attrs->product = strdup(name);
246
	asprintf(&attrs->usb_id, "%04x:%04x", id.vendor, id.product);
247
	asprintf(&attrs->vendor, "0x%04x", id.vendor);
248
249
	has_keys = bit_find(key_bits, 0, BTN_MISC);
250
	has_buttons = bit_find(key_bits, BTN_MISC, BTN_JOYSTICK);
251
	has_lmr = bit_find(key_bits, BTN_LEFT, BTN_MIDDLE);
252
	has_rel_axes = bit_find(rel_bits, 0, REL_MAX);
253
	has_abs_axes = bit_find(abs_bits, 0, ABS_MAX);
254
	has_mt = bit_find(abs_bits, ABS_MT_SLOT, ABS_MAX);
255
256
	if (has_abs_axes) {
257
		if (has_mt) {
258
			if (!has_buttons) {
259
				/*
260
				 * XXX: I'm not sure that joystick detection is
261
				 * done right. xf86-evdev does not support them.
262
				 */
263
				if (bit_is_set(key_bits, BTN_JOYSTICK)) {
264
					flags = ATTR_JOYSTICK;
265
					goto out;
266
				} else {
267
					has_buttons = true;
268
				}
269
			}
270
		}
271
272
		if (bit_is_set(abs_bits, ABS_X) &&
273
		    bit_is_set(abs_bits, ABS_Y)) {
274
			if (bit_is_set(key_bits, BTN_TOOL_PEN) ||
275
			    bit_is_set(key_bits, BTN_STYLUS) ||
276
			    bit_is_set(key_bits, BTN_STYLUS2)) {
277
				flags = ATTR_TABLET;
278
				goto out;
279
			} else if (bit_is_set(abs_bits, ABS_PRESSURE) ||
280
				   bit_is_set(key_bits, BTN_TOUCH)) {
281
				if (has_lmr ||
282
				    bit_is_set(key_bits, BTN_TOOL_FINGER)) {
283
					flags = ATTR_TOUCHPAD;
284
				} else {
285
					flags = ATTR_TOUCHSCREEN;
286
				}
287
				goto out;
288
			} else if (!(bit_is_set(rel_bits, REL_X) &&
289
				     bit_is_set(rel_bits, REL_Y)) &&
290
				    has_lmr) {
291
				/* some touchscreens use BTN_LEFT rather than BTN_TOUCH */
292
				flags = ATTR_TOUCHSCREEN;
293
				goto out;
294
			}
295
		}
296
	}
297
298
	if (has_keys)
299
		flags = ATTR_KEYBOARD;
300
	else if (has_rel_axes || has_abs_axes || has_buttons)
301
		flags = ATTR_POINTER;
302
303
out:
304
	attrs->flags |= flags;
305
}
306
307
/* Returns list of devices supporting evdev protocol */
308
static void
309
get_evdev_blacklist(struct dev_list *devs)
310
{
311
	struct dirent *entry;
312
	DIR *dp;
313
	static const char ev_dir[] = _PATH_DEV "input";
314
#define EV_LEN  nitems(ev_dir)
315
	char path[PATH_MAX + 1];
316
	char phys[80];
317
	int fd;
318
319
	snprintf(path, sizeof(path), "%s/", ev_dir);
320
	if ((dp = opendir(ev_dir)) == NULL)
321
		return;
322
323
	while ((entry = readdir(dp)) != NULL) {
324
		if (entry->d_type != DT_CHR)
325
			continue;
326
		if (strncmp(entry->d_name, "event", 5) != 0)
327
			continue;
328
		strlcpy(path + EV_LEN, entry->d_name, sizeof(path) - EV_LEN);
329
		fd = open(path, O_RDONLY | O_CLOEXEC);
330
		if (fd < 0)
331
			continue;
332
		/* XXX: Should uinput- and cuse-backed devices be skipped? */
333
		if (ioctl(fd, EVIOCGPHYS(sizeof(phys) - 1), phys) == 0 &&
334
		    phys[0] != 0)
335
			dev_list_insert(devs, bname(phys));
336
		close(fd);
337
	}
338
	closedir(dp);
339
	return;
340
}
341
342
static void
343
get_usb_id(char **pptr, int fd)
344
{
345
	unsigned short vendor;
346
	unsigned short product;
347
	unsigned int speed;
348
#define	WEBCAMD_IOCTL_GET_USB_VENDOR_ID _IOR('q', 250, unsigned short)
349
#define	WEBCAMD_IOCTL_GET_USB_PRODUCT_ID _IOR('q', 251, unsigned short)
350
#define	WEBCAMD_IOCTL_GET_USB_SPEED _IOR('q', 252, unsigned int)
351
	if (ioctl(fd, WEBCAMD_IOCTL_GET_USB_VENDOR_ID, &vendor) == 0 &&
352
	    ioctl(fd, WEBCAMD_IOCTL_GET_USB_PRODUCT_ID, &product) == 0 &&
353
	    ioctl(fd, WEBCAMD_IOCTL_GET_USB_SPEED, &speed) == 0) {
354
		if (asprintf(pptr, "%04x:%04x", vendor, product) == -1)
355
			*pptr = NULL;
356
	}
357
}
358
359
static char *
360
get_prop_value(const char *buf, const char *prop, size_t *len)
361
{
362
	char *prop_pos;
363
	size_t prop_len;
364
365
	prop_len = strlen(prop);
366
	prop_pos = strstr(buf, prop);
367
	if (prop_pos == NULL ||
368
	    (prop_pos != buf && prop_pos[-1] != ' ') ||
369
	    prop_pos[prop_len] != '=')
370
		return (NULL);
371
372
	*len = strchrnul(prop_pos + prop_len + 1, ' ') - prop_pos - prop_len - 1;
373
	return (prop_pos + prop_len + 1);
374
}
375
376
static void
377
get_sysctl_attrs(InputAttributes *attrs, const char* driver, int unit)
378
{
379
	char mib[32];
380
	char name[80], pnpinfo[1024], *pnp_id;
381
	const char *vendorstr, *prodstr, *devicestr;
382
	size_t len, vendorlen, prodlen, devicelen, pnplen;
383
	uint32_t product, vendor;
384
385
	snprintf(mib, sizeof(mib), "dev.%s.%d.%%desc", driver, unit);
386
	len = sizeof(name);
387
	if (sysctlbyname(mib, name, &len, NULL, 0) < 0)
388
		return;
389
	*(strchrnul(name, ',')) = '\0'; /* strip name */
390
	attrs->product = strdup(name);
391
392
	snprintf(mib, sizeof(mib), "dev.%s.%d.%%pnpinfo", driver, unit);
393
	len = sizeof(pnpinfo);
394
	if (sysctlbyname(mib, pnpinfo, &len, NULL, 0) < 0)
395
		return;
396
397
	vendorstr = get_prop_value(pnpinfo, "vendor", &vendorlen);
398
	prodstr = get_prop_value(pnpinfo, "product", &prodlen);
399
	devicestr = get_prop_value(pnpinfo, "device", &devicelen);
400
	pnp_id = get_prop_value(pnpinfo, "_HID", &pnplen);
401
	if (pnp_id != NULL && pnplen == 4 && strncmp(pnp_id, "none", 4) == 0)
402
		pnp_id = NULL;
403
	if (pnp_id != NULL) {
404
		pnp_id[pnplen] = '\0';
405
		attrs->pnp_id = strdup(pnp_id);
406
	}
407
	if (prodstr != NULL && vendorstr != NULL) {
408
		/* bus = BUS_USB; */
409
		vendor = strtol(vendorstr, NULL, 0);
410
		product = strtol(prodstr, NULL, 0);
411
	} else if (devicestr != NULL && vendorstr != NULL) {
412
		/* bus = BUS_PCI; */
413
		vendor = strtol(vendorstr, NULL, 0);
414
		product = strtol(devicestr, NULL, 0);
415
	} else
416
		return;
417
418
	asprintf(&attrs->usb_id, "%04x:%04x", vendor, product);
419
	asprintf(&attrs->vendor, "0x%04x", vendor);
420
421
	return;
422
}
423
424
static const char *
425
skip_path_dev(const char *ptr)
426
{
427
	if (strstr(ptr, _PATH_DEV) == ptr)
428
		ptr += strlen(_PATH_DEV);
429
	return (ptr);
430
}
431
432
static void
433
device_added(const char *devicename, struct dev_list *blacklist)
434
{
435
	InputAttributes attrs = { };
436
	InputOption *options = NULL;
437
	char *config_info = NULL;
438
	DeviceIntPtr dev = NULL;
439
	struct hw_type hw_type;
440
	int unit = 0;
441
	int fd = -1;
442
	int i;
443
	bool allow_no_device = false;
444
445
	for (i = 0; hw_types0[i].driver != NULL; i++) {
446
		if (strcmp(devicename, hw_types0[i].driver) == 0) {
447
			hw_type = hw_types0[i];
448
			goto found;
449
		}
450
	}
451
	for (i = 0; hw_types1[i].driver != NULL; i++) {
452
		if (sscanf(devicename, hw_types1[i].driver, &unit) == 1) {
453
			hw_type = hw_types1[i];
454
			goto found;
455
		}
456
	}
457
	goto ignore;
458
459
found:
460
	if (hw_type.xdriver == NULL)
461
		goto ignore;
462
463
	/* set flags, if any */
464
	attrs.flags |= hw_type.flag;
465
466
	if (strcmp(hw_type.xdriver, "evdev") == 0) {
467
		get_evdev_attrs(&attrs, devicename);
468
		/* Set keyboard rules explicitly for libinput */
469
		if (attrs.flags & ATTR_KEYBOARD) {
470
			options = input_option_new(options, "xkb_rules",
471
			    "evdev");
472
			if (options == NULL)
473
				goto error;
474
		}
475
	} else {
476
		if (is_kernel_evdev) {
477
			if (dev_list_empty(blacklist))
478
				get_evdev_blacklist(blacklist);
479
			/*
480
			 * Prefer evdev input kernel interface to native one.
481
			 * Assume that both evdev 'physical path' and non-evdev
482
			 * character device path endings are device names so
483
			 * we can compare them and skip latter.
484
			 */
485
			if (dev_list_search(blacklist, bname(devicename)))
486
				goto ignore;
487
		}
488
	}
489
490
	if (strcmp(hw_type.xdriver, "kbd") == 0) {
491
		bool match = (strstr(hw_type.driver,
492
		    _PATH_DEV "kbdmux") == hw_type.driver);
493
494
		if (is_kbdmux) {
495
			allow_no_device = true;
496
			if (!match)
497
				goto ignore;
498
		} else {
499
			if (match)
500
				goto ignore;
501
		}
502
	}
503
504
	options = input_option_new(options, "_source", "server/devd");
505
	if (options == NULL)
506
		goto error;
507
508
	if (hw_type.sysctldesc != NULL)
509
		get_sysctl_attrs(&attrs, hw_type.sysctldesc, unit);
510
511
	if (attrs.product == NULL)
512
		attrs.product = strdup(skip_path_dev(devicename));
513
514
	options = input_option_new(options, "name", attrs.product);
515
	if (options == NULL)
516
		goto error;
517
518
	attrs.device = strdup(devicename);
519
520
	fd = open(devicename, O_RDONLY);
521
	if (fd > -1) {
522
		if (attrs.usb_id == NULL)
523
			get_usb_id(&attrs.usb_id, fd);
524
		close(fd);
525
		options = input_option_new(options, "device", devicename);
526
		if (options == NULL)
527
			goto error;
528
	} else if (allow_no_device) {
529
		/*
530
		 * Don't pass "device" option if the keyboard is
531
		 * already attached to the console (ie. open() fails).
532
		 * This would activate a special logic in
533
		 * xf86-input-keyboard. Prevent any other attached to
534
		 * console keyboards being processed. There can be
535
		 * only one such device.
536
		 */
537
	} else {
538
		goto ignore;
539
	}
540
541
	options = input_option_new(options, "driver", hw_type.xdriver);
542
	if (options == NULL)
543
		goto error;
544
545
	if (asprintf(&config_info, "devd:%s",
546
	    skip_path_dev(devicename)) == -1) {
547
		config_info = NULL;
548
		goto error;
549
	}
550
551
	if (device_is_duplicate(config_info))
552
		goto duplicate;
553
554
	options = input_option_new(options, "config_info", config_info);
555
	if (options == NULL)
556
		goto error;
557
558
	LogMessage(X_INFO, "config/devd: adding input device '%s'\n",
559
	    devicename);
560
561
	NewInputDeviceRequest(options, &attrs, &dev);
562
	goto done;
563
564
duplicate:
565
	LogMessage(X_WARNING, "config/devd: device '%s' already "
566
	    "added. Ignoring\n", devicename);
567
	goto done;
568
569
error:
570
	LogMessage(X_INFO, "config/devd: error adding device '%s'\n",
571
	    devicename);
572
	goto done;
573
574
ignore:
575
	LogMessage(X_INFO, "config/devd: ignoring device '%s'\n",
576
	    devicename);
577
	goto done;
578
579
done:
580
	free(config_info);
581
	input_option_free_list(&options);
582
	free(attrs.usb_id);
583
	free(attrs.pnp_id);
584
	free(attrs.product);
585
	free(attrs.device);
586
	free(attrs.vendor);
587
}
588
589
static void
590
devpath_scan_sub(char *path, int off, int rem, void *udata)
591
{
592
	struct dirent *entry;
593
	DIR *dp;
594
595
	if ((dp = opendir(path)) == NULL) {
596
		LogMessage(X_INFO, "Cannot open directory '%s'\n", path);
597
		return;
598
	}
599
	while ((entry = readdir(dp)) != NULL) {
600
		int len = strlen(entry->d_name);
601
		if (len > rem)
602
			continue;
603
		strcpy(path + off, entry->d_name);
604
		off += len;
605
		rem -= len;
606
		switch (entry->d_type) {
607
		case DT_DIR:
608
			if (strcmp(entry->d_name, ".") == 0 ||
609
			    strcmp(entry->d_name, "..") == 0)
610
				break;
611
			if (rem < 1)
612
				break;
613
			path[off] = '/';
614
			path[off+1] = '\0';
615
			off++;
616
			rem--;
617
			/* recurse */
618
			devpath_scan_sub(path, off, rem, udata);
619
			off--;
620
			rem++;
621
			break;
622
		case DT_SOCK:
623
		case DT_FIFO:
624
		case DT_LNK:
625
		case DT_CHR:
626
			/* add device, if any */			
627
			device_added(path, udata);
628
			break;
629
		default:
630
			break;
631
		}
632
		off -= len;
633
		rem += len;
634
	}
635
	closedir(dp);
636
}
637
638
static void
639
devpath_scan(void *udata)
640
{
641
	char path[PATH_MAX + 1];
642
643
	strlcpy(path, _PATH_DEV, sizeof(path));
644
645
	devpath_scan_sub(path, strlen(path), PATH_MAX - strlen(path), udata);
646
}
647
648
static void
649
device_removed(char *devicename)
650
{
651
	char *config_info;
652
653
	if (asprintf(&config_info, "devd:%s",
654
	    skip_path_dev(devicename)) == -1)
655
		return;
656
657
	if (device_is_duplicate(config_info)) {
658
		LogMessage(X_INFO, "config/devd: removing input device '%s'\n",
659
		    devicename);
660
	}
661
	remove_devices("devd", config_info);
662
663
	free(config_info);
664
}
665
666
static bool is_kbdmux_enabled(void)
667
{
668
	/* Xorg uses /dev/ttyv0 as a console device */
669
	static const char device[]= { _PATH_DEV "ttyv0" };
670
	keyboard_info_t info;
671
	int fd;
672
673
	fd = open(device, O_RDONLY);
674
675
	if (fd < 0)
676
		return false;
677
678
	if (ioctl(fd, KDGKBINFO, &info) == -1) {
679
		close(fd);
680
		return false;
681
	}
682
683
	close(fd);
684
685
	if (!strncmp(info.kb_name, "kbdmux", 6))
686
		return true;
687
688
	return false;
689
}
690
691
static void
692
disconnect_devd(int sock)
693
{
694
	if (sock >= 0) {
695
		RemoveGeneralSocket(sock);
696
		close(sock);
697
	}
698
}
699
700
static int
701
connect_devd(void)
702
{
703
	struct sockaddr_un devd;
704
	int sock;
705
706
	sock = socket(AF_UNIX, SOCK_STREAM, 0);
707
	if (sock < 0) {
708
		LogMessage(X_ERROR, "config/devd: fail opening stream socket\n");
709
		return -1;
710
	}
711
712
	devd.sun_family = AF_UNIX;
713
	strlcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(devd.sun_path));
714
715
	if (connect(sock, (struct sockaddr *) &devd, sizeof(devd)) < 0) {
716
		close(sock);
717
		LogMessage(X_ERROR, "config/devd: fail to connect to devd\n");
718
		return -1;
719
	}
720
721
	AddGeneralSocket(sock);
722
723
	return	sock;
724
}
725
726
static CARD32
727
reconnect_handler(OsTimerPtr timer, CARD32 time, void *arg)
728
{
729
	int newsock;
730
731
	if ((newsock = connect_devd()) > 0) {
732
		sock_devd = newsock;
733
		TimerFree(rtimer);
734
		rtimer = NULL;
735
		LogMessage(X_INFO, "config/devd: reopening devd socket\n");
736
		return 0;
737
	}
738
739
	/* Try again after RECONNECT_DELAY */
740
	return RECONNECT_DELAY;
741
}
742
743
static ssize_t
744
socket_getline(int fd, char **out)
745
{
746
	char *buf, *newbuf;
747
	ssize_t ret, cap, sz = 0;
748
	char c;
749
750
	cap = 1024;
751
	buf = malloc(cap * sizeof(char));
752
	if (!buf)
753
		return -1;
754
755
	for (;;) {
756
		ret = read(sock_devd, &c, 1);
757
		if (ret < 0) {
758
			if (errno == EINTR)
759
				continue;
760
			free(buf);
761
			return -1;
762
		/* EOF - devd socket is lost */
763
		} else if (ret == 0) {
764
			disconnect_devd(sock_devd);
765
			rtimer = TimerSet(NULL, 0, 1, reconnect_handler, NULL);
766
			LogMessage(X_WARNING, "config/devd: devd socket is lost\n");
767
			return -1;
768
		}
769
		if (c == '\n')
770
			break;
771
772
		if (sz + 1 >= cap) {
773
			cap *= 2;
774
			newbuf = realloc(buf, cap * sizeof(char));
775
			if (!newbuf) {
776
				free(buf);
777
				return -1;
778
			}
779
			buf = newbuf;
780
		}
781
		buf[sz] = c;
782
		sz++;
783
	}
784
785
	buf[sz] = '\0';
786
	if (sz >= 0)
787
		*out = buf;
788
	else
789
		free(buf);
790
791
	/* Number of bytes in the line, not counting the line break */
792
	return sz;
793
}
794
795
static void
796
wakeup_handler(void *data, int err, void *read_mask)
797
{
798
	static const char cdev_create[] = { "!system=DEVFS subsystem=CDEV type=CREATE cdev=" };
799
	static const char cdev_destroy[] = { "!system=DEVFS subsystem=CDEV type=DESTROY cdev=" };
800
	static const char cdev_path[] = { _PATH_DEV };
801
	char *line = NULL;
802
	char *devicename;
803
	char *walk;
804
	struct dev_list blacklist;
805
806
	if (err < 0)
807
		return;
808
809
	if (FD_ISSET(sock_devd, (fd_set *) read_mask)) {
810
		if (socket_getline(sock_devd, &line) < 0)
811
			return;
812
		if (strstr(line, cdev_create) == line) {
813
			devicename = line + strlen(cdev_create) - strlen(cdev_path);
814
			memcpy(devicename, cdev_path, strlen(cdev_path));
815
			walk = strchr(devicename, ' ');
816
			if (walk != NULL)
817
				walk[0] = '\0';
818
			/* Blacklist is lazy-populated in device_added() */
819
			dev_list_init(&blacklist);
820
			device_added(devicename, &blacklist);
821
			dev_list_destroy(&blacklist);
822
		} else if (strstr(line, cdev_destroy) == line) {
823
			devicename = line + strlen(cdev_destroy) - strlen(cdev_path);
824
			memcpy(devicename, cdev_path, strlen(cdev_path));
825
			walk = strchr(devicename, ' ');
826
			if (walk != NULL)
827
				walk[0] = '\0';
828
			device_removed(devicename);
829
		}
830
		free(line);
831
	}
832
}
833
834
static void
835
block_handler(void *data, struct timeval **tv, void *read_mask)
836
{
837
}
838
839
int
840
config_devd_init(void)
841
{
842
	struct dev_list blacklist;
843
844
	LogMessage(X_INFO, "config/devd: probing input devices...\n");
845
846
	/* Blacklist is lazy-populated in device_added() */
847
        dev_list_init(&blacklist);
848
849
	/* Check if kbdmux is enabled */
850
	is_kbdmux = is_kbdmux_enabled();
851
852
	/* Check if evdev support is compiled into kernel */
853
	is_kernel_evdev = feature_present("evdev") != 0;
854
855
	/* Connect to devd, so that we don't loose any events */
856
	if ((sock_devd = connect_devd()) < 0)
857
		return 0;
858
859
	/* Scan what is currently connected */
860
	devpath_scan(&blacklist);
861
862
	/* Register wakeup handler */
863
	RegisterBlockAndWakeupHandlers(block_handler,
864
	    wakeup_handler, NULL);
865
866
        dev_list_destroy(&blacklist);
867
868
	return 1;
869
}
870
871
void
872
config_devd_fini(void)
873
{
874
	LogMessage(X_INFO, "config/devd: terminating backend...\n");
875
876
	if (rtimer) {
877
		TimerFree(rtimer);
878
		rtimer = NULL;
879
	}
880
881
	disconnect_devd(sock_devd);
882
883
	RemoveBlockAndWakeupHandlers(block_handler,
884
	    wakeup_handler, NULL);
885
}

Return to bug 196678