aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/evdev.c
diff options
context:
space:
mode:
authorHenrik Rydberg <rydberg@euromail.se>2012-08-29 14:48:02 -0400
committerHenrik Rydberg <rydberg@euromail.se>2012-09-19 13:50:18 -0400
commita274ac15ed069bae4118e3251359240379b6801b (patch)
treedb3f95f8866703b2d50945472a4d8969497f328b /drivers/input/evdev.c
parent4369c64c79a22b98d3b7eff9d089196cd878a10a (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.c68
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 {
54static struct evdev *evdev_table[EVDEV_MINORS]; 54static struct evdev *evdev_table[EVDEV_MINORS];
55static DEFINE_MUTEX(evdev_table_mutex); 55static DEFINE_MUTEX(evdev_table_mutex);
56 56
57static void evdev_pass_event(struct evdev_client *client, 57static 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
84static 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 */
96static void evdev_event(struct input_handle *handle, 117static 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 */
144static 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
127static int evdev_fasync(int fd, struct file *file, int on) 152static int evdev_fasync(int fd, struct file *file, int on)
@@ -1050,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids);
1050 1075
1051static struct input_handler evdev_handler = { 1076static 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,