Commit d3132792 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Jiri Kosina

HID: usbhid: do not sleep when opening device

usbhid tries to give the device 50 milliseconds to drain its queues when
opening the device, but does it naively by simply sleeping in open handler,
which slows down device probing (and thus may affect overall boot time).

However we do not need to sleep as we can instead mark a point of time in
the future when we should start processing the events.
Reported-by: default avatarNicolas Boichat <drinkcat@chromium.org>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Reviewed-by: default avatarGuenter Roeck <groeck@chromium.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent a789d5f8
......@@ -26,6 +26,7 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/string.h>
#include <linux/timekeeping.h>
#include <linux/usb.h>
......@@ -95,6 +96,18 @@ static int hid_start_in(struct hid_device *hid)
set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
} else {
clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
/*
* 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.
*/
usbhid->input_start_time =
ktime_add_ms(ktime_get_coarse(), 50);
}
}
}
spin_unlock_irqrestore(&usbhid->lock, flags);
......@@ -280,20 +293,23 @@ static void hid_irq_in(struct urb *urb)
if (!test_bit(HID_OPENED, &usbhid->iofl))
break;
usbhid_mark_busy(usbhid);
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);
if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
if (ktime_before(ktime_get_coarse(),
usbhid->input_start_time))
break;
clear_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);
......@@ -720,17 +736,6 @@ static 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.
*/
if (res == 0)
msleep(50);
clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
Done:
mutex_unlock(&usbhid->mutex);
return res;
......
......@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/timer.h>
......@@ -83,6 +84,7 @@ struct usbhid_device {
struct mutex mutex; /* start/stop/open/close */
spinlock_t lock; /* fifo spinlock */
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
ktime_t input_start_time; /* When to start handling input */
struct timer_list io_retry; /* Retry timer */
unsigned long stop_retry; /* Time to give up, in jiffies */
unsigned int retry_delay; /* Delay length in ms */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment