aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/evdev.c
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2011-04-13 02:29:38 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2011-04-13 02:35:24 -0400
commit9fb0f14e31b6101a0cc69a333b43541044f9b0a6 (patch)
treea384acf387f5dff50e0c3a56fa54336dedd286c5 /drivers/input/evdev.c
parentb1e064b81e238d47cb56544b34c9baf473e09837 (diff)
Input: evdev - indicate buffer overrun with SYN_DROPPED
Add a new EV_SYN code, SYN_DROPPED, to inform the client when input events have been dropped from the evdev input buffer due to a buffer overrun. The client should use this event as a hint to reset its state or ignore all following events until the next packet begins. Signed-off-by: Jeff Brown <jeffbrown@android.com> [dtor@mail.ru: Implement Henrik's suggestion and drop old events in case of overflow.] Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r--drivers/input/evdev.c33
1 files changed, 21 insertions, 12 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 7f42d3a454d2..88d8e4cb419a 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -39,13 +39,13 @@ struct evdev {
39}; 39};
40 40
41struct evdev_client { 41struct evdev_client {
42 int head; 42 unsigned int head;
43 int tail; 43 unsigned int tail;
44 spinlock_t buffer_lock; /* protects access to buffer, head and tail */ 44 spinlock_t buffer_lock; /* protects access to buffer, head and tail */
45 struct fasync_struct *fasync; 45 struct fasync_struct *fasync;
46 struct evdev *evdev; 46 struct evdev *evdev;
47 struct list_head node; 47 struct list_head node;
48 int bufsize; 48 unsigned int bufsize;
49 struct input_event buffer[]; 49 struct input_event buffer[];
50}; 50};
51 51
@@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex);
55static void evdev_pass_event(struct evdev_client *client, 55static void evdev_pass_event(struct evdev_client *client,
56 struct input_event *event) 56 struct input_event *event)
57{ 57{
58 /* 58 /* Interrupts are disabled, just acquire the lock. */
59 * Interrupts are disabled, just acquire the lock.
60 * Make sure we don't leave with the client buffer
61 * "empty" by having client->head == client->tail.
62 */
63 spin_lock(&client->buffer_lock); 59 spin_lock(&client->buffer_lock);
64 do { 60
65 client->buffer[client->head++] = *event; 61 client->buffer[client->head++] = *event;
66 client->head &= client->bufsize - 1; 62 client->head &= client->bufsize - 1;
67 } while (client->head == client->tail); 63
64 if (unlikely(client->head == client->tail)) {
65 /*
66 * This effectively "drops" all unconsumed events, leaving
67 * EV_SYN/SYN_DROPPED plus the newest event in the queue.
68 */
69 client->tail = (client->head - 2) & (client->bufsize - 1);
70
71 client->buffer[client->tail].time = event->time;
72 client->buffer[client->tail].type = EV_SYN;
73 client->buffer[client->tail].code = SYN_DROPPED;
74 client->buffer[client->tail].value = 0;
75 }
76
68 spin_unlock(&client->buffer_lock); 77 spin_unlock(&client->buffer_lock);
69 78
70 if (event->type == EV_SYN) 79 if (event->type == EV_SYN)