FreeBSD Bugzilla – Attachment 172378 Details for
Bug 196678
x11-servers/xorg-server: Update to 1.20.7 + make config/devd recognize /dev/input/eventX from multimedia/webcamd
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch-config_devd.c with device type autodetection
patch-config_devd.c (text/plain), 21.74 KB, created by
Vladimir Kondratyev
on 2016-07-11 13:05:43 UTC
(
hide
)
Description:
patch-config_devd.c with device type autodetection
Filename:
MIME Type:
Creator:
Vladimir Kondratyev
Created:
2016-07-11 13:05:43 UTC
Size:
21.74 KB
patch
obsolete
>--- /dev/null 2016-07-11 15:11:00.000000000 +0300 >+++ config/devd.c 2016-07-11 15:15:58.959332000 +0300 >@@ -0,0 +1,885 @@ >+/* >+ * Copyright (c) 2012 Baptiste Daroussin >+ * Copyright (c) 2013, 2014 Alex Kozlov >+ * Copyright (c) 2014 Robert Millan >+ * Copyright (c) 2014 Jean-Sebastien Pedron >+ * >+ * Permission is hereby granted, free of charge, to any person obtaining a >+ * copy of this software and associated documentation files (the "Software"), >+ * to deal in the Software without restriction, including without limitation >+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, >+ * and/or sell copies of the Software, and to permit persons to whom the >+ * Software is furnished to do so, subject to the following conditions: >+ * >+ * The above copyright notice and this permission notice (including the next >+ * paragraph) shall be included in all copies or substantial portions of the >+ * Software. >+ * >+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR >+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, >+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL >+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER >+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING >+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER >+ * DEALINGS IN THE SOFTWARE. >+ * >+ * Author: Baptiste Daroussin <bapt@FreeBSD.org> >+ */ >+ >+#ifdef HAVE_DIX_CONFIG_H >+#include <dix-config.h> >+#endif >+ >+#include <sys/param.h> >+#include <sys/ioccom.h> >+#include <sys/kbio.h> >+#include <sys/queue.h> >+#include <sys/socket.h> >+#include <sys/stat.h> >+#include <sys/sysctl.h> >+#include <sys/un.h> >+ >+#include <ctype.h> >+#include <dirent.h> >+#include <errno.h> >+#include <fcntl.h> >+#include <limits.h> >+#include <stddef.h> >+#include <stdlib.h> >+#include <stdio.h> >+#include <stdbool.h> >+#include <string.h> >+#include <unistd.h> >+#include <paths.h> >+ >+#include "input.h" >+#include "inputstr.h" >+#include "hotplug.h" >+#include "config-backends.h" >+#include "os.h" >+ >+#define DEVD_SOCK_PATH "/var/run/devd.pipe" >+ >+#define RECONNECT_DELAY (5 * 1000) >+ >+static int sock_devd; >+static bool is_kbdmux = false; >+static bool is_kernel_evdev = false; >+OsTimerPtr rtimer; >+ >+struct hw_type { >+ const char *driver; >+ int flag; >+ const char *xdriver; >+ const char *sysctldesc; >+}; >+ >+static const struct hw_type hw_types0[] = { >+ { _PATH_DEV "sysmouse", ATTR_POINTER, "mouse", NULL }, >+ { _PATH_DEV "vboxguest", ATTR_POINTER, "vboxmouse", NULL }, >+ { NULL, 0, NULL, NULL }, >+}; >+ >+static const struct hw_type hw_types1[] = { >+ { _PATH_DEV "ukbd%d", ATTR_KEYBOARD, "kbd", "ukbd" }, >+ { _PATH_DEV "atkbd%d", ATTR_KEYBOARD, "kbd", "atkbd" }, >+ { _PATH_DEV "kbdmux%d", ATTR_KEYBOARD, "kbd", NULL }, >+ { _PATH_DEV "ums%d", ATTR_POINTER, "mouse", "ums" }, >+ { _PATH_DEV "psm%d", ATTR_POINTER, "mouse", "psm" }, >+ { _PATH_DEV "joy%d", ATTR_JOYSTICK, "mouse", "joy" }, >+ { _PATH_DEV "atp%d", ATTR_TOUCHPAD, "mouse", "atp" }, >+ { _PATH_DEV "wsp%d", ATTR_TOUCHPAD, "mouse", "wsp" }, >+ { _PATH_DEV "uep%d", ATTR_TOUCHSCREEN, "mouse", "uep" }, >+ { _PATH_DEV "input/event%d", 0, "evdev", NULL }, >+ { NULL, 0, NULL, NULL }, >+}; >+ >+/* like basename() but returns a pointer to incoming string */ >+static char * >+bname(const char *path) >+{ >+ char *bname = NULL; >+ >+ if (path != NULL) >+ bname = strrchr(path, '/'); >+ return (bname == NULL) ? (char *)path : bname + 1; >+} >+ >+struct dev_entry { >+ SLIST_ENTRY(dev_entry) next; >+ char name[]; >+}; >+SLIST_HEAD(dev_list, dev_entry); >+ >+#define dev_list_init(dev_list) SLIST_INIT(dev_list) >+#define dev_list_empty(dev_list) SLIST_EMPTY(dev_list) >+ >+static void >+dev_list_insert(struct dev_list *devs, const char *devname) >+{ >+ struct dev_entry *dev; >+ >+ dev = malloc(offsetof(struct dev_entry, name) + strlen(devname) + 1); >+ if (dev != NULL) { >+ strcpy(dev->name, devname); >+ SLIST_INSERT_HEAD(devs, dev, next); >+ } >+} >+ >+static void >+dev_list_destroy(struct dev_list *devs) >+{ >+ struct dev_entry *dev; >+ >+ while (!SLIST_EMPTY(devs)) { >+ dev = SLIST_FIRST(devs); >+ SLIST_REMOVE_HEAD(devs, next); >+ free(dev); >+ } >+} >+ >+static bool >+dev_list_search(struct dev_list *devs, const char *devname) >+{ >+ struct dev_entry *dev; >+ >+ if (devname != NULL) >+ SLIST_FOREACH(dev, devs, next) >+ if (strcmp(devname, dev->name) == 0) >+ return true; >+ return false; >+} >+ >+/* Some definitions from linux/input.h */ >+struct input_id { >+ uint16_t bustype; >+ uint16_t vendor; >+ uint16_t product; >+ uint16_t version; >+}; >+ >+#define EVIOCGBIT(ev,len) _IOC(IOC_OUT, 'E', 0x20 + (ev), len) >+#define EVIOCGID _IOR('E', 0x02, struct input_id) >+#define EVIOCGNAME(len) _IOC(IOC_OUT, 'E', 0x06, len) >+#define EVIOCGPHYS(len) _IOC(IOC_OUT, 'E', 0x07, len) >+ >+#define EV_KEY 0x01 >+#define EV_REL 0x02 >+#define EV_ABS 0x03 >+#define BTN_MISC 0x100 >+#define BTN_LEFT 0x110 >+#define BTN_RIGHT 0x111 >+#define BTN_MIDDLE 0x112 >+#define BTN_JOYSTICK 0x120 >+#define BTN_TOOL_PEN 0x140 >+#define BTN_TOOL_FINGER 0x145 >+#define BTN_TOUCH 0x14a >+#define BTN_STYLUS 0x14b >+#define BTN_STYLUS2 0x14c >+#define KEY_MAX 0x2ff >+#define KEY_CNT (KEY_MAX+1) >+#define REL_X 0x00 >+#define REL_Y 0x01 >+#define REL_MAX 0x0f >+#define REL_CNT (REL_MAX+1) >+#define ABS_X 0x00 >+#define ABS_Y 0x01 >+#define ABS_PRESSURE 0x18 >+#define ABS_MT_SLOT 0x2f >+#define ABS_MAX 0x3f >+#define ABS_CNT (ABS_MAX+1) >+ >+#define LONG_BITS (sizeof(long) * 8) >+#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS) >+ >+static inline bool >+bit_is_set(const unsigned long *array, int bit) >+{ >+ return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS))); >+} >+ >+static inline bool >+bit_find(const unsigned long *array, int start, int stop) >+{ >+ int i; >+ >+ for (i = start; i < stop; i++) >+ if (bit_is_set(array, i)) >+ return true; >+ >+ return false; >+} >+ >+/* >+ * Event device type detection routine. >+ * Derived from EvdevProbe() function of xf86-input-evdev driver >+ */ >+static void >+get_evdev_attrs(InputAttributes *attrs, const char *devicename) >+{ >+ int fd, flags; >+ bool has_keys, has_buttons, has_lmr; >+ bool has_rel_axes, has_abs_axes, has_mt; >+ unsigned long key_bits[NLONGS(KEY_CNT)]; >+ unsigned long rel_bits[NLONGS(REL_CNT)]; >+ unsigned long abs_bits[NLONGS(ABS_CNT)]; >+ struct input_id id; >+ char name[80]; >+ >+ flags = 0; >+ >+ fd = open(devicename, O_RDONLY | O_CLOEXEC); >+ if (fd < 0) >+ goto out; >+ if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), name) < 0 || >+ ioctl(fd, EVIOCGID, &id) < 0 || >+ ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) < 0 || >+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits) < 0 || >+ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0) { >+ close(fd); >+ goto out; >+ } >+ close(fd); >+ >+ *(strchrnul(name, ',')) = '\0'; /* strip name */ >+ attrs->product = strdup(name); >+ asprintf(&attrs->usb_id, "%04x:%04x", id.vendor, id.product); >+ asprintf(&attrs->vendor, "0x%04x", id.vendor); >+ >+ has_keys = bit_find(key_bits, 0, BTN_MISC); >+ has_buttons = bit_find(key_bits, BTN_MISC, BTN_JOYSTICK); >+ has_lmr = bit_find(key_bits, BTN_LEFT, BTN_MIDDLE); >+ has_rel_axes = bit_find(rel_bits, 0, REL_MAX); >+ has_abs_axes = bit_find(abs_bits, 0, ABS_MAX); >+ has_mt = bit_find(abs_bits, ABS_MT_SLOT, ABS_MAX); >+ >+ if (has_abs_axes) { >+ if (has_mt) { >+ if (!has_buttons) { >+ /* >+ * XXX: I'm not sure that joystick detection is >+ * done right. xf86-evdev does not support them. >+ */ >+ if (bit_is_set(key_bits, BTN_JOYSTICK)) { >+ flags = ATTR_JOYSTICK; >+ goto out; >+ } else { >+ has_buttons = true; >+ } >+ } >+ } >+ >+ if (bit_is_set(abs_bits, ABS_X) && >+ bit_is_set(abs_bits, ABS_Y)) { >+ if (bit_is_set(key_bits, BTN_TOOL_PEN) || >+ bit_is_set(key_bits, BTN_STYLUS) || >+ bit_is_set(key_bits, BTN_STYLUS2)) { >+ flags = ATTR_TABLET; >+ goto out; >+ } else if (bit_is_set(abs_bits, ABS_PRESSURE) || >+ bit_is_set(key_bits, BTN_TOUCH)) { >+ if (has_lmr || >+ bit_is_set(key_bits, BTN_TOOL_FINGER)) { >+ flags = ATTR_TOUCHPAD; >+ } else { >+ flags = ATTR_TOUCHSCREEN; >+ } >+ goto out; >+ } else if (!(bit_is_set(rel_bits, REL_X) && >+ bit_is_set(rel_bits, REL_Y)) && >+ has_lmr) { >+ /* some touchscreens use BTN_LEFT rather than BTN_TOUCH */ >+ flags = ATTR_TOUCHSCREEN; >+ goto out; >+ } >+ } >+ } >+ >+ if (has_keys) >+ flags = ATTR_KEYBOARD; >+ else if (has_rel_axes || has_abs_axes || has_buttons) >+ flags = ATTR_POINTER; >+ >+out: >+ attrs->flags |= flags; >+} >+ >+/* Returns list of devices supporting evdev protocol */ >+static void >+get_evdev_blacklist(struct dev_list *devs) >+{ >+ struct dirent *entry; >+ DIR *dp; >+ static const char ev_dir[] = _PATH_DEV "input"; >+#define EV_LEN nitems(ev_dir) >+ char path[PATH_MAX + 1]; >+ char phys[80]; >+ int fd; >+ >+ snprintf(path, sizeof(path), "%s/", ev_dir); >+ if ((dp = opendir(ev_dir)) == NULL) >+ return; >+ >+ while ((entry = readdir(dp)) != NULL) { >+ if (entry->d_type != DT_CHR) >+ continue; >+ if (strncmp(entry->d_name, "event", 5) != 0) >+ continue; >+ strlcpy(path + EV_LEN, entry->d_name, sizeof(path) - EV_LEN); >+ fd = open(path, O_RDONLY | O_CLOEXEC); >+ if (fd < 0) >+ continue; >+ /* XXX: Should uinput- and cuse-backed devices be skipped? */ >+ if (ioctl(fd, EVIOCGPHYS(sizeof(phys) - 1), phys) == 0 && >+ phys[0] != 0) >+ dev_list_insert(devs, bname(phys)); >+ close(fd); >+ } >+ closedir(dp); >+ return; >+} >+ >+static void >+get_usb_id(char **pptr, int fd) >+{ >+ unsigned short vendor; >+ unsigned short product; >+ unsigned int speed; >+#define WEBCAMD_IOCTL_GET_USB_VENDOR_ID _IOR('q', 250, unsigned short) >+#define WEBCAMD_IOCTL_GET_USB_PRODUCT_ID _IOR('q', 251, unsigned short) >+#define WEBCAMD_IOCTL_GET_USB_SPEED _IOR('q', 252, unsigned int) >+ if (ioctl(fd, WEBCAMD_IOCTL_GET_USB_VENDOR_ID, &vendor) == 0 && >+ ioctl(fd, WEBCAMD_IOCTL_GET_USB_PRODUCT_ID, &product) == 0 && >+ ioctl(fd, WEBCAMD_IOCTL_GET_USB_SPEED, &speed) == 0) { >+ if (asprintf(pptr, "%04x:%04x", vendor, product) == -1) >+ *pptr = NULL; >+ } >+} >+ >+static char * >+get_prop_value(const char *buf, const char *prop, size_t *len) >+{ >+ char *prop_pos; >+ size_t prop_len; >+ >+ prop_len = strlen(prop); >+ prop_pos = strstr(buf, prop); >+ if (prop_pos == NULL || >+ (prop_pos != buf && prop_pos[-1] != ' ') || >+ prop_pos[prop_len] != '=') >+ return (NULL); >+ >+ *len = strchrnul(prop_pos + prop_len + 1, ' ') - prop_pos - prop_len - 1; >+ return (prop_pos + prop_len + 1); >+} >+ >+static void >+get_sysctl_attrs(InputAttributes *attrs, const char* driver, int unit) >+{ >+ char mib[32]; >+ char name[80], pnpinfo[1024], *pnp_id; >+ const char *vendorstr, *prodstr, *devicestr; >+ size_t len, vendorlen, prodlen, devicelen, pnplen; >+ uint32_t product, vendor; >+ >+ snprintf(mib, sizeof(mib), "dev.%s.%d.%%desc", driver, unit); >+ len = sizeof(name); >+ if (sysctlbyname(mib, name, &len, NULL, 0) < 0) >+ return; >+ *(strchrnul(name, ',')) = '\0'; /* strip name */ >+ attrs->product = strdup(name); >+ >+ snprintf(mib, sizeof(mib), "dev.%s.%d.%%pnpinfo", driver, unit); >+ len = sizeof(pnpinfo); >+ if (sysctlbyname(mib, pnpinfo, &len, NULL, 0) < 0) >+ return; >+ >+ vendorstr = get_prop_value(pnpinfo, "vendor", &vendorlen); >+ prodstr = get_prop_value(pnpinfo, "product", &prodlen); >+ devicestr = get_prop_value(pnpinfo, "device", &devicelen); >+ pnp_id = get_prop_value(pnpinfo, "_HID", &pnplen); >+ if (pnp_id != NULL && pnplen == 4 && strncmp(pnp_id, "none", 4) == 0) >+ pnp_id = NULL; >+ if (pnp_id != NULL) { >+ pnp_id[pnplen] = '\0'; >+ attrs->pnp_id = strdup(pnp_id); >+ } >+ if (prodstr != NULL && vendorstr != NULL) { >+ /* bus = BUS_USB; */ >+ vendor = strtol(vendorstr, NULL, 0); >+ product = strtol(prodstr, NULL, 0); >+ } else if (devicestr != NULL && vendorstr != NULL) { >+ /* bus = BUS_PCI; */ >+ vendor = strtol(vendorstr, NULL, 0); >+ product = strtol(devicestr, NULL, 0); >+ } else >+ return; >+ >+ asprintf(&attrs->usb_id, "%04x:%04x", vendor, product); >+ asprintf(&attrs->vendor, "0x%04x", vendor); >+ >+ return; >+} >+ >+static const char * >+skip_path_dev(const char *ptr) >+{ >+ if (strstr(ptr, _PATH_DEV) == ptr) >+ ptr += strlen(_PATH_DEV); >+ return (ptr); >+} >+ >+static void >+device_added(const char *devicename, struct dev_list *blacklist) >+{ >+ InputAttributes attrs = { }; >+ InputOption *options = NULL; >+ char *config_info = NULL; >+ DeviceIntPtr dev = NULL; >+ struct hw_type hw_type; >+ int unit = 0; >+ int fd = -1; >+ int i; >+ bool allow_no_device = false; >+ >+ for (i = 0; hw_types0[i].driver != NULL; i++) { >+ if (strcmp(devicename, hw_types0[i].driver) == 0) { >+ hw_type = hw_types0[i]; >+ goto found; >+ } >+ } >+ for (i = 0; hw_types1[i].driver != NULL; i++) { >+ if (sscanf(devicename, hw_types1[i].driver, &unit) == 1) { >+ hw_type = hw_types1[i]; >+ goto found; >+ } >+ } >+ goto ignore; >+ >+found: >+ if (hw_type.xdriver == NULL) >+ goto ignore; >+ >+ /* set flags, if any */ >+ attrs.flags |= hw_type.flag; >+ >+ if (strcmp(hw_type.xdriver, "evdev") == 0) { >+ get_evdev_attrs(&attrs, devicename); >+ /* Set keyboard rules explicitly for libinput */ >+ if (attrs.flags & ATTR_KEYBOARD) { >+ options = input_option_new(options, "xkb_rules", >+ "evdev"); >+ if (options == NULL) >+ goto error; >+ } >+ } else { >+ if (is_kernel_evdev) { >+ if (dev_list_empty(blacklist)) >+ get_evdev_blacklist(blacklist); >+ /* >+ * Prefer evdev input kernel interface to native one. >+ * Assume that both evdev 'physical path' and non-evdev >+ * character device path endings are device names so >+ * we can compare them and skip latter. >+ */ >+ if (dev_list_search(blacklist, bname(devicename))) >+ goto ignore; >+ } >+ } >+ >+ if (strcmp(hw_type.xdriver, "kbd") == 0) { >+ bool match = (strstr(hw_type.driver, >+ _PATH_DEV "kbdmux") == hw_type.driver); >+ >+ if (is_kbdmux) { >+ allow_no_device = true; >+ if (!match) >+ goto ignore; >+ } else { >+ if (match) >+ goto ignore; >+ } >+ } >+ >+ options = input_option_new(options, "_source", "server/devd"); >+ if (options == NULL) >+ goto error; >+ >+ if (hw_type.sysctldesc != NULL) >+ get_sysctl_attrs(&attrs, hw_type.sysctldesc, unit); >+ >+ if (attrs.product == NULL) >+ attrs.product = strdup(skip_path_dev(devicename)); >+ >+ options = input_option_new(options, "name", attrs.product); >+ if (options == NULL) >+ goto error; >+ >+ attrs.device = strdup(devicename); >+ >+ fd = open(devicename, O_RDONLY); >+ if (fd > -1) { >+ if (attrs.usb_id == NULL) >+ get_usb_id(&attrs.usb_id, fd); >+ close(fd); >+ options = input_option_new(options, "device", devicename); >+ if (options == NULL) >+ goto error; >+ } else if (allow_no_device) { >+ /* >+ * Don't pass "device" option if the keyboard is >+ * already attached to the console (ie. open() fails). >+ * This would activate a special logic in >+ * xf86-input-keyboard. Prevent any other attached to >+ * console keyboards being processed. There can be >+ * only one such device. >+ */ >+ } else { >+ goto ignore; >+ } >+ >+ options = input_option_new(options, "driver", hw_type.xdriver); >+ if (options == NULL) >+ goto error; >+ >+ if (asprintf(&config_info, "devd:%s", >+ skip_path_dev(devicename)) == -1) { >+ config_info = NULL; >+ goto error; >+ } >+ >+ if (device_is_duplicate(config_info)) >+ goto duplicate; >+ >+ options = input_option_new(options, "config_info", config_info); >+ if (options == NULL) >+ goto error; >+ >+ LogMessage(X_INFO, "config/devd: adding input device '%s'\n", >+ devicename); >+ >+ NewInputDeviceRequest(options, &attrs, &dev); >+ goto done; >+ >+duplicate: >+ LogMessage(X_WARNING, "config/devd: device '%s' already " >+ "added. Ignoring\n", devicename); >+ goto done; >+ >+error: >+ LogMessage(X_INFO, "config/devd: error adding device '%s'\n", >+ devicename); >+ goto done; >+ >+ignore: >+ LogMessage(X_INFO, "config/devd: ignoring device '%s'\n", >+ devicename); >+ goto done; >+ >+done: >+ free(config_info); >+ input_option_free_list(&options); >+ free(attrs.usb_id); >+ free(attrs.pnp_id); >+ free(attrs.product); >+ free(attrs.device); >+ free(attrs.vendor); >+} >+ >+static void >+devpath_scan_sub(char *path, int off, int rem, void *udata) >+{ >+ struct dirent *entry; >+ DIR *dp; >+ >+ if ((dp = opendir(path)) == NULL) { >+ LogMessage(X_INFO, "Cannot open directory '%s'\n", path); >+ return; >+ } >+ while ((entry = readdir(dp)) != NULL) { >+ int len = strlen(entry->d_name); >+ if (len > rem) >+ continue; >+ strcpy(path + off, entry->d_name); >+ off += len; >+ rem -= len; >+ switch (entry->d_type) { >+ case DT_DIR: >+ if (strcmp(entry->d_name, ".") == 0 || >+ strcmp(entry->d_name, "..") == 0) >+ break; >+ if (rem < 1) >+ break; >+ path[off] = '/'; >+ path[off+1] = '\0'; >+ off++; >+ rem--; >+ /* recurse */ >+ devpath_scan_sub(path, off, rem, udata); >+ off--; >+ rem++; >+ break; >+ case DT_SOCK: >+ case DT_FIFO: >+ case DT_LNK: >+ case DT_CHR: >+ /* add device, if any */ >+ device_added(path, udata); >+ break; >+ default: >+ break; >+ } >+ off -= len; >+ rem += len; >+ } >+ closedir(dp); >+} >+ >+static void >+devpath_scan(void *udata) >+{ >+ char path[PATH_MAX + 1]; >+ >+ strlcpy(path, _PATH_DEV, sizeof(path)); >+ >+ devpath_scan_sub(path, strlen(path), PATH_MAX - strlen(path), udata); >+} >+ >+static void >+device_removed(char *devicename) >+{ >+ char *config_info; >+ >+ if (asprintf(&config_info, "devd:%s", >+ skip_path_dev(devicename)) == -1) >+ return; >+ >+ if (device_is_duplicate(config_info)) { >+ LogMessage(X_INFO, "config/devd: removing input device '%s'\n", >+ devicename); >+ } >+ remove_devices("devd", config_info); >+ >+ free(config_info); >+} >+ >+static bool is_kbdmux_enabled(void) >+{ >+ /* Xorg uses /dev/ttyv0 as a console device */ >+ static const char device[]= { _PATH_DEV "ttyv0" }; >+ keyboard_info_t info; >+ int fd; >+ >+ fd = open(device, O_RDONLY); >+ >+ if (fd < 0) >+ return false; >+ >+ if (ioctl(fd, KDGKBINFO, &info) == -1) { >+ close(fd); >+ return false; >+ } >+ >+ close(fd); >+ >+ if (!strncmp(info.kb_name, "kbdmux", 6)) >+ return true; >+ >+ return false; >+} >+ >+static void >+disconnect_devd(int sock) >+{ >+ if (sock >= 0) { >+ RemoveGeneralSocket(sock); >+ close(sock); >+ } >+} >+ >+static int >+connect_devd(void) >+{ >+ struct sockaddr_un devd; >+ int sock; >+ >+ sock = socket(AF_UNIX, SOCK_STREAM, 0); >+ if (sock < 0) { >+ LogMessage(X_ERROR, "config/devd: fail opening stream socket\n"); >+ return -1; >+ } >+ >+ devd.sun_family = AF_UNIX; >+ strlcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(devd.sun_path)); >+ >+ if (connect(sock, (struct sockaddr *) &devd, sizeof(devd)) < 0) { >+ close(sock); >+ LogMessage(X_ERROR, "config/devd: fail to connect to devd\n"); >+ return -1; >+ } >+ >+ AddGeneralSocket(sock); >+ >+ return sock; >+} >+ >+static CARD32 >+reconnect_handler(OsTimerPtr timer, CARD32 time, void *arg) >+{ >+ int newsock; >+ >+ if ((newsock = connect_devd()) > 0) { >+ sock_devd = newsock; >+ TimerFree(rtimer); >+ rtimer = NULL; >+ LogMessage(X_INFO, "config/devd: reopening devd socket\n"); >+ return 0; >+ } >+ >+ /* Try again after RECONNECT_DELAY */ >+ return RECONNECT_DELAY; >+} >+ >+static ssize_t >+socket_getline(int fd, char **out) >+{ >+ char *buf, *newbuf; >+ ssize_t ret, cap, sz = 0; >+ char c; >+ >+ cap = 1024; >+ buf = malloc(cap * sizeof(char)); >+ if (!buf) >+ return -1; >+ >+ for (;;) { >+ ret = read(sock_devd, &c, 1); >+ if (ret < 0) { >+ if (errno == EINTR) >+ continue; >+ free(buf); >+ return -1; >+ /* EOF - devd socket is lost */ >+ } else if (ret == 0) { >+ disconnect_devd(sock_devd); >+ rtimer = TimerSet(NULL, 0, 1, reconnect_handler, NULL); >+ LogMessage(X_WARNING, "config/devd: devd socket is lost\n"); >+ return -1; >+ } >+ if (c == '\n') >+ break; >+ >+ if (sz + 1 >= cap) { >+ cap *= 2; >+ newbuf = realloc(buf, cap * sizeof(char)); >+ if (!newbuf) { >+ free(buf); >+ return -1; >+ } >+ buf = newbuf; >+ } >+ buf[sz] = c; >+ sz++; >+ } >+ >+ buf[sz] = '\0'; >+ if (sz >= 0) >+ *out = buf; >+ else >+ free(buf); >+ >+ /* Number of bytes in the line, not counting the line break */ >+ return sz; >+} >+ >+static void >+wakeup_handler(void *data, int err, void *read_mask) >+{ >+ static const char cdev_create[] = { "!system=DEVFS subsystem=CDEV type=CREATE cdev=" }; >+ static const char cdev_destroy[] = { "!system=DEVFS subsystem=CDEV type=DESTROY cdev=" }; >+ static const char cdev_path[] = { _PATH_DEV }; >+ char *line = NULL; >+ char *devicename; >+ char *walk; >+ struct dev_list blacklist; >+ >+ if (err < 0) >+ return; >+ >+ if (FD_ISSET(sock_devd, (fd_set *) read_mask)) { >+ if (socket_getline(sock_devd, &line) < 0) >+ return; >+ if (strstr(line, cdev_create) == line) { >+ devicename = line + strlen(cdev_create) - strlen(cdev_path); >+ memcpy(devicename, cdev_path, strlen(cdev_path)); >+ walk = strchr(devicename, ' '); >+ if (walk != NULL) >+ walk[0] = '\0'; >+ /* Blacklist is lazy-populated in device_added() */ >+ dev_list_init(&blacklist); >+ device_added(devicename, &blacklist); >+ dev_list_destroy(&blacklist); >+ } else if (strstr(line, cdev_destroy) == line) { >+ devicename = line + strlen(cdev_destroy) - strlen(cdev_path); >+ memcpy(devicename, cdev_path, strlen(cdev_path)); >+ walk = strchr(devicename, ' '); >+ if (walk != NULL) >+ walk[0] = '\0'; >+ device_removed(devicename); >+ } >+ free(line); >+ } >+} >+ >+static void >+block_handler(void *data, struct timeval **tv, void *read_mask) >+{ >+} >+ >+int >+config_devd_init(void) >+{ >+ struct dev_list blacklist; >+ >+ LogMessage(X_INFO, "config/devd: probing input devices...\n"); >+ >+ /* Blacklist is lazy-populated in device_added() */ >+ dev_list_init(&blacklist); >+ >+ /* Check if kbdmux is enabled */ >+ is_kbdmux = is_kbdmux_enabled(); >+ >+ /* Check if evdev support is compiled into kernel */ >+ is_kernel_evdev = feature_present("evdev") != 0; >+ >+ /* Connect to devd, so that we don't loose any events */ >+ if ((sock_devd = connect_devd()) < 0) >+ return 0; >+ >+ /* Scan what is currently connected */ >+ devpath_scan(&blacklist); >+ >+ /* Register wakeup handler */ >+ RegisterBlockAndWakeupHandlers(block_handler, >+ wakeup_handler, NULL); >+ >+ dev_list_destroy(&blacklist); >+ >+ return 1; >+} >+ >+void >+config_devd_fini(void) >+{ >+ LogMessage(X_INFO, "config/devd: terminating backend...\n"); >+ >+ if (rtimer) { >+ TimerFree(rtimer); >+ rtimer = NULL; >+ } >+ >+ disconnect_devd(sock_devd); >+ >+ RemoveBlockAndWakeupHandlers(block_handler, >+ wakeup_handler, NULL); >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 196678
:
151548
|
151549
|
160696
|
160697
|
161034
|
161035
|
166727
|
167354
|
167426
|
167594
|
172378
|
175616
|
179892
|
180700
|
180710
|
180880
|
191592
|
195909
|
196037
|
197417
|
198703
|
203086
|
209380
|
211620
|
211740
|
211748
|
211749
|
211907