mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
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>
This commit is contained in:
parent
ff0c57ac70
commit
5b65c2a029
@ -320,10 +320,7 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
|
|||||||
int offset;
|
int offset;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (size < hdata->f11.report_size)
|
if (!(irq & hdata->f11.irq_mask) || size <= 0)
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(irq & hdata->f11.irq_mask))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
offset = (hdata->max_fingers >> 2) + 1;
|
offset = (hdata->max_fingers >> 2) + 1;
|
||||||
@ -332,9 +329,19 @@ static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
|
|||||||
int fs_bit_position = (i & 0x3) << 1;
|
int fs_bit_position = (i & 0x3) << 1;
|
||||||
int finger_state = (data[fs_byte_position] >> fs_bit_position) &
|
int finger_state = (data[fs_byte_position] >> fs_bit_position) &
|
||||||
0x03;
|
0x03;
|
||||||
|
int position = offset + 5 * i;
|
||||||
|
|
||||||
rmi_f11_process_touch(hdata, i, finger_state,
|
if (position + 5 > size) {
|
||||||
&data[offset + 5 * i]);
|
/* partial report, go on with what we received */
|
||||||
|
printk_once(KERN_WARNING
|
||||||
|
"%s %s: Detected incomplete finger report. Finger reports may occasionally get dropped on this platform.\n",
|
||||||
|
dev_driver_string(&hdev->dev),
|
||||||
|
dev_name(&hdev->dev));
|
||||||
|
hid_dbg(hdev, "Incomplete finger report\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rmi_f11_process_touch(hdata, i, finger_state, &data[position]);
|
||||||
}
|
}
|
||||||
input_mt_sync_frame(hdata->input);
|
input_mt_sync_frame(hdata->input);
|
||||||
input_sync(hdata->input);
|
input_sync(hdata->input);
|
||||||
@ -352,6 +359,11 @@ static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
|
|||||||
if (!(irq & hdata->f30.irq_mask))
|
if (!(irq & hdata->f30.irq_mask))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (size < (int)hdata->f30.report_size) {
|
||||||
|
hid_warn(hdev, "Click Button pressed, but the click data is missing\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < hdata->gpio_led_count; i++) {
|
for (i = 0; i < hdata->gpio_led_count; i++) {
|
||||||
if (test_bit(i, &hdata->button_mask)) {
|
if (test_bit(i, &hdata->button_mask)) {
|
||||||
value = (data[i / 8] >> (i & 0x07)) & BIT(0);
|
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)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size)
|
||||||
|
{
|
||||||
|
int valid_size = size;
|
||||||
|
/*
|
||||||
|
* On the Dell XPS 13 9333, the bus sometimes get confused and fills
|
||||||
|
* the report with a sentinel value "ff". Synaptics told us that such
|
||||||
|
* behavior does not comes from the touchpad itself, so we filter out
|
||||||
|
* such reports here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while ((data[valid_size - 1] == 0xff) && valid_size > 0)
|
||||||
|
valid_size--;
|
||||||
|
|
||||||
|
return valid_size;
|
||||||
|
}
|
||||||
|
|
||||||
static int rmi_raw_event(struct hid_device *hdev,
|
static int rmi_raw_event(struct hid_device *hdev,
|
||||||
struct hid_report *report, u8 *data, int size)
|
struct hid_report *report, u8 *data, int size)
|
||||||
{
|
{
|
||||||
|
size = rmi_check_sanity(hdev, data, size);
|
||||||
|
if (size < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
switch (data[0]) {
|
switch (data[0]) {
|
||||||
case RMI_READ_DATA_REPORT_ID:
|
case RMI_READ_DATA_REPORT_ID:
|
||||||
return rmi_read_data_event(hdev, data, size);
|
return rmi_read_data_event(hdev, data, size);
|
||||||
|
Loading…
Reference in New Issue
Block a user