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