Commit 46f781e0 authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Jiri Kosina
Browse files

HID: multitouch: fix sticky fingers



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: 4f4001bc ("HID: multitouch: fix rare Win 8 cases when the touch up event gets missing")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.com>
parent aa4daea4
Loading
Loading
Loading
Loading
+14 −13
Original line number Diff line number Diff line
@@ -94,9 +94,8 @@ enum report_mode {
	TOUCHPAD_REPORT_ALL = TOUCHPAD_REPORT_BUTTONS | TOUCHPAD_REPORT_CONTACTS,
};

#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 */
@@ -172,7 +171,11 @@ struct mt_device {
	struct timer_list release_timer;	/* to release sticky fingers */
	struct hid_haptic_device *haptic;	/* haptic related configuration */
	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? */
@@ -986,6 +989,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);
@@ -1019,12 +1023,6 @@ static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
	app->left_button_state = 0;
	if (td->is_haptic_touchpad)
		hid_haptic_pressure_reset(td->haptic);

	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)
@@ -1202,7 +1200,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;
@@ -1337,7 +1337,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
@@ -1814,6 +1814,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);
@@ -1836,7 +1837,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);
}