From f10b01dcd4af3cac52eac6fbb63d67468b6458f9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 26 Nov 2017 14:42:26 +0100 Subject: [PATCH] Fix left-button not working with some hid-multitouch touchpads --- ...roperly-deal-with-Win8-PTP-reports-w.patch | 106 ++++++++++++++++++ ...nly-look-at-non-touch-fields-in-firs.patch | 84 ++++++++++++++ ...ombine-all-left-button-events-in-a-f.patch | 78 +++++++++++++ kernel.spec | 10 ++ 4 files changed, 278 insertions(+) create mode 100644 0001-HID-multitouch-Properly-deal-with-Win8-PTP-reports-w.patch create mode 100644 0002-HID-multitouch-Only-look-at-non-touch-fields-in-firs.patch create mode 100644 0003-HID-multitouch-Combine-all-left-button-events-in-a-f.patch diff --git a/0001-HID-multitouch-Properly-deal-with-Win8-PTP-reports-w.patch b/0001-HID-multitouch-Properly-deal-with-Win8-PTP-reports-w.patch new file mode 100644 index 000000000..e15ec6bb1 --- /dev/null +++ b/0001-HID-multitouch-Properly-deal-with-Win8-PTP-reports-w.patch @@ -0,0 +1,106 @@ +From f5c1da991de077420fda17a236342de5a0068f5d Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 22 Nov 2017 12:57:08 +0100 +Subject: [PATCH v2 1/3] 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: Hans de Goede +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +--- + drivers/hid/hid-multitouch.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 9ef24b518f12..d8b1cad74faf 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -119,6 +119,9 @@ struct mt_device { + unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ + int cc_index; /* contact count field index in the report */ + 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 mt_report_id; /* the report ID of the multitouch device */ + 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, + EV_MSC, MSC_TIMESTAMP); + input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); + 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; + case HID_DG_CONTACTCOUNT: + /* 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, + static void mt_touch_report(struct hid_device *hid, struct hid_report *report) + { + struct mt_device *td = hid_get_drvdata(hid); ++ __s32 cls = td->mtclass.name; + struct hid_field *field; + unsigned count; +- int r, n; ++ int r, n, scantime = 0; + + /* sticky fingers release in progress, abort */ + 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) + * Includes multi-packet support where subsequent + * 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) { + struct hid_field *field = report->field[td->cc_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->prev_scantime = scantime; + + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; +@@ -1329,6 +1356,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) + td->maxcontact_report_id = -1; + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; + td->cc_index = -1; ++ td->scantime_index = -1; + td->mt_report_id = -1; + hid_set_drvdata(hdev, td); + +-- +2.14.3 + diff --git a/0002-HID-multitouch-Only-look-at-non-touch-fields-in-firs.patch b/0002-HID-multitouch-Only-look-at-non-touch-fields-in-firs.patch new file mode 100644 index 000000000..3ea374ff5 --- /dev/null +++ b/0002-HID-multitouch-Only-look-at-non-touch-fields-in-firs.patch @@ -0,0 +1,84 @@ +From c25d877f4ee97deb92170129eee4777a5d5997d9 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 22 Nov 2017 12:57:09 +0100 +Subject: [PATCH v2 2/3] HID: multitouch: Only look at non touch fields in + first packet of a frame + +Devices in "single finger hybrid mode" will send one report per finger, +on some devices only the first report of such a multi-packet frame will +contain a value for BTN_LEFT, in subsequent reports (if multiple fingers +are down) the value is always 0, causing hid-mt to report BTN_LEFT going +1 - 0 - 1 - 0 when pressing a clickpad and putting down a second finger. +This happens for example on USB 0603:0002 mt touchpads. + +This commit fixes this by only reporting non touch fields for the first +packet of a (possibly) multi-packet frame. + +Signed-off-by: Hans de Goede +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +--- + drivers/hid/hid-multitouch.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index d8b1cad74faf..760c4a042e6a 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -787,9 +787,11 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field, + } + + static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, +- struct hid_usage *usage, __s32 value) ++ struct hid_usage *usage, __s32 value, ++ bool first_packet) + { + struct mt_device *td = hid_get_drvdata(hid); ++ __s32 cls = td->mtclass.name; + __s32 quirks = td->mtclass.quirks; + struct input_dev *input = field->hidinput->input; + +@@ -846,6 +848,15 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, + break; + + default: ++ /* ++ * For Win8 PTP touchpads we should only look at ++ * non finger/touch events in the first_packet of ++ * a (possible) multi-packet frame. ++ */ ++ if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && ++ !first_packet) ++ return; ++ + if (usage->type) + input_event(input, usage->type, usage->code, + value); +@@ -866,6 +877,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) + struct mt_device *td = hid_get_drvdata(hid); + __s32 cls = td->mtclass.name; + struct hid_field *field; ++ bool first_packet; + unsigned count; + int r, n, scantime = 0; + +@@ -901,6 +913,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) + } + td->prev_scantime = scantime; + ++ first_packet = td->num_received == 0; + for (r = 0; r < report->maxfield; r++) { + field = report->field[r]; + count = field->report_count; +@@ -910,7 +923,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) + + for (n = 0; n < count; n++) + mt_process_mt_event(hid, field, &field->usage[n], +- field->value[n]); ++ field->value[n], first_packet); + } + + if (td->num_received >= td->num_expected) +-- +2.14.3 + diff --git a/0003-HID-multitouch-Combine-all-left-button-events-in-a-f.patch b/0003-HID-multitouch-Combine-all-left-button-events-in-a-f.patch new file mode 100644 index 000000000..7fda714cb --- /dev/null +++ b/0003-HID-multitouch-Combine-all-left-button-events-in-a-f.patch @@ -0,0 +1,78 @@ +From 1719566899e5a69b4ba767beb07dab7ceb9ae5a8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 22 Nov 2017 12:57:10 +0100 +Subject: [PATCH v2 3/3] HID: multitouch: Combine all left-button events in a + frame + +According to the Win8 Precision Touchpad spec, inside the HID_UP_BUTTON +usage-page usage 1 is for a clickpad getting clicked, 2 for an external +left button and 3 for an external right button. Since Linux uses +BTN_LEFT for a clickpad being clicked we end up mapping both usage 1 +and 2 to BTN_LEFT and if a single report contains both then we ended +up always reporting the value of both in a single SYN, e.g. : +BTN_LEFT 1, BTN_LEFT 0, SYN. This happens for example with Hantick +HTT5288 i2c mt touchpads. + +This commit fixes this by not immediately reporting left button when we +parse the report, but instead storing or-ing together the values and +reporting the result from mt_sync_frame() when we've a complete frame. + +Signed-off-by: Hans de Goede +Reviewed-by: Benjamin Tissoires +Signed-off-by: Jiri Kosina +--- + drivers/hid/hid-multitouch.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 760c4a042e6a..76088f2cf598 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -122,6 +122,7 @@ struct mt_device { + 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 */ ++ int left_button_state; /* left button state */ + unsigned last_slot_field; /* the last field of a slot */ + unsigned mt_report_id; /* the report ID of the multitouch device */ + unsigned long initial_quirks; /* initial quirks state */ +@@ -743,10 +744,16 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) + */ + static void mt_sync_frame(struct mt_device *td, struct input_dev *input) + { ++ __s32 cls = td->mtclass.name; ++ ++ if (cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) ++ input_event(input, EV_KEY, BTN_LEFT, td->left_button_state); ++ + input_mt_sync_frame(input); + input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp); + input_sync(input); + td->num_received = 0; ++ td->left_button_state = 0; + if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) + set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); + else +@@ -857,6 +864,19 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, + !first_packet) + return; + ++ /* ++ * For Win8 PTP touchpads we map both the clickpad click ++ * and any "external" left buttons to BTN_LEFT if a ++ * device claims to have both we need to report 1 for ++ * BTN_LEFT if either is pressed, so we or all values ++ * together and report the result in mt_sync_frame(). ++ */ ++ if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && ++ usage->type == EV_KEY && usage->code == BTN_LEFT) { ++ td->left_button_state |= value; ++ return; ++ } ++ + if (usage->type) + input_event(input, usage->type, usage->code, + value); +-- +2.14.3 + diff --git a/kernel.spec b/kernel.spec index a2994a2eb..88629d15d 100644 --- a/kernel.spec +++ b/kernel.spec @@ -641,6 +641,13 @@ Patch628: 0001-Bluetooth-btusb-Add-a-Kconfig-option-to-enable-USB-a.patch # rhbz 1516584 Patch629: drm-ttm-don-t-attempt-to-use-hugepages-if-dma32-requested.mbox +# Fix left-button not working with some hid-multitouch touchpads +# Adding these suggested by Benjamin Tissoires +# Queued in hid.git/for-4.16/hid-quirks-cleanup/multitouch for merging into 4.16 +Patch630: 0001-HID-multitouch-Properly-deal-with-Win8-PTP-reports-w.patch +Patch631: 0002-HID-multitouch-Only-look-at-non-touch-fields-in-firs.patch +Patch632: 0003-HID-multitouch-Combine-all-left-button-events-in-a-f.patch + # END OF PATCH DEFINITIONS %endif @@ -2190,6 +2197,9 @@ fi # # %changelog +* Sun Nov 26 2017 Hans de Goede +- Fix left-button not working with some hid-multitouch touchpads + * Thu Nov 23 2017 Laura Abbott - 4.15.0-0.rc0.git7.2 - Fix for TTM regression (rhbz 1516584)