summaryrefslogtreecommitdiffstats
path: root/drivers/hid/i2c-hid
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>2017-03-08 09:11:14 -0500
committerJiri Kosina <jkosina@suse.cz>2017-03-21 09:59:56 -0400
commit9143059fafd4eebed2d43ffb5455178d4010e60a (patch)
tree58710b0bd2717dea4c871740bcd95c436ae53db0 /drivers/hid/i2c-hid
parent81bbef23db51c0b450d90607fbbc2ad80ee0d43f (diff)
HID: remove initial reading of reports at connect
It looks like a bunch of devices do not like to be polled for their reports at init time. When you look into the details, it seems that for those that are requiring the quirk HID_QUIRK_NO_INIT_REPORTS, the driver fails to retrieve part of the features/inputs while others (more generic) work. IMO, it should be acceptable to remove the need for the quirk in the general case. On the small amount of cases where we actually need to read the current values, the driver in charge (hid-mt or wacom) already retrieves the features manually. There are 2 cases where we might need to retrieve the reports at init: 1. hiddev devices with specific use-space tool 2. a device that would require the driver to fetch a specific feature/input at plug For case 2, I have seen this a few time on hid-multitouch. It is solved in hid-multitouch directly by fetching the feature. I hope it won't be too common and this can be solved on a per-case basis (crossing fingers). For case 1, we moved the implementation of HID_QUIRK_NO_INIT_REPORTS in hiddev. When somebody starts calling ioctls that needs an initial update, the hiddev device will fetch the initial state of the reports to mimic the current behavior. This adds a small amount of time during the first HIDIOCGUSAGE(S), but it should be acceptable in most cases. To keep the currently known broken devices, we have to keep around HID_QUIRK_NO_INIT_REPORTS, but the scope will only be for hiddev. Note that I don't think hidraw would be affected and I checked that the FF drivers that need to interact with the report fields are all using output reports, which are not initialized by usbhid_init_reports(). NO_INIT_INPUT_REPORTS is then replaced by HID_QUIRK_NO_INIT_REPORTS: there is no point keeping it for just one device. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/i2c-hid')
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c63
1 files changed, 0 insertions, 63 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index ea3c3546cef7..042b90d451ee 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -508,66 +508,6 @@ static int i2c_hid_get_report_length(struct hid_report *report)
508 report->device->report_enum[report->type].numbered + 2; 508 report->device->report_enum[report->type].numbered + 2;
509} 509}
510 510
511static void i2c_hid_init_report(struct hid_report *report, u8 *buffer,
512 size_t bufsize)
513{
514 struct hid_device *hid = report->device;
515 struct i2c_client *client = hid->driver_data;
516 struct i2c_hid *ihid = i2c_get_clientdata(client);
517 unsigned int size, ret_size;
518
519 size = i2c_hid_get_report_length(report);
520 if (i2c_hid_get_report(client,
521 report->type == HID_FEATURE_REPORT ? 0x03 : 0x01,
522 report->id, buffer, size))
523 return;
524
525 i2c_hid_dbg(ihid, "report (len=%d): %*ph\n", size, size, buffer);
526
527 ret_size = buffer[0] | (buffer[1] << 8);
528
529 if (ret_size != size) {
530 dev_err(&client->dev, "error in %s size:%d / ret_size:%d\n",
531 __func__, size, ret_size);
532 return;
533 }
534
535 /* hid->driver_lock is held as we are in probe function,
536 * we just need to setup the input fields, so using
537 * hid_report_raw_event is safe. */
538 hid_report_raw_event(hid, report->type, buffer + 2, size - 2, 1);
539}
540
541/*
542 * Initialize all reports
543 */
544static void i2c_hid_init_reports(struct hid_device *hid)
545{
546 struct hid_report *report;
547 struct i2c_client *client = hid->driver_data;
548 struct i2c_hid *ihid = i2c_get_clientdata(client);
549 u8 *inbuf = kzalloc(ihid->bufsize, GFP_KERNEL);
550
551 if (!inbuf) {
552 dev_err(&client->dev, "can not retrieve initial reports\n");
553 return;
554 }
555
556 /*
557 * The device must be powered on while we fetch initial reports
558 * from it.
559 */
560 pm_runtime_get_sync(&client->dev);
561
562 list_for_each_entry(report,
563 &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
564 i2c_hid_init_report(report, inbuf, ihid->bufsize);
565
566 pm_runtime_put(&client->dev);
567
568 kfree(inbuf);
569}
570
571/* 511/*
572 * Traverse the supplied list of reports and find the longest 512 * Traverse the supplied list of reports and find the longest
573 */ 513 */
@@ -789,9 +729,6 @@ static int i2c_hid_start(struct hid_device *hid)
789 return ret; 729 return ret;
790 } 730 }
791 731
792 if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS))
793 i2c_hid_init_reports(hid);
794
795 return 0; 732 return 0;
796} 733}
797 734