The kernel fuzz handling is buggy, especially when we want to rely on the fuzz value for our hysteresis. But since this is a hw property and (at least sometimes) set by the driver, we can't make this a pure libinput hwdb set either.
So our workaround is: * extract the (non-zero) fuzz into a udev property so we don't lose it * set the fuzz to 0 to disable the in-kernel hysteresis * overwrite our internal absinfo with the property fuzz This way we get to use the hw-specified fuzz without having the kernel muck around with it. We also get to use the EVDEV_ABS_ values in 60-evdev.hwdb to override a driver-set fuzz. Two drawbacks: - we're resetting the kernel fuzz to 0, this affects any other users of the device node. That's probably a minor impact only. - we can only save this in a udev property there's a risk of this information getting lost when playing around with udev rules. That too should be a minor issue. https://bugs.freedesktop.org/show_bug.cgi?id=105303 Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- meson.build | 2 +- src/evdev.c | 39 +++++++++++++++++++++++ src/evdev.h | 3 ++ udev/90-libinput-model-quirks.rules.in | 1 - udev/libinput-model-quirks.c | 58 ++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 60caf997..1c12fe1c 100644 --- a/meson.build +++ b/meson.build @@ -87,7 +87,7 @@ executable('libinput-device-group', install_dir : udev_dir) executable('libinput-model-quirks', 'udev/libinput-model-quirks.c', - dependencies : dep_udev, + dependencies : [dep_udev, dep_libevdev], include_directories : [includes_src, includes_include], install : true, install_dir : udev_dir) diff --git a/src/evdev.c b/src/evdev.c index 257824aa..40a5d975 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1505,6 +1505,7 @@ static void evdev_extract_abs_axes(struct evdev_device *device) { struct libevdev *evdev = device->evdev; + int fuzz; if (!libevdev_has_event_code(evdev, EV_ABS, ABS_X) || !libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) @@ -1512,6 +1513,12 @@ evdev_extract_abs_axes(struct evdev_device *device) if (evdev_fix_abs_resolution(device, ABS_X, ABS_Y)) device->abs.is_fake_resolution = true; + + if ((fuzz = evdev_read_fuzz_prop(device, ABS_X))) + libevdev_set_abs_fuzz(evdev, ABS_X, fuzz); + if ((fuzz = evdev_read_fuzz_prop(device, ABS_Y))) + libevdev_set_abs_fuzz(evdev, ABS_Y, fuzz); + device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_X); device->abs.absinfo_y = libevdev_get_abs_info(evdev, ABS_Y); device->abs.dimensions.x = abs(device->abs.absinfo_x->maximum - @@ -1529,6 +1536,11 @@ evdev_extract_abs_axes(struct evdev_device *device) ABS_MT_POSITION_Y)) device->abs.is_fake_resolution = true; + if ((fuzz = evdev_read_fuzz_prop(device, ABS_MT_POSITION_X))) + libevdev_set_abs_fuzz(evdev, ABS_X, fuzz); + if ((fuzz = evdev_read_fuzz_prop(device, ABS_MT_POSITION_Y))) + libevdev_set_abs_fuzz(evdev, ABS_Y, fuzz); + device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X); device->abs.absinfo_y = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y); device->abs.dimensions.x = abs(device->abs.absinfo_x->maximum - @@ -2162,6 +2174,33 @@ evdev_read_calibration_prop(struct evdev_device *device) calibration[5]); } +int +evdev_read_fuzz_prop(struct evdev_device *device, unsigned int code) +{ + const char *prop; + char name[32]; + int rc; + int fuzz = 0; + + rc = snprintf(name, sizeof(name), "LIBINPUT_FUZZ_%02x", code); + if (rc == -1) + return 0; + + prop = udev_device_get_property_value(device->udev_device, name); + if (prop == NULL) + return 0; + + rc = safe_atoi(prop, &fuzz); + if (rc == -1 || fuzz < 0) { + evdev_log_bug_libinput(device, + "invalid LIBINPUT_FUZZ property value: %s\n", + prop); + return 0; + } + + return fuzz; +} + bool evdev_device_has_capability(struct evdev_device *device, enum libinput_device_capability capability) diff --git a/src/evdev.h b/src/evdev.h index 7fc21690..e5361ad2 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -378,6 +378,9 @@ evdev_init_calibration(struct evdev_device *device, void evdev_read_calibration_prop(struct evdev_device *device); +int +evdev_read_fuzz_prop(struct evdev_device *device, unsigned int code); + enum switch_reliability evdev_read_switch_reliability_prop(struct evdev_device *device); diff --git a/udev/90-libinput-model-quirks.rules.in b/udev/90-libinput-model-quirks.rules.in index e7d56bbe..5ddc0ba4 100644 --- a/udev/90-libinput-model-quirks.rules.in +++ b/udev/90-libinput-model-quirks.rules.in @@ -15,7 +15,6 @@ KERNEL!="event*", GOTO="libinput_model_quirks_end" # First, run the program and import the LIBINPUT_MODEL_FIRMWARE_VERSION # environment (if any) KERNELS=="*input*", \ - ENV{ID_INPUT_TOUCHPAD}=="1", \ IMPORT{program}="@UDEV_TEST_PATH@libinput-model-quirks %S%p" # Second, match on anything with that env set and import from the hwdb diff --git a/udev/libinput-model-quirks.c b/udev/libinput-model-quirks.c index 2dc917d5..d1d5a68a 100644 --- a/udev/libinput-model-quirks.c +++ b/udev/libinput-model-quirks.c @@ -31,6 +31,7 @@ #include <unistd.h> #include <libudev.h> #include <linux/input.h> +#include <libevdev/libevdev.h> #include "libinput-util.h" @@ -107,6 +108,61 @@ handle_touchpad(struct udev_device *device) handle_touchpad_synaptics(device); } +/** + * For a non-zero fuzz on the x/y axes, print that fuzz as property and + * reset the kernel's fuzz to 0. + * https://bugs.freedesktop.org/show_bug.cgi?id=105202 + */ +static void +handle_absfuzz(struct udev_device *device) +{ + const char *devnode; + struct libevdev *evdev = NULL; + int fd = -1; + int rc; + unsigned int *code; + unsigned int axes[] = {ABS_X, + ABS_Y, + ABS_MT_POSITION_X, + ABS_MT_POSITION_Y}; + + devnode = udev_device_get_devnode(device); + if (!devnode) + goto out; + + fd = open(devnode, O_RDWR); + if (fd == -1 && errno == EACCES) + fd = open(devnode, O_RDONLY); + if (fd < 0) + goto out; + + rc = libevdev_new_from_fd(fd, &evdev); + if (rc != 0) + goto out; + + if (!libevdev_has_event_type(evdev, EV_ABS)) + goto out; + + ARRAY_FOR_EACH(axes, code) { + struct input_absinfo abs; + int fuzz; + + fuzz = libevdev_get_abs_fuzz(evdev, *code); + if (!fuzz) + continue; + + abs = *libevdev_get_abs_info(evdev, *code); + abs.fuzz = 0; + libevdev_kernel_set_abs_info(evdev, *code, &abs); + + printf("LIBINPUT_FUZZ_%02x=%d\n", *code, fuzz); + } + +out: + close(fd); + libevdev_free(evdev); +} + int main(int argc, char **argv) { int rc = 1; @@ -127,6 +183,8 @@ int main(int argc, char **argv) if (!device) goto out; + handle_absfuzz(device); + if (prop_value(device, "ID_INPUT_TOUCHPAD")) handle_touchpad(device); -- 2.14.3 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel