aboutsummaryrefslogtreecommitdiff
path: root/drivers/hid/usbhid/hid-core.c
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2014-09-05 18:08:47 +0200
committerJiri Kosina <jkosina@suse.cz>2014-09-08 09:29:15 +0200
commit0b750b3baa2d64f1b77aecc10f20deeb28efe60d (patch)
tree1d60afffd83b736b23f9ca6fcec482bcd89c13fe /drivers/hid/usbhid/hid-core.c
parentff0c57ac70434bc936cb0110eaf033a0a1a62e52 (diff)
HID: usbhid: add always-poll quirk
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>
Diffstat (limited to 'drivers/hid/usbhid/hid-core.c')
-rw-r--r--drivers/hid/usbhid/hid-core.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 79cf503e37bf..ddd547ad6d7e 100644
--- 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_device *hid)
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_device *hid)
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_device *hid)
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);