Skip to content

Commit

Permalink
Input: evdev - Add the events() callback
Browse files Browse the repository at this point in the history
By sending a full frame of events at the same time, the irqsoff
latency at heavy load is brought down from 200 us to 100 us.

Cc: Daniel Kurtz <djkurtz@chromium.org>
Tested-by: Benjamin Tissoires <benjamin.tissoires@enac.fr>
Tested-by: Ping Cheng <pingc@wacom.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
  • Loading branch information
Henrik Rydberg committed Sep 19, 2012
1 parent 4369c64 commit a274ac1
Showing 1 changed file with 47 additions and 21 deletions.
68 changes: 47 additions & 21 deletions drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,9 @@ struct evdev_client {
static struct evdev *evdev_table[EVDEV_MINORS];
static DEFINE_MUTEX(evdev_table_mutex);

static void evdev_pass_event(struct evdev_client *client,
struct input_event *event,
ktime_t mono, ktime_t real)
static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);

/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);

client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1;

Expand All @@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client,
client->packet_head = client->head;
kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
}

static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count,
ktime_t mono, ktime_t real)
{
struct evdev *evdev = client->evdev;
const struct input_value *v;
struct input_event event;
bool wakeup = false;

event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
mono : real);

/* Interrupts are disabled, just acquire the lock. */
spin_lock(&client->buffer_lock);

for (v = vals; v != vals + count; v++) {
event.type = v->type;
event.code = v->code;
event.value = v->value;
__pass_event(client, &event);
if (v->type == EV_SYN && v->code == SYN_REPORT)
wakeup = true;
}

spin_unlock(&client->buffer_lock);

if (wakeup)
wake_up_interruptible(&evdev->wait);
}

/*
* Pass incoming event to all connected clients.
* Pass incoming events to all connected clients.
*/
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
static void evdev_events(struct input_handle *handle,
const struct input_value *vals, unsigned int count)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
struct input_event event;
ktime_t time_mono, time_real;

time_mono = ktime_get();
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());

event.type = type;
event.code = code;
event.value = value;

rcu_read_lock();

client = rcu_dereference(evdev->grab);

if (client)
evdev_pass_event(client, &event, time_mono, time_real);
evdev_pass_values(client, vals, count, time_mono, time_real);
else
list_for_each_entry_rcu(client, &evdev->client_list, node)
evdev_pass_event(client, &event, time_mono, time_real);
evdev_pass_values(client, vals, count,
time_mono, time_real);

rcu_read_unlock();
}

if (type == EV_SYN && code == SYN_REPORT)
wake_up_interruptible(&evdev->wait);
/*
* Pass incoming event to all connected clients.
*/
static void evdev_event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
struct input_value vals[] = { { type, code, value } };

evdev_events(handle, vals, 1);
}

static int evdev_fasync(int fd, struct file *file, int on)
Expand Down Expand Up @@ -1050,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids);

static struct input_handler evdev_handler = {
.event = evdev_event,
.events = evdev_events,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
.fops = &evdev_fops,
Expand Down

0 comments on commit a274ac1

Please sign in to comment.