Skip to content

Commit

Permalink
HID: wacom: Update last_slot_field during pre_report phase
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jigpu authored and Jiri Kosina committed Aug 11, 2016
1 parent 08fc947 commit 003f50a
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 37 deletions.
62 changes: 26 additions & 36 deletions drivers/hid/wacom_wac.c
Original file line number Diff line number Diff line change
Expand Up @@ -1544,21 +1544,18 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_features *features = &wacom_wac->features;
struct input_dev *input = wacom_wac->touch_input;
unsigned touch_max = wacom_wac->features.touch_max;

switch (usage->hid) {
case HID_GD_X:
features->last_slot_field = usage->hid;
if (touch_max == 1)
wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4);
else
wacom_map_usage(input, usage, field, EV_ABS,
ABS_MT_POSITION_X, 4);
break;
case HID_GD_Y:
features->last_slot_field = usage->hid;
if (touch_max == 1)
wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4);
else
Expand All @@ -1567,22 +1564,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
break;
case HID_DG_WIDTH:
case HID_DG_HEIGHT:
features->last_slot_field = usage->hid;
wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0);
wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
break;
case HID_DG_CONTACTID:
features->last_slot_field = usage->hid;
break;
case HID_DG_INRANGE:
features->last_slot_field = usage->hid;
break;
case HID_DG_INVERT:
features->last_slot_field = usage->hid;
break;
case HID_DG_TIPSWITCH:
features->last_slot_field = usage->hid;
wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0);
break;
case HID_DG_CONTACTCOUNT:
Expand Down Expand Up @@ -1660,7 +1646,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev,


if (usage->usage_index + 1 == field->report_count) {
if (usage->hid == wacom_wac->features.last_slot_field)
if (usage->hid == wacom_wac->hid_data.last_slot_field)
wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input);
}

Expand All @@ -1673,31 +1659,35 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev,
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct hid_data* hid_data = &wacom_wac->hid_data;
int i;

if (hid_data->cc_report != 0 &&
hid_data->cc_report != report->id) {
int i;

hid_data->cc_report = report->id;
hid_data->cc_index = -1;
hid_data->cc_value_index = -1;

for (i = 0; i < report->maxfield; i++) {
struct hid_field *field = report->field[i];
int j;

for (j = 0; j < field->maxusage; j++) {
if (field->usage[j].hid == HID_DG_CONTACTCOUNT) {
hid_data->cc_index = i;
hid_data->cc_value_index = j;

/* break */
i = report->maxfield;
j = field->maxusage;
}
for (i = 0; i < report->maxfield; i++) {
struct hid_field *field = report->field[i];
int j;

for (j = 0; j < field->maxusage; j++) {
struct hid_usage *usage = &field->usage[j];

switch (usage->hid) {
case HID_GD_X:
case HID_GD_Y:
case HID_DG_WIDTH:
case HID_DG_HEIGHT:
case HID_DG_CONTACTID:
case HID_DG_INRANGE:
case HID_DG_INVERT:
case HID_DG_TIPSWITCH:
hid_data->last_slot_field = usage->hid;
break;
case HID_DG_CONTACTCOUNT:
hid_data->cc_report = report->id;
hid_data->cc_index = i;
hid_data->cc_value_index = j;
break;
}
}
}

if (hid_data->cc_report != 0 &&
hid_data->cc_index >= 0) {
struct hid_field *field = report->field[hid_data->cc_index];
Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/wacom_wac.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,6 @@ struct wacom_features {
int pktlen;
bool check_for_hid_type;
int hid_type;
int last_slot_field;
};

struct wacom_shared {
Expand Down Expand Up @@ -214,6 +213,7 @@ struct hid_data {
int cc_report;
int cc_index;
int cc_value_index;
int last_slot_field;
int num_expected;
int num_received;
};
Expand Down

0 comments on commit 003f50a

Please sign in to comment.