Commit af8dc4d0 authored by Hans de Goede's avatar Hans de Goede Committed by Jiri Kosina

HID: multitouch: Properly deal with Win8 PTP reports with 0 touches

The Windows Precision Touchpad spec "Figure 4 Button Only Down and Up"
and "Table 9 Report Sequence for Button Only Down and Up" indicate
that the first packet of a (possibly hybrid mode multi-packet) frame
may contain a contact-count of 0 if only a button is pressed and no
fingers are detected.

This means that a value of 0 for contact-count is a valid value and
should be used as expected contact count when it is the first packet
(num_received == 0), as extra check to make sure that this is the first
packet of a buttons only frame, we also check that the timestamp is
different.
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent fb55b402
...@@ -119,6 +119,9 @@ struct mt_device { ...@@ -119,6 +119,9 @@ struct mt_device {
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
int cc_index; /* contact count field index in the report */ int cc_index; /* contact count field index in the report */
int cc_value_index; /* contact count value index in the field */ int cc_value_index; /* contact count value index in the field */
int scantime_index; /* scantime field index in the report */
int scantime_val_index; /* scantime value index in the field */
int prev_scantime; /* scantime reported in the previous packet */
unsigned last_slot_field; /* the last field of a slot */ unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */ unsigned mt_report_id; /* the report ID of the multitouch device */
unsigned long initial_quirks; /* initial quirks state */ unsigned long initial_quirks; /* initial quirks state */
...@@ -599,6 +602,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -599,6 +602,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_MSC, MSC_TIMESTAMP); EV_MSC, MSC_TIMESTAMP);
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
/* Ignore if indexes are out of bounds. */
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
td->scantime_index = field->index;
td->scantime_val_index = usage->usage_index;
return 1; return 1;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
/* Ignore if indexes are out of bounds. */ /* Ignore if indexes are out of bounds. */
...@@ -855,9 +864,10 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -855,9 +864,10 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
static void mt_touch_report(struct hid_device *hid, struct hid_report *report) static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
{ {
struct mt_device *td = hid_get_drvdata(hid); struct mt_device *td = hid_get_drvdata(hid);
__s32 cls = td->mtclass.name;
struct hid_field *field; struct hid_field *field;
unsigned count; unsigned count;
int r, n; int r, n, scantime = 0;
/* sticky fingers release in progress, abort */ /* sticky fingers release in progress, abort */
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
...@@ -867,12 +877,29 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) ...@@ -867,12 +877,29 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* Includes multi-packet support where subsequent * Includes multi-packet support where subsequent
* packets are sent with zero contactcount. * packets are sent with zero contactcount.
*/ */
if (td->scantime_index >= 0) {
field = report->field[td->scantime_index];
scantime = field->value[td->scantime_val_index];
}
if (td->cc_index >= 0) { if (td->cc_index >= 0) {
struct hid_field *field = report->field[td->cc_index]; struct hid_field *field = report->field[td->cc_index];
int value = field->value[td->cc_value_index]; int value = field->value[td->cc_value_index];
if (value)
/*
* For Win8 PTPs the first packet (td->num_received == 0) may
* have a contactcount of 0 if there only is a button event.
* We double check that this is not a continuation packet
* of a possible multi-packet frame be checking that the
* timestamp has changed.
*/
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
td->num_received == 0 && td->prev_scantime != scantime)
td->num_expected = value;
/* A non 0 contact count always indicates a first packet */
else if (value)
td->num_expected = value; td->num_expected = value;
} }
td->prev_scantime = scantime;
for (r = 0; r < report->maxfield; r++) { for (r = 0; r < report->maxfield; r++) {
field = report->field[r]; field = report->field[r];
...@@ -1329,6 +1356,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1329,6 +1356,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->maxcontact_report_id = -1; td->maxcontact_report_id = -1;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
td->cc_index = -1; td->cc_index = -1;
td->scantime_index = -1;
td->mt_report_id = -1; td->mt_report_id = -1;
hid_set_drvdata(hdev, td); hid_set_drvdata(hdev, td);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment