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:
parent
b1e064b81e
commit
9fb0f14e31
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue