--- x11-servers/xorg-server/files/patch-config_devd.c +++ x11-servers/xorg-server/files/patch-config_devd.c @@ -1,6 +1,6 @@ ---- config/devd.c.orig 2014-12-16 23:03:10 UTC -+++ config/devd.c -@@ -0,0 +1,530 @@ +--- config/devd.c 2015-01-12 10:47:19.000000000 +0100 ++++ config/devd.c 2015-01-13 12:02:22.000000000 +0100 +@@ -0,0 +1,574 @@ +/* + * Copyright (c) 2012 Baptiste Daroussin + * Copyright (c) 2013, 2014 Alex Kozlov @@ -41,12 +41,14 @@ +#include + +#include ++#include +#include +#include +#include +#include +#include +#include ++#include + +#include "input.h" +#include "inputstr.h" @@ -56,13 +58,9 @@ + +#define DEVD_SOCK_PATH "/var/run/devd.pipe" + -+#define DEVD_EVENT_ADD '+' -+#define DEVD_EVENT_REMOVE '-' -+ -+#define RECONNECT_DELAY 5 * 1000 ++#define RECONNECT_DELAY (5 * 1000) + +static int sock_devd; -+static bool is_console_kbd = false; +static bool is_kbdmux = false; +OsTimerPtr rtimer; + @@ -70,70 +68,51 @@ + const char *driver; + int flag; + const char *xdriver; ++ const char *sysctldesc; +}; + -+static struct hw_type hw_types[] = { -+ { "ukbd", ATTR_KEYBOARD, "kbd" }, -+ { "atkbd", ATTR_KEYBOARD, "kbd" }, -+ { "kbdmux", ATTR_KEYBOARD, "kbd" }, -+ { "sysmouse", ATTR_POINTER, "mouse" }, -+ { "ums", ATTR_POINTER, "mouse" }, -+ { "psm", ATTR_POINTER, "mouse" }, -+ { "joy", ATTR_JOYSTICK, NULL }, -+ { "atp", ATTR_TOUCHPAD, NULL }, -+ { "uep", ATTR_TOUCHSCREEN, NULL }, -+ { NULL, -1, NULL }, ++static const struct hw_type hw_types0[] = { ++ { _PATH_DEV "sysmouse", ATTR_POINTER, "mouse", NULL }, ++ { NULL, 0, NULL, NULL }, +}; + -+static bool -+sysctl_exists(const struct hw_type *device, int unit, -+ char *devname, size_t devname_len) -+{ -+ char sysctlname[PATH_MAX]; -+ size_t len; -+ int ret; -+ -+ if (device == NULL || device->driver == NULL) -+ return false; -+ -+ /* Check if a sysctl exists. */ -+ snprintf(sysctlname, sizeof(sysctlname), "dev.%s.%i.%%desc", -+ device->driver, unit); -+ ret = sysctlbyname(sysctlname, NULL, &len, NULL, 0); ++static const struct hw_type hw_types1[] = { ++ { _PATH_DEV "ukbd%d", ATTR_KEYBOARD, "kbd", "dev.ukbd.%d.%%desc" }, ++ { _PATH_DEV "atkbd%d", ATTR_KEYBOARD, "kbd", "dev.atkbd.%d.%%desc" }, ++ { _PATH_DEV "kbdmux%d", ATTR_KEYBOARD, "kbd", NULL }, ++ { _PATH_DEV "ums%d", ATTR_POINTER, "mouse", "dev.ums.%d.%%desc" }, ++ { _PATH_DEV "psm%d", ATTR_POINTER, "mouse", "dev.psm.%d.%%desc" }, ++ { _PATH_DEV "joy%d", ATTR_JOYSTICK, "mouse", "dev.joy.%d.%%desc" }, ++ { _PATH_DEV "atp%d", ATTR_TOUCHPAD, "mouse", "dev.atp.%d.%%desc" }, ++ { _PATH_DEV "wsp%d", ATTR_TOUCHPAD, "mouse", "dev.wsp.%d.%%desc" }, ++ { _PATH_DEV "uep%d", ATTR_TOUCHSCREEN, "mouse", "dev.uep.%d.%%desc" }, ++ { _PATH_DEV "input/event%d", ATTR_TOUCHPAD, "evdev", NULL}, ++ { NULL, 0, NULL, NULL }, ++}; + -+ if (ret == 0 && len > 0) { -+ snprintf(devname, devname_len, "%s%i", device->driver, unit); -+ return true; ++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; + } -+ -+ return false; +} + -+static bool -+devpath_exists(const struct hw_type *device, -+ char *devname, size_t devname_len) -+{ -+ char *devpath; -+ struct stat st; -+ int ret; -+ -+ if (device == NULL || device->driver == NULL) -+ return false; -+ -+ /* Check if /dev/$driver exists. */ -+ asprintf(&devpath, "/dev/%s", device->driver); -+ if (devpath == NULL) -+ return false; -+ -+ ret = stat(devpath, &st); -+ free(devpath); -+ -+ if (ret == 0) { -+ strncpy(devname, device->driver, devname_len); -+ return true; -+ } -+ -+ return false; ++static const char * ++skip_path_dev(const char *ptr) ++{ ++ if (strstr(ptr, _PATH_DEV) == ptr) ++ ptr += strlen(_PATH_DEV); ++ return (ptr); +} + +static char * @@ -161,58 +140,66 @@ +} + +static void -+device_added(const char *devname) ++device_added(const char *devicename, bool allow_no_device) +{ -+ char path[PATH_MAX]; -+ char sysctlname[PATH_MAX]; -+ char *vendor; -+ char *product = NULL; -+ char *config_info = NULL; -+ char *walk; -+ InputOption *options = NULL; + InputAttributes attrs = { }; ++ InputOption *options = NULL; ++ char *config_info = NULL; + DeviceIntPtr dev = NULL; ++ struct hw_type hw_type; ++ char *product = NULL; ++ char sysctlname[64]; ++ char *vendor = NULL; ++ int unit = 0; ++ int fd = -1; ++ char *walk; + int i; -+ int fd; -+ -+ for (i = 0; hw_types[i].driver != NULL; i++) { -+ size_t len; + -+ len = strlen(hw_types[i].driver); -+ if (strcmp(devname, hw_types[i].driver) == 0 || -+ (strncmp(devname, hw_types[i].driver, len) == 0 && -+ isnumber(*(devname + len)))) { -+ attrs.flags |= hw_types[i].flag; -+ break; ++ for (i = 0; hw_types0[i].driver != NULL; i++) { ++ if (strcmp(devicename, hw_types0[i].driver) == 0) { ++ hw_type = hw_types0[i]; ++ goto found; + } + } -+ -+ if (hw_types[i].driver == NULL || hw_types[i].xdriver == NULL) { -+ LogMessage(X_INFO, "config/devd: ignoring device %s\n", -+ devname); -+ return; ++ 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; + -+ /* Skip keyboard devices if kbdmux is enabled */ -+ if (is_kbdmux && is_console_kbd && hw_types[i].flag & ATTR_KEYBOARD) { -+ LogMessage(X_INFO, "config/devd: kbdmux is enabled, ignoring device %s\n", -+ devname); -+ return; ++found: ++ if (hw_type.xdriver == NULL) ++ goto ignore; ++ ++ if (strcmp(hw_type.xdriver, "kbd") == 0) { ++ bool match = (strstr(hw_type.driver, ++ _PATH_DEV "kbdmux") == hw_type.driver); ++ ++ if (is_kbdmux) { ++ if (!match) ++ goto ignore; ++ } else { ++ if (match) ++ goto ignore; ++ } + } + -+ snprintf(path, sizeof(path), "/dev/%s", devname); -+ + options = input_option_new(NULL, "_source", "server/devd"); -+ if (!options) -+ return; ++ if (options == NULL) ++ goto error; + -+ snprintf(sysctlname, sizeof(sysctlname), "dev.%s.%s.%%desc", -+ hw_types[i].driver, devname + strlen(hw_types[i].driver)); -+ vendor = sysctl_get_str(sysctlname); -+ if (vendor == NULL) { -+ options = input_option_new(options, "name", devname); ++ if (hw_type.sysctldesc != NULL) { ++ snprintf(sysctlname, sizeof(sysctlname), ++ hw_type.sysctldesc, unit); ++ vendor = sysctl_get_str(sysctlname); + } -+ else { ++ ++ if (vendor == NULL) { ++ options = input_option_new(options, "name", ++ skip_path_dev(devicename)); ++ } else { + if ((walk = strchr(vendor, ' ')) != NULL) { + walk[0] = '\0'; + walk++; @@ -222,93 +209,157 @@ + } + + attrs.vendor = strdup(vendor); -+ if (product) { ++ if (product != NULL) { + attrs.product = strdup(product); -+ options = input_option_new(options, "name", product); ++ options = input_option_new(options, ++ "name", product); ++ } else { ++ options = input_option_new(options, ++ "name", "Unknown"); + } -+ else -+ options = input_option_new(options, "name", "(unnamed)"); -+ -+ free(vendor); + } ++ attrs.device = strdup(devicename); + -+ /* XXX implement usb_id */ -+ attrs.usb_id = NULL; -+ attrs.device = strdup(path); -+ options = input_option_new(options, "driver", hw_types[i].xdriver); -+ -+ fd = open(path, O_RDONLY); -+ if (fd > 0) { ++ fd = open(devicename, O_RDONLY); ++ if (fd > -1) { ++ get_usb_id(&attrs.usb_id, fd); + close(fd); -+ options = input_option_new(options, "device", path); -+ } -+ else { -+ if (attrs.flags & ~ATTR_KEYBOARD) { -+ LogMessage(X_INFO, "config/devd: device %s already opened\n", -+ path); -+ -+ /* -+ * Fail if cannot open device, it breaks AllowMouseOpenFail, -+ * but it should not matter when config/devd enabled -+ */ -+ goto unwind; -+ } -+ -+ if (is_console_kbd) { -+ /* -+ * There can be only one keyboard attached to console and -+ * it is already added. -+ */ -+ LogMessage(X_WARNING, "config/devd: console keyboard is " -+ "already added, ignoring %s (%s)\n", -+ attrs.product, path); -+ goto unwind; -+ } -+ else -+ /* -+ * 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. -+ */ -+ is_console_kbd = true; -+ } ++ 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", devname) == -1) { ++ if (asprintf(&config_info, "devd:%s", ++ skip_path_dev(devicename)) == -1) { + config_info = NULL; -+ goto unwind; ++ goto error; + } + -+ if (device_is_duplicate(config_info)) { -+ LogMessage(X_WARNING, "config/devd: device %s (%s) already added. " -+ "ignoring\n", attrs.product, path); -+ goto unwind; -+ } ++ if (device_is_duplicate(config_info)) ++ goto duplicate; + + options = input_option_new(options, "config_info", config_info); -+ LogMessage(X_INFO, "config/devd: adding input device %s (%s)\n", -+ attrs.product, path); ++ 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; + -+unwind: ++done: + free(config_info); + input_option_free_list(&options); + free(attrs.usb_id); + free(attrs.product); + free(attrs.device); + free(attrs.vendor); ++ free(vendor); ++} ++ ++static void ++devpath_scan_sub(char *path, int off, int rem) ++{ ++ 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); ++ off--; ++ rem++; ++ break; ++ case DT_SOCK: ++ case DT_FIFO: ++ case DT_LNK: ++ case DT_CHR: ++ /* add device, if any */ ++ device_added(path, false); ++ break; ++ default: ++ break; ++ } ++ off -= len; ++ rem += len; ++ } ++ closedir(dp); +} + +static void -+device_removed(char *devname) ++devpath_scan(void) ++{ ++ char path[PATH_MAX + 1]; ++ ++ strlcpy(path, _PATH_DEV, sizeof(path)); ++ ++ devpath_scan_sub(path, strlen(path), PATH_MAX - strlen(path)); ++} ++ ++static void ++device_removed(char *devicename) +{ + char *config_info; + -+ if (asprintf(&config_info, "devd:%s", devname) == -1) ++ 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); @@ -317,8 +368,7 @@ +static bool is_kbdmux_enabled(void) +{ + /* Xorg uses /dev/ttyv0 as a console device */ -+ /* const char device[]="/dev/console"; */ -+ const char device[]="/dev/ttyv0"; ++ static const char device[]= { _PATH_DEV "ttyv0" }; + keyboard_info_t info; + int fd; + @@ -447,7 +497,11 @@ +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; + + if (err < 0) @@ -456,20 +510,20 @@ + if (FD_ISSET(sock_devd, (fd_set *) read_mask)) { + if (socket_getline(sock_devd, &line) < 0) + return; -+ -+ walk = strchr(line + 1, ' '); -+ if (walk != NULL) -+ walk[0] = '\0'; -+ -+ switch (*line) { -+ case DEVD_EVENT_ADD: -+ device_added(line + 1); -+ break; -+ case DEVD_EVENT_REMOVE: -+ device_removed(line + 1); -+ break; -+ default: -+ break; ++ 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'; ++ device_added(devicename, false); ++ } 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); + } @@ -483,34 +537,25 @@ +int +config_devd_init(void) +{ -+ char devicename[1024]; -+ int i, j; -+ + LogMessage(X_INFO, "config/devd: probing input devices...\n"); + -+ /* -+ * Add fake keyboard and give up on keyboards management -+ * if kbdmux is enabled -+ */ -+ if ((is_kbdmux = is_kbdmux_enabled()) == true) -+ device_added("kbdmux"); -+ -+ for (i = 0; hw_types[i].driver != NULL; i++) { -+ /* First scan the sysctl to determine the hardware */ -+ for (j = 0; j < 16; j++) { -+ if (sysctl_exists(&hw_types[i], j, -+ devicename, sizeof(devicename)) != 0) -+ device_added(devicename); -+ } ++ /* Check if kbdmux is enabled */ ++ is_kbdmux = is_kbdmux_enabled(); + -+ if (devpath_exists(&hw_types[i], devicename, sizeof(devicename)) != 0) -+ device_added(devicename); -+ } ++ /* Try to add kbdmux device first */ ++ if (is_kbdmux) ++ device_added(_PATH_DEV "kbdmux0", true); + ++ /* Connect to devd, so that we don't loose any events */ + if ((sock_devd = connect_devd()) < 0) + return 0; + -+ RegisterBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); ++ /* Scan what is currently connected */ ++ devpath_scan(); ++ ++ /* Register wakeup handler */ ++ RegisterBlockAndWakeupHandlers(block_handler, ++ wakeup_handler, NULL); + + return 1; +} @@ -527,7 +572,6 @@ + + disconnect_devd(sock_devd); + -+ RemoveBlockAndWakeupHandlers(block_handler, wakeup_handler, NULL); -+ -+ is_console_kbd = false; ++ RemoveBlockAndWakeupHandlers(block_handler, ++ wakeup_handler, NULL); +}