]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
HID: multitouch: fix sticky fingers
authorBenjamin Tissoires <bentiss@kernel.org>
Wed, 8 Oct 2025 14:06:58 +0000 (16:06 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 29 Oct 2025 13:01:18 +0000 (14:01 +0100)
commit 46f781e0d151844589dc2125c8cce3300546f92a upstream.

The sticky fingers quirk (MT_QUIRK_STICKY_FINGERS) was only considering
the case when slots were not released during the last report.
This can be problematic if the firmware forgets to release a finger
while others are still present.

This was observed on the Synaptics DLL0945 touchpad found on the Dell
XPS 9310 and the Dell Inspiron 5406.

Fixes: 4f4001bc76fd ("HID: multitouch: fix rare Win 8 cases when the touch up event gets missing")
Cc: stable@vger.kernel.org
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hid/hid-multitouch.c

index 006af6e1430738fc9eaa6346f9696e0a5faa9aa1..5d966acbb0fd4f7591a563eda44e307a36d94fcc 100644 (file)
@@ -81,9 +81,8 @@ enum latency_mode {
        HID_LATENCY_HIGH = 1,
 };
 
-#define MT_IO_FLAGS_RUNNING            0
-#define MT_IO_FLAGS_ACTIVE_SLOTS       1
-#define MT_IO_FLAGS_PENDING_SLOTS      2
+#define MT_IO_SLOTS_MASK               GENMASK(7, 0) /* reserve first 8 bits for slot tracking */
+#define MT_IO_FLAGS_RUNNING            32
 
 static const bool mtrue = true;                /* default for true */
 static const bool mfalse;              /* default for false */
@@ -159,7 +158,11 @@ struct mt_device {
        struct mt_class mtclass;        /* our mt device class */
        struct timer_list release_timer;        /* to release sticky fingers */
        struct hid_device *hdev;        /* hid_device we're attached to */
-       unsigned long mt_io_flags;      /* mt flags (MT_IO_FLAGS_*) */
+       unsigned long mt_io_flags;      /* mt flags (MT_IO_FLAGS_RUNNING)
+                                        * first 8 bits are reserved for keeping the slot
+                                        * states, this is fine because we only support up
+                                        * to 250 slots (MT_MAX_MAXCONTACT)
+                                        */
        __u8 inputmode_value;   /* InputMode HID feature value */
        __u8 maxcontacts;
        bool is_buttonpad;      /* is this device a button pad? */
@@ -904,6 +907,7 @@ static void mt_release_pending_palms(struct mt_device *td,
 
        for_each_set_bit(slotnum, app->pending_palm_slots, td->maxcontacts) {
                clear_bit(slotnum, app->pending_palm_slots);
+               clear_bit(slotnum, &td->mt_io_flags);
 
                input_mt_slot(input, slotnum);
                input_mt_report_slot_inactive(input);
@@ -935,12 +939,6 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
 
        app->num_received = 0;
        app->left_button_state = 0;
-
-       if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
-               set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
-       else
-               clear_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
-       clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
 }
 
 static int mt_compute_timestamp(struct mt_application *app, __s32 value)
@@ -1094,7 +1092,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
                input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
                input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
 
-               set_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
+               set_bit(slotnum, &td->mt_io_flags);
+       } else {
+               clear_bit(slotnum, &td->mt_io_flags);
        }
 
        return 0;
@@ -1229,7 +1229,7 @@ static void mt_touch_report(struct hid_device *hid,
         * defect.
         */
        if (app->quirks & MT_QUIRK_STICKY_FINGERS) {
-               if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
+               if (td->mt_io_flags & MT_IO_SLOTS_MASK)
                        mod_timer(&td->release_timer,
                                  jiffies + msecs_to_jiffies(100));
                else
@@ -1647,6 +1647,7 @@ static void mt_release_contacts(struct hid_device *hid)
                        for (i = 0; i < mt->num_slots; i++) {
                                input_mt_slot(input_dev, i);
                                input_mt_report_slot_inactive(input_dev);
+                               clear_bit(i, &td->mt_io_flags);
                        }
                        input_mt_sync_frame(input_dev);
                        input_sync(input_dev);
@@ -1669,7 +1670,7 @@ static void mt_expired_timeout(struct timer_list *t)
         */
        if (test_and_set_bit_lock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
                return;
-       if (test_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags))
+       if (td->mt_io_flags & MT_IO_SLOTS_MASK)
                mt_release_contacts(hdev);
        clear_bit_unlock(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
 }