diff options
Diffstat (limited to 'src/udev/udev-builtin-keyboard.c')
-rw-r--r-- | src/udev/udev-builtin-keyboard.c | 251 |
1 files changed, 178 insertions, 73 deletions
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index d8ee4cbb61..01f3879f37 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -18,19 +18,15 @@ ***/ #include <stdio.h> -#include <errno.h> #include <string.h> #include <stdlib.h> -#include <fcntl.h> #include <sys/ioctl.h> -#include <linux/limits.h> #include <linux/input.h> #include "udev.h" static const struct key *keyboard_lookup_key(const char *str, unsigned len); #include "keyboard-keys-from-name.h" -#include "keyboard-keys-to-name.h" static int install_force_release(struct udev_device *dev, const unsigned *release, unsigned release_count) { struct udev_device *atkbd; @@ -41,6 +37,9 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas unsigned i; int ret; + assert(dev); + assert(release); + atkbd = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL); if (!atkbd) return -ENODEV; @@ -66,99 +65,205 @@ static int install_force_release(struct udev_device *dev, const unsigned *releas return ret; } -static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { - struct udev_list_entry *entry; +static void map_keycode(int fd, const char *devnode, int scancode, const char *keycode) +{ struct { unsigned scan; unsigned key; - } map[1024]; - unsigned map_count = 0; + } map; + char *endptr; + const struct key *k; + unsigned keycode_num; + + /* translate identifier to key code */ + k = keyboard_lookup_key(keycode, strlen(keycode)); + if (k) { + keycode_num = k->id; + } else { + /* check if it's a numeric code already */ + keycode_num = strtoul(keycode, &endptr, 0); + if (endptr[0] !='\0') { + log_error("Unknown key identifier '%s'", keycode); + return; + } + } + + map.scan = scancode; + map.key = keycode_num; + + log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", + map.scan, map.scan, map.key, map.key); + + if (ioctl(fd, EVIOCSKEYCODE, &map) < 0) + log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", devnode, map.scan, map.key); +} + +static inline char* parse_token(const char *current, int32_t *val_out) { + char *next; + int32_t val; + + if (!current) + return NULL; + + val = strtol(current, &next, 0); + if (*next && *next != ':') + return NULL; + + if (next != current) + *val_out = val; + + if (*next) + next++; + + return next; +} + +static void override_abs(int fd, const char *devnode, + unsigned evcode, const char *value) { + struct input_absinfo absinfo; + int rc; + char *next; + + rc = ioctl(fd, EVIOCGABS(evcode), &absinfo); + if (rc < 0) { + log_error_errno(errno, "Unable to EVIOCGABS device \"%s\"", devnode); + return; + } + + next = parse_token(value, &absinfo.minimum); + next = parse_token(next, &absinfo.maximum); + next = parse_token(next, &absinfo.resolution); + next = parse_token(next, &absinfo.fuzz); + next = parse_token(next, &absinfo.flat); + if (!next) { + log_error("Unable to parse EV_ABS override '%s' for '%s'", value, devnode); + return; + } + + log_debug("keyboard: %x overridden with %"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32"/%"PRIi32" for \"%s\"", + evcode, + absinfo.minimum, absinfo.maximum, absinfo.resolution, absinfo.fuzz, absinfo.flat, + devnode); + rc = ioctl(fd, EVIOCSABS(evcode), &absinfo); + if (rc < 0) + log_error_errno(errno, "Unable to EVIOCSABS device \"%s\"", devnode); +} + +static void set_trackpoint_sensitivity(struct udev_device *dev, const char *value) +{ + struct udev_device *pdev; + char val_s[DECIMAL_STR_MAX(int)]; + int r, val_i; + + assert(dev); + assert(value); + + /* The sensitivity sysfs attr belongs to the serio parent device */ + pdev = udev_device_get_parent_with_subsystem_devtype(dev, "serio", NULL); + if (!pdev) { + log_warning("Failed to get serio parent for '%s'", udev_device_get_devnode(dev)); + return; + } + + r = safe_atoi(value, &val_i); + if (r < 0) { + log_error("Unable to parse POINTINGSTICK_SENSITIVITY '%s' for '%s'", value, udev_device_get_devnode(dev)); + return; + } + + xsprintf(val_s, "%d", val_i); + + r = udev_device_set_sysattr_value(pdev, "sensitivity", val_s); + if (r < 0) + log_error_errno(r, "Failed to write 'sensitivity' attribute for '%s': %m", udev_device_get_devnode(pdev)); +} + +static int open_device(const char *devnode) { + int fd; + + fd = open(devnode, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); + if (fd < 0) + return log_error_errno(errno, "Error opening device \"%s\": %m", devnode); + + return fd; +} + +static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) { + struct udev_list_entry *entry; unsigned release[1024]; unsigned release_count = 0; + _cleanup_close_ int fd = -1; + const char *node; + + node = udev_device_get_devnode(dev); + if (!node) { + log_error("No device node for \"%s\"", udev_device_get_syspath(dev)); + return EXIT_FAILURE; + } udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev)) { const char *key; - unsigned scancode, keycode_num; char *endptr; - const char *keycode; - const struct key *k; key = udev_list_entry_get_name(entry); - if (!startswith(key, "KEYBOARD_KEY_")) - continue; - - /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */ - scancode = strtoul(key + 13, &endptr, 16); - if (endptr[0] != '\0') { - log_error("Error, unable to parse scan code from '%s'", key); - continue; - } + if (startswith(key, "KEYBOARD_KEY_")) { + const char *keycode; + unsigned scancode; + + /* KEYBOARD_KEY_<hex scan code>=<key identifier string> */ + scancode = strtoul(key + 13, &endptr, 16); + if (endptr[0] != '\0') { + log_warning("Unable to parse scan code from \"%s\"", key); + continue; + } - keycode = udev_list_entry_get_value(entry); + keycode = udev_list_entry_get_value(entry); - /* a leading '!' needs a force-release entry */ - if (keycode[0] == '!') { - keycode++; + /* a leading '!' needs a force-release entry */ + if (keycode[0] == '!') { + keycode++; - release[release_count] = scancode; - if (release_count < ELEMENTSOF(release)-1) - release_count++; + release[release_count] = scancode; + if (release_count < ELEMENTSOF(release)-1) + release_count++; - if (keycode[0] == '\0') - continue; - } - - /* translate identifier to key code */ - k = keyboard_lookup_key(keycode, strlen(keycode)); - if (k) { - keycode_num = k->id; - } else { - /* check if it's a numeric code already */ - keycode_num = strtoul(keycode, &endptr, 0); - if (endptr[0] !='\0') { - log_error("Error, unknown key identifier '%s'", keycode); - continue; + if (keycode[0] == '\0') + continue; } - } - map[map_count].scan = scancode; - map[map_count].key = keycode_num; - if (map_count < ELEMENTSOF(map)-1) - map_count++; - } + if (fd == -1) { + fd = open_device(node); + if (fd < 0) + return EXIT_FAILURE; + } - if (map_count > 0 || release_count > 0) { - const char *node; - int fd; - unsigned i; + map_keycode(fd, node, scancode, keycode); + } else if (startswith(key, "EVDEV_ABS_")) { + unsigned evcode; - node = udev_device_get_devnode(dev); - if (!node) { - log_error("Error, no device node for '%s'", udev_device_get_syspath(dev)); - return EXIT_FAILURE; - } + /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */ + evcode = strtoul(key + 10, &endptr, 16); + if (endptr[0] != '\0') { + log_warning("Unable to parse EV_ABS code from \"%s\"", key); + continue; + } - fd = open(udev_device_get_devnode(dev), O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); - if (fd < 0) { - log_error_errno(errno, "Error, opening device '%s': %m", node); - return EXIT_FAILURE; - } + if (fd == -1) { + fd = open_device(node); + if (fd < 0) + return EXIT_FAILURE; + } - /* install list of map codes */ - for (i = 0; i < map_count; i++) { - log_debug("keyboard: mapping scan code %d (0x%x) to key code %d (0x%x)", - map[i].scan, map[i].scan, map[i].key, map[i].key); - if (ioctl(fd, EVIOCSKEYCODE, &map[i]) < 0) - log_error_errno(errno, "Error calling EVIOCSKEYCODE on device node '%s' (scan code 0x%x, key code %d): %m", node, map[i].scan, map[i].key); + override_abs(fd, node, evcode, udev_list_entry_get_value(entry)); + } else if (streq(key, "POINTINGSTICK_SENSITIVITY")) { + set_trackpoint_sensitivity(dev, udev_list_entry_get_value(entry)); } - - /* install list of force-release codes */ - if (release_count > 0) - install_force_release(dev, release, release_count); - - close(fd); } + /* install list of force-release codes */ + if (release_count > 0) + install_force_release(dev, release, release_count); + return EXIT_SUCCESS; } |