Skip to content

Commit 4f4001b

Browse files
bentissJiri Kosina
authored andcommitted
HID: multitouch: fix rare Win 8 cases when the touch up event gets missing
Instead of blindly trusting the hardware to send us release, we should consider some events can get lost and release them when we judge time has come. The Windows 8 spec allows to be confident in the fact that the device will continuously report events when a finger touches the surface. This has been tested on the HID recording database I have, and all of those devices behave properly. Also, Arek tested it on his Lenovo Yoga 910, which exports such bug in some situations, when the movements are rather slow. We use an atomic bit here to guard against concurrent accesses to the mt slots because both mt_process_mt_event() and mt_expired_timeout() are called in interrupt context. Signed-off-by: Arek Burdach <arek.burdach@gmail.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Tested-by: Arek Burdach <arek.burdach@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
1 parent fd91189 commit 4f4001b

File tree

1 file changed

+79
-23
lines changed

1 file changed

+79
-23
lines changed

drivers/hid/hid-multitouch.c

Lines changed: 79 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <linux/slab.h>
4545
#include <linux/input/mt.h>
4646
#include <linux/string.h>
47+
#include <linux/timer.h>
4748

4849

4950
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
@@ -70,12 +71,15 @@ MODULE_LICENSE("GPL");
7071
#define MT_QUIRK_FORCE_GET_FEATURE BIT(13)
7172
#define MT_QUIRK_FIX_CONST_CONTACT_ID BIT(14)
7273
#define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15)
74+
#define MT_QUIRK_STICKY_FINGERS BIT(16)
7375

7476
#define MT_INPUTMODE_TOUCHSCREEN 0x02
7577
#define MT_INPUTMODE_TOUCHPAD 0x03
7678

7779
#define MT_BUTTONTYPE_CLICKPAD 0
7880

81+
#define MT_IO_FLAGS_RUNNING 0
82+
7983
struct mt_slot {
8084
__s32 x, y, cx, cy, p, w, h;
8185
__s32 contactid; /* the device ContactID assigned to this slot */
@@ -104,8 +108,10 @@ struct mt_fields {
104108
struct mt_device {
105109
struct mt_slot curdata; /* placeholder of incoming data */
106110
struct mt_class mtclass; /* our mt device class */
111+
struct timer_list release_timer; /* to release sticky fingers */
107112
struct mt_fields *fields; /* temporary placeholder for storing the
108113
multitouch fields */
114+
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
109115
int cc_index; /* contact count field index in the report */
110116
int cc_value_index; /* contact count value index in the field */
111117
unsigned last_slot_field; /* the last field of a slot */
@@ -214,7 +220,8 @@ static struct mt_class mt_classes[] = {
214220
.quirks = MT_QUIRK_ALWAYS_VALID |
215221
MT_QUIRK_IGNORE_DUPLICATES |
216222
MT_QUIRK_HOVERING |
217-
MT_QUIRK_CONTACT_CNT_ACCURATE },
223+
MT_QUIRK_CONTACT_CNT_ACCURATE |
224+
MT_QUIRK_STICKY_FINGERS },
218225
{ .name = MT_CLS_EXPORT_ALL_INPUTS,
219226
.quirks = MT_QUIRK_ALWAYS_VALID |
220227
MT_QUIRK_CONTACT_CNT_ACCURATE,
@@ -804,6 +811,10 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
804811
unsigned count;
805812
int r, n;
806813

814+
/* sticky fingers release in progress, abort */
815+
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
816+
return;
817+
807818
/*
808819
* Includes multi-packet support where subsequent
809820
* packets are sent with zero contactcount.
@@ -829,6 +840,29 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
829840

830841
if (td->num_received >= td->num_expected)
831842
mt_sync_frame(td, report->field[0]->hidinput->input);
843+
844+
/*
845+
* Windows 8 specs says 2 things:
846+
* - once a contact has been reported, it has to be reported in each
847+
* subsequent report
848+
* - the report rate when fingers are present has to be at least
849+
* the refresh rate of the screen, 60 or 120 Hz
850+
*
851+
* I interprete this that the specification forces a report rate of
852+
* at least 60 Hz for a touchscreen to be certified.
853+
* Which means that if we do not get a report whithin 16 ms, either
854+
* something wrong happens, either the touchscreen forgets to send
855+
* a release. Taking a reasonable margin allows to remove issues
856+
* with USB communication or the load of the machine.
857+
*
858+
* Given that Win 8 devices are forced to send a release, this will
859+
* only affect laggish machines and the ones that have a firmware
860+
* defect.
861+
*/
862+
if (td->mtclass.quirks & MT_QUIRK_STICKY_FINGERS)
863+
mod_timer(&td->release_timer, jiffies + msecs_to_jiffies(100));
864+
865+
clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
832866
}
833867

834868
static int mt_touch_input_configured(struct hid_device *hdev,
@@ -1140,6 +1174,46 @@ static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage)
11401174
}
11411175
}
11421176

1177+
static void mt_release_contacts(struct hid_device *hid)
1178+
{
1179+
struct hid_input *hidinput;
1180+
struct mt_device *td = hid_get_drvdata(hid);
1181+
1182+
list_for_each_entry(hidinput, &hid->inputs, list) {
1183+
struct input_dev *input_dev = hidinput->input;
1184+
struct input_mt *mt = input_dev->mt;
1185+
int i;
1186+
1187+
if (mt) {
1188+
for (i = 0; i < mt->num_slots; i++) {
1189+
input_mt_slot(input_dev, i);
1190+
input_mt_report_slot_state(input_dev,
1191+
MT_TOOL_FINGER,
1192+
false);
1193+
}
1194+
input_mt_sync_frame(input_dev);
1195+
input_sync(input_dev);
1196+
}
1197+
}
1198+
1199+
td->num_received = 0;
1200+
}
1201+
1202+
static void mt_expired_timeout(unsigned long arg)
1203+
{
1204+
struct hid_device *hdev = (void *)arg;
1205+
struct mt_device *td = hid_get_drvdata(hdev);
1206+
1207+
/*
1208+
* An input report came in just before we release the sticky fingers,
1209+
* it will take care of the sticky fingers.
1210+
*/
1211+
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
1212+
return;
1213+
mt_release_contacts(hdev);
1214+
clear_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags);
1215+
}
1216+
11431217
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
11441218
{
11451219
int ret, i;
@@ -1209,6 +1283,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
12091283
*/
12101284
hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
12111285

1286+
setup_timer(&td->release_timer, mt_expired_timeout, (long)hdev);
1287+
12121288
ret = hid_parse(hdev);
12131289
if (ret != 0)
12141290
return ret;
@@ -1236,28 +1312,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
12361312
}
12371313

12381314
#ifdef CONFIG_PM
1239-
static void mt_release_contacts(struct hid_device *hid)
1240-
{
1241-
struct hid_input *hidinput;
1242-
1243-
list_for_each_entry(hidinput, &hid->inputs, list) {
1244-
struct input_dev *input_dev = hidinput->input;
1245-
struct input_mt *mt = input_dev->mt;
1246-
int i;
1247-
1248-
if (mt) {
1249-
for (i = 0; i < mt->num_slots; i++) {
1250-
input_mt_slot(input_dev, i);
1251-
input_mt_report_slot_state(input_dev,
1252-
MT_TOOL_FINGER,
1253-
false);
1254-
}
1255-
input_mt_sync_frame(input_dev);
1256-
input_sync(input_dev);
1257-
}
1258-
}
1259-
}
1260-
12611315
static int mt_reset_resume(struct hid_device *hdev)
12621316
{
12631317
mt_release_contacts(hdev);
@@ -1282,6 +1336,8 @@ static void mt_remove(struct hid_device *hdev)
12821336
{
12831337
struct mt_device *td = hid_get_drvdata(hdev);
12841338

1339+
del_timer_sync(&td->release_timer);
1340+
12851341
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
12861342
hid_hw_stop(hdev);
12871343
hdev->quirks = td->initial_quirks;

0 commit comments

Comments
 (0)