| From 0b750b3baa2d64f1b77aecc10f20deeb28efe60d Mon Sep 17 00:00:00 2001 |
| From: Johan Hovold <johan@kernel.org> |
| Date: Fri, 5 Sep 2014 18:08:47 +0200 |
| Subject: HID: usbhid: add always-poll quirk |
| |
| From: Johan Hovold <johan@kernel.org> |
| |
| commit 0b750b3baa2d64f1b77aecc10f20deeb28efe60d upstream. |
| |
| Add quirk to make sure that a device is always polled for input events |
| even if it hasn't been opened. |
| |
| This is needed for devices that disconnects from the bus unless the |
| interrupt endpoint has been polled at least once or when not responding |
| to an input event (e.g. after having shut down X). |
| |
| Signed-off-by: Johan Hovold <johan@kernel.org> |
| Signed-off-by: Jiri Kosina <jkosina@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/hid/usbhid/hid-core.c | 26 +++++++++++++++++++++++--- |
| include/linux/hid.h | 1 + |
| 2 files changed, 24 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/hid/usbhid/hid-core.c |
| +++ b/drivers/hid/usbhid/hid-core.c |
| @@ -82,7 +82,7 @@ static int hid_start_in(struct hid_devic |
| struct usbhid_device *usbhid = hid->driver_data; |
| |
| spin_lock_irqsave(&usbhid->lock, flags); |
| - if (hid->open > 0 && |
| + if ((hid->open > 0 || hid->quirks & HID_QUIRK_ALWAYS_POLL) && |
| !test_bit(HID_DISCONNECTED, &usbhid->iofl) && |
| !test_bit(HID_SUSPENDED, &usbhid->iofl) && |
| !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { |
| @@ -292,6 +292,8 @@ static void hid_irq_in(struct urb *urb) |
| case 0: /* success */ |
| usbhid_mark_busy(usbhid); |
| usbhid->retry_delay = 0; |
| + if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open) |
| + break; |
| hid_input_report(urb->context, HID_INPUT_REPORT, |
| urb->transfer_buffer, |
| urb->actual_length, 1); |
| @@ -735,8 +737,10 @@ void usbhid_close(struct hid_device *hid |
| if (!--hid->open) { |
| spin_unlock_irq(&usbhid->lock); |
| hid_cancel_delayed_stuff(usbhid); |
| - usb_kill_urb(usbhid->urbin); |
| - usbhid->intf->needs_remote_wakeup = 0; |
| + if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) { |
| + usb_kill_urb(usbhid->urbin); |
| + usbhid->intf->needs_remote_wakeup = 0; |
| + } |
| } else { |
| spin_unlock_irq(&usbhid->lock); |
| } |
| @@ -1134,6 +1138,19 @@ static int usbhid_start(struct hid_devic |
| |
| set_bit(HID_STARTED, &usbhid->iofl); |
| |
| + if (hid->quirks & HID_QUIRK_ALWAYS_POLL) { |
| + ret = usb_autopm_get_interface(usbhid->intf); |
| + if (ret) |
| + goto fail; |
| + usbhid->intf->needs_remote_wakeup = 1; |
| + ret = hid_start_in(hid); |
| + if (ret) { |
| + dev_err(&hid->dev, |
| + "failed to start in urb: %d\n", ret); |
| + } |
| + usb_autopm_put_interface(usbhid->intf); |
| + } |
| + |
| /* Some keyboards don't work until their LEDs have been set. |
| * Since BIOSes do set the LEDs, it must be safe for any device |
| * that supports the keyboard boot protocol. |
| @@ -1166,6 +1183,9 @@ static void usbhid_stop(struct hid_devic |
| if (WARN_ON(!usbhid)) |
| return; |
| |
| + if (hid->quirks & HID_QUIRK_ALWAYS_POLL) |
| + usbhid->intf->needs_remote_wakeup = 0; |
| + |
| clear_bit(HID_STARTED, &usbhid->iofl); |
| spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ |
| set_bit(HID_DISCONNECTED, &usbhid->iofl); |
| --- a/include/linux/hid.h |
| +++ b/include/linux/hid.h |
| @@ -287,6 +287,7 @@ struct hid_item { |
| #define HID_QUIRK_HIDINPUT_FORCE 0x00000080 |
| #define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 |
| #define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200 |
| +#define HID_QUIRK_ALWAYS_POLL 0x00000400 |
| #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 |
| #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000 |
| #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000 |