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>
This commit is contained in:
Jeff Brown 2011-04-12 23:29:38 -07:00 committed by Dmitry Torokhov
parent b1e064b81e
commit 9fb0f14e31
3 changed files with 28 additions and 12 deletions

View file

@ -85,6 +85,12 @@ sent in the evdev event stream.
- Used to synchronize and separate touch events. See the - Used to synchronize and separate touch events. See the
multi-touch-protocol.txt document for more information. multi-touch-protocol.txt document for more information.
* SYN_DROPPED:
- Used to indicate buffer overrun in the evdev client's event queue.
Client should ignore all events up to and including next SYN_REPORT
event and query the device (using EVIOCG* ioctls) to obtain its
current state.
EV_KEY: EV_KEY:
---------- ----------
EV_KEY events take the form KEY_<name> or BTN_<name>. For example, KEY_A is used EV_KEY events take the form KEY_<name> or BTN_<name>. For example, KEY_A is used

View file

@ -39,13 +39,13 @@ struct evdev {
}; };
struct evdev_client { struct evdev_client {
int head; unsigned int head;
int tail; unsigned int tail;
spinlock_t buffer_lock; /* protects access to buffer, head and tail */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct evdev *evdev; struct evdev *evdev;
struct list_head node; struct list_head node;
int bufsize; unsigned int bufsize;
struct input_event buffer[]; struct input_event buffer[];
}; };
@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex);
static void evdev_pass_event(struct evdev_client *client, static void evdev_pass_event(struct evdev_client *client,
struct input_event *event) struct input_event *event)
{ {
/* /* Interrupts are disabled, just acquire the lock. */
* Interrupts are disabled, just acquire the lock.
* Make sure we don't leave with the client buffer
* "empty" by having client->head == client->tail.
*/
spin_lock(&client->buffer_lock); spin_lock(&client->buffer_lock);
do {
client->buffer[client->head++] = *event; client->buffer[client->head++] = *event;
client->head &= client->bufsize - 1; client->head &= client->bufsize - 1;
} while (client->head == client->tail);
if (unlikely(client->head == client->tail)) {
/*
* This effectively "drops" all unconsumed events, leaving
* EV_SYN/SYN_DROPPED plus the newest event in the queue.
*/
client->tail = (client->head - 2) & (client->bufsize - 1);
client->buffer[client->tail].time = event->time;
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;
}
spin_unlock(&client->buffer_lock); spin_unlock(&client->buffer_lock);
if (event->type == EV_SYN) if (event->type == EV_SYN)

View file

@ -167,6 +167,7 @@ struct input_keymap_entry {
#define SYN_REPORT 0 #define SYN_REPORT 0
#define SYN_CONFIG 1 #define SYN_CONFIG 1
#define SYN_MT_REPORT 2 #define SYN_MT_REPORT 2
#define SYN_DROPPED 3
/* /*
* Keys and buttons * Keys and buttons