touchpad: add quirk for the T450 and T460 generation hardware
authorPeter Hutterer <peter.hutterer@who-t.net>
Mon, 7 Mar 2016 06:05:25 +0000 (16:05 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Fri, 11 Mar 2016 00:02:26 +0000 (10:02 +1000)
The touchpad's sensors are too far apart (or the firmware interferes), causing
in a jerky movement visible especially on slow motion. We get a bunch of
normal motion events, then only ABS_MT_PRESSURE updates without x/y updates.
After about one mm of movement x/y updates resume, with the first event
covering the distance between the last motion event. That event is usually
accelerated and thus causes a large jump. Subsequent events are sufficiently
fine-grained again.

This patch counts the number of non-motion events. Once we hit 10 in a row, we
mark the first motion update as non-dirty, effectively discarding the motion
and thus stopping the pointer jumps.

https://bugs.freedesktop.org/show_bug.cgi?id=94379

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Tested-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
src/evdev-mt-touchpad.c
src/evdev-mt-touchpad.h
src/evdev.c
src/evdev.h
udev/90-libinput-model-quirks.hwdb

index 00d6539677fb8a81f9cb46f390808e0dd4b6cc88..d0a8e27cfb079c21a84704cebaf53daed2ebb111 100644 (file)
@@ -337,7 +337,7 @@ tp_process_absolute(struct tp_dispatch *tp,
        case ABS_MT_PRESSURE:
                t->pressure = e->value;
                t->dirty = true;
-               tp->queued |= TOUCHPAD_EVENT_MOTION;
+               tp->queued |= TOUCHPAD_EVENT_OTHERAXIS;
                break;
        }
 }
@@ -880,8 +880,10 @@ tp_position_fake_touches(struct tp_dispatch *tp)
 }
 
 static inline bool
-tp_need_motion_history_reset(struct tp_dispatch *tp)
+tp_need_motion_history_reset(struct tp_dispatch *tp, uint64_t time)
 {
+       bool rc = false;
+
        /* semi-mt finger postions may "jump" when nfingers changes */
        if (tp->semi_mt && tp->nfingers_down != tp->old_nfingers_down)
                return true;
@@ -894,7 +896,29 @@ tp_need_motion_history_reset(struct tp_dispatch *tp)
                 tp->old_nfingers_down > tp->num_slots))
                return true;
 
-       return false;
+       /* Quirk: if we had multiple events without x/y axis
+          information, the next x/y event is going to be a jump. So we
+          reset that touch to non-dirty effectively swallowing that event
+          and restarting with the next event again.
+        */
+       if (tp->device->model_flags & EVDEV_MODEL_LENOVO_T450_TOUCHPAD) {
+               if (tp->queued & TOUCHPAD_EVENT_MOTION) {
+                       if (tp->quirks.nonmotion_event_count > 10) {
+                               struct tp_touch *t;
+
+                               tp_for_each_touch(tp, t)
+                               t->dirty = false;
+                               rc = true;
+                       }
+                       tp->quirks.nonmotion_event_count = 0;
+               }
+
+               if ((tp->queued & (TOUCHPAD_EVENT_OTHERAXIS|TOUCHPAD_EVENT_MOTION)) ==
+                   TOUCHPAD_EVENT_OTHERAXIS)
+                       tp->quirks.nonmotion_event_count++;
+       }
+
+       return rc;
 }
 
 static void
@@ -909,7 +933,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
        tp_unhover_touches(tp, time);
        tp_position_fake_touches(tp);
 
-       want_motion_reset = tp_need_motion_history_reset(tp);
+       want_motion_reset = tp_need_motion_history_reset(tp, time);
 
        for (i = 0; i < tp->ntouches; i++) {
                t = tp_get_touch(tp, i);
index eae327bfbb03aeba2df75215963531755299fc73..1f05a03ee9fde7c8fe55dc59b0b1306f11c35adc 100644 (file)
@@ -41,6 +41,7 @@ enum touchpad_event {
        TOUCHPAD_EVENT_MOTION           = (1 << 0),
        TOUCHPAD_EVENT_BUTTON_PRESS     = (1 << 1),
        TOUCHPAD_EVENT_BUTTON_RELEASE   = (1 << 2),
+       TOUCHPAD_EVENT_OTHERAXIS        = (1 << 3),
 };
 
 enum touchpad_model {
@@ -353,6 +354,17 @@ struct tp_dispatch {
                int upper_thumb_line;
                int lower_thumb_line;
        } thumb;
+
+       struct {
+               /* A quirk used on the T450 series Synaptics hardware.
+                * Slowly moving the finger causes multiple events with only
+                * ABS_MT_PRESSURE but no x/y information. When the x/y
+                * event comes, it will be a jump of ~20 units. We use the
+                * below to count non-motion events to discard that first
+                * event with the jump.
+                */
+               unsigned int nonmotion_event_count;
+       } quirks;
 };
 
 #define tp_for_each_touch(_tp, _t) \
index 51768fe8364b31c0a26905b3f832c3b4de2fbde4..a5c965d5264e39a9c9ab1f10214c37836351e041 100644 (file)
@@ -1680,6 +1680,7 @@ evdev_read_model_flags(struct evdev_device *device)
                { "LIBINPUT_MODEL_CYBORG_RAT", EVDEV_MODEL_CYBORG_RAT },
                { "LIBINPUT_MODEL_CYAPA", EVDEV_MODEL_CYAPA },
                { "LIBINPUT_MODEL_ALPS_RUSHMORE", EVDEV_MODEL_ALPS_RUSHMORE },
+               { "LIBINPUT_MODEL_LENOVO_T450_TOUCHPAD", EVDEV_MODEL_LENOVO_T450_TOUCHPAD },
                { NULL, EVDEV_MODEL_DEFAULT },
        };
        const struct model_map *m = model_map;
index 482712bf1953ee5804a4252446cd2346751107fa..4a5d807d77295757702eeaa498f75e236374ad95 100644 (file)
@@ -113,6 +113,7 @@ enum evdev_device_model {
        EVDEV_MODEL_CYBORG_RAT = (1 << 14),
        EVDEV_MODEL_CYAPA = (1 << 15),
        EVDEV_MODEL_ALPS_RUSHMORE = (1 << 16),
+       EVDEV_MODEL_LENOVO_T450_TOUCHPAD= (1 << 17),
 };
 
 struct mt_slot {
index eb2859e2ef6b62ecfcca94efa2e72abc24f07515..d5978f771f8ec4073aa2f1b8023ad703e76acbd0 100644 (file)
@@ -100,6 +100,13 @@ libinput:name:Cypress APA Trackpad (cyapa):dmi:*
 libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX230*
  LIBINPUT_MODEL_LENOVO_X230=1
 
+# Lenovo T450/T460 and all other Lenovos of the *50 and *60 generation,
+# including the X1 Carbon 3rd gen
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPad??50*:
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPad??60*:
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX1Carbon3rd:*
+ LIBINPUT_MODEL_LENOVO_T450_TOUCHPAD=1
+
 ##########################################
 # Synaptics
 ##########################################