From patchwork Fri Nov 10 19:50:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gerecke, Jason" X-Patchwork-Id: 10053661 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 EDF4E603FA for ; Fri, 10 Nov 2017 19:50:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E01EF28696 for ; Fri, 10 Nov 2017 19:50:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D4D7B2B2F5; Fri, 10 Nov 2017 19:50:39 +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 4B66D2AB4C for ; Fri, 10 Nov 2017 19:50:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753610AbdKJTui (ORCPT ); Fri, 10 Nov 2017 14:50:38 -0500 Received: from mail-qt0-f194.google.com ([209.85.216.194]:54090 "EHLO mail-qt0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753562AbdKJTui (ORCPT ); Fri, 10 Nov 2017 14:50:38 -0500 Received: by mail-qt0-f194.google.com with SMTP id n61so13158743qte.10 for ; Fri, 10 Nov 2017 11:50:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=S0iC4WbtBI02TL5TkRwkrlMGOibvng2Hn6pSleTxezg=; b=TlLepvhCDmWC6iTOfxCzQhi5WzNuezDVdnTz89DnLYZ000a7K28FiL9e8xO2VhBLiQ /TLclUIZ6vMI1zBy1q6eIrFS4hbByvOPUTa1FhP/PpzmTIulreNpM9a2BAKSHmwF1gQU 2zZk7xOu89yzGQM+8uRIioFXrcakyQxdUupfRR1572oneFZW0xzGA+e6I7umpeJAcEdg /r9BoW4N6df6LpSwoTkFxqYB0CZ41rjGdlcmSgFrrO9+8UpyVPsAwF0sy97t8aIH1jON +VUrte8QsJE3OxNrXVTzJUhysU/sr7U2mj22n0cVcf8JwdksF12DoP/Lydtjw6Y4DAxC Yn1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=S0iC4WbtBI02TL5TkRwkrlMGOibvng2Hn6pSleTxezg=; b=K/OnLGxtqpX+KYO/UkZyumAkpgqxqaMLfXyjbTiYs8mXhLdDUxG7m/wS/reIn3EsPX lFZa9+KKW7xkPgbcSdEFmq5PbgRh2M9Ow8CwyjeDV6rJ1GxnJANfMKFjCsGe2a4J0hr4 MboqVEAUJNSvKH85HJ3BHqeLY8GxOw5QvjKSch6SANLIxaWsi5mYxnGlannxGxinT8z8 MHRmrR8NalRd9INVZm5kDS2qQQDhdcN6V5jWWGk3myj47t5/Id39n6Cm9sqhKNR3q7cR IrFTDFT0gwB2WdRYHRPfoieVAh38/1WYcgh+2i5FN5Khi+oXZYKwSLqqFbosRRtrejs7 e7bw== X-Gm-Message-State: AJaThX7NuWlf1EnPmUZpXxk4VOmbkZ6XFAqZtEFXnP825hiJm7NggkRO 9pZi1HFx7irMaq+ZFzcvCfXOKrT0 X-Google-Smtp-Source: AGs4zMaLnrqmIcifsI34ngGUciYG2jTF2/Z+h7J/ZjzOfNu11J+3V+rLgGiR80JZFZ07Tz7E398AFQ== X-Received: by 10.200.63.208 with SMTP id v16mr2455840qtk.249.1510343436999; Fri, 10 Nov 2017 11:50:36 -0800 (PST) Received: from wacom-arch2.corp.onewacom.com ([50.225.60.4]) by smtp.gmail.com with ESMTPSA id t18sm6736173qtc.58.2017.11.10.11.50.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Nov 2017 11:50:36 -0800 (PST) From: Jason Gerecke To: linux-input@vger.kernel.org, Jiri Kosina Cc: Benjamin Tissoires , Ping Cheng , Jason Gerecke , Jason Gerecke Subject: [PATCH 2/2] HID: wacom: Queue events with missing type/serial data for later processing Date: Fri, 10 Nov 2017 11:50:01 -0800 Message-Id: <20171110195001.13081-2-killertofu@gmail.com> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171110195001.13081-1-killertofu@gmail.com> References: <20171110195001.13081-1-killertofu@gmail.com> 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 Userspace expects to receive tool type and serial number information for the active pen in the very first kernel report, if such data is supported by the hardware. While this expectation is not an issue for EMR devices, AES sensors will often send several packets worth of in- range data before relaying type/serial data to the kernel. Sending this data "late" can result in proximity-tracking issues by xf86-input-wacom, or an inability to distinguish different pens by input-wacom. Options for dealing with this situation include ignoring reports from the tablet until we get the necessary data, or using the information from the last-seen pen instead of the (eventual) real data. Neither option is particularly attractive: the former results in truncated strokes and the latter causes issues with switching between pens. This commit instead opts to queue up events with missing information until we receive a report which contains it. At that point, we can update the driver's state variables (id[0] and serial[0]) and replay the queued events. Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires --- drivers/hid/wacom_sys.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/hid/wacom_wac.c | 1 + drivers/hid/wacom_wac.h | 3 ++ 3 files changed, 114 insertions(+) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index ab3178bef0b6..0cf78d24cb53 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -56,6 +56,107 @@ static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf, return retval; } +static void wacom_wac_queue_insert(struct hid_device *hdev, + struct kfifo_rec_ptr_2 *fifo, + u8 *raw_data, int size) +{ + bool warned = false; + + while (kfifo_avail(fifo) < size) { + if (!warned) + hid_warn(hdev, "%s: kfifo has filled, starting to drop events\n", __func__); + warned = true; + + kfifo_skip(fifo); + } + + kfifo_in(fifo, raw_data, size); +} + +static void wacom_wac_queue_flush(struct hid_device *hdev, + struct kfifo_rec_ptr_2 *fifo) +{ + while (!kfifo_is_empty(fifo)) { + u8 buf[WACOM_PKGLEN_MAX]; + int size; + int err; + + size = kfifo_out(fifo, buf, sizeof(buf)); + err = hid_report_raw_event(hdev, HID_INPUT_REPORT, buf, size, false); + if (err) { + hid_warn(hdev, "%s: unable to flush event due to error %d\n", + __func__, err); + } + } +} + +static int wacom_wac_pen_serial_enforce(struct hid_device *hdev, + struct hid_report *report, u8 *raw_data, int size) +{ + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct wacom_features *features = &wacom_wac->features; + bool flush = false; + bool insert = false; + int i, j; + + if (wacom_wac->serial[0] || !(features->quirks & WACOM_QUIRK_TOOLSERIAL)) + return 0; + + /* Queue events which have invalid tool type or serial number */ + for (i = 0; i < report->maxfield; i++) { + for (j = 0; j < report->field[i]->maxusage; j++) { + struct hid_field *field = report->field[i]; + struct hid_usage *usage = &field->usage[j]; + unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); + unsigned int offset; + unsigned int size; + unsigned int value; + + if (equivalent_usage != HID_DG_INRANGE && + equivalent_usage != HID_DG_TOOLSERIALNUMBER && + equivalent_usage != WACOM_HID_WD_SERIALHI && + equivalent_usage != WACOM_HID_WD_TOOLTYPE) + continue; + + offset = field->report_offset; + size = field->report_size; + value = hid_field_extract(hdev, raw_data+1, offset + j * size, size); + + /* If we go out of range, we need to flush the queue ASAP */ + if (equivalent_usage == HID_DG_INRANGE) + value = !value; + + if (value) { + flush = true; + switch (equivalent_usage) { + case HID_DG_TOOLSERIALNUMBER: + wacom_wac->serial[0] = value; + break; + + case WACOM_HID_WD_SERIALHI: + wacom_wac->serial[0] |= ((__u64)value) << 32; + break; + + case WACOM_HID_WD_TOOLTYPE: + wacom_wac->id[0] = value; + break; + } + } + else { + insert = true; + } + } + } + + if (flush) + wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo); + else if (insert) + wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo, raw_data, size); + + return insert && !flush; +} + static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *raw_data, int size) { @@ -64,6 +165,9 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, if (size > WACOM_PKGLEN_MAX) return 1; + if (wacom_wac_pen_serial_enforce(hdev, report, raw_data, size)) + return -1; + memcpy(wacom->wacom_wac.data, raw_data, size); wacom_wac_irq(&wacom->wacom_wac, size); @@ -2578,6 +2682,10 @@ static int wacom_probe(struct hid_device *hdev, goto fail; } + error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL); + if (error) + goto fail; + wacom_wac->hid_data.inputmode = -1; wacom_wac->mode_report = -1; @@ -2641,6 +2749,8 @@ static void wacom_remove(struct hid_device *hdev) if (wacom->wacom_wac.features.type != REMOTE) wacom_release_resources(wacom); + kfifo_free(&wacom_wac->pen_fifo); + hid_set_drvdata(hdev, NULL); } diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ff679ee3b358..7fa373225d8a 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2085,6 +2085,7 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0); break; case HID_DG_TOOLSERIALNUMBER: + features->quirks |= WACOM_QUIRK_TOOLSERIAL; wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0); /* Adjust AES usages to match modern convention */ diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 00bcc8ad5945..90b79a723474 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -11,6 +11,7 @@ #include #include +#include /* maximum packet length for USB/BT devices */ #define WACOM_PKGLEN_MAX 361 @@ -88,6 +89,7 @@ #define WACOM_QUIRK_SENSE 0x0002 #define WACOM_QUIRK_AESPEN 0x0004 #define WACOM_QUIRK_BATTERY 0x0008 +#define WACOM_QUIRK_TOOLSERIAL 0x0010 /* device types */ #define WACOM_DEVICETYPE_NONE 0x0000 @@ -338,6 +340,7 @@ struct wacom_wac { struct input_dev *pen_input; struct input_dev *touch_input; struct input_dev *pad_input; + struct kfifo_rec_ptr_2 pen_fifo; int pid; int num_contacts_left; u8 bt_features;