aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Gerecke <killertofu@gmail.com>2016-07-21 12:10:46 -0400
committerJiri Kosina <jkosina@suse.cz>2016-08-11 16:37:13 -0400
commit003f50ab673c241a5596c05c88fd25ba71db086d (patch)
tree59681d43d7e07077e7e5a06a21f3ef64854d0da3
parent08fc94733211f94755dd15028fb0a0129310fb5d (diff)
HID: wacom: Update last_slot_field during pre_report phase
If a touchscreen contains both multitouch and single-touch reports in its descriptor in that order, the driver may overwrite information it saved about the format of the multitouch report. This can cause the report processing code to get tripped up and send an incorrect event stream to userspace. In particular, this can cause last_slot_field to be overwritten with the result that the driver prematurely assumes it has finished processing a slot and sending the ABS_MT_SLOT event at the wrong point in time, associating events for the current contact with the following contact instead. To prevent this from occurring, we update the value of last_slot_field durring the pre_report phase to ensure that it is correct for the report that is to be processed. Signed-off-by: Jason Gerecke <jason.gerecke@wacom.com> Reviewed-by: Ping Cheng <pingc@wacom.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/wacom_wac.c62
-rw-r--r--drivers/hid/wacom_wac.h2
2 files changed, 27 insertions, 37 deletions
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 1eae13cdc502..347e459dc113 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1544,13 +1544,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
1544{ 1544{
1545 struct wacom *wacom = hid_get_drvdata(hdev); 1545 struct wacom *wacom = hid_get_drvdata(hdev);
1546 struct wacom_wac *wacom_wac = &wacom->wacom_wac; 1546 struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1547 struct wacom_features *features = &wacom_wac->features;
1548 struct input_dev *input = wacom_wac->touch_input; 1547 struct input_dev *input = wacom_wac->touch_input;
1549 unsigned touch_max = wacom_wac->features.touch_max; 1548 unsigned touch_max = wacom_wac->features.touch_max;
1550 1549
1551 switch (usage->hid) { 1550 switch (usage->hid) {
1552 case HID_GD_X: 1551 case HID_GD_X:
1553 features->last_slot_field = usage->hid;
1554 if (touch_max == 1) 1552 if (touch_max == 1)
1555 wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4); 1553 wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
1556 else 1554 else
@@ -1558,7 +1556,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
1558 ABS_MT_POSITION_X, 4); 1556 ABS_MT_POSITION_X, 4);
1559 break; 1557 break;
1560 case HID_GD_Y: 1558 case HID_GD_Y:
1561 features->last_slot_field = usage->hid;
1562 if (touch_max == 1) 1559 if (touch_max == 1)
1563 wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4); 1560 wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
1564 else 1561 else
@@ -1567,22 +1564,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
1567 break; 1564 break;
1568 case HID_DG_WIDTH: 1565 case HID_DG_WIDTH:
1569 case HID_DG_HEIGHT: 1566 case HID_DG_HEIGHT:
1570 features->last_slot_field = usage->hid;
1571 wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); 1567 wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
1572 wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0); 1568 wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
1573 input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); 1569 input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
1574 break; 1570 break;
1575 case HID_DG_CONTACTID:
1576 features->last_slot_field = usage->hid;
1577 break;
1578 case HID_DG_INRANGE:
1579 features->last_slot_field = usage->hid;
1580 break;
1581 case HID_DG_INVERT:
1582 features->last_slot_field = usage->hid;
1583 break;
1584 case HID_DG_TIPSWITCH: 1571 case HID_DG_TIPSWITCH:
1585 features->last_slot_field = usage->hid;
1586 wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); 1572 wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
1587 break; 1573 break;
1588 case HID_DG_CONTACTCOUNT: 1574 case HID_DG_CONTACTCOUNT:
@@ -1660,7 +1646,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
1660 1646
1661 1647
1662 if (usage->usage_index + 1 == field->report_count) { 1648 if (usage->usage_index + 1 == field->report_count) {
1663 if (usage->hid == wacom_wac->features.last_slot_field) 1649 if (usage->hid == wacom_wac->hid_data.last_slot_field)
1664 wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); 1650 wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
1665 } 1651 }
1666 1652
@@ -1673,31 +1659,35 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
1673 struct wacom *wacom = hid_get_drvdata(hdev); 1659 struct wacom *wacom = hid_get_drvdata(hdev);
1674 struct wacom_wac *wacom_wac = &wacom->wacom_wac; 1660 struct wacom_wac *wacom_wac = &wacom->wacom_wac;
1675 struct hid_data* hid_data = &wacom_wac->hid_data; 1661 struct hid_data* hid_data = &wacom_wac->hid_data;
1662 int i;
1676 1663
1677 if (hid_data->cc_report != 0 && 1664 for (i = 0; i < report->maxfield; i++) {
1678 hid_data->cc_report != report->id) { 1665 struct hid_field *field = report->field[i];
1679 int i; 1666 int j;
1680 1667
1681 hid_data->cc_report = report->id; 1668 for (j = 0; j < field->maxusage; j++) {
1682 hid_data->cc_index = -1; 1669 struct hid_usage *usage = &field->usage[j];
1683 hid_data->cc_value_index = -1; 1670
1684 1671 switch (usage->hid) {
1685 for (i = 0; i < report->maxfield; i++) { 1672 case HID_GD_X:
1686 struct hid_field *field = report->field[i]; 1673 case HID_GD_Y:
1687 int j; 1674 case HID_DG_WIDTH:
1688 1675 case HID_DG_HEIGHT:
1689 for (j = 0; j < field->maxusage; j++) { 1676 case HID_DG_CONTACTID:
1690 if (field->usage[j].hid == HID_DG_CONTACTCOUNT) { 1677 case HID_DG_INRANGE:
1691 hid_data->cc_index = i; 1678 case HID_DG_INVERT:
1692 hid_data->cc_value_index = j; 1679 case HID_DG_TIPSWITCH:
1693 1680 hid_data->last_slot_field = usage->hid;
1694 /* break */ 1681 break;
1695 i = report->maxfield; 1682 case HID_DG_CONTACTCOUNT:
1696 j = field->maxusage; 1683 hid_data->cc_report = report->id;
1697 } 1684 hid_data->cc_index = i;
1685 hid_data->cc_value_index = j;
1686 break;
1698 } 1687 }
1699 } 1688 }
1700 } 1689 }
1690
1701 if (hid_data->cc_report != 0 && 1691 if (hid_data->cc_report != 0 &&
1702 hid_data->cc_index >= 0) { 1692 hid_data->cc_index >= 0) {
1703 struct hid_field *field = report->field[hid_data->cc_index]; 1693 struct hid_field *field = report->field[hid_data->cc_index];
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 53d16537fd2a..b794e80aa72a 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -185,7 +185,6 @@ struct wacom_features {
185 int pktlen; 185 int pktlen;
186 bool check_for_hid_type; 186 bool check_for_hid_type;
187 int hid_type; 187 int hid_type;
188 int last_slot_field;
189}; 188};
190 189
191struct wacom_shared { 190struct wacom_shared {
@@ -214,6 +213,7 @@ struct hid_data {
214 int cc_report; 213 int cc_report;
215 int cc_index; 214 int cc_index;
216 int cc_value_index; 215 int cc_value_index;
216 int last_slot_field;
217 int num_expected; 217 int num_expected;
218 int num_received; 218 int num_received;
219}; 219};