mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-04-17 22:00:40 +02:00
pad: be more robust to kernel bugs of multiple EV_ABS
This is a workaround for a kernel bug with the Wacom Mobile Studio Pro
13: this device sends erroneous ABS_WHEEL events when pressing
buttons:
- evdev:
- [ 0, 0, 1, 256, 1] # EV_KEY / BTN_0 1
- [ 0, 0, 3, 8, 17] # EV_ABS / ABS_WHEEL 17 (+17)
- [ 0, 0, 3, 8, 0] # EV_ABS / ABS_WHEEL 0 (-17)
- [ 0, 0, 3, 40, 15] # EV_ABS / ABS_MISC 15 (+15)
- [ 0, 0, 0, 0, 0] # ------------ SYN_REPORT (0) ---------- +0ms
ABS_WHEEL to 17 then to 0 in the same frame. We should (and do) treat this
as a zero event and drop the 17 to the floor. Alas, we then generate a
ring event for the zero value despite our current value being zero
anyway. This again causes confusing behavior.
This is simple enough to work around, at least until the kernel is fixed
but also to prevent this happening in the future: warn if we get
multiple events and if so and the later event is zero, undo the axis
change state.
Closes: #1081
Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1136>
This commit is contained in:
parent
d9f121b4d1
commit
9ae15c6a45
2 changed files with 43 additions and 16 deletions
|
|
@ -141,29 +141,47 @@ pad_process_relative(struct pad_dispatch *pad,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pad_update_changed_axis(struct pad_dispatch *pad,
|
||||
enum pad_axes axis,
|
||||
const struct input_event *e)
|
||||
{
|
||||
if (pad->changed_axes & axis) {
|
||||
evdev_log_bug_kernel_ratelimit(pad->device,
|
||||
&pad->duplicate_abs_limit,
|
||||
"Multiple EV_ABS %s events in the same SYN_REPORT\n",
|
||||
libevdev_event_code_get_name(EV_ABS, e->code));
|
||||
|
||||
/* Special heuristics probably good enough:
|
||||
* if we get multiple EV_ABS in the same SYN_REPORT
|
||||
* and one of them is zero, assume they're all
|
||||
* zero and unchanged. That's not perfectly
|
||||
* correct but probably covers all cases */
|
||||
if (e->value == 0) {
|
||||
pad->changed_axes &= ~axis;
|
||||
if (pad->changed_axes == 0)
|
||||
pad_unset_status(pad, PAD_AXES_UPDATED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pad->changed_axes |= axis;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
}
|
||||
|
||||
static void
|
||||
pad_process_absolute(struct pad_dispatch *pad,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
enum pad_axes axis = PAD_AXIS_NONE;
|
||||
|
||||
switch (e->code) {
|
||||
case ABS_WHEEL:
|
||||
pad->changed_axes |= PAD_AXIS_RING1;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
case ABS_THROTTLE:
|
||||
pad->changed_axes |= PAD_AXIS_RING2;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
case ABS_RX:
|
||||
pad->changed_axes |= PAD_AXIS_STRIP1;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
case ABS_RY:
|
||||
pad->changed_axes |= PAD_AXIS_STRIP2;
|
||||
pad_set_status(pad, PAD_AXES_UPDATED);
|
||||
break;
|
||||
case ABS_WHEEL: axis = PAD_AXIS_RING1; break;
|
||||
case ABS_THROTTLE: axis = PAD_AXIS_RING2; break;
|
||||
case ABS_RX: axis = PAD_AXIS_STRIP1; break;
|
||||
case ABS_RY: axis = PAD_AXIS_STRIP2; break;
|
||||
case ABS_MISC:
|
||||
/* The wacom driver always sends a 0 axis event on finger
|
||||
up, but we also get an ABS_MISC 15 on touch down and
|
||||
|
|
@ -187,6 +205,10 @@ pad_process_absolute(struct pad_dispatch *pad,
|
|||
e->code);
|
||||
break;
|
||||
}
|
||||
|
||||
if (axis != PAD_AXIS_NONE) {
|
||||
pad_update_changed_axis(pad, axis, e);
|
||||
}
|
||||
}
|
||||
|
||||
static inline double
|
||||
|
|
@ -800,6 +822,9 @@ pad_init(struct pad_dispatch *pad, struct evdev_device *device)
|
|||
|
||||
rc = pad_init_leds(pad, device, wacom);
|
||||
|
||||
/* at most 5 "Multiple EV_ABS events" log messages per hour */
|
||||
ratelimit_init(&pad->duplicate_abs_limit, s2us(60 * 60), 5);
|
||||
|
||||
#if HAVE_LIBWACOM
|
||||
if (wacom)
|
||||
libwacom_destroy(wacom);
|
||||
|
|
|
|||
|
|
@ -93,6 +93,8 @@ struct pad_dispatch {
|
|||
struct {
|
||||
struct list mode_group_list;
|
||||
} modes;
|
||||
|
||||
struct ratelimit duplicate_abs_limit;
|
||||
};
|
||||
|
||||
static inline struct pad_dispatch*
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue