From 0c3e99437a66e4c869c60c2398449e6d98f3a988 Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Thu, 15 Jan 2015 09:06:50 -0800 Subject: Input: evdev - flush pending events on clock type change When client changes the type of clock used for the time stamps in input events flush pending events from the client's queue (since client would not know which events have old time stamps and which ones have new ones) and and queue SYN_DROPPED event. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 55 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index b1a52abc58df..8d4c6ca781ff 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -62,26 +62,6 @@ struct evdev_client { struct input_event buffer[]; }; -static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) -{ - switch (clkid) { - - case CLOCK_REALTIME: - client->clk_type = EV_CLK_REAL; - break; - case CLOCK_MONOTONIC: - client->clk_type = EV_CLK_MONO; - break; - case CLOCK_BOOTTIME: - client->clk_type = EV_CLK_BOOT; - break; - default: - return -EINVAL; - } - - return 0; -} - /* flush queued events of type @type, caller must hold client->buffer_lock */ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) { @@ -128,8 +108,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) client->head = head; } -/* queue SYN_DROPPED event */ -static void evdev_queue_syn_dropped(struct evdev_client *client) +/* queue SYN_DROPPED event and flush queue if flush parameter is true */ +static void evdev_queue_syn_dropped(struct evdev_client *client, bool flush) { unsigned long flags; struct input_event ev; @@ -148,6 +128,9 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) spin_lock_irqsave(&client->buffer_lock, flags); + if (flush) + client->packet_head = client->head = client->tail; + client->buffer[client->head++] = ev; client->head &= client->bufsize - 1; @@ -160,6 +143,32 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) spin_unlock_irqrestore(&client->buffer_lock, flags); } +static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) +{ + if (client->clk_type == clkid) + return 0; + + switch (clkid) { + + case CLOCK_REALTIME: + client->clk_type = EV_CLK_REAL; + break; + case CLOCK_MONOTONIC: + client->clk_type = EV_CLK_MONO; + break; + case CLOCK_BOOTTIME: + client->clk_type = EV_CLK_BOOT; + break; + default: + return -EINVAL; + } + + /* Flush pending events and queue SYN_DROPPED event.*/ + evdev_queue_syn_dropped(client, true); + + return 0; +} + static void __pass_event(struct evdev_client *client, const struct input_event *event) { @@ -794,7 +803,7 @@ static int evdev_handle_get_val(struct evdev_client *client, ret = bits_to_user(mem, maxbit, maxlen, p, compat); if (ret < 0) - evdev_queue_syn_dropped(client); + evdev_queue_syn_dropped(client, false); kfree(mem); -- cgit v1.2.3 From b881d53770e68f3f9b6097a61dd1685180393f20 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 5 Feb 2015 15:56:28 -0800 Subject: Input: evdev - do not queue SYN_DROPPED if queue is empty There is no point in queueing EV_SYN/SYN_DROPPED on clock type change when there are no events in the client's queue and doing so confuses tests in libinput package, so let's not do that. Reported-and-tested-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers/input/evdev.c') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e7cee3880b75..a18f41b89b6a 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -108,10 +108,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) client->head = head; } -/* queue SYN_DROPPED event and flush queue if flush parameter is true */ -static void evdev_queue_syn_dropped(struct evdev_client *client, bool flush) +static void __evdev_queue_syn_dropped(struct evdev_client *client) { - unsigned long flags; struct input_event ev; ktime_t time; @@ -126,11 +124,6 @@ static void evdev_queue_syn_dropped(struct evdev_client *client, bool flush) ev.code = SYN_DROPPED; ev.value = 0; - spin_lock_irqsave(&client->buffer_lock, flags); - - if (flush) - client->packet_head = client->head = client->tail; - client->buffer[client->head++] = ev; client->head &= client->bufsize - 1; @@ -139,12 +132,21 @@ static void evdev_queue_syn_dropped(struct evdev_client *client, bool flush) client->tail = (client->head - 1) & (client->bufsize - 1); client->packet_head = client->tail; } +} + +static void evdev_queue_syn_dropped(struct evdev_client *client) +{ + unsigned long flags; + spin_lock_irqsave(&client->buffer_lock, flags); + __evdev_queue_syn_dropped(client); spin_unlock_irqrestore(&client->buffer_lock, flags); } static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) { + unsigned long flags; + if (client->clk_type == clkid) return 0; @@ -163,8 +165,18 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) return -EINVAL; } - /* Flush pending events and queue SYN_DROPPED event.*/ - evdev_queue_syn_dropped(client, true); + /* + * Flush pending events and queue SYN_DROPPED event, + * but only if the queue is not empty. + */ + spin_lock_irqsave(&client->buffer_lock, flags); + + if (client->head != client->tail) { + client->packet_head = client->head = client->tail; + __evdev_queue_syn_dropped(client); + } + + spin_unlock_irqrestore(&client->buffer_lock, flags); return 0; } @@ -803,7 +815,7 @@ static int evdev_handle_get_val(struct evdev_client *client, ret = bits_to_user(mem, maxbit, maxlen, p, compat); if (ret < 0) - evdev_queue_syn_dropped(client, false); + evdev_queue_syn_dropped(client); kfree(mem); -- cgit v1.2.3