From patchwork Thu Jan 14 16:45:22 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aniroop Mathur X-Patchwork-Id: 8034021 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id C95289F744 for ; Thu, 14 Jan 2016 16:45:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D4E4D20499 for ; Thu, 14 Jan 2016 16:45:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E997420497 for ; Thu, 14 Jan 2016 16:45:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756312AbcANQpx (ORCPT ); Thu, 14 Jan 2016 11:45:53 -0500 Received: from mailout1.samsung.com ([203.254.224.24]:44072 "EHLO mailout1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755347AbcANQpx (ORCPT ); Thu, 14 Jan 2016 11:45:53 -0500 Received: from epcpsbgm1new.samsung.com (epcpsbgm1 [203.254.230.26]) by mailout1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0O0Y01U29BWDKT90@mailout1.samsung.com>; Fri, 15 Jan 2016 01:45:50 +0900 (KST) X-AuditID: cbfee61a-f79266d000003652-41-5697d0be4ab0 Received: from epmmp1.local.host ( [203.254.227.16]) by epcpsbgm1new.samsung.com (EPCPMTA) with SMTP id 35.D9.13906.EB0D7965; Fri, 15 Jan 2016 01:45:50 +0900 (KST) Received: from localhost.localdomain ([107.108.166.41]) by mmp1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0O0Y007V6BW01X00@mmp1.samsung.com>; Fri, 15 Jan 2016 01:45:50 +0900 (KST) From: Aniroop Mathur To: dmitry.torokhov@gmail.com Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, aniroop.mathur@gmail.com, s.samuel@samsung.com, r.mahale@samsung.com, Aniroop Mathur Subject: [PATCH] [v6]Input: evdev: fix bug of dropping valid full packet after syn_dropped event Date: Thu, 14 Jan 2016 22:15:22 +0530 Message-id: <1452789923-13327-1-git-send-email-a.mathur@samsung.com> X-Mailer: git-send-email 1.7.9.5 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFvrMJMWRmVeSWpSXmKPExsVy+t9jAd19F6aHGdy/ZWBx8cc5Foufu2ew WBxe9ILR4uanb6wWl3fNYbM49a6ByWLz3qssDuweO2fdZffo27KK0ePzJrkA5igum5TUnMyy 1CJ9uwSujEOPehgLdqlVPJv7gL2B8Yx8FyMnh4SAicTz9sUsELaYxIV769m6GLk4hASWMkr0 vpvCDOH8ZJRoPHGevYuRg4NNQFvi/Wc2kAYRAVmJjuOzwGqYBdYxSkz8chAsISyQJPHp6Ttm kHoWAVWJI++CQcK8Ai4Sr2Y9YAMJSwgoSMyZZDOBkXsBI8MqRonUguSC4qT0XMO81HK94sTc 4tK8dL3k/NxNjOCgeCa1g/HgLvdDjAIcjEo8vAtuTwsTYk0sK67MPcQowcGsJMK78eD0MCHe lMTKqtSi/Pii0pzU4kOM0hwsSuK8tZciw4QE0hNLUrNTUwtSi2CyTBycUg2Mbv9SZnpdc1we ELDGjYtF2/2RhELs9vWmrr4n+yqPnFr1ceKUCuFJa55tu+O7VmBTyOm0uCrW9b8vRAZzPJ4R JLHM4Ynr+Yxre1lvuulweMu+CntbIPv8rvKZpPvTPv0WOGd6S2jxnAz9nX8eHDnMkvh69dSp IZ+X+fsonF38PGmv5vbpPYbfkpVYijMSDbWYi4oTAa14JUkGAgAA Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If last event in old queue that was dropped was EV_SYN/SYN_REPORT, then lets generate EV_SYN/SYN_REPORT immediately after queing EV_SYN/SYN_DROPPED so that clients would not ignore next valid full packet events. Difference from v5: - Corrected header to store last event occured for pass_event and clock_change function - Moved buffer lock after evdev_queue_syn_dropped to avoid shifting of head during bits_to_user processing in evdev_handle_get_val function. As input cores passes packets (not single events) to evdev handler so after flushing queue for particular events, there will always be syn_report in the buffer at the end. And if flush request is for syn_report, then syn_report will not be queued after syn_dropped, anyways. Signed-off-by: Aniroop Mathur --- drivers/input/evdev.c | 57 ++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e9ae3d5..b474e81 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -156,7 +156,12 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) static void __evdev_queue_syn_dropped(struct evdev_client *client) { struct input_event ev; + struct input_event last_ev; ktime_t time; + unsigned int mask = client->bufsize - 1; + + /* store last event */ + last_ev = client->buffer[(client->head - 1) & mask]; time = client->clk_type == EV_CLK_REAL ? ktime_get_real() : @@ -170,22 +175,28 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client) ev.value = 0; client->buffer[client->head++] = ev; - client->head &= client->bufsize - 1; + client->head &= mask; if (unlikely(client->head == client->tail)) { /* drop queue but keep our SYN_DROPPED event */ - client->tail = (client->head - 1) & (client->bufsize - 1); + client->tail = (client->head - 1) & mask; client->packet_head = client->tail; } -} -static void evdev_queue_syn_dropped(struct evdev_client *client) -{ - unsigned long flags; + /* + * If last packet was completely stored, then queue SYN_REPORT + * so that clients would not ignore next valid full packet + */ + if (last_ev.type == EV_SYN && last_ev.code == SYN_REPORT) { + last_ev.time = ev.time; + client->buffer[client->head++] = last_ev; + client->head &= mask; + client->packet_head = client->head; - spin_lock_irqsave(&client->buffer_lock, flags); - __evdev_queue_syn_dropped(client); - spin_unlock_irqrestore(&client->buffer_lock, flags); + /* drop queue but keep our SYN_DROPPED & SYN_REPORT event */ + if (unlikely(client->head == client->tail)) + client->tail = (client->head - 2) & mask; + } } static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) @@ -218,7 +229,7 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) spin_lock_irqsave(&client->buffer_lock, flags); if (client->head != client->tail) { - client->packet_head = client->head = client->tail; + client->packet_head = client->tail = client->head; __evdev_queue_syn_dropped(client); } @@ -231,22 +242,24 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) static void __pass_event(struct evdev_client *client, const struct input_event *event) { + unsigned int mask = client->bufsize - 1; + client->buffer[client->head++] = *event; - client->head &= client->bufsize - 1; + client->head &= mask; if (unlikely(client->head == client->tail)) { /* * This effectively "drops" all unconsumed events, leaving - * EV_SYN/SYN_DROPPED plus the newest event in the queue. + * EV_SYN/SYN_DROPPED, EV_SYN/SYN_REPORT (if required) and + * newest event in the queue. */ - client->tail = (client->head - 2) & (client->bufsize - 1); + client->head = (client->head - 1) & mask; + client->packet_head = client->tail = client->head; + __evdev_queue_syn_dropped(client); - 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; - - client->packet_head = client->tail; + client->buffer[client->head++] = *event; + client->head &= mask; + /* No need to check for buffer overflow as it just occurred */ } if (event->type == EV_SYN && event->code == SYN_REPORT) { @@ -935,11 +948,11 @@ static int evdev_handle_get_val(struct evdev_client *client, __evdev_flush_queue(client, type); - spin_unlock_irq(&client->buffer_lock); - ret = bits_to_user(mem, maxbit, maxlen, p, compat); if (ret < 0) - evdev_queue_syn_dropped(client); + __evdev_queue_syn_dropped(client); + + spin_unlock_irq(&client->buffer_lock); kfree(mem);