c458b04
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
c458b04
Date: Wed, 10 Sep 2014 18:02:37 -0700
c458b04
Subject: [PATCH] HID: rmi: check sanity of the incoming report
c458b04
e241709
commit 5b65c2a0296644dd3dbdd590d6f00174d18c96b3 upstream.
e241709
c458b04
In the Dell XPS 13 9333, it appears that sometimes the bus get confused
c458b04
and corrupts the incoming data. It fills the input report with the
c458b04
sentinel value "ff". Synaptics told us that such behavior does not comes
c458b04
from the touchpad itself, so we filter out such reports here.
c458b04
c458b04
Unfortunately, we can not simply discard the incoming data because they
c458b04
may contain useful information. Most of the time, the misbehavior is
c458b04
quite near the end of the report, so we can still use the valid part of
c458b04
it.
c458b04
c458b04
Fixes:
c458b04
https://bugzilla.redhat.com/show_bug.cgi?id=1123584
c458b04
c458b04
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
c458b04
Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
c458b04
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
e241709
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
c458b04
---
c458b04
 drivers/hid/hid-rmi.c | 44 ++++++++++++++++++++++++++++++++++++++------
c458b04
 1 file changed, 38 insertions(+), 6 deletions(-)
c458b04
c458b04
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
c458b04
index 8389e8109218..3cccff73b9b9 100644
c458b04
--- a/drivers/hid/hid-rmi.c
c458b04
+++ b/drivers/hid/hid-rmi.c
c458b04
@@ -320,10 +320,7 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
c458b04
 	int offset;
c458b04
 	int i;
c458b04
 
c458b04
-	if (size < hdata->f11.report_size)
c458b04
-		return 0;
c458b04
-
c458b04
-	if (!(irq & hdata->f11.irq_mask))
c458b04
+	if (!(irq & hdata->f11.irq_mask) || size <= 0)
c458b04
 		return 0;
c458b04
 
c458b04
 	offset = (hdata->max_fingers >> 2) + 1;
c458b04
@@ -332,9 +329,19 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
c458b04
 		int fs_bit_position = (i & 0x3) << 1;
c458b04
 		int finger_state = (data[fs_byte_position] >> fs_bit_position) &
c458b04
 					0x03;
c458b04
+		int position = offset + 5 * i;
c458b04
+
c458b04
+		if (position + 5 > size) {
c458b04
+			/* partial report, go on with what we received */
c458b04
+			printk_once(KERN_WARNING
c458b04
+				"%s %s: Detected incomplete finger report. Finger reports may occasionally get dropped on this platform.\n",
c458b04
+				 dev_driver_string(&hdev->dev),
c458b04
+				 dev_name(&hdev->dev));
c458b04
+			hid_dbg(hdev, "Incomplete finger report\n");
c458b04
+			break;
c458b04
+		}
c458b04
 
c458b04
-		rmi_f11_process_touch(hdata, i, finger_state,
c458b04
-				&data[offset + 5 * i]);
c458b04
+		rmi_f11_process_touch(hdata, i, finger_state, &data[position]);
c458b04
 	}
c458b04
 	input_mt_sync_frame(hdata->input);
c458b04
 	input_sync(hdata->input);
c458b04
@@ -352,6 +359,11 @@ static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
c458b04
 	if (!(irq & hdata->f30.irq_mask))
c458b04
 		return 0;
c458b04
 
c458b04
+	if (size < (int)hdata->f30.report_size) {
c458b04
+		hid_warn(hdev, "Click Button pressed, but the click data is missing\n");
c458b04
+		return 0;
c458b04
+	}
c458b04
+
c458b04
 	for (i = 0; i < hdata->gpio_led_count; i++) {
c458b04
 		if (test_bit(i, &hdata->button_mask)) {
c458b04
 			value = (data[i / 8] >> (i & 0x07)) & BIT(0);
c458b04
@@ -412,9 +424,29 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
c458b04
 	return 1;
c458b04
 }
c458b04
 
c458b04
+static int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size)
c458b04
+{
c458b04
+	int valid_size = size;
c458b04
+	/*
c458b04
+	 * On the Dell XPS 13 9333, the bus sometimes get confused and fills
c458b04
+	 * the report with a sentinel value "ff". Synaptics told us that such
c458b04
+	 * behavior does not comes from the touchpad itself, so we filter out
c458b04
+	 * such reports here.
c458b04
+	 */
c458b04
+
c458b04
+	while ((data[valid_size - 1] == 0xff) && valid_size > 0)
c458b04
+		valid_size--;
c458b04
+
c458b04
+	return valid_size;
c458b04
+}
c458b04
+
c458b04
 static int rmi_raw_event(struct hid_device *hdev,
c458b04
 		struct hid_report *report, u8 *data, int size)
c458b04
 {
c458b04
+	size = rmi_check_sanity(hdev, data, size);
c458b04
+	if (size < 2)
c458b04
+		return 0;
c458b04
+
c458b04
 	switch (data[0]) {
c458b04
 	case RMI_READ_DATA_REPORT_ID:
c458b04
 		return rmi_read_data_event(hdev, data, size);
c458b04
-- 
c458b04
1.9.3
c458b04