aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2014-09-05 12:08:47 -0400
committerJiri Kosina <jkosina@suse.cz>2014-09-08 03:29:15 -0400
commit0b750b3baa2d64f1b77aecc10f20deeb28efe60d (patch)
tree1d60afffd83b736b23f9ca6fcec482bcd89c13fe
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>
-rw-r--r--drivers/hid/usbhid/hid-core.c26
-rw-r--r--include/linux/hid.h1
2 files changed, 24 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)
82 struct usbhid_device *usbhid = hid->driver_data; 82 struct usbhid_device *usbhid = hid->driver_data;
83 83
84 spin_lock_irqsave(&usbhid->lock, flags); 84 spin_lock_irqsave(&usbhid->lock, flags);
85 if (hid->open > 0 && 85 if ((hid->open > 0 || hid->quirks & HID_QUIRK_ALWAYS_POLL) &&
86 !test_bit(HID_DISCONNECTED, &usbhid->iofl) && 86 !test_bit(HID_DISCONNECTED, &usbhid->iofl) &&
87 !test_bit(HID_SUSPENDED, &usbhid->iofl) && 87 !test_bit(HID_SUSPENDED, &usbhid->iofl) &&
88 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { 88 !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
@@ -292,6 +292,8 @@ static void hid_irq_in(struct urb *urb)
292 case 0: /* success */ 292 case 0: /* success */
293 usbhid_mark_busy(usbhid); 293 usbhid_mark_busy(usbhid);
294 usbhid->retry_delay = 0; 294 usbhid->retry_delay = 0;
295 if ((hid->quirks & HID_QUIRK_ALWAYS_POLL) && !hid->open)
296 break;
295 hid_input_report(urb->context, HID_INPUT_REPORT, 297 hid_input_report(urb->context, HID_INPUT_REPORT,
296 urb->transfer_buffer, 298 urb->transfer_buffer,
297 urb->actual_length, 1); 299 urb->actual_length, 1);
@@ -735,8 +737,10 @@ void usbhid_close(struct hid_device *hid)
735 if (!--hid->open) { 737 if (!--hid->open) {
736 spin_unlock_irq(&usbhid->lock); 738 spin_unlock_irq(&usbhid->lock);
737 hid_cancel_delayed_stuff(usbhid); 739 hid_cancel_delayed_stuff(usbhid);
738 usb_kill_urb(usbhid->urbin); 740 if (!(hid->quirks & HID_QUIRK_ALWAYS_POLL)) {
739 usbhid->intf->needs_remote_wakeup = 0; 741 usb_kill_urb(usbhid->urbin);
742 usbhid->intf->needs_remote_wakeup = 0;
743 }
740 } else { 744 } else {
741 spin_unlock_irq(&usbhid->lock); 745 spin_unlock_irq(&usbhid->lock);
742 } 746 }
@@ -1134,6 +1138,19 @@ static int usbhid_start(struct hid_device *hid)
1134 1138
1135 set_bit(HID_STARTED, &usbhid->iofl); 1139 set_bit(HID_STARTED, &usbhid->iofl);
1136 1140
1141 if (hid->quirks & HID_QUIRK_ALWAYS_POLL) {
1142 ret = usb_autopm_get_interface(usbhid->intf);
1143 if (ret)
1144 goto fail;
1145 usbhid->intf->needs_remote_wakeup = 1;
1146 ret = hid_start_in(hid);
1147 if (ret) {
1148 dev_err(&hid->dev,
1149 "failed to start in urb: %d\n", ret);
1150 }
1151 usb_autopm_put_interface(usbhid->intf);
1152 }
1153
1137 /* Some keyboards don't work until their LEDs have been set. 1154 /* Some keyboards don't work until their LEDs have been set.
1138 * Since BIOSes do set the LEDs, it must be safe for any device 1155 * Since BIOSes do set the LEDs, it must be safe for any device
1139 * that supports the keyboard boot protocol. 1156 * that supports the keyboard boot protocol.
@@ -1166,6 +1183,9 @@ static void usbhid_stop(struct hid_device *hid)
1166 if (WARN_ON(!usbhid)) 1183 if (WARN_ON(!usbhid))
1167 return; 1184 return;
1168 1185
1186 if (hid->quirks & HID_QUIRK_ALWAYS_POLL)
1187 usbhid->intf->needs_remote_wakeup = 0;
1188
1169 clear_bit(HID_STARTED, &usbhid->iofl); 1189 clear_bit(HID_STARTED, &usbhid->iofl);
1170 spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */ 1190 spin_lock_irq(&usbhid->lock); /* Sync with error and led handlers */
1171 set_bit(HID_DISCONNECTED, &usbhid->iofl); 1191 set_bit(HID_DISCONNECTED, &usbhid->iofl);
diff --git a/include/linux/hid.h b/include/linux/hid.h
index f53c4a9cca1d..26ee25fced27 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -287,6 +287,7 @@ struct hid_item {
287#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 287#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
288#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 288#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
289#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200 289#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200
290#define HID_QUIRK_ALWAYS_POLL 0x00000400
290#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 291#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
291#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000 292#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
292#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000 293#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000