forked from rpms/kernel
		
	
		
			
				
	
	
		
			107 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			107 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From f5c1da991de077420fda17a236342de5a0068f5d Mon Sep 17 00:00:00 2001
 | 
						|
From: Hans de Goede <hdegoede@redhat.com>
 | 
						|
Date: Wed, 22 Nov 2017 12:57:08 +0100
 | 
						|
Subject: [PATCH v2 1/3] HID: multitouch: Properly deal with Win8 PTP reports
 | 
						|
 with 0 touches
 | 
						|
 | 
						|
The Windows Precision Touchpad spec "Figure 4 Button Only Down and Up"
 | 
						|
and "Table 9 Report Sequence for Button Only Down and Up" indicate
 | 
						|
that the first packet of a (possibly hybrid mode multi-packet) frame
 | 
						|
may contain a contact-count of 0 if only a button is pressed and no
 | 
						|
fingers are detected.
 | 
						|
 | 
						|
This means that a value of 0 for contact-count is a valid value and
 | 
						|
should be used as expected contact count when it is the first packet
 | 
						|
(num_received == 0), as extra check to make sure that this is the first
 | 
						|
packet of a buttons only frame, we also check that the timestamp is
 | 
						|
different.
 | 
						|
 | 
						|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
 | 
						|
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
 | 
						|
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
 | 
						|
---
 | 
						|
 drivers/hid/hid-multitouch.c | 32 ++++++++++++++++++++++++++++++--
 | 
						|
 1 file changed, 30 insertions(+), 2 deletions(-)
 | 
						|
 | 
						|
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
 | 
						|
index 9ef24b518f12..d8b1cad74faf 100644
 | 
						|
--- a/drivers/hid/hid-multitouch.c
 | 
						|
+++ b/drivers/hid/hid-multitouch.c
 | 
						|
@@ -119,6 +119,9 @@ struct mt_device {
 | 
						|
 	unsigned long mt_io_flags;	/* mt flags (MT_IO_FLAGS_*) */
 | 
						|
 	int cc_index;	/* contact count field index in the report */
 | 
						|
 	int cc_value_index;	/* contact count value index in the field */
 | 
						|
+	int scantime_index;	/* scantime field index in the report */
 | 
						|
+	int scantime_val_index;	/* scantime value index in the field */
 | 
						|
+	int prev_scantime;	/* scantime reported in the previous packet */
 | 
						|
 	unsigned last_slot_field;	/* the last field of a slot */
 | 
						|
 	unsigned mt_report_id;	/* the report ID of the multitouch device */
 | 
						|
 	unsigned long initial_quirks;	/* initial quirks state */
 | 
						|
@@ -599,6 +602,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 | 
						|
 				EV_MSC, MSC_TIMESTAMP);
 | 
						|
 			input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
 | 
						|
 			mt_store_field(usage, td, hi);
 | 
						|
+			/* Ignore if indexes are out of bounds. */
 | 
						|
+			if (field->index >= field->report->maxfield ||
 | 
						|
+			    usage->usage_index >= field->report_count)
 | 
						|
+				return 1;
 | 
						|
+			td->scantime_index = field->index;
 | 
						|
+			td->scantime_val_index = usage->usage_index;
 | 
						|
 			return 1;
 | 
						|
 		case HID_DG_CONTACTCOUNT:
 | 
						|
 			/* Ignore if indexes are out of bounds. */
 | 
						|
@@ -855,9 +864,10 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 | 
						|
 static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 | 
						|
 {
 | 
						|
 	struct mt_device *td = hid_get_drvdata(hid);
 | 
						|
+	__s32 cls = td->mtclass.name;
 | 
						|
 	struct hid_field *field;
 | 
						|
 	unsigned count;
 | 
						|
-	int r, n;
 | 
						|
+	int r, n, scantime = 0;
 | 
						|
 
 | 
						|
 	/* sticky fingers release in progress, abort */
 | 
						|
 	if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
 | 
						|
@@ -867,12 +877,29 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 | 
						|
 	 * Includes multi-packet support where subsequent
 | 
						|
 	 * packets are sent with zero contactcount.
 | 
						|
 	 */
 | 
						|
+	if (td->scantime_index >= 0) {
 | 
						|
+		field = report->field[td->scantime_index];
 | 
						|
+		scantime = field->value[td->scantime_val_index];
 | 
						|
+	}
 | 
						|
 	if (td->cc_index >= 0) {
 | 
						|
 		struct hid_field *field = report->field[td->cc_index];
 | 
						|
 		int value = field->value[td->cc_value_index];
 | 
						|
-		if (value)
 | 
						|
+
 | 
						|
+		/*
 | 
						|
+		 * For Win8 PTPs the first packet (td->num_received == 0) may
 | 
						|
+		 * have a contactcount of 0 if there only is a button event.
 | 
						|
+		 * We double check that this is not a continuation packet
 | 
						|
+		 * of a possible multi-packet frame be checking that the
 | 
						|
+		 * timestamp has changed.
 | 
						|
+		 */
 | 
						|
+		if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
 | 
						|
+		    td->num_received == 0 && td->prev_scantime != scantime)
 | 
						|
+			td->num_expected = value;
 | 
						|
+		/* A non 0 contact count always indicates a first packet */
 | 
						|
+		else if (value)
 | 
						|
 			td->num_expected = value;
 | 
						|
 	}
 | 
						|
+	td->prev_scantime = scantime;
 | 
						|
 
 | 
						|
 	for (r = 0; r < report->maxfield; r++) {
 | 
						|
 		field = report->field[r];
 | 
						|
@@ -1329,6 +1356,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
 | 
						|
 	td->maxcontact_report_id = -1;
 | 
						|
 	td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
 | 
						|
 	td->cc_index = -1;
 | 
						|
+	td->scantime_index = -1;
 | 
						|
 	td->mt_report_id = -1;
 | 
						|
 	hid_set_drvdata(hdev, td);
 | 
						|
 
 | 
						|
-- 
 | 
						|
2.14.3
 | 
						|
 |