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