diff options
author | Henrik Rydberg <rydberg@euromail.se> | 2012-08-29 14:48:02 -0400 |
---|---|---|
committer | Henrik Rydberg <rydberg@euromail.se> | 2012-09-19 13:50:18 -0400 |
commit | a274ac15ed069bae4118e3251359240379b6801b (patch) | |
tree | db3f95f8866703b2d50945472a4d8969497f328b /drivers/input/evdev.c | |
parent | 4369c64c79a22b98d3b7eff9d089196cd878a10a (diff) |
Input: evdev - Add the events() callback
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>
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 68 |
1 files changed, 47 insertions, 21 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index a0692c551be5..118d0300f1fb 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -54,16 +54,9 @@ struct evdev_client { | |||
54 | static struct evdev *evdev_table[EVDEV_MINORS]; | 54 | static struct evdev *evdev_table[EVDEV_MINORS]; |
55 | static DEFINE_MUTEX(evdev_table_mutex); | 55 | static DEFINE_MUTEX(evdev_table_mutex); |
56 | 56 | ||
57 | static void evdev_pass_event(struct evdev_client *client, | 57 | static void __pass_event(struct evdev_client *client, |
58 | struct input_event *event, | 58 | const struct input_event *event) |
59 | ktime_t mono, ktime_t real) | ||
60 | { | 59 | { |
61 | event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
62 | mono : real); | ||
63 | |||
64 | /* Interrupts are disabled, just acquire the lock. */ | ||
65 | spin_lock(&client->buffer_lock); | ||
66 | |||
67 | client->buffer[client->head++] = *event; | 60 | client->buffer[client->head++] = *event; |
68 | client->head &= client->bufsize - 1; | 61 | client->head &= client->bufsize - 1; |
69 | 62 | ||
@@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client, | |||
86 | client->packet_head = client->head; | 79 | client->packet_head = client->head; |
87 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 80 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
88 | } | 81 | } |
82 | } | ||
83 | |||
84 | static void evdev_pass_values(struct evdev_client *client, | ||
85 | const struct input_value *vals, unsigned int count, | ||
86 | ktime_t mono, ktime_t real) | ||
87 | { | ||
88 | struct evdev *evdev = client->evdev; | ||
89 | const struct input_value *v; | ||
90 | struct input_event event; | ||
91 | bool wakeup = false; | ||
92 | |||
93 | event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
94 | mono : real); | ||
95 | |||
96 | /* Interrupts are disabled, just acquire the lock. */ | ||
97 | spin_lock(&client->buffer_lock); | ||
98 | |||
99 | for (v = vals; v != vals + count; v++) { | ||
100 | event.type = v->type; | ||
101 | event.code = v->code; | ||
102 | event.value = v->value; | ||
103 | __pass_event(client, &event); | ||
104 | if (v->type == EV_SYN && v->code == SYN_REPORT) | ||
105 | wakeup = true; | ||
106 | } | ||
89 | 107 | ||
90 | spin_unlock(&client->buffer_lock); | 108 | spin_unlock(&client->buffer_lock); |
109 | |||
110 | if (wakeup) | ||
111 | wake_up_interruptible(&evdev->wait); | ||
91 | } | 112 | } |
92 | 113 | ||
93 | /* | 114 | /* |
94 | * Pass incoming event to all connected clients. | 115 | * Pass incoming events to all connected clients. |
95 | */ | 116 | */ |
96 | static void evdev_event(struct input_handle *handle, | 117 | static void evdev_events(struct input_handle *handle, |
97 | unsigned int type, unsigned int code, int value) | 118 | const struct input_value *vals, unsigned int count) |
98 | { | 119 | { |
99 | struct evdev *evdev = handle->private; | 120 | struct evdev *evdev = handle->private; |
100 | struct evdev_client *client; | 121 | struct evdev_client *client; |
101 | struct input_event event; | ||
102 | ktime_t time_mono, time_real; | 122 | ktime_t time_mono, time_real; |
103 | 123 | ||
104 | time_mono = ktime_get(); | 124 | time_mono = ktime_get(); |
105 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); | 125 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); |
106 | 126 | ||
107 | event.type = type; | ||
108 | event.code = code; | ||
109 | event.value = value; | ||
110 | |||
111 | rcu_read_lock(); | 127 | rcu_read_lock(); |
112 | 128 | ||
113 | client = rcu_dereference(evdev->grab); | 129 | client = rcu_dereference(evdev->grab); |
114 | 130 | ||
115 | if (client) | 131 | if (client) |
116 | evdev_pass_event(client, &event, time_mono, time_real); | 132 | evdev_pass_values(client, vals, count, time_mono, time_real); |
117 | else | 133 | else |
118 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 134 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
119 | evdev_pass_event(client, &event, time_mono, time_real); | 135 | evdev_pass_values(client, vals, count, |
136 | time_mono, time_real); | ||
120 | 137 | ||
121 | rcu_read_unlock(); | 138 | rcu_read_unlock(); |
139 | } | ||
122 | 140 | ||
123 | if (type == EV_SYN && code == SYN_REPORT) | 141 | /* |
124 | wake_up_interruptible(&evdev->wait); | 142 | * Pass incoming event to all connected clients. |
143 | */ | ||
144 | static void evdev_event(struct input_handle *handle, | ||
145 | unsigned int type, unsigned int code, int value) | ||
146 | { | ||
147 | struct input_value vals[] = { { type, code, value } }; | ||
148 | |||
149 | evdev_events(handle, vals, 1); | ||
125 | } | 150 | } |
126 | 151 | ||
127 | static int evdev_fasync(int fd, struct file *file, int on) | 152 | static int evdev_fasync(int fd, struct file *file, int on) |
@@ -1050,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids); | |||
1050 | 1075 | ||
1051 | static struct input_handler evdev_handler = { | 1076 | static struct input_handler evdev_handler = { |
1052 | .event = evdev_event, | 1077 | .event = evdev_event, |
1078 | .events = evdev_events, | ||
1053 | .connect = evdev_connect, | 1079 | .connect = evdev_connect, |
1054 | .disconnect = evdev_disconnect, | 1080 | .disconnect = evdev_disconnect, |
1055 | .fops = &evdev_fops, | 1081 | .fops = &evdev_fops, |