You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
240 lines
8.8 KiB
240 lines
8.8 KiB
From e6682abae36dcfe8a093686a3bd67b3568157c35 Mon Sep 17 00:00:00 2001 |
|
From: Peter Hutterer <peter.hutterer@who-t.net> |
|
Date: Thu, 19 Mar 2015 14:19:58 +1000 |
|
Subject: [PATCH] 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. |
|
|
|
(cherry picked from commit 51c0c2869845a058268d54c3111d55d0dd485704) |
|
|
|
Changes to the upstream commit: |
|
- 60-keyboard.rules is left in place, the 60-keyboard.hwdb is left |
|
unmodified. This avoids any potential breakage from user-installed hwdb |
|
files that are triggered by that rule. |
|
|
|
Conflicts: |
|
hwdb/60-keyboard.hwdb |
|
rules/60-keyboard.rules |
|
|
|
Resolves: #1500119 |
|
--- |
|
Makefile.am | 2 + |
|
hwdb/60-evdev.hwdb | 37 ++++++++++++++ |
|
rules/60-evdev.rules | 14 ++++++ |
|
src/udev/udev-builtin-keyboard.c | 86 ++++++++++++++++++++++++++++++-- |
|
4 files changed, 135 insertions(+), 4 deletions(-) |
|
create mode 100644 hwdb/60-evdev.hwdb |
|
create mode 100644 rules/60-evdev.rules |
|
|
|
diff --git a/Makefile.am b/Makefile.am |
|
index a1ebf5cb07..13c93f485e 100644 |
|
--- a/Makefile.am |
|
+++ b/Makefile.am |
|
@@ -3499,6 +3499,7 @@ dist_udevrules_DATA += \ |
|
rules/42-usb-hid-pm.rules \ |
|
rules/50-udev-default.rules \ |
|
rules/60-drm.rules \ |
|
+ rules/60-evdev.rules \ |
|
rules/60-keyboard.rules \ |
|
rules/60-persistent-storage-tape.rules \ |
|
rules/60-persistent-serial.rules \ |
|
@@ -3702,6 +3703,7 @@ dist_udevhwdb_DATA = \ |
|
hwdb/20-acpi-vendor.hwdb \ |
|
hwdb/20-OUI.hwdb \ |
|
hwdb/20-net-ifname.hwdb \ |
|
+ hwdb/60-evdev.hwdb \ |
|
hwdb/60-keyboard.hwdb \ |
|
hwdb/70-mouse.hwdb \ |
|
hwdb/70-touchpad.hwdb |
|
diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb |
|
new file mode 100644 |
|
index 0000000000..ad2d09e721 |
|
--- /dev/null |
|
+++ b/hwdb/60-evdev.hwdb |
|
@@ -0,0 +1,37 @@ |
|
+# This file is part of systemd. |
|
+# |
|
+# The lookup keys are composed in: |
|
+# 60-evdev.rules |
|
+# |
|
+# Note: The format of the "evdev:" prefix match key is a |
|
+# contract between the rules file and the hardware data, it might |
|
+# change in later revisions to support more or better matches, it |
|
+# is not necessarily expected to be a stable ABI. |
|
+# |
|
+# Match string formats: |
|
+# evdev:<modalias> |
|
+# evdev:name:<device name>:dmi:<dmi string> |
|
+# |
|
+# To add local entries, create a new file |
|
+# /etc/udev/hwdb.d/61-evdev-local.hwdb |
|
+# and add your rules there. To load the new rules execute (as root): |
|
+# udevadm hwdb --update |
|
+# udevadm trigger /dev/input/eventXX |
|
+# where /dev/input/eventXX is the device in question. If in |
|
+# doubt, simply use /dev/input/event* to reload all input rules. |
|
+# |
|
+# If your changes are generally applicable, open a bug report on |
|
+# http://bugs.freedesktop.org/enter_bug.cgi?product=systemd |
|
+# and include your new rules, a description of the device, and the |
|
+# output of |
|
+# udevadm info /dev/input/eventXX |
|
+# (or /dev/input/event*). |
|
+# |
|
+# Allowed properties are: |
|
+# EVDEV_ABS_<axis>=<min>:<max>:<res>:<fuzz>:<flat> |
|
+# |
|
+# where <axis> is the hexadecimal EV_ABS code as listed in linux/input.h |
|
+# and min, max, res, fuzz, flat are the decimal values to the respective |
|
+# fields of the struct input_absinfo as listed in linux/input.h. |
|
+# If a field is missing the field will be left as-is. Not all fields need to |
|
+# be present. e.g. ::45 sets the resolution to 45 units/mm. |
|
diff --git a/rules/60-evdev.rules b/rules/60-evdev.rules |
|
new file mode 100644 |
|
index 0000000000..67308ad230 |
|
--- /dev/null |
|
+++ b/rules/60-evdev.rules |
|
@@ -0,0 +1,14 @@ |
|
+# do not edit this file, it will be overwritten on update |
|
+ |
|
+ACTION=="remove", GOTO="evdev_end" |
|
+KERNEL!="event*", GOTO="evdev_end" |
|
+ |
|
+# skip later rules when we find something for this input device |
|
+IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=evdev:", \ |
|
+ RUN{builtin}+="keyboard", GOTO="evdev_end" |
|
+ |
|
+# device matching the input device name and the machine's DMI data |
|
+KERNELS=="input*", IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:$attr{[dmi/id]modalias}'", \ |
|
+ RUN{builtin}+="keyboard", GOTO="evdev_end" |
|
+ |
|
+LABEL="evdev_end" |
|
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c |
|
index 86f4018ef5..eaa21abf60 100644 |
|
--- a/src/udev/udev-builtin-keyboard.c |
|
+++ b/src/udev/udev-builtin-keyboard.c |
|
@@ -99,6 +99,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]; |
|
@@ -143,14 +206,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)); |
|
} |
|
} |
|
|
|
|