diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2017-03-08 15:11:14 +0100 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2017-03-21 14:59:56 +0100 |
commit | 9143059fafd4eebed2d43ffb5455178d4010e60a (patch) | |
tree | 58710b0bd2717dea4c871740bcd95c436ae53db0 /drivers/hid/usbhid | |
parent | Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jik... (diff) | |
download | linux-9143059fafd4eebed2d43ffb5455178d4010e60a.tar.xz linux-9143059fafd4eebed2d43ffb5455178d4010e60a.zip |
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/usbhid')
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 11 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 2 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 13 |
3 files changed, 17 insertions, 9 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 961bc6fdd2d9..00e72c6ffc76 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -753,11 +753,9 @@ void usbhid_init_reports(struct hid_device *hid) struct hid_report_enum *report_enum; int err, ret; - if (!(hid->quirks & HID_QUIRK_NO_INIT_INPUT_REPORTS)) { - report_enum = &hid->report_enum[HID_INPUT_REPORT]; - list_for_each_entry(report, &report_enum->report_list, list) - usbhid_submit_report(hid, report, USB_DIR_IN); - } + report_enum = &hid->report_enum[HID_INPUT_REPORT]; + list_for_each_entry(report, &report_enum->report_list, list) + usbhid_submit_report(hid, report, USB_DIR_IN); report_enum = &hid->report_enum[HID_FEATURE_REPORT]; list_for_each_entry(report, &report_enum->report_list, list) @@ -1120,9 +1118,6 @@ static int usbhid_start(struct hid_device *hid) usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; usbhid->urbctrl->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS)) - usbhid_init_reports(hid); - set_bit(HID_STARTED, &usbhid->iofl); if (hid->quirks & HID_QUIRK_ALWAYS_POLL) { diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index d6847a664446..ec4fdba39722 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -158,7 +158,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_INPUT_REPORTS }, + { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 700145b15088..667171829f65 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -54,6 +54,7 @@ struct hiddev { struct hid_device *hid; struct list_head list; spinlock_t list_lock; + bool initialized; }; struct hiddev_list { @@ -689,6 +690,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case HIDIOCINITREPORT: usbhid_init_reports(hid); + hiddev->initialized = true; r = 0; break; @@ -790,6 +792,10 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case HIDIOCGUSAGES: case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: + if (!hiddev->initialized) { + usbhid_init_reports(hid); + hiddev->initialized = true; + } r = hiddev_ioctl_usage(hiddev, cmd, user_arg); break; @@ -910,6 +916,13 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) kfree(hiddev); return -1; } + + /* + * If HID_QUIRK_NO_INIT_REPORTS is set, make sure we don't initialize + * the reports. + */ + hiddev->initialized = hid->quirks & HID_QUIRK_NO_INIT_REPORTS; + return 0; } |