From patchwork Wed Dec 5 00:42:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712855 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8BAE017D5 for ; Wed, 5 Dec 2018 00:43:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7A54928790 for ; Wed, 5 Dec 2018 00:43:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6ED6F287AE; Wed, 5 Dec 2018 00:43:46 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 F350528790 for ; Wed, 5 Dec 2018 00:43:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726554AbeLEAmy (ORCPT ); Tue, 4 Dec 2018 19:42:54 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:43921 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725904AbeLEAmy (ORCPT ); Tue, 4 Dec 2018 19:42:54 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 7F575F52; Tue, 4 Dec 2018 19:42:52 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:42:53 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=f6T5afCfbSIx/ IZSw2eDCVOPTs4vfPtmyp4UlGxir3g=; b=GgrYvSUSV1D6R2TasBIju2SRun1Yi IZFvoIOcvoOKF+4iFedP5XoyUyvVUMT+LD3KXh+kSTWZRNw7b7updcVtKFxlNoXt EnBVuOmIOfZRFaMmU44MJtxhdyTy8yDJKbXGu2XHe7FPtgeHtTnMXlsz08X7rd38 aUgF4EvklF43Cfx7Jhe7wXSfkmrbLH/ANXfX8+hJQcg9J/wX+Vwb+lxqSEW20KOi uGpRx44R0IFh3QqHXbsY33n/hxi5n5mEprEPfL1UqdNpkajSi2cKxslrMFg3GxFH A4oR+BtQPpkeX4ZTMnDQCCimZd1LMDRGBpoVDHGS6eMYkeRNtI/j4v3Zg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=f6T5afCfbSIx/IZSw2eDCVOPTs4vfPtmyp4UlGxir3g=; b=bytmm5Dh pkmwfpjMIsTP2EOMNc7U/IaZQY2Ff71fpAstvQDLx8z985x8kSE/kPk54a6yuJCx HOk6tJvrUd/RAqhCGnt0HWI+mYFwPooUg+kyXMLGBFAeGUpIaCQVXJOT6ofV5TcP etmCX2YI7q54IQqoSZ72uD6PHNtjMmyYnNlm0TzQbERVUKmQ7nvONzgBoDp+muGx 5FVmZhFJ+gtGTySe38dQEE8uTlqf2fuEUowi4hZZYDHkB+nui+KhEziUT66uBlP3 kx51zxp2K84bLCYldPfaIJtPwSHmRsUmpB8ru2FPH9m2tEnaTEqIT58lHaHxON07 KD5vVs4568vkNg== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id 42F0FE48FA; Tue, 4 Dec 2018 19:42:49 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 1/8] Input: add `REL_WHEEL_HI_RES` and `REL_HWHEEL_HI_RES` Date: Wed, 5 Dec 2018 10:42:21 +1000 Message-Id: <20181205004228.10714-2-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 This event code represents scroll reports from high-resolution wheels and is modelled after the approach Windows uses. The value 120 is one detent (wheel click) of movement. Mice with higher-resolution scrolling can send fractions of 120 which must be accumulated in userspace. Userspace can either wait for a full 120 to accumulate or scroll by fractions of one logical scroll movement as the events come in. 120 was picked as magic number because it has a high number of integer fractions that can be used by high-resolution wheels. For more information see https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn613912(v=vs.85) These new axes obsolete REL_WHEEL and REL_HWHEEL. The legacy axes are emulated by the kernel but the most accurate (and most granular) data is available through the new axes. Signed-off-by: Peter Hutterer Acked-by: Dmitry Torokhov --- No changes since v1 Documentation/input/event-codes.rst | 21 ++++++++++++++++++++- include/uapi/linux/input-event-codes.h | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Documentation/input/event-codes.rst b/Documentation/input/event-codes.rst index a8c0873beb95..b24b5343f5eb 100644 --- a/Documentation/input/event-codes.rst +++ b/Documentation/input/event-codes.rst @@ -190,7 +190,26 @@ A few EV_REL codes have special meanings: * REL_WHEEL, REL_HWHEEL: - These codes are used for vertical and horizontal scroll wheels, - respectively. + respectively. The value is the number of detents moved on the wheel, the + physical size of which varies by device. For high-resolution wheels + this may be an approximation based on the high-resolution scroll events, + see REL_WHEEL_HI_RES. These event codes are legacy codes and + REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES should be preferred where + available. + +* REL_WHEEL_HI_RES, REL_HWHEEL_HI_RES: + + - High-resolution scroll wheel data. The accumulated value 120 represents + movement by one detent. For devices that do not provide high-resolution + scrolling, the value is always a multiple of 120. For devices with + high-resolution scrolling, the value may be a fraction of 120. + + If a vertical scroll wheel supports high-resolution scrolling, this code + will be emitted in addition to REL_WHEEL or REL_HWHEEL. The REL_WHEEL + and REL_HWHEEL may be an approximation based on the high-resolution + scroll events. There is no guarantee that the high-resolution data + is a multiple of 120 at the time of an emulated REL_WHEEL or REL_HWHEEL + event. EV_ABS ------ diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 3eb5a4c3d60a..265ef2028660 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -716,6 +716,8 @@ * the situation described above. */ #define REL_RESERVED 0x0a +#define REL_WHEEL_HI_RES 0x0b +#define REL_HWHEEL_HI_RES 0x0c #define REL_MAX 0x0f #define REL_CNT (REL_MAX+1) From patchwork Wed Dec 5 00:42:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712853 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 088381731 for ; Wed, 5 Dec 2018 00:43:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E074328668 for ; Wed, 5 Dec 2018 00:43:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D2A45286C7; Wed, 5 Dec 2018 00:43:37 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 79F9628668 for ; Wed, 5 Dec 2018 00:43:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726702AbeLEAng (ORCPT ); Tue, 4 Dec 2018 19:43:36 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:52729 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726715AbeLEAm5 (ORCPT ); Tue, 4 Dec 2018 19:42:57 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id D9CAAF53; Tue, 4 Dec 2018 19:42:55 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:42:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=k0SRJk9N+O36M b6BBb8a+KFCArA/YJkSqsoiZZ63uUo=; b=mQTx0HGG38qmF8JpsSklhhOZ8yghv zLgaQfcCXHdONW7ZyA9zaEqlA5CGE4RlnVBx9zrmBOG483QsPtMbUd8G/5Pmgtl7 pR2PHk2c/dSATOwseZOEsblPz6rWeJ2TQYRJC4bOSdSyVaMmuQ5XvQJ87RKW6lMk GcCm04s8XbfenGRX44uoT3feZLOiK6KVp/KGFzvpXQ47cafjPCPQBUc6Ps4A7bxf IL3hOBwZFZXFN3es2ntOqSoA0wqWIlnSNW5JiICtOHlAzaIpspWx0MxslsyPkltp ZFlOBEzng0eDhLqEG9P5w4YB5qgskAMZUXYPHZq03vUV6B0R5Ji8/0pdA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=k0SRJk9N+O36Mb6BBb8a+KFCArA/YJkSqsoiZZ63uUo=; b=kbfDlyq8 O5bcKWogQ2ttWIQQ72S47C0JNp+U4k802xRO4/iNlvznGmvusSbi+LtY2MxERtex lKwF+VSUZK4NL9wVqyj0Gh7stgAA0MjBji2XYfFSMiuD3LFsf7o+x89AOZSI3uOx kZMdcwqbCn5sEIKWWsx9i7eSrTAlBRCdMO31xjm3r9O2bbDYxabO7N0GOLl2Kjtw UXkKS91w0t4poYM+VYrXznjjrfIWoJD0zd7PYxaiWBHPiGFNcY4EI82HWp1zJbYd axnGuNYLrLZTf/j35T5emuDrzfz1YZGAvsfSaRmYyFwCkscDxoJTXrIlwMrfiCw2 ZsX3JFg/5j6jPQ== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id 70194E4750; Tue, 4 Dec 2018 19:42:52 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 2/8] HID: core: store the collections as a basic tree Date: Wed, 5 Dec 2018 10:42:22 +1000 Message-Id: <20181205004228.10714-3-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 For each collection parsed, store a pointer to the parent collection (if any). This makes it a lot easier to look up which collection(s) any given item is part of Signed-off-by: Peter Hutterer --- No changes since v1 drivers/hid/hid-core.c | 4 ++++ include/linux/hid.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5bec9244c45b..43d488a45120 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -172,6 +172,8 @@ static int open_collection(struct hid_parser *parser, unsigned type) collection->type = type; collection->usage = usage; collection->level = parser->collection_stack_ptr - 1; + collection->parent = parser->active_collection; + parser->active_collection = collection; if (type == HID_COLLECTION_APPLICATION) parser->device->maxapplication++; @@ -190,6 +192,8 @@ static int close_collection(struct hid_parser *parser) return -EINVAL; } parser->collection_stack_ptr--; + if (parser->active_collection) + parser->active_collection = parser->active_collection->parent; return 0; } diff --git a/include/linux/hid.h b/include/linux/hid.h index a355d61940f2..fdfda898656c 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -427,6 +427,7 @@ struct hid_local { */ struct hid_collection { + struct hid_collection *parent; unsigned type; unsigned usage; unsigned level; @@ -650,6 +651,7 @@ struct hid_parser { unsigned int *collection_stack; unsigned int collection_stack_ptr; unsigned int collection_stack_size; + struct hid_collection *active_collection; struct hid_device *device; unsigned int scan_flags; }; From patchwork Wed Dec 5 00:42:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712851 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CEAE413BF for ; Wed, 5 Dec 2018 00:43:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BCBBF2CA49 for ; Wed, 5 Dec 2018 00:43:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B14432CA62; Wed, 5 Dec 2018 00:43:35 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 EC9162CA49 for ; Wed, 5 Dec 2018 00:43:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726744AbeLEAnB (ORCPT ); Tue, 4 Dec 2018 19:43:01 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:45003 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726731AbeLEAnA (ORCPT ); Tue, 4 Dec 2018 19:43:00 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 2E2BDCB5; Tue, 4 Dec 2018 19:42:59 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:42:59 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=El/5AD1IxDyIY e1C6QEB3WZxrJCG31Xg0m6pkSD0av8=; b=L7006ckOtlK93TnS8WTw4XmN8M/Vg nbAqH7kFKwoL25+BS/bXsX9Madro17o8L2fpMbXRFVteBy8q5PCqdgGP7zgAuVrV 59B+8Lm7Ixx/OdHOO4Vi38Gz3t9QuZcgxC7Z+hrid2lZBgs2BQdwrhtBk2PDpBfi q3uRUQ/Hxrg3odnuN8Fy71A+pkhEbI2O/EeRU26mZb4roYLzXnnADR5q7E3No88b KXBqJ5OpsTm3lC8FAYN6AmzsuLk3z7EfutBr6fpO9Ecf5+dV0ZAufbAKETieHP8/ 2vPMGkSyzCOMiFUZjnY13yF+7OCFkapGLJT65UEz4YmbiAhot8RgbT4BA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=El/5AD1IxDyIYe1C6QEB3WZxrJCG31Xg0m6pkSD0av8=; b=gpOFRZuT 9o5hj53VnAF/wQcOeaxOm/4gOc2U+bUtow3r7Tr4336hl5vJdI+JRqOOxbDUJZWv zOgo53w1zP6dpRiTZQK6ruV4MfiYvlzX8M9le4Hpo1XVCMgjNtwvMXCuf31Js7tA wIO2WTP+HOYgiKP8NsBTWvwJgrbfiMrPqG4GMyP9I2BZH4bvHexWB7QV4YfdMs5F J6adNDukEqKtzWHuqujRTH0igtFaMKzN1ayl5nE3RKi0sALCwQCHx3O4Qn9SCl4K w78d2JOa3AMCe2r7c0fZVJOH2EWULX1oGPJyULNiG3t1pNmCVogtxsNIZ/5GiQPM N8q+aZyJP/PMBw== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id A038CE48FA; Tue, 4 Dec 2018 19:42:55 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 3/8] HID: core: process the Resolution Multiplier Date: Wed, 5 Dec 2018 10:42:23 +1000 Message-Id: <20181205004228.10714-4-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 The Resolution Multiplier is a feature report that modifies the value of Usages within the same Logical Collection. If the multiplier is set to anything but 1, the hardware reports (value * multiplier) for the same amount of physical movement, i.e. the value we receive in the kernel is pre-multiplied. The hardware may either send a single (value * multiplier), or by sending multiplier as many reports with the same value, or a combination of these two options. For example, when the Microsoft Sculpt Ergonomic mouse Resolution Multiplier is set to 12, the Wheel sends out 12 for every detent but AC Pan sends out a value of 3 at 4 times the frequency. The effective multiplier is based on the physical min/max of the multiplier field, a logical min/max of [0,1] with a physical min/max of [1,8] means the multiplier is either 1 or 8. The Resolution Multiplier was introduced for high-resolution scrolling in Windows Vista and is commonly used on Microsoft mice. The recommendation for the Resolution Multiplier is to default to 1 for backwards compatibility. This patch adds an arbitrary upper limit at 255. The only known use case for the Resolution Multiplier is for scroll wheels where the multiplier has to be a fraction of 120 to work with Windows. Signed-off-by: Peter Hutterer --- Changes since v1, v2: - expanded the commit message with more detail drivers/hid/hid-core.c | 170 +++++++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 5 ++ 2 files changed, 175 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 43d488a45120..f41d5fe51abe 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -294,6 +294,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign field->usage[i].collection_index = parser->local.collection_index[j]; field->usage[i].usage_index = i; + field->usage[i].resolution_multiplier = 1; } field->maxusage = usages; @@ -947,6 +948,167 @@ struct hid_report *hid_validate_values(struct hid_device *hid, } EXPORT_SYMBOL_GPL(hid_validate_values); +static int hid_calculate_multiplier(struct hid_device *hid, + struct hid_field *multiplier) +{ + int m; + __s32 v = *multiplier->value; + __s32 lmin = multiplier->logical_minimum; + __s32 lmax = multiplier->logical_maximum; + __s32 pmin = multiplier->physical_minimum; + __s32 pmax = multiplier->physical_maximum; + + /* + * "Because OS implementations will generally divide the control's + * reported count by the Effective Resolution Multiplier, designers + * should take care not to establish a potential Effective + * Resolution Multiplier of zero." + * HID Usage Table, v1.12, Section 4.3.1, p31 + */ + if (lmax - lmin == 0) + return 1; + /* + * Handling the unit exponent is left as an exercise to whoever + * finds a device where that exponent is not 0. + */ + m = ((v - lmin)/(lmax - lmin) * (pmax - pmin) + pmin); + if (unlikely(multiplier->unit_exponent != 0)) { + hid_warn(hid, + "unsupported Resolution Multiplier unit exponent %d\n", + multiplier->unit_exponent); + } + + /* There are no devices with an effective multiplier > 255 */ + if (unlikely(m == 0 || m > 255 || m < -255)) { + hid_warn(hid, "unsupported Resolution Multiplier %d\n", m); + m = 1; + } + + return m; +} + +static void hid_apply_multiplier_to_field(struct hid_device *hid, + struct hid_field *field, + struct hid_collection *multiplier_collection, + int effective_multiplier) +{ + struct hid_collection *collection; + struct hid_usage *usage; + int i; + + /* + * If multiplier_collection is NULL, the multiplier applies + * to all fields in the report. + * Otherwise, it is the Logical Collection the multiplier applies to + * but our field may be in a subcollection of that collection. + */ + for (i = 0; i < field->maxusage; i++) { + usage = &field->usage[i]; + + collection = &hid->collection[usage->collection_index]; + while (collection && collection != multiplier_collection) + collection = collection->parent; + + if (collection || multiplier_collection == NULL) + usage->resolution_multiplier = effective_multiplier; + + } +} + +static void hid_apply_multiplier(struct hid_device *hid, + struct hid_field *multiplier) +{ + struct hid_report_enum *rep_enum; + struct hid_report *rep; + struct hid_field *field; + struct hid_collection *multiplier_collection; + int effective_multiplier; + int i; + + /* + * "The Resolution Multiplier control must be contained in the same + * Logical Collection as the control(s) to which it is to be applied. + * If no Resolution Multiplier is defined, then the Resolution + * Multiplier defaults to 1. If more than one control exists in a + * Logical Collection, the Resolution Multiplier is associated with + * all controls in the collection. If no Logical Collection is + * defined, the Resolution Multiplier is associated with all + * controls in the report." + * HID Usage Table, v1.12, Section 4.3.1, p30 + * + * Thus, search from the current collection upwards until we find a + * logical collection. Then search all fields for that same parent + * collection. Those are the fields the multiplier applies to. + * + * If we have more than one multiplier, it will overwrite the + * applicable fields later. + */ + multiplier_collection = &hid->collection[multiplier->usage->collection_index]; + while (multiplier_collection && + multiplier_collection->type != HID_COLLECTION_LOGICAL) + multiplier_collection = multiplier_collection->parent; + + effective_multiplier = hid_calculate_multiplier(hid, multiplier); + + rep_enum = &hid->report_enum[HID_INPUT_REPORT]; + list_for_each_entry(rep, &rep_enum->report_list, list) { + for (i = 0; i < rep->maxfield; i++) { + field = rep->field[i]; + hid_apply_multiplier_to_field(hid, field, + multiplier_collection, + effective_multiplier); + } + } +} + +/* + * hid_setup_resolution_multiplier - set up all resolution multipliers + * + * @device: hid device + * + * Search for all Resolution Multiplier Feature Reports and apply their + * value to all matching Input items. This only updates the internal struct + * fields. + * + * The Resolution Multiplier is applied by the hardware. If the multiplier + * is anything other than 1, the hardware will send pre-multiplied events + * so that the same physical interaction generates an accumulated + * accumulated_value = value * * multiplier + * This may be achieved by sending + * - "value * multiplier" for each event, or + * - "value" but "multiplier" times as frequently, or + * - a combination of the above + * The only guarantee is that the same physical interaction always generates + * an accumulated 'value * multiplier'. + * + * This function must be called before any event processing and after + * any SetRequest to the Resolution Multiplier. + */ +void hid_setup_resolution_multiplier(struct hid_device *hid) +{ + struct hid_report_enum *rep_enum; + struct hid_report *rep; + struct hid_usage *usage; + int i, j; + + rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; + list_for_each_entry(rep, &rep_enum->report_list, list) { + for (i = 0; i < rep->maxfield; i++) { + /* Ignore if report count is out of bounds. */ + if (rep->field[i]->report_count < 1) + continue; + + for (j = 0; j < rep->field[i]->maxusage; j++) { + usage = &rep->field[i]->usage[j]; + if (usage->hid == HID_GD_RESOLUTION_MULTIPLIER) + hid_apply_multiplier(hid, + rep->field[i]); + } + } + } +} +EXPORT_SYMBOL_GPL(hid_setup_resolution_multiplier); + /** * hid_open_report - open a driver-specific device report * @@ -1043,9 +1205,17 @@ int hid_open_report(struct hid_device *device) hid_err(device, "unbalanced delimiter at end of report description\n"); goto err; } + + /* + * fetch initial values in case the device's + * default multiplier isn't the recommended 1 + */ + hid_setup_resolution_multiplier(device); + kfree(parser->collection_stack); vfree(parser); device->status |= HID_STAT_PARSED; + return 0; } } diff --git a/include/linux/hid.h b/include/linux/hid.h index fdfda898656c..fd8d860365a4 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -219,6 +219,7 @@ struct hid_item { #define HID_GD_VBRZ 0x00010045 #define HID_GD_VNO 0x00010046 #define HID_GD_FEATURE 0x00010047 +#define HID_GD_RESOLUTION_MULTIPLIER 0x00010048 #define HID_GD_SYSTEM_CONTROL 0x00010080 #define HID_GD_UP 0x00010090 #define HID_GD_DOWN 0x00010091 @@ -437,6 +438,8 @@ struct hid_usage { unsigned hid; /* hid usage code */ unsigned collection_index; /* index into collection array */ unsigned usage_index; /* index into usage array */ + __s8 resolution_multiplier;/* Effective Resolution Multiplier + (HUT v1.12, 4.3.1), default: 1 */ /* hidinput data */ __u16 code; /* input driver code */ __u8 type; /* input driver type */ @@ -894,6 +897,8 @@ struct hid_report *hid_validate_values(struct hid_device *hid, unsigned int type, unsigned int id, unsigned int field_index, unsigned int report_counts); + +void hid_setup_resolution_multiplier(struct hid_device *hid); int hid_open_report(struct hid_device *device); int hid_check_keys_pressed(struct hid_device *hid); int hid_connect(struct hid_device *hid, unsigned int connect_mask); From patchwork Wed Dec 5 00:42:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712841 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3F9D11731 for ; Wed, 5 Dec 2018 00:43:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2E2E52CA71 for ; Wed, 5 Dec 2018 00:43:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 201822CA52; Wed, 5 Dec 2018 00:43:07 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 6D6962CA52 for ; Wed, 5 Dec 2018 00:43:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726048AbeLEAnF (ORCPT ); Tue, 4 Dec 2018 19:43:05 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:51963 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726684AbeLEAnD (ORCPT ); Tue, 4 Dec 2018 19:43:03 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 539CD9F6; Tue, 4 Dec 2018 19:43:02 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:43:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=4nh/gMm0Rp8ZP nBrhgwTENSa1vBkF+BMM0sXvXIyJsc=; b=gyiZzDWVyGnSbretAtrQJpPkia5RJ rMcKRTChjp0+mMoz+XIHoHC3p9rcCZd7nI3DIO/FspRWGen1aiFT4kGq3iVBoX54 xHFM+C4Xs2SM5ZszXaTDPf1CXeWvlhbvAyiGzNdJoUSYpxlzqzg3umRP3SAJO56d Z3/xnX9SZTtkZBabq67SGeUzTyo98FgxW1L2r7pUmVTC6qDijfqcTpicki1w+vQs 2WLe9ecjFiA58P570Fexcmf0O6GJyNvYJYuOCsLyBEfnY1o71Ouyz4NkwUvT7HBK zx7Vv332brHkH42zUWNeclvwszVOfEUJ5iN1jzGejFG2jIvxjf3jU6iDg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=4nh/gMm0Rp8ZPnBrhgwTENSa1vBkF+BMM0sXvXIyJsc=; b=YAKMv8wQ HFPCKa5z90ur8ouiOZHJDV8AUnJtGSZXUzJjx4Ymub6J48gaStjBMJrwqU7TdhyW pqhz/LUTR4QGCkd083o2kA7uFTB+6aRxoDH3OOeneJZNyU4coh4Z0S5egylemnxV /fb9kKg8aoJv6rQhQed1lloUQ4KphGQ+zRYUZiSTGzWCBkJM0aHjNM60UeJ4uY0X OYnYUUOkTzW1dObBJksXI4SZ3xuzR5bHvc38E3UUNGusvSD+RVVi48o4R+BWXvQ7 nRI0LV/cnh1t7t8W/feFG41VFAb8AzM1Z7q05Yz2/6hIwfckXwLWmo8H2hdGrNW1 BKsWLCSuha7nNg== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id D5B0EE49AD; Tue, 4 Dec 2018 19:42:58 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 4/8] HID: input: use the Resolution Multiplier for high-resolution scrolling Date: Wed, 5 Dec 2018 10:42:24 +1000 Message-Id: <20181205004228.10714-5-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 Windows uses a magic number of 120 for a wheel click. High-resolution scroll wheels are supposed to use a fraction of 120 to signal smaller scroll steps. This is implemented by the Resolution Multiplier in the device itself. If the multiplier is present in the report descriptor, set it to the logical max and then use the resolution multiplier to calculate the high-resolution events. This is the recommendation by Microsoft, see http://msdn.microsoft.com/en-us/windows/hardware/gg487477.aspx Note that all mice encountered so far have a logical min/max of 0/1, so it's a binary "yes or no" to high-res scrolling anyway. To make userspace simpler, always enable the REL_WHEEL_HI_RES bit. Where the device doesn't support high-resolution scrolling, the value for the high-res data will simply be a multiple of 120 every time. For userspace, if REL_WHEEL_HI_RES is available that is the one to be used. Potential side-effect: a device with a Resolution Multiplier applying to other Input items will have those items set to the logical max as well. This cannot easily be worked around but it is doubtful such devices exist. Signed-off-by: Peter Hutterer --- Changes since v1: - drop the wheel factor and calculate the hi-res value as the event comes in. This fixes the issue with a multiplier of 16, makes the code simpler too because we don't have to refresh anything after setting the multiplier. Changes since v2: - unchanged drivers/hid/hid-input.c | 108 ++++++++++++++++++++++++++++++++++++++-- include/linux/hid.h | 3 ++ 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d6fab5798487..59a5608b8dc0 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -712,7 +712,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_abs_clear(usage->hid & 0xf); break; - case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: + case HID_GD_WHEEL: + if (field->flags & HID_MAIN_ITEM_RELATIVE) { + set_bit(REL_WHEEL, input->relbit); + map_rel(REL_WHEEL_HI_RES); + } else { + map_abs(usage->hid & 0xf); + } + break; + case HID_GD_SLIDER: case HID_GD_DIAL: if (field->flags & HID_MAIN_ITEM_RELATIVE) map_rel(usage->hid & 0xf); else @@ -1012,7 +1020,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x22f: map_key_clear(KEY_ZOOMRESET); break; case 0x233: map_key_clear(KEY_SCROLLUP); break; case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel(REL_HWHEEL); break; + case 0x238: /* AC Pan */ + set_bit(REL_HWHEEL, input->relbit); + map_rel(REL_HWHEEL_HI_RES); + break; case 0x23d: map_key_clear(KEY_EDIT); break; case 0x25f: map_key_clear(KEY_CANCEL); break; case 0x269: map_key_clear(KEY_INSERT); break; @@ -1200,6 +1211,38 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } +static void hidinput_handle_scroll(struct hid_usage *usage, + struct input_dev *input, + __s32 value) +{ + int code; + int hi_res, lo_res; + + if (value == 0) + return; + + if (usage->code == REL_WHEEL_HI_RES) + code = REL_WHEEL; + else + code = REL_HWHEEL; + + /* + * Windows reports one wheel click as value 120. Where a high-res + * scroll wheel is present, a fraction of 120 is reported instead. + * Our REL_WHEEL_HI_RES axis does the same because all HW must + * adhere to the 120 expectation. + */ + hi_res = value * 120/usage->resolution_multiplier; + + usage->wheel_accumulated += hi_res; + lo_res = usage->wheel_accumulated/120; + if (lo_res) + usage->wheel_accumulated -= lo_res * 120; + + input_event(input, EV_REL, code, lo_res); + input_event(input, EV_REL, usage->code, hi_res); +} + void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct input_dev *input; @@ -1262,6 +1305,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ return; + if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES || + usage->code == REL_HWHEEL_HI_RES)) { + hidinput_handle_scroll(usage, input, value); + return; + } + if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->code == ABS_VOLUME)) { int count = abs(value); @@ -1489,6 +1538,58 @@ static void hidinput_close(struct input_dev *dev) hid_hw_close(hid); } +static void hidinput_change_resolution_multipliers(struct hid_device *hid) +{ + struct hid_report_enum *rep_enum; + struct hid_report *rep; + struct hid_usage *usage; + int i, j; + + rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; + list_for_each_entry(rep, &rep_enum->report_list, list) { + bool update_needed = false; + + if (rep->maxfield == 0) + continue; + + /* + * If we have more than one feature within this report we + * need to fill in the bits from the others before we can + * overwrite the ones for the Resolution Multiplier. + */ + if (rep->maxfield > 1) { + hid_hw_request(hid, rep, HID_REQ_GET_REPORT); + hid_hw_wait(hid); + } + + for (i = 0; i < rep->maxfield; i++) { + __s32 logical_max = rep->field[i]->logical_maximum; + + /* There is no good reason for a Resolution + * Multiplier to have a count other than 1. + * Ignore that case. + */ + if (rep->field[i]->report_count != 1) + continue; + + for (j = 0; j < rep->field[i]->maxusage; j++) { + usage = &rep->field[i]->usage[j]; + + if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER) + continue; + + *rep->field[i]->value = logical_max; + update_needed = true; + } + } + if (update_needed) + hid_hw_request(hid, rep, HID_REQ_SET_REPORT); + } + + /* refresh our structs */ + hid_setup_resolution_multiplier(hid); +} + static void report_features(struct hid_device *hid) { struct hid_driver *drv = hid->driver; @@ -1782,6 +1883,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } } + hidinput_change_resolution_multipliers(hid); + list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { if (drv->input_configured && drv->input_configured(hid, hidinput)) @@ -1840,4 +1943,3 @@ void hidinput_disconnect(struct hid_device *hid) cancel_work_sync(&hid->led_work); } EXPORT_SYMBOL_GPL(hidinput_disconnect); - diff --git a/include/linux/hid.h b/include/linux/hid.h index fd8d860365a4..93db548f8761 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -233,6 +233,7 @@ struct hid_item { #define HID_DC_BATTERYSTRENGTH 0x00060020 #define HID_CP_CONSUMER_CONTROL 0x000c0001 +#define HID_CP_AC_PAN 0x000c0238 #define HID_DG_DIGITIZER 0x000d0001 #define HID_DG_PEN 0x000d0002 @@ -441,11 +442,13 @@ struct hid_usage { __s8 resolution_multiplier;/* Effective Resolution Multiplier (HUT v1.12, 4.3.1), default: 1 */ /* hidinput data */ + __s8 wheel_factor; /* 120/resolution_multiplier */ __u16 code; /* input driver code */ __u8 type; /* input driver type */ __s8 hat_min; /* hat switch fun */ __s8 hat_max; /* ditto */ __s8 hat_dir; /* ditto */ + __s16 wheel_accumulated; /* hi-res wheel */ }; struct hid_input; From patchwork Wed Dec 5 00:42:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712849 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 362C613BF for ; Wed, 5 Dec 2018 00:43:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 252162CA49 for ; Wed, 5 Dec 2018 00:43:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 19A892CA62; Wed, 5 Dec 2018 00:43:32 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 B07242CA49 for ; Wed, 5 Dec 2018 00:43:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726537AbeLEAnJ (ORCPT ); Tue, 4 Dec 2018 19:43:09 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:45061 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726294AbeLEAnI (ORCPT ); Tue, 4 Dec 2018 19:43:08 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id BDD52F55; Tue, 4 Dec 2018 19:43:06 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:43:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=9mpnncxGYKGhn b4VIU3POQ0P/Q4AaNNvBQuHvU6YplA=; b=GZ7sdT0jEcg0fm7V3xGxWbpRpFoj7 vJtXYOoECWACbJCSQVleIDHUCev7eSMfKee+ad1yK6pib+tBGJQ5ZxPVC+LU5Olj x6mwxZ7fNnvXpybnjUbJXuQtBn4vm/cTcryQpAETGaU8NdVOUBc/04mQHhqhOLhM TKFJBCGIdTqsHb8wLkxYUHF5JxjQgzu5tcgspZWc4vmmuysbBsbaNHDYN8jobe9G OnTJNXC1xCZNY3uBzwsxv7wGAF05qFO1Bbdj6E17whZD9nv8eMAlqdTjAZndQ3tn R3VWAXB83SMZPbLlLqYBWFNnJtD66QKm5lGhSY5Klzu4BMZaX8Asrj3KQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=9mpnncxGYKGhnb4VIU3POQ0P/Q4AaNNvBQuHvU6YplA=; b=HxOnTWEU Ddu/baJvN1v+8HhG+WvK1XDCNrPafanr10opxYSq8WuWhyR3Gs2UPho5cot2pY3F +jTBJqRrJEKyjcs846isr8ORORvLjlOVFz/Ysfz4kuPTJ6yzYRbyrxQf3A4PDM6f g0exBw6oh1cyNivsaqxZt6f7qN30SHE4p59rwICCQzJcXb8lIK4cMY2jLwlG3Nqg eP2lMckJqf5aDgcIpS5UC05C9BIkNcgyrGsD/Yv//dCvla3mp6w2mgmwXjrG0gFY +YWhT8F9hU0lRxDz8Kb4ZYB6KVVVrKzJHjy1TXHhNpPE0e/jAFLM57+kptN+3OYx 7V2K4Dfm3K/Tlw== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id 0FA38E450E; Tue, 4 Dec 2018 19:43:01 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 5/8] HID: logitech-hidpp: fix typo, hiddpp to hidpp Date: Wed, 5 Dec 2018 10:42:25 +1000 Message-Id: <20181205004228.10714-6-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 Signed-off-by: Peter Hutterer --- Unchanged since v1 drivers/hid/hid-logitech-hidpp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 19cc980eebce..22b37a3844d1 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -1465,7 +1465,7 @@ struct hidpp_ff_work_data { u8 size; }; -static const signed short hiddpp_ff_effects[] = { +static const signed short hidpp_ff_effects[] = { FF_CONSTANT, FF_PERIODIC, FF_SINE, @@ -1480,7 +1480,7 @@ static const signed short hiddpp_ff_effects[] = { -1 }; -static const signed short hiddpp_ff_effects_v2[] = { +static const signed short hidpp_ff_effects_v2[] = { FF_RAMP, FF_FRICTION, FF_INERTIA, @@ -1873,11 +1873,11 @@ static int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) version = bcdDevice & 255; /* Set supported force feedback capabilities */ - for (j = 0; hiddpp_ff_effects[j] >= 0; j++) - set_bit(hiddpp_ff_effects[j], dev->ffbit); + for (j = 0; hidpp_ff_effects[j] >= 0; j++) + set_bit(hidpp_ff_effects[j], dev->ffbit); if (version > 1) - for (j = 0; hiddpp_ff_effects_v2[j] >= 0; j++) - set_bit(hiddpp_ff_effects_v2[j], dev->ffbit); + for (j = 0; hidpp_ff_effects_v2[j] >= 0; j++) + set_bit(hidpp_ff_effects_v2[j], dev->ffbit); /* Read number of slots available in device */ error = hidpp_send_fap_command_sync(hidpp, feature_index, From patchwork Wed Dec 5 00:42:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712847 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B57E71731 for ; Wed, 5 Dec 2018 00:43:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A412C2CA49 for ; Wed, 5 Dec 2018 00:43:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 985CF2CA62; Wed, 5 Dec 2018 00:43:29 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 283022CA49 for ; Wed, 5 Dec 2018 00:43:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726833AbeLEAnM (ORCPT ); Tue, 4 Dec 2018 19:43:12 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:60697 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726828AbeLEAnL (ORCPT ); Tue, 4 Dec 2018 19:43:11 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id EFE7EEF3; Tue, 4 Dec 2018 19:43:09 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:43:10 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=k0wpaOF+B4pJS qXa2tG5vClg3F+LRFCjDb4ghPCqbbY=; b=gn5eGRnoSGNLJ57Ek4X53SfBDtGku qf5Omy7o6wyJOZTvBce8Tt0Sm9Hylbj5/XCSFQwQZwbNNajuqIYfmmjB2fhDiRSC fSOnrWAfmFRpwobPVQYdbzh215RXl4tPTRHpD+iC5RSii/6BwL8kFlkJ1e7tso3w 1BSa880POVHiF1ewRzgn20gJukFtd7ka7sAw80oR3ZhPNOTIDOPG8eB4s/lURRXz HKlgOQHkXEYo4iqH3OK69JZk3vm3XTvAxUs72XzmMvs5kbRtKTVY2vewXOIzglbR vQw7aYHRC9sGT4/+EuYNni9eRCWYNyUkN1G09TJXbl8p9Ic2n/650BZsQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=k0wpaOF+B4pJSqXa2tG5vClg3F+LRFCjDb4ghPCqbbY=; b=UvPqHrpm rv5W2RO1CoWUY+Q4x0wPg3JUR9hsEMAdQ488bFJlPUKgXEPkg85lZJoPlStksU0D Ya7dkKWOMurO3iPGMrU+pLr2iHHyulcKdvclX3Q0VPrSeBMU58DFcpZMfjm1ixuL L3dqOJnvu7g8dcXRoVb7Yfw0pl9rXWgYjyQB6xKd+0GxMVl8UMkbYi6LqH9XinGb jGITQc5/a8IzICpMB1hZIc1sEJjKMFgt5c+bNVY7Pg7nPeFpjpjE6u2igccph7gV BX1xCLg7XwDmAsuHESUA1IQcHWIzBWY7MpnRmDq8AxawRNiQJBAMU0yUDsPTDDu/ TwUbdQXzcjFYSw== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id 8EC8AE49CB; Tue, 4 Dec 2018 19:43:06 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 6/8] HID: logitech: Add function to enable HID++ 1.0 "scrolling acceleration" Date: Wed, 5 Dec 2018 10:42:26 +1000 Message-Id: <20181205004228.10714-7-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 From: Harry Cutts "Scrolling acceleration" is a bit of a misnomer: it doesn't deal with acceleration at all. However, that's the name used in Logitech's spec, so I used it here. Signed-off-by: Harry Cutts Reviewed-by: Benjamin Tissoires Signed-off-by: Peter Hutterer --- Unchanged since v1 drivers/hid/hid-logitech-hidpp.c | 47 +++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 22b37a3844d1..95ba9db6e613 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -400,32 +400,53 @@ static void hidpp_prefix_name(char **name, int name_length) #define HIDPP_SET_LONG_REGISTER 0x82 #define HIDPP_GET_LONG_REGISTER 0x83 -#define HIDPP_REG_GENERAL 0x00 - -static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) +/** + * hidpp10_set_register_bit() - Sets a single bit in a HID++ 1.0 register. + * @hidpp_dev: the device to set the register on. + * @register_address: the address of the register to modify. + * @byte: the byte of the register to modify. Should be less than 3. + * Return: 0 if successful, otherwise a negative error code. + */ +static int hidpp10_set_register_bit(struct hidpp_device *hidpp_dev, + u8 register_address, u8 byte, u8 bit) { struct hidpp_report response; int ret; u8 params[3] = { 0 }; ret = hidpp_send_rap_command_sync(hidpp_dev, - REPORT_ID_HIDPP_SHORT, - HIDPP_GET_REGISTER, - HIDPP_REG_GENERAL, - NULL, 0, &response); + REPORT_ID_HIDPP_SHORT, + HIDPP_GET_REGISTER, + register_address, + NULL, 0, &response); if (ret) return ret; memcpy(params, response.rap.params, 3); - /* Set the battery bit */ - params[0] |= BIT(4); + params[byte] |= BIT(bit); return hidpp_send_rap_command_sync(hidpp_dev, - REPORT_ID_HIDPP_SHORT, - HIDPP_SET_REGISTER, - HIDPP_REG_GENERAL, - params, 3, &response); + REPORT_ID_HIDPP_SHORT, + HIDPP_SET_REGISTER, + register_address, + params, 3, &response); +} + + +#define HIDPP_REG_GENERAL 0x00 + +static int hidpp10_enable_battery_reporting(struct hidpp_device *hidpp_dev) +{ + return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_GENERAL, 0, 4); +} + +#define HIDPP_REG_FEATURES 0x01 + +/* On HID++ 1.0 devices, high-res scroll was called "scrolling acceleration". */ +static int hidpp10_enable_scrolling_acceleration(struct hidpp_device *hidpp_dev) +{ + return hidpp10_set_register_bit(hidpp_dev, HIDPP_REG_FEATURES, 0, 6); } #define HIDPP_REG_BATTERY_STATUS 0x07 From patchwork Wed Dec 5 00:42:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712845 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 903501731 for ; Wed, 5 Dec 2018 00:43:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7BE382CA49 for ; Wed, 5 Dec 2018 00:43:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6F2F82CA62; Wed, 5 Dec 2018 00:43:28 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 542312CA49 for ; Wed, 5 Dec 2018 00:43:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726857AbeLEAnQ (ORCPT ); Tue, 4 Dec 2018 19:43:16 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:57371 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726828AbeLEAnP (ORCPT ); Tue, 4 Dec 2018 19:43:15 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 618A8F63; Tue, 4 Dec 2018 19:43:13 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:43:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=AN454XcRs1240 RLBYkm/rek3hiQlojlnwrRUjcJG5BU=; b=gtWNe1o/8WrIVRtsdqpmpa4nKnNfo VgoQaDt4y9lonyiu0fWewRPb8r+Kz9odIrZI16Szr11p2OKe7aBQtMToIxQfQOkp 5vCMc5sqZnLJbgVWadF6beXp+dd2TLAvUNpql8jntFafSLr7zhnAAcYR0AOTuDxA JvU0tH2cxQE2jTaKy8C8puHV3xS3Arx6SZDOdkAAVvCa+N2Fe6+xXSNekkKAlLTS ArsgqwxilGDqAzYLKgR6/17fa0r4G8wH+i8aSeAVJVWwTO/Os/ViyHIhKuOoeHff tp3dXW/25YaXRfAX815nkmhFT2WA2jAQlQAVHnJEh8y/Qsg+Xjx02rVeQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=AN454XcRs1240RLBYkm/rek3hiQlojlnwrRUjcJG5BU=; b=ZeOqzRUR 7GzZrIogJJrzE22z8zHtKNY15aS1ymQOay6AC5l0BeZwvVfLGDZUGpSccfVzrjGf XUkttZZWNMajTbce3zDjGOcD0Ua+iADlehVADluVkyifjFti0JPmPAS0mvCjsCOY tsMj6Lvr3vfn72uxCOJ6hHRYKttvxdM9WWzQ0WsZXkkPtWBCNsTA4b7MUwJGrM9j PoYVBvdiFyQ1mrFxWtQ5kp11uV2EUFYvM3wnc6kQgAvG73WLT5aN07NawgzpMm1Z eOrqglnAleoTCiKEK+5RKGHnRO8KXloM3ah1kqQiIwH+hgS354mwsLFlLIBb1NM+ gu56NY3JZVlD8Q== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id C20E9E49AD; Tue, 4 Dec 2018 19:43:09 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 7/8] HID: logitech: Enable high-resolution scrolling on Logitech mice Date: Wed, 5 Dec 2018 10:42:27 +1000 Message-Id: <20181205004228.10714-8-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 From: Harry Cutts There are three features used by various Logitech mice for high-resolution scrolling: the scrolling acceleration bit in HID++ 1.0, and the x2120 and x2121 features in HID++ 2.0 and above. This patch supports all three, and uses the multiplier reported by the mouse for the HID++ 2.0+ features. The full list of product IDs of mice which support high-resolution scrolling was provided by Logitech, but the patch was tested using the following mice (using the Unifying receiver): * HID++ 1.0: Anywhere MX, Performance MX * x2120: M560 * x2121: MX Anywhere 2, MX Master 2S This patch is a combinations of the now-reverted commits 1ff2e1a44e0, d56ca9855bf9, 5fe2ccbef9d, 044ee89028 together with some extra bits for the directional and timeout-based reset. The previous patch series was in hid-input, it appears this remainder handling is logitech-specific and was moved to hid-logitech-hidpp.c and renamed accordingly. Signed-off-by: Harry Cutts Signed-off-by: Peter Hutterer --- Changes to v1: - get rid of the timer in favour of sched_clock() - drop storing the multiplier and calculate value on the fly Changes to v2: - m560 now has REL_HWHEEL_HI_RES (untested, I don't have the device) drivers/hid/hid-logitech-hidpp.c | 301 ++++++++++++++++++++++++++++++- 1 file changed, 295 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 95ba9db6e613..a66daf8acd87 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,14 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_QUIRK_NO_HIDINPUT BIT(23) #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) #define HIDPP_QUIRK_UNIFYING BIT(25) +#define HIDPP_QUIRK_HI_RES_SCROLL_1P0 BIT(26) +#define HIDPP_QUIRK_HI_RES_SCROLL_X2120 BIT(27) +#define HIDPP_QUIRK_HI_RES_SCROLL_X2121 BIT(28) + +/* Convenience constant to check for any high-res support. */ +#define HIDPP_QUIRK_HI_RES_SCROLL (HIDPP_QUIRK_HI_RES_SCROLL_1P0 | \ + HIDPP_QUIRK_HI_RES_SCROLL_X2120 | \ + HIDPP_QUIRK_HI_RES_SCROLL_X2121) #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT @@ -128,6 +137,25 @@ struct hidpp_battery { bool online; }; +/** + * struct hidpp_scroll_counter - Utility class for processing high-resolution + * scroll events. + * @dev: the input device for which events should be reported. + * @wheel_multiplier: the scalar multiplier to be applied to each wheel event + * @remainder: counts the number of high-resolution units moved since the last + * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should + * only be used by class methods. + * @direction: direction of last movement (1 or -1) + * @last_time: last event time, used to reset remainder after inactivity + */ +struct hidpp_scroll_counter { + struct input_dev *dev; + int wheel_multiplier; + int remainder; + int direction; + unsigned long long last_time; +}; + struct hidpp_device { struct hid_device *hid_dev; struct mutex send_mutex; @@ -149,6 +177,7 @@ struct hidpp_device { unsigned long capabilities; struct hidpp_battery battery; + struct hidpp_scroll_counter vertical_wheel_counter; }; /* HID++ 1.0 error codes */ @@ -391,6 +420,67 @@ static void hidpp_prefix_name(char **name, int name_length) *name = new_name; } +/** + * hidpp_scroll_counter_handle_scroll() - Send high- and low-resolution scroll + * events given a high-resolution wheel + * movement. + * @counter: a hid_scroll_counter struct describing the wheel. + * @hi_res_value: the movement of the wheel, in the mouse's high-resolution + * units. + * + * Given a high-resolution movement, this function converts the movement into + * fractions of 120 and emits high-resolution scroll events for the input + * device. It also uses the multiplier from &struct hid_scroll_counter to + * emit low-resolution scroll events when appropriate for + * backwards-compatibility with userspace input libraries. + */ +static void hidpp_scroll_counter_handle_scroll(struct hidpp_scroll_counter *counter, + int hi_res_value) +{ + int low_res_value, remainder, direction; + unsigned long long now, previous; + + hi_res_value = hi_res_value * 120/counter->wheel_multiplier; + input_report_rel(counter->dev, REL_WHEEL_HI_RES, hi_res_value); + + remainder = counter->remainder; + direction = hi_res_value > 0 ? 1 : -1; + + now = sched_clock(); + previous = counter->last_time; + counter->last_time = now; + /* + * Reset the remainder after a period of inactivity or when the + * direction changes. This prevents the REL_WHEEL emulation point + * from sliding for devices that don't always provide the same + * number of movements per detent. + */ + if (now - previous > 1000000000 || direction != counter->direction) + remainder = 0; + + counter->direction = direction; + remainder += hi_res_value; + + /* Some wheels will rest 7/8ths of a detent from the previous detent + * after slow movement, so we want the threshold for low-res events to + * be in the middle between two detents (e.g. after 4/8ths) as + * opposed to on the detents themselves (8/8ths). + */ + if (abs(remainder) >= 60) { + /* Add (or subtract) 1 because we want to trigger when the wheel + * is half-way to the next detent (i.e. scroll 1 detent after a + * 1/2 detent movement, 2 detents after a 1 1/2 detent movement, + * etc.). + */ + low_res_value = remainder / 120; + if (low_res_value == 0) + low_res_value = (hi_res_value > 0 ? 1 : -1); + input_report_rel(counter->dev, REL_WHEEL, low_res_value); + remainder -= low_res_value * 120; + } + counter->remainder = remainder; +} + /* -------------------------------------------------------------------------- */ /* HIDP++ 1.0 commands */ /* -------------------------------------------------------------------------- */ @@ -1157,6 +1247,99 @@ static int hidpp_battery_get_property(struct power_supply *psy, return ret; } +/* -------------------------------------------------------------------------- */ +/* 0x2120: Hi-resolution scrolling */ +/* -------------------------------------------------------------------------- */ + +#define HIDPP_PAGE_HI_RESOLUTION_SCROLLING 0x2120 + +#define CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE 0x10 + +static int hidpp_hrs_set_highres_scrolling_mode(struct hidpp_device *hidpp, + bool enabled, u8 *multiplier) +{ + u8 feature_index; + u8 feature_type; + int ret; + u8 params[1]; + struct hidpp_report response; + + ret = hidpp_root_get_feature(hidpp, + HIDPP_PAGE_HI_RESOLUTION_SCROLLING, + &feature_index, + &feature_type); + if (ret) + return ret; + + params[0] = enabled ? BIT(0) : 0; + ret = hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_HI_RESOLUTION_SCROLLING_SET_HIGHRES_SCROLLING_MODE, + params, sizeof(params), &response); + if (ret) + return ret; + *multiplier = response.fap.params[1]; + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* 0x2121: HiRes Wheel */ +/* -------------------------------------------------------------------------- */ + +#define HIDPP_PAGE_HIRES_WHEEL 0x2121 + +#define CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY 0x00 +#define CMD_HIRES_WHEEL_SET_WHEEL_MODE 0x20 + +static int hidpp_hrw_get_wheel_capability(struct hidpp_device *hidpp, + u8 *multiplier) +{ + u8 feature_index; + u8 feature_type; + int ret; + struct hidpp_report response; + + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, + &feature_index, &feature_type); + if (ret) + goto return_default; + + ret = hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_HIRES_WHEEL_GET_WHEEL_CAPABILITY, + NULL, 0, &response); + if (ret) + goto return_default; + + *multiplier = response.fap.params[0]; + return 0; +return_default: + hid_warn(hidpp->hid_dev, + "Couldn't get wheel multiplier (error %d)\n", ret); + return ret; +} + +static int hidpp_hrw_set_wheel_mode(struct hidpp_device *hidpp, bool invert, + bool high_resolution, bool use_hidpp) +{ + u8 feature_index; + u8 feature_type; + int ret; + u8 params[1]; + struct hidpp_report response; + + ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_HIRES_WHEEL, + &feature_index, &feature_type); + if (ret) + return ret; + + params[0] = (invert ? BIT(2) : 0) | + (high_resolution ? BIT(1) : 0) | + (use_hidpp ? BIT(0) : 0); + + return hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_HIRES_WHEEL_SET_WHEEL_MODE, + params, sizeof(params), &response); +} + /* -------------------------------------------------------------------------- */ /* 0x4301: Solar Keyboard */ /* -------------------------------------------------------------------------- */ @@ -2408,10 +2591,15 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) input_report_key(mydata->input, BTN_RIGHT, !!(data[1] & M560_MOUSE_BTN_RIGHT)); - if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) + if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) { input_report_rel(mydata->input, REL_HWHEEL, -1); - else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) + input_report_rel(mydata->input, REL_HWHEEL_HI_RES, + -120); + } else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) { input_report_rel(mydata->input, REL_HWHEEL, 1); + input_report_rel(mydata->input, REL_HWHEEL_HI_RES, + 120); + } v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); input_report_rel(mydata->input, REL_X, v); @@ -2420,7 +2608,8 @@ static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) input_report_rel(mydata->input, REL_Y, v); v = hid_snto32(data[6], 8); - input_report_rel(mydata->input, REL_WHEEL, v); + hidpp_scroll_counter_handle_scroll( + &hidpp->vertical_wheel_counter, v); input_sync(mydata->input); } @@ -2447,6 +2636,8 @@ static void m560_populate_input(struct hidpp_device *hidpp, __set_bit(REL_Y, mydata->input->relbit); __set_bit(REL_WHEEL, mydata->input->relbit); __set_bit(REL_HWHEEL, mydata->input->relbit); + __set_bit(REL_WHEEL_HI_RES, mydata->input->relbit); + __set_bit(REL_HWHEEL_HI_RES, mydata->input->relbit); } static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, @@ -2548,6 +2739,37 @@ static int g920_get_config(struct hidpp_device *hidpp) return 0; } +/* -------------------------------------------------------------------------- */ +/* High-resolution scroll wheels */ +/* -------------------------------------------------------------------------- */ + +static int hi_res_scroll_enable(struct hidpp_device *hidpp) +{ + int ret; + u8 multiplier = 1; + + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2121) { + ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false); + if (ret == 0) + ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier); + } else if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_X2120) { + ret = hidpp_hrs_set_highres_scrolling_mode(hidpp, true, + &multiplier); + } else /* if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL_1P0) */ { + ret = hidpp10_enable_scrolling_acceleration(hidpp); + multiplier = 8; + } + if (ret) + return ret; + + if (multiplier == 0) + multiplier = 1; + + hidpp->vertical_wheel_counter.wheel_multiplier = multiplier; + hid_info(hidpp->hid_dev, "multiplier = %d\n", multiplier); + return 0; +} + /* -------------------------------------------------------------------------- */ /* Generic HID++ devices */ /* -------------------------------------------------------------------------- */ @@ -2593,6 +2815,9 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, wtp_populate_input(hidpp, input, origin_is_hid_core); else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) m560_populate_input(hidpp, input, origin_is_hid_core); + + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) + hidpp->vertical_wheel_counter.dev = input; } static int hidpp_input_configured(struct hid_device *hdev, @@ -2711,6 +2936,27 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, return 0; } +static int hidpp_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + /* This function will only be called for scroll events, due to the + * restriction imposed in hidpp_usages. + */ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + struct hidpp_scroll_counter *counter = &hidpp->vertical_wheel_counter; + /* A scroll event may occur before the multiplier has been retrieved or + * the input device set, or high-res scroll enabling may fail. In such + * cases we must return early (falling back to default behaviour) to + * avoid a crash in hidpp_scroll_counter_handle_scroll. + */ + if (!(hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) || value == 0 + || counter->dev == NULL || counter->wheel_multiplier == 0) + return 0; + + hidpp_scroll_counter_handle_scroll(counter, value); + return 1; +} + static int hidpp_initialize_battery(struct hidpp_device *hidpp) { static atomic_t battery_no = ATOMIC_INIT(0); @@ -2922,6 +3168,9 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) if (hidpp->battery.ps) power_supply_changed(hidpp->battery.ps); + if (hidpp->quirks & HIDPP_QUIRK_HI_RES_SCROLL) + hi_res_scroll_enable(hidpp); + if (!(hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT) || hidpp->delayed_input) /* if the input nodes are already created, we can stop now */ return; @@ -3107,6 +3356,10 @@ static void hidpp_remove(struct hid_device *hdev) mutex_destroy(&hidpp->send_mutex); } +#define LDJ_DEVICE(product) \ + HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, \ + USB_VENDOR_ID_LOGITECH, (product)) + static const struct hid_device_id hidpp_devices[] = { { /* wireless touchpad */ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, @@ -3121,10 +3374,39 @@ static const struct hid_device_id hidpp_devices[] = { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651), .driver_data = HIDPP_QUIRK_CLASS_WTP }, + { /* Mouse Logitech Anywhere MX */ + LDJ_DEVICE(0x1017), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, + { /* Mouse Logitech Cube */ + LDJ_DEVICE(0x4010), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, + { /* Mouse Logitech M335 */ + LDJ_DEVICE(0x4050), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech M515 */ + LDJ_DEVICE(0x4007), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, { /* Mouse logitech M560 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x402d), - .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, + LDJ_DEVICE(0x402d), + .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 + | HIDPP_QUIRK_HI_RES_SCROLL_X2120 }, + { /* Mouse Logitech M705 (firmware RQM17) */ + LDJ_DEVICE(0x101b), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, + { /* Mouse Logitech M705 (firmware RQM67) */ + LDJ_DEVICE(0x406d), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech M720 */ + LDJ_DEVICE(0x405e), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Anywhere 2 */ + LDJ_DEVICE(0x404a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0xb013), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0xb018), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0xb01f), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Anywhere 2S */ + LDJ_DEVICE(0x406a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Master */ + LDJ_DEVICE(0x4041), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0x4060), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { LDJ_DEVICE(0x4071), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech MX Master 2S */ + LDJ_DEVICE(0x4069), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, + { /* Mouse Logitech Performance MX */ + LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, { /* Keyboard logitech K400 */ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, 0x4024), @@ -3144,12 +3426,19 @@ static const struct hid_device_id hidpp_devices[] = { MODULE_DEVICE_TABLE(hid, hidpp_devices); +static const struct hid_usage_id hidpp_usages[] = { + { HID_GD_WHEEL, EV_REL, REL_WHEEL_HI_RES }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} +}; + static struct hid_driver hidpp_driver = { .name = "logitech-hidpp-device", .id_table = hidpp_devices, .probe = hidpp_probe, .remove = hidpp_remove, .raw_event = hidpp_raw_event, + .usage_table = hidpp_usages, + .event = hidpp_event, .input_configured = hidpp_input_configured, .input_mapping = hidpp_input_mapping, .input_mapped = hidpp_input_mapped, From patchwork Wed Dec 5 00:42:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Hutterer X-Patchwork-Id: 10712843 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E2BE313BF for ; Wed, 5 Dec 2018 00:43:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CC5F42CA49 for ; Wed, 5 Dec 2018 00:43:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BC3282CA62; Wed, 5 Dec 2018 00:43:25 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI 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 58B7D2CA49 for ; Wed, 5 Dec 2018 00:43:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726888AbeLEAnS (ORCPT ); Tue, 4 Dec 2018 19:43:18 -0500 Received: from wout2-smtp.messagingengine.com ([64.147.123.25]:35421 "EHLO wout2-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726828AbeLEAnR (ORCPT ); Tue, 4 Dec 2018 19:43:17 -0500 Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.west.internal (Postfix) with ESMTP id 8B469F68; Tue, 4 Dec 2018 19:43:16 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute3.internal (MEProxy); Tue, 04 Dec 2018 19:43:17 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=who-t.net; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=+YYg4uhf70OKm hFN9YmF5qswdQNugSbQgP5G4iECx7w=; b=jGBZTkUFbPJjpqmu1uf3+b+lVh8t0 DOfS1UlliUU4l6svAlh9jI9EhOHi8z7E33mUO2+kAQ9AhJZVMQk2je2Gd/ki4LSS XracmWJIjGRg3b0swpHzh7veWYt/76uxOB3T4M6ixZNY+hw5JsX9+3P5KN/sxGSY ixe0SNtXHdZe7WYkuj37ePJp7tjbRd02O1QBJRgrXQuklQZ+QJ8DkArrYKA0yUAU rU8mubymI17LEy3IA9MJR0+jhU3lgcqGSc4fS5aSd0mFV91wZfKlXRC2pR24Kthd lpKAqx/Jj8fYKgTFBFIuQEzHC9oMskudCMzelyjPmxjvM5hU0gnHH/Qdg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=+YYg4uhf70OKmhFN9YmF5qswdQNugSbQgP5G4iECx7w=; b=X22RKtVP S6/BujsaqUEaQ1blfKhSKFZQu3dSjNSzmb3NQuiebg+Ack9FYNCV9u3LgHnGlydj 8P8f/rtNmhjUyhhPEj+lWqOvOuBLEe5a9kTnH3m+mNOSZZCGmpekM1OgaBt3O3dR JBP5jCSzM9w4I8y2lK/iJ/2P6r1GoHIRroqJ3jSb90U9juV3zj2zy5qd0mSEwb6i zQCUTo8CINkmPp0TUeqIPBPsDmaoqzVt3ApOuOwr204mCMnpnixv4nxuwfS23nsO EVk3eiF19b12NTNxWRVlFK8zmVv6iPzeeQDAki4bVfq092yn0JzSEN2S1X+bNj+q qUXW4wXCGXEGjg== X-ME-Sender: X-ME-Proxy: Received: from jelly.home.gateway (167-179-166-29.a7b3a6.bne.nbn.aussiebb.net [167.179.166.29]) by mail.messagingengine.com (Postfix) with ESMTPA id 0A49DE4925; Tue, 4 Dec 2018 19:43:12 -0500 (EST) From: Peter Hutterer To: linux-input@vger.kernel.org Cc: Dmitry Torokhov , Jiri Kosina , Harry Cutts , torvalds@linux-foundation.org, Nestor Lopez Casado , linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH v3 8/8] HID: logitech: Use LDJ_DEVICE macro for existing Logitech mice Date: Wed, 5 Dec 2018 10:42:28 +1000 Message-Id: <20181205004228.10714-9-peter.hutterer@who-t.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181205004228.10714-1-peter.hutterer@who-t.net> References: <20181205004228.10714-1-peter.hutterer@who-t.net> MIME-Version: 1.0 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 From: Harry Cutts Signed-off-by: Harry Cutts Reviewed-by: Benjamin Tissoires Signed-off-by: Peter Hutterer --- Changes to v1, v2: - reordered from 6/8 to 8/8 so the intermediate steps all build drivers/hid/hid-logitech-hidpp.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index a66daf8acd87..15ed6177a7a3 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -3362,13 +3362,11 @@ static void hidpp_remove(struct hid_device *hdev) static const struct hid_device_id hidpp_devices[] = { { /* wireless touchpad */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4011), + LDJ_DEVICE(0x4011), .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, { /* wireless touchpad T650 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4101), + LDJ_DEVICE(0x4101), .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, { /* wireless touchpad T651 */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, @@ -3408,16 +3406,13 @@ static const struct hid_device_id hidpp_devices[] = { { /* Mouse Logitech Performance MX */ LDJ_DEVICE(0x101a), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_1P0 }, { /* Keyboard logitech K400 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4024), + LDJ_DEVICE(0x4024), .driver_data = HIDPP_QUIRK_CLASS_K400 }, { /* Solar Keyboard Logitech K750 */ - HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, 0x4002), + LDJ_DEVICE(0x4002), .driver_data = HIDPP_QUIRK_CLASS_K750 }, - { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, - USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, + { LDJ_DEVICE(HID_ANY_ID) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL), .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},