HID: usbhid: add always-poll quirk
Johan Hovold [Fri, 5 Sep 2014 16:08:47 +0000 (18:08 +0200)]
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).

Bug 200094818

Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
(cherry picked from commit 0b750b3baa2d64f1b77aecc10f20deeb28efe60d in mainline v3.18)

Change-Id: I8220fa3c64b64b5fbadec0c3db231d1266342af4
Reviewed-on: http://git-master/r/1154422
(cherry picked from commit 75e507f9dee005fbfad7b88e0aa77a327b06f6bb)
Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-on: http://git-master/r/1169173
GVS: Gerrit_Virtual_Submit
Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>

drivers/hid/usbhid/hid-core.c
include/linux/hid.h

index e949cd4..31dd227 100644 (file)
@@ -83,7 +83,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)) {
@@ -307,6 +307,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);
@@ -809,8 +811,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);
        }
@@ -1206,6 +1210,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.
@@ -1246,6 +1263,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);
index 40e9c9d..184dc57 100644 (file)
@@ -283,6 +283,7 @@ struct hid_item {
 #define HID_QUIRK_MULTI_INPUT                  0x00000040
 #define HID_QUIRK_HIDINPUT_FORCE               0x00000080
 #define HID_QUIRK_NO_EMPTY_INPUT               0x00000100
+#define HID_QUIRK_ALWAYS_POLL                  0x00000400
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00010000
 #define HID_QUIRK_FULLSPEED_INTERVAL           0x10000000
 #define HID_QUIRK_NO_INIT_REPORTS              0x20000000