Received: by 2002:a05:7412:37c9:b0:e2:908c:2ebd with SMTP id jz9csp269767rdb; Mon, 18 Sep 2023 14:45:29 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEiLG27axLN73erz3d0CDo/HPM8Yuvw0Sbg91d6kT7ggMdTtYrYfIdljR41Ro/Gyyxg0uk3 X-Received: by 2002:a05:6a21:3b46:b0:14c:6397:ac6e with SMTP id zy6-20020a056a213b4600b0014c6397ac6emr8004100pzb.23.1695073529620; Mon, 18 Sep 2023 14:45:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695073529; cv=none; d=google.com; s=arc-20160816; b=AgiDJK1xlJmv7TOQI17yB4CaEHW2mCWJ1RO8PnBdmNJkwM/8brWVJVTOhZ6V/b4Lpw FaWmUWTduVYYlm0HEFEpOYGykOufcxQOQLTWnbYCMMA4Ykm38pxw1LkJRDRt244A9apo 7P8wPueINPPLDEGnhGlD303U7F41a+7vgWQ2tbPty5soniMnalKG/HqEnsQdeV8QEVku fM1CZLbAQwLAl782XrEvEj/RYwJQp99JOijhjsTYOFEbq3yZ3RM8BPP7AEX4f9OJIMHy 5GqLi4f+Icxpv8Kg19wf4v9yf91BoMD9yIZfyhLOblFhbRRmGq0JQjCsGF9H0vz8vMOY hbjg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=dfRSoo3qIAJs9yRjFcRKTJjlagEPLA7cOh8uxaHtW9c=; fh=mOe1ko3f8kPYDE7PL8LsZW2fNDy1pqWYuuuyh7fh9Yg=; b=rzYzB2ojNlrdR7urJxTOYIskG3IohacYQrBo+G5T0ugY9gYertO4Qn8Fy/JhJXGUS1 btotB5ssrY81eBL0srpWGHh4EvFj3tlpfUv7U1brmyXjz4882SwgASe1xiGjIZOnjb/D Gtuy6/3g1MP9AbBRmRAnnN84IL7fluHkGIUn0KevArjIrcZ3l6wVJc4gE5CVNlwPITpl YZwnf24jq6yi/Mlp+lfDUoI1zyF0juxyL2D6sB43TUAUPnA0ivSmIA/MED39pVkzReJj q99z6RznivCgPT8T9Q83/UcCH+JvUgeizjbnMR5cAbuDVHrhZkVkPjUuOtAGIpTa9QUQ +JIw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@khvoinitsky.org header.s=key1 header.b=Q7EXapfh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=khvoinitsky.org Return-Path: Received: from groat.vger.email (groat.vger.email. [23.128.96.35]) by mx.google.com with ESMTPS id l9-20020a170902f68900b001bf88e777f9si9237505plg.33.2023.09.18.14.45.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Sep 2023 14:45:29 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) client-ip=23.128.96.35; Authentication-Results: mx.google.com; dkim=pass header.i=@khvoinitsky.org header.s=key1 header.b=Q7EXapfh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.35 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=khvoinitsky.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by groat.vger.email (Postfix) with ESMTP id 43E5A8025DC9; Mon, 18 Sep 2023 09:03:34 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at groat.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229595AbjIRQDZ (ORCPT + 99 others); Mon, 18 Sep 2023 12:03:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57724 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229630AbjIRQDX (ORCPT ); Mon, 18 Sep 2023 12:03:23 -0400 X-Greylist: delayed 1457 seconds by postgrey-1.37 at lindbergh.monkeyblade.net; Mon, 18 Sep 2023 09:01:27 PDT Received: from out-211.mta1.migadu.com (out-211.mta1.migadu.com [IPv6:2001:41d0:203:375::d3]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B59D444A5 for ; Mon, 18 Sep 2023 09:01:27 -0700 (PDT) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=khvoinitsky.org; s=key1; t=1695048674; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=dfRSoo3qIAJs9yRjFcRKTJjlagEPLA7cOh8uxaHtW9c=; b=Q7EXapfhVZAriNnfVz4CsGwM0MUcqE4o7YL9j1zT/ndAInhOoM29DXTUubkGiS8j4n/fXS HxnNCkC/i1BjFycWMVbQgbcepqqeaQzMqzQkWfp8c8g+XR+GZqm++MZx5LMsvPa40tn/ML 5/4aiYEUdWL3Nf5GQ0mHm7H51jA3KTo= From: Mikhail Khvainitski To: Jiri Kosina , Benjamin Tissoires Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Mikhail Khvainitski Subject: [PATCH] HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd Date: Mon, 18 Sep 2023 17:50:42 +0300 Message-ID: <20230918145042.37368-1-me@khvoinitsky.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT X-Spam-Status: No, score=-0.9 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on groat.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (groat.vger.email [0.0.0.0]); Mon, 18 Sep 2023 09:03:34 -0700 (PDT) Built-in firmware of cptkbd handles scrolling by itself (when middle button is pressed) but with issues: it does not support horizontal and hi-res scrolling and upon middle button release it sends middle button click even if there was a scrolling event. Commit 3cb5ff0220e3 ("HID: lenovo: Hide middle-button press until release") workarounds last issue but it's impossible to workaround scrolling-related issues without firmware modification. Likely, Dennis Schneider has reverse engineered the firmware and provided an instruction on how to patch it [1]. However, aforementioned workaround prevents userspace (libinput) from knowing exact moment when middle button has been pressed down and performing "On-Button scrolling". This commit makes it possible to disable this workaround by sysfs knob. Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1] Signed-off-by: Mikhail Khvainitski --- drivers/hid/hid-lenovo.c | 84 +++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 44763c0da444..8993fa1ce66a 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -53,6 +53,7 @@ struct lenovo_drvdata { int press_speed; u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */ bool fn_lock; + bool middleclick_workaround_cptkbd; }; #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) @@ -603,6 +604,36 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, return count; } +static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = to_hid_device(dev); + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + cptkbd_data->middleclick_workaround_cptkbd); +} + +static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct hid_device *hdev = to_hid_device(dev); + struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); + int value; + + if (kstrtoint(buf, 10, &value)) + return -EINVAL; + if (value < 0 || value > 1) + return -EINVAL; + + cptkbd_data->middleclick_workaround_cptkbd = !!value; + + return count; +} + static struct device_attribute dev_attr_fn_lock = __ATTR(fn_lock, S_IWUSR | S_IRUGO, @@ -614,10 +645,16 @@ static struct device_attribute dev_attr_sensitivity_cptkbd = attr_sensitivity_show_cptkbd, attr_sensitivity_store_cptkbd); +static struct device_attribute dev_attr_middleclick_workaround_cptkbd = + __ATTR(middleclick_workaround, S_IWUSR | S_IRUGO, + attr_middleclick_workaround_show_cptkbd, + attr_middleclick_workaround_store_cptkbd); + static struct attribute *lenovo_attributes_cptkbd[] = { &dev_attr_fn_lock.attr, &dev_attr_sensitivity_cptkbd.attr, + &dev_attr_middleclick_workaround_cptkbd.attr, NULL }; @@ -668,31 +705,33 @@ static int lenovo_event_cptkbd(struct hid_device *hdev, { struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev); - /* "wheel" scroll events */ - if (usage->type == EV_REL && (usage->code == REL_WHEEL || - usage->code == REL_HWHEEL)) { - /* Scroll events disable middle-click event */ - cptkbd_data->middlebutton_state = 2; - return 0; - } + if (cptkbd_data->middleclick_workaround_cptkbd) { + /* "wheel" scroll events */ + if (usage->type == EV_REL && (usage->code == REL_WHEEL || + usage->code == REL_HWHEEL)) { + /* Scroll events disable middle-click event */ + cptkbd_data->middlebutton_state = 2; + return 0; + } - /* Middle click events */ - if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) { - if (value == 1) { - cptkbd_data->middlebutton_state = 1; - } else if (value == 0) { - if (cptkbd_data->middlebutton_state == 1) { - /* No scrolling inbetween, send middle-click */ - input_event(field->hidinput->input, - EV_KEY, BTN_MIDDLE, 1); - input_sync(field->hidinput->input); - input_event(field->hidinput->input, - EV_KEY, BTN_MIDDLE, 0); - input_sync(field->hidinput->input); + /* Middle click events */ + if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) { + if (value == 1) { + cptkbd_data->middlebutton_state = 1; + } else if (value == 0) { + if (cptkbd_data->middlebutton_state == 1) { + /* No scrolling inbetween, send middle-click */ + input_event(field->hidinput->input, + EV_KEY, BTN_MIDDLE, 1); + input_sync(field->hidinput->input); + input_event(field->hidinput->input, + EV_KEY, BTN_MIDDLE, 0); + input_sync(field->hidinput->input); + } + cptkbd_data->middlebutton_state = 0; } - cptkbd_data->middlebutton_state = 0; + return 1; } - return 1; } if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) { @@ -1146,6 +1185,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) cptkbd_data->middlebutton_state = 0; cptkbd_data->fn_lock = true; cptkbd_data->sensitivity = 0x05; + cptkbd_data->middleclick_workaround_cptkbd = true; lenovo_features_set_cptkbd(hdev); ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); -- 2.42.0