aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2014-09-10 21:02:37 -0400
committerJiri Kosina <jkosina@suse.cz>2014-09-12 16:57:41 -0400
commit5b65c2a0296644dd3dbdd590d6f00174d18c96b3 (patch)
treeb791b06d54ddb993f8c1cbd700a4d3a773e022fc
parentff0c57ac70434bc936cb0110eaf033a0a1a62e52 (diff)
HID: rmi: check sanity of the incoming report
In the Dell XPS 13 9333, it appears that sometimes the bus get confused and corrupts the incoming data. It fills the input report with the sentinel value "ff". Synaptics told us that such behavior does not comes from the touchpad itself, so we filter out such reports here. Unfortunately, we can not simply discard the incoming data because they may contain useful information. Most of the time, the misbehavior is quite near the end of the report, so we can still use the valid part of it. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1123584 Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Andrew Duggan <aduggan@synaptics.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-rmi.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 8389e8109218..3cccff73b9b9 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -320,10 +320,7 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
320 int offset; 320 int offset;
321 int i; 321 int i;
322 322
323 if (size < hdata->f11.report_size) 323 if (!(irq & hdata->f11.irq_mask) || size <= 0)
324 return 0;
325
326 if (!(irq & hdata->f11.irq_mask))
327 return 0; 324 return 0;
328 325
329 offset = (hdata->max_fingers >> 2) + 1; 326 offset = (hdata->max_fingers >> 2) + 1;
@@ -332,9 +329,19 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
332 int fs_bit_position = (i & 0x3) << 1; 329 int fs_bit_position = (i & 0x3) << 1;
333 int finger_state = (data[fs_byte_position] >> fs_bit_position) & 330 int finger_state = (data[fs_byte_position] >> fs_bit_position) &
334 0x03; 331 0x03;
332 int position = offset + 5 * i;
333
334 if (position + 5 > size) {
335 /* partial report, go on with what we received */
336 printk_once(KERN_WARNING
337 "%s %s: Detected incomplete finger report. Finger reports may occasionally get dropped on this platform.\n",
338 dev_driver_string(&hdev->dev),
339 dev_name(&hdev->dev));
340 hid_dbg(hdev, "Incomplete finger report\n");
341 break;
342 }
335 343
336 rmi_f11_process_touch(hdata, i, finger_state, 344 rmi_f11_process_touch(hdata, i, finger_state, &data[position]);
337 &data[offset + 5 * i]);
338 } 345 }
339 input_mt_sync_frame(hdata->input); 346 input_mt_sync_frame(hdata->input);
340 input_sync(hdata->input); 347 input_sync(hdata->input);
@@ -352,6 +359,11 @@ static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
352 if (!(irq & hdata->f30.irq_mask)) 359 if (!(irq & hdata->f30.irq_mask))
353 return 0; 360 return 0;
354 361
362 if (size < (int)hdata->f30.report_size) {
363 hid_warn(hdev, "Click Button pressed, but the click data is missing\n");
364 return 0;
365 }
366
355 for (i = 0; i < hdata->gpio_led_count; i++) { 367 for (i = 0; i < hdata->gpio_led_count; i++) {
356 if (test_bit(i, &hdata->button_mask)) { 368 if (test_bit(i, &hdata->button_mask)) {
357 value = (data[i / 8] >> (i & 0x07)) & BIT(0); 369 value = (data[i / 8] >> (i & 0x07)) & BIT(0);
@@ -412,9 +424,29 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
412 return 1; 424 return 1;
413} 425}
414 426
427static int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size)
428{
429 int valid_size = size;
430 /*
431 * On the Dell XPS 13 9333, the bus sometimes get confused and fills
432 * the report with a sentinel value "ff". Synaptics told us that such
433 * behavior does not comes from the touchpad itself, so we filter out
434 * such reports here.
435 */
436
437 while ((data[valid_size - 1] == 0xff) && valid_size > 0)
438 valid_size--;
439
440 return valid_size;
441}
442
415static int rmi_raw_event(struct hid_device *hdev, 443static int rmi_raw_event(struct hid_device *hdev,
416 struct hid_report *report, u8 *data, int size) 444 struct hid_report *report, u8 *data, int size)
417{ 445{
446 size = rmi_check_sanity(hdev, data, size);
447 if (size < 2)
448 return 0;
449
418 switch (data[0]) { 450 switch (data[0]) {
419 case RMI_READ_DATA_REPORT_ID: 451 case RMI_READ_DATA_REPORT_ID:
420 return rmi_read_data_event(hdev, data, size); 452 return rmi_read_data_event(hdev, data, size);