From patchwork Thu Jul 21 16:10:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Gerecke X-Patchwork-Id: 9241899 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 309AD60574 for ; Thu, 21 Jul 2016 16:11:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2118027C0B for ; Thu, 21 Jul 2016 16:11:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 154D127EED; Thu, 21 Jul 2016 16:11:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7724D27C0B for ; Thu, 21 Jul 2016 16:11:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753354AbcGUQLE (ORCPT ); Thu, 21 Jul 2016 12:11:04 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:36395 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753047AbcGUQLC (ORCPT ); Thu, 21 Jul 2016 12:11:02 -0400 Received: by mail-pf0-f193.google.com with SMTP id y134so5691762pfg.3 for ; Thu, 21 Jul 2016 09:11:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=aer6T+TmkbuUj315fwF0v/8CYlxyJ3sCwKCyLXJmC5k=; b=Y902t80h9YXqqlWESAHdfjkjTnwJGSxNbL1z9WkClNSCvNM8JOyelpq7sgLl7xPJkI yaJnoBervPYJ70YmgglOsEjZmLR+/pmprXPxM5+48MXnyBaVb6a1Y3y8AvrrReypVPNp FB94Rs0SL/NySjkFydZjFoXXVCKeuJFB38H9KYS0z5fJ0L91GxYA0SjT4tczeDWTtvuT JFTWQ7lqHe54mAXQxeDDqJfL7F52GNZGGg6ol82DWetdRL+9Igvq2RbqDcUGlF8LUKLA kl9dFCz4ncxBFQ5Z/XV1sSjEwJcRSjWNVBQJobxrCpl4tHRrxCJohAUZLa5bKfcGjUyr 7vMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=aer6T+TmkbuUj315fwF0v/8CYlxyJ3sCwKCyLXJmC5k=; b=FNM8L4qSUcv2Zf0Txuh7zXh0+g9IrGvAWZTM6rJyyr4WgqIcHPOQyHEw0DulYJSuQs 68cG4Zx90sUwHQQ5aXLdvhY4XZnjvoQLDFFV2tlMFiz7wcdbZwdAJzqbz/UIzCZIAWrR ojSbtpSW3iQEiG3IUSL9XWr2q9tMaMLIX1Q1Y/Bz7/UK32tRwjRryOPwPDx5iDaiBIZo X4JvjIYXxTzk7LJRPEEUJltobR4iBvsNxbRD/hP5E7SB6I0aa1wHXeH/ascT4wG4KSq/ CBGZAQIYTMbVYvmvyMXCGUOdpyd4AvvO37htTX3Tu5uR8UuqtoRw7vzI/VowTalMWSHO xQpQ== X-Gm-Message-State: ALyK8tIUfWsczsaT9ZXyqByb8trIRlWvALkYFYUV98RiJU2FheMegqc6COOn4UU1PLY3WQ== X-Received: by 10.98.103.70 with SMTP id b67mr74465292pfc.30.1469117461314; Thu, 21 Jul 2016 09:11:01 -0700 (PDT) Received: from wtc005007.corp.onewacom.com (75-164-214-67.ptld.qwest.net. [75.164.214.67]) by smtp.gmail.com with ESMTPSA id i137sm13385428pfe.64.2016.07.21.09.10.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Jul 2016 09:10:59 -0700 (PDT) From: Jason Gerecke To: linux-input@vger.kernel.org Cc: Ping Cheng , Aaron Skomra , Benjamin Tissoires , Jason Gerecke , Jason Gerecke Subject: [PATCH v2] HID: wacom: Update last_slot_field during pre_report phase Date: Thu, 21 Jul 2016 09:10:46 -0700 Message-Id: <20160721161046.25608-1-killertofu@gmail.com> X-Mailer: git-send-email 2.9.0 In-Reply-To: References: Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If a touchscreen contains both multitouch and single-touch reports in its descriptor in that order, the driver may overwrite information it saved about the format of the multitouch report. This can cause the report processing code to get tripped up and send an incorrect event stream to userspace. In particular, this can cause last_slot_field to be overwritten with the result that the driver prematurely assumes it has finished processing a slot and sending the ABS_MT_SLOT event at the wrong point in time, associating events for the current contact with the following contact instead. To prevent this from occurring, we update the value of last_slot_field durring the pre_report phase to ensure that it is correct for the report that is to be processed. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Reviewed-by: Benjamin Tissoires --- Changes from v1: * The v1 patch cut off processing by wacom_wac_finger_usage_mapping once it saw a HID_DG_CONTACTCOUNT usage in any report. This method of handling the bug has two potential problems: 1) reports which place the HID_DG_CONTACTCOUNT usage near the beginning of the packet will not properly map the rest of the usages, and 2) devices which have multiple reports with the HID_DG_CONTACTCOUNT usage will only send reports formatted like the first discovered. Neither of these should cause issues for currently available hardware, but to maximize forward compatibility, the revised scheme contained here was devised. drivers/hid/wacom_wac.c | 62 +++++++++++++++++++++---------------------------- drivers/hid/wacom_wac.h | 2 +- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index fcf2264..d2611f3 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1556,13 +1556,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; switch (usage->hid) { case HID_GD_X: - features->last_slot_field = usage->hid; if (touch_max == 1) wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4); else @@ -1570,7 +1568,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, ABS_MT_POSITION_X, 4); break; case HID_GD_Y: - features->last_slot_field = usage->hid; if (touch_max == 1) wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4); else @@ -1579,22 +1576,11 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, break; case HID_DG_WIDTH: case HID_DG_HEIGHT: - features->last_slot_field = usage->hid; wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0); input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); break; - case HID_DG_CONTACTID: - features->last_slot_field = usage->hid; - break; - case HID_DG_INRANGE: - features->last_slot_field = usage->hid; - break; - case HID_DG_INVERT: - features->last_slot_field = usage->hid; - break; case HID_DG_TIPSWITCH: - features->last_slot_field = usage->hid; wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); break; case HID_DG_CONTACTCOUNT: @@ -1672,7 +1658,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev, if (usage->usage_index + 1 == field->report_count) { - if (usage->hid == wacom_wac->features.last_slot_field) + if (usage->hid == wacom_wac->hid_data.last_slot_field) wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); } @@ -1685,31 +1671,35 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev, struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct hid_data* hid_data = &wacom_wac->hid_data; + int i; - if (hid_data->cc_report != 0 && - hid_data->cc_report != report->id) { - int i; - - hid_data->cc_report = report->id; - hid_data->cc_index = -1; - hid_data->cc_value_index = -1; - - for (i = 0; i < report->maxfield; i++) { - struct hid_field *field = report->field[i]; - int j; - - for (j = 0; j < field->maxusage; j++) { - if (field->usage[j].hid == HID_DG_CONTACTCOUNT) { - hid_data->cc_index = i; - hid_data->cc_value_index = j; - - /* break */ - i = report->maxfield; - j = field->maxusage; - } + for (i = 0; i < report->maxfield; i++) { + struct hid_field *field = report->field[i]; + int j; + + for (j = 0; j < field->maxusage; j++) { + struct hid_usage *usage = &field->usage[j]; + + switch (usage->hid) { + case HID_GD_X: + case HID_GD_Y: + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + case HID_DG_CONTACTID: + case HID_DG_INRANGE: + case HID_DG_INVERT: + case HID_DG_TIPSWITCH: + hid_data->last_slot_field = usage->hid; + break; + case HID_DG_CONTACTCOUNT: + hid_data->cc_report = report->id; + hid_data->cc_index = i; + hid_data->cc_value_index = j; + break; } } } + if (hid_data->cc_report != 0 && hid_data->cc_index >= 0) { struct hid_field *field = report->field[hid_data->cc_index]; diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 8a8974c..267025c 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -185,7 +185,6 @@ struct wacom_features { int pktlen; bool check_for_hid_type; int hid_type; - int last_slot_field; }; struct wacom_shared { @@ -214,6 +213,7 @@ struct hid_data { int cc_report; int cc_index; int cc_value_index; + int last_slot_field; int num_expected; int num_received; };