aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2015-10-07 08:33:43 -0400
committerJiri Kosina <jkosina@suse.cz>2015-10-11 18:49:19 -0400
commit6d4f5440a3a2bb2e9d0d582bbf98234e9e9bb095 (patch)
tree2dddc9cb6e7edb926ffc9d088c9bc344c3051ff2
parentdc425a1c8c02b45fbab8b3ba522649d238cf84db (diff)
HID: multitouch: Fetch feature reports on demand for Win8 devices
Some newer Intel Skylake based Dell laptops with Win8 precision touchpad fail when initial feature reports are fetched from it. Below is an example output with some additional debug included: i2c_hid i2c-DLL0704:01: Fetching the HID descriptor i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=20 00 i2c_hid i2c-DLL0704:01: HID Descriptor: 1e 00 00 01 99 02 21 00 24 ... ... i2c_hid i2c-DLL0704:01: i2c_hid_get_report i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 38 02 23 00 i2c_hid i2c-DLL0704:01: report (len=4): 04 00 08 05 i2c_hid i2c-DLL0704:01: report id 13 i2c_hid i2c-DLL0704:01: i2c_hid_get_report i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 3d 02 23 00 i2c_hid i2c-DLL0704:01: failed to retrieve report from device. i2c_hid i2c-DLL0704:01: report id 7 i2c_hid i2c-DLL0704:01: i2c_hid_get_report i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 37 02 23 00 i2c_hid i2c-DLL0704:01: report (len=259): 03 01 07 fc 28 fe 84 40 ... i2c_hid i2c-DLL0704:01: report id 4 i2c_hid i2c-DLL0704:01: i2c_hid_get_report i2c_hid i2c-DLL0704:01: __i2c_hid_command: cmd=22 00 34 02 23 00 We manage to fetch few reports but then the touchpad dies: i2c_designware i2c_designware.1: i2c_dw_handle_tx_abort: lost arbitration i2c_hid i2c-DLL0704:01: failed to retrieve report from device. it eventually pulls the whole I2C bus low: i2c_designware i2c_designware.1: controller timed out i2c_hid i2c-DLL0704:01: failed to set a report to device. Fix this by preventing initial feature report retrieval for Win8 devices. Instead we fetch reports as needed in mt_feature_mapping(). This prevents fetching reports which might cause problems with the device in question. Suggested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Tested-by: Seth Forshee <seth.forshee@canonical.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-multitouch.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 661b4fce1a5d..dd64461e5e85 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -309,6 +309,41 @@ static struct attribute_group mt_attribute_group = {
309 .attrs = sysfs_attrs 309 .attrs = sysfs_attrs
310}; 310};
311 311
312static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
313{
314 struct mt_device *td = hid_get_drvdata(hdev);
315 int ret, size = hid_report_len(report);
316 u8 *buf;
317
318 /*
319 * Only fetch the feature report if initial reports are not already
320 * been retrieved. Currently this is only done for Windows 8 touch
321 * devices.
322 */
323 if (!(hdev->quirks & HID_QUIRK_NO_INIT_REPORTS))
324 return;
325 if (td->mtclass.name != MT_CLS_WIN_8)
326 return;
327
328 buf = hid_alloc_report_buf(report, GFP_KERNEL);
329 if (!buf)
330 return;
331
332 ret = hid_hw_raw_request(hdev, report->id, buf, size,
333 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
334 if (ret < 0) {
335 dev_warn(&hdev->dev, "failed to fetch feature %d\n",
336 report->id);
337 } else {
338 ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf,
339 size, 0);
340 if (ret)
341 dev_warn(&hdev->dev, "failed to report feature\n");
342 }
343
344 kfree(buf);
345}
346
312static void mt_feature_mapping(struct hid_device *hdev, 347static void mt_feature_mapping(struct hid_device *hdev,
313 struct hid_field *field, struct hid_usage *usage) 348 struct hid_field *field, struct hid_usage *usage)
314{ 349{
@@ -327,6 +362,8 @@ static void mt_feature_mapping(struct hid_device *hdev,
327 362
328 break; 363 break;
329 case HID_DG_CONTACTMAX: 364 case HID_DG_CONTACTMAX:
365 mt_get_feature(hdev, field->report);
366
330 td->maxcontact_report_id = field->report->id; 367 td->maxcontact_report_id = field->report->id;
331 td->maxcontacts = field->value[0]; 368 td->maxcontacts = field->value[0];
332 if (!td->maxcontacts && 369 if (!td->maxcontacts &&
@@ -343,6 +380,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
343 break; 380 break;
344 } 381 }
345 382
383 mt_get_feature(hdev, field->report);
346 if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD) 384 if (field->value[usage->usage_index] == MT_BUTTONTYPE_CLICKPAD)
347 td->is_buttonpad = true; 385 td->is_buttonpad = true;
348 386
@@ -1029,8 +1067,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
1029 * reports. Fortunately, the Win8 spec says that all touches 1067 * reports. Fortunately, the Win8 spec says that all touches
1030 * should be sent during each report, making the initialization 1068 * should be sent during each report, making the initialization
1031 * of input reports unnecessary. 1069 * of input reports unnecessary.
1070 *
1071 * In addition some touchpads do not behave well if we read
1072 * all feature reports from them. Instead we prevent
1073 * initial report fetching and then selectively fetch each
1074 * report we are interested in.
1032 */ 1075 */
1033 hdev->quirks |= HID_QUIRK_NO_INIT_INPUT_REPORTS; 1076 hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
1034 1077
1035 td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL); 1078 td = devm_kzalloc(&hdev->dev, sizeof(struct mt_device), GFP_KERNEL);
1036 if (!td) { 1079 if (!td) {