summaryrefslogtreecommitdiff
path: root/src/udev/udev-builtin-keyboard.c
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2015-03-19 14:19:58 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2015-04-11 08:44:33 +1000
commit51c0c2869845a058268d54c3111d55d0dd485704 (patch)
treec2da7abb5eee37b67e998393e24c100dfaff5b6f /src/udev/udev-builtin-keyboard.c
parent8a0fd83cf03547653a195582ba004d2ff69dfbd0 (diff)
downloadsystemd-51c0c2869845a058268d54c3111d55d0dd485704.tar.gz
udev: builtin-keyboard: add support for EVDEV_ABS_*
Parse properties in the form EVDEV_ABS_00="<min>:<max>:<res>:<fuzz>:<flat>" and apply them to the kernel device. Future processes that open that device will see the updated EV_ABS range. This is particularly useful for touchpads that don't provide a resolution in the kernel driver but can be fixed up through hwdb entries (e.g. bcm5974). All values in the property are optional, e.g. a string of "::45" is valid to set the resolution to 45. The order intentionally orders resolution before fuzz and flat despite it being the last element in the absinfo struct. The use-case for setting fuzz/flat is almost non-existent, resolution is probably the most common case we'll need. To avoid multiple hwdb invocations for the same device, replace the hwdb "keyboard:" prefix with "evdev:" and drop the separate 60-keyboard.rules file. The new 60-evdev.rules is called for all event nodes anyway, we don't need a separate rules file and second callout to the hwdb builtin.
Diffstat (limited to 'src/udev/udev-builtin-keyboard.c')
-rw-r--r--src/udev/udev-builtin-keyboard.c86
1 files changed, 82 insertions, 4 deletions
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index 785a607c9a..2a71ea56a5 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -95,6 +95,69 @@ static void map_keycode(int fd, const char *devnode, int scancode, const char *k
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, "Error, 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("Error, unable to parse EV_ABS override '%s' for '%s'\n",
+ value, devnode);
+ return;
+ }
+
+ log_debug("keyboard: override %x with %d/%d/%d/%d/%d", evcode,
+ absinfo.minimum, absinfo.maximum, absinfo.resolution,
+ absinfo.fuzz, absinfo.flat);
+ rc = ioctl(fd, EVIOCSABS(evcode), &absinfo);
+ if (rc < 0)
+ log_error_errno(errno, "Error, unable to update device '%s'",
+ devnode);
+}
+
+static int open_device(const char *devnode) {
+ int fd;
+
+ fd = open(devnode, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (fd < 0)
+ log_error_errno(errno, "Error, opening device '%s': %m", devnode);
+
+ return fd < 0 ? -errno : fd;
+}
+
static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], bool test) {
struct udev_list_entry *entry;
unsigned release[1024];
@@ -139,14 +202,29 @@ static int builtin_keyboard(struct udev_device *dev, int argc, char *argv[], boo
}
if (fd == -1) {
- fd = open(node, O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0) {
- log_error_errno(errno, "Error, opening device '%s': %m", node);
+ fd = open_device(node);
+ if (fd < 0)
return EXIT_FAILURE;
- }
}
map_keycode(fd, node, scancode, keycode);
+ } else if (startswith(key, "EVDEV_ABS_")) {
+ unsigned evcode;
+
+ /* EVDEV_ABS_<EV_ABS code>=<min>:<max>:<res>:<fuzz>:<flat> */
+ evcode = strtoul(key + 10, &endptr, 16);
+ if (endptr[0] != '\0') {
+ log_error("Error, unable to parse EV_ABS code from '%s'", key);
+ continue;
+ }
+
+ if (fd == -1) {
+ fd = open_device(node);
+ if (fd < 0)
+ return EXIT_FAILURE;
+ }
+
+ override_abs(fd, node, evcode, udev_list_entry_get_value(entry));
}
}