Input: evdev - do not queue SYN_DROPPED if queue is empty
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 5 Feb 2015 23:56:28 +0000 (15:56 -0800)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Fri, 6 Feb 2015 03:29:02 +0000 (19:29 -0800)
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 <benjamin.tissoires@redhat.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/evdev.c

index e7cee38..a18f41b 100644 (file)
@@ -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);