]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
HID: usbhid: prevent unwanted events to be sent when re-opening the device
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Tue, 30 Sep 2014 18:28:22 +0000 (14:28 -0400)
committerJiri Kosina <jkosina@suse.cz>
Wed, 29 Oct 2014 10:04:54 +0000 (11:04 +0100)
When events occurs while no one is listening to the node (hid->open == 0
and usb_kill_urb() called) some events are still stacked somewhere in
the USB (kernel or device?) stack. When the node gets reopened, these
events are drained, and this results in spurious touch down/up, or mouse
button clicks.

The problem was spotted with touchscreens in fdo bug #81781 [1], but it
actually occurs with any mouse using hid-generic or touchscreen.

A way to reproduce it is to call:

$ xinput disable 9 ; sleep 5 ; xinput enable 9

With 9 being the device ID for the touchscreen/mouse. During the "sleep",
produce some touch events or click events. When "xinput enable" is called,
at least one click is generated.

This patch tries to fix this by draining the queue for 50 msec and
during this time frame, not forwarding these old events to the hid layer.

Hans completed the explanation:
"""
Devices like mice (basically any hid device) will have a fifo
on the device side, when we stop submitting urbs to get hid reports from
it, that fifo will fill up, and when we resume we will get whatever
is there in that fifo.
"""

[1] https://bugs.freedesktop.org/show_bug.cgi?id=81781

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/usbhid.h

index ca6849a0121e7bee62b23740f52c0a66bddde5e8..04e34b917045a76e6f5d91b801d86218e00ecf3c 100644 (file)
@@ -278,18 +278,20 @@ static void hid_irq_in(struct urb *urb)
                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);
-               /*
-                * autosuspend refused while keys are pressed
-                * because most keyboards don't wake up when
-                * a key is released
-                */
-               if (hid_check_keys_pressed(hid))
-                       set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
-               else
-                       clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
+               if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
+                       hid_input_report(urb->context, HID_INPUT_REPORT,
+                                        urb->transfer_buffer,
+                                        urb->actual_length, 1);
+                       /*
+                        * autosuspend refused while keys are pressed
+                        * because most keyboards don't wake up when
+                        * a key is released
+                        */
+                       if (hid_check_keys_pressed(hid))
+                               set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
+                       else
+                               clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
+               }
                break;
        case -EPIPE:            /* stall */
                usbhid_mark_busy(usbhid);
@@ -688,6 +690,7 @@ int usbhid_open(struct hid_device *hid)
                        goto done;
                }
                usbhid->intf->needs_remote_wakeup = 1;
+               set_bit(HID_RESUME_RUNNING, &usbhid->iofl);
                res = hid_start_in(hid);
                if (res) {
                        if (res != -ENOSPC) {
@@ -701,6 +704,15 @@ int usbhid_open(struct hid_device *hid)
                        }
                }
                usb_autopm_put_interface(usbhid->intf);
+
+               /*
+                * In case events are generated while nobody was listening,
+                * some are released when the device is re-opened.
+                * Wait 50 msec for the queue to empty before allowing events
+                * to go through hid.
+                */
+               msleep(50);
+               clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
        }
 done:
        mutex_unlock(&hid_open_mut);
index f633c24ce28b8d8f81d831c37059992914e7c32b..807922b49aa494afd09363d941e85dac2f7d6fe0 100644 (file)
@@ -52,6 +52,7 @@ struct usb_interface *usbhid_find_interface(int minor);
 #define HID_STARTED            8
 #define HID_KEYS_PRESSED       10
 #define HID_NO_BANDWIDTH       11
+#define HID_RESUME_RUNNING     12
 
 /*
  * USB-specific HID struct, to be pointed to