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:
Родитель
b1e064b81e
Коммит
9fb0f14e31
|
@ -85,6 +85,12 @@ sent in the evdev event stream.
|
|||
- Used to synchronize and separate touch events. See the
|
||||
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 events take the form KEY_<name> or BTN_<name>. For example, KEY_A is used
|
||||
|
|
|
@ -39,13 +39,13 @@ struct evdev {
|
|||
};
|
||||
|
||||
struct evdev_client {
|
||||
int head;
|
||||
int tail;
|
||||
unsigned int head;
|
||||
unsigned int tail;
|
||||
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
|
||||
struct fasync_struct *fasync;
|
||||
struct evdev *evdev;
|
||||
struct list_head node;
|
||||
int bufsize;
|
||||
unsigned int bufsize;
|
||||
struct input_event buffer[];
|
||||
};
|
||||
|
||||
|
@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex);
|
|||
static void evdev_pass_event(struct evdev_client *client,
|
||||
struct input_event *event)
|
||||
{
|
||||
/*
|
||||
* Interrupts are disabled, just acquire the lock.
|
||||
* Make sure we don't leave with the client buffer
|
||||
* "empty" by having client->head == client->tail.
|
||||
*/
|
||||
/* Interrupts are disabled, just acquire the lock. */
|
||||
spin_lock(&client->buffer_lock);
|
||||
do {
|
||||
client->buffer[client->head++] = *event;
|
||||
client->head &= client->bufsize - 1;
|
||||
} while (client->head == client->tail);
|
||||
|
||||
client->buffer[client->head++] = *event;
|
||||
client->head &= client->bufsize - 1;
|
||||
|
||||
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);
|
||||
|
||||
if (event->type == EV_SYN)
|
||||
|
|
|
@ -167,6 +167,7 @@ struct input_keymap_entry {
|
|||
#define SYN_REPORT 0
|
||||
#define SYN_CONFIG 1
|
||||
#define SYN_MT_REPORT 2
|
||||
#define SYN_DROPPED 3
|
||||
|
||||
/*
|
||||
* Keys and buttons
|
||||
|
|
Загрузка…
Ссылка в новой задаче