This is a kernel bug, reject such devices outright. This saves us from a bunch of extra double checks to make sure that the resolutions are always set up.
Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- src/evdev.c | 32 +++++++++++++++++----- test/device.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/evdev.c b/src/evdev.c index a6d6fae..243cd22 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1377,13 +1377,6 @@ evdev_fix_abs_resolution(struct evdev_device *device, absx = libevdev_get_abs_info(evdev, xcode); absy = libevdev_get_abs_info(evdev, ycode); - if ((absx->resolution == 0 && absy->resolution != 0) || - (absx->resolution != 0 && absy->resolution == 0)) { - log_bug_kernel(libinput, - "Kernel has only x or y resolution, not both.\n"); - return 0; - } - if (absx->resolution == 0 || absx->resolution == EVDEV_FAKE_RESOLUTION) { fixed = *absx; fixed.resolution = xresolution; @@ -1487,8 +1480,10 @@ evdev_check_min_max(struct evdev_device *device, unsigned int code) static int evdev_reject_device(struct evdev_device *device) { + struct libinput *libinput = device->base.seat->libinput; struct libevdev *evdev = device->evdev; unsigned int code; + const struct input_absinfo *absx, *absy; if (libevdev_has_event_code(evdev, EV_ABS, ABS_X) ^ libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) @@ -1498,6 +1493,29 @@ evdev_reject_device(struct evdev_device *device) libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_Y)) return -1; + if (libevdev_has_event_code(evdev, EV_ABS, ABS_X)) { + absx = libevdev_get_abs_info(evdev, ABS_X); + absy = libevdev_get_abs_info(evdev, ABS_Y); + if ((absx->resolution == 0 && absy->resolution != 0) || + (absx->resolution != 0 && absy->resolution == 0)) { + log_bug_kernel(libinput, + "Kernel has only x or y resolution, not both.\n"); + return -1; + } + } + + if (!evdev_is_fake_mt_device(device) && + libevdev_has_event_code(evdev, EV_ABS, ABS_MT_POSITION_X)) { + absx = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X); + absy = libevdev_get_abs_info(evdev, ABS_MT_POSITION_Y); + if ((absx->resolution == 0 && absy->resolution != 0) || + (absx->resolution != 0 && absy->resolution == 0)) { + log_bug_kernel(libinput, + "Kernel has only x or y MT resolution, not both.\n"); + return -1; + } + } + for (code = 0; code < ABS_CNT; code++) { switch (code) { case ABS_MISC: diff --git a/test/device.c b/test/device.c index c9d5255..cf9885a 100644 --- a/test/device.c +++ b/test/device.c @@ -894,6 +894,91 @@ START_TEST(abs_mt_device_no_range) } END_TEST +START_TEST(abs_device_missing_res) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + struct input_absinfo absinfo[] = { + { ABS_X, 0, 10, 0, 0, 10 }, + { ABS_Y, 0, 10, 0, 0, 0 }, + { -1, -1, -1, -1, -1, -1 } + }; + + li = litest_create_context(); + litest_disable_log_handler(li); + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + + absinfo[0].resolution = 0; + absinfo[1].resolution = 20; + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + + litest_restore_log_handler(li); + libinput_unref(li); + +} +END_TEST + +START_TEST(abs_mt_device_missing_res) +{ + struct libevdev_uinput *uinput; + struct libinput *li; + struct libinput_device *device; + struct input_absinfo absinfo[] = { + { ABS_X, 0, 10, 0, 0, 10 }, + { ABS_Y, 0, 10, 0, 0, 10 }, + { ABS_MT_SLOT, 0, 2, 0, 0, 0 }, + { ABS_MT_TRACKING_ID, 0, 255, 0, 0, 0 }, + { ABS_MT_POSITION_X, 0, 10, 0, 0, 10 }, + { ABS_MT_POSITION_Y, 0, 10, 0, 0, 0 }, + { -1, -1, -1, -1, -1, -1 } + }; + + li = litest_create_context(); + litest_disable_log_handler(li); + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + + absinfo[4].resolution = 0; + absinfo[5].resolution = 20; + uinput = litest_create_uinput_abs_device("test device", NULL, + absinfo, + EV_KEY, BTN_LEFT, + EV_KEY, BTN_RIGHT, + -1); + device = libinput_path_add_device(li, + libevdev_uinput_get_devnode(uinput)); + ck_assert(device == NULL); + libevdev_uinput_destroy(uinput); + + litest_restore_log_handler(li); + libinput_unref(li); + +} +END_TEST int main (int argc, char **argv) { litest_add("device:sendevents", device_sendevents_config, LITEST_ANY, LITEST_TOUCHPAD); @@ -928,6 +1013,8 @@ int main (int argc, char **argv) litest_add_no_device("device:invalid devices", abs_mt_device_no_absy); litest_add_no_device("device:invalid devices", abs_device_no_range); litest_add_no_device("device:invalid devices", abs_mt_device_no_range); + litest_add_no_device("device:invalid devices", abs_device_missing_res); + litest_add_no_device("device:invalid devices", abs_mt_device_missing_res); return litest_run(argc, argv); } -- 2.3.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel