From patchwork Thu Sep 3 13:08:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Tissoires X-Patchwork-Id: 7116751 X-Patchwork-Delegate: jikos@jikos.cz Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6AC969F32B for ; Thu, 3 Sep 2015 13:08:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B25A320851 for ; Thu, 3 Sep 2015 13:08:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 24D0320852 for ; Thu, 3 Sep 2015 13:08:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753877AbbICNIm (ORCPT ); Thu, 3 Sep 2015 09:08:42 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43452 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754031AbbICNIf (ORCPT ); Thu, 3 Sep 2015 09:08:35 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 85560C1C35E7; Thu, 3 Sep 2015 13:08:35 +0000 (UTC) Received: from t540p.bos.redhat.com (dhcp-25-234.bos.redhat.com [10.18.25.234]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t83D8W7t031290; Thu, 3 Sep 2015 09:08:34 -0400 From: Benjamin Tissoires To: Jiri Kosina , Nestor Lopez Casado Cc: simon@mungewell.org, BALATON Zoltan , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Benjamin Tissoires Subject: [PATCH 2/2] HID: logitech-hidpp: add support to disable tap-to-click on the K400 Date: Thu, 3 Sep 2015 09:08:30 -0400 Message-Id: <1441285710-21276-3-git-send-email-benjamin.tissoires@redhat.com> In-Reply-To: <1441285710-21276-1-git-send-email-benjamin.tissoires@redhat.com> References: <1441285710-21276-1-git-send-email-benjamin.tissoires@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The Logitech K400 keyboard has an embedded touchpad which is seen as a mouse from the OS point of view. There is a hardware shortcut to disable tap-to-click but the setting is not remembered accross reset, annoying some users. We can toggle this feature from the host by using the feature 0x6010: Touchpad FW items Reported-by: BALATON Zoltan Tested-by: BALATON Zoltan Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-logitech-hidpp.c | 133 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 81d1bc0..452e5d5 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -33,6 +33,11 @@ module_param(disable_raw_mode, bool, 0644); MODULE_PARM_DESC(disable_raw_mode, "Disable Raw mode reporting for touchpads and keep firmware gestures."); +static bool disable_tap_to_click; +module_param(disable_tap_to_click, bool, 0644); +MODULE_PARM_DESC(disable_tap_to_click, + "Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently)."); + #define REPORT_ID_HIDPP_SHORT 0x10 #define REPORT_ID_HIDPP_LONG 0x11 @@ -41,6 +46,7 @@ MODULE_PARM_DESC(disable_raw_mode, #define HIDPP_QUIRK_CLASS_WTP BIT(0) #define HIDPP_QUIRK_CLASS_M560 BIT(1) +#define HIDPP_QUIRK_CLASS_K400 BIT(2) /* bits 2..20 are reserved for classes */ #define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) @@ -557,6 +563,52 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp) } /* -------------------------------------------------------------------------- */ +/* 0x6010: Touchpad FW items */ +/* -------------------------------------------------------------------------- */ + +#define HIDPP_PAGE_TOUCHPAD_FW_ITEMS 0x6010 + +#define CMD_TOUCHPAD_FW_ITEMS_SET 0x10 + +struct hidpp_touchpad_fw_items { + uint8_t presence; + uint8_t desired_state; + uint8_t state; + uint8_t persistent; +}; + +/** + * send a set state command to the device by reading the current items->state + * field. items is then filled with the current state. + */ +static int hidpp_touchpad_fw_items_set(struct hidpp_device *hidpp, + u8 feature_index, + struct hidpp_touchpad_fw_items *items) +{ + struct hidpp_report response; + int ret; + u8 *params = (u8 *)response.fap.params; + + ret = hidpp_send_fap_command_sync(hidpp, feature_index, + CMD_TOUCHPAD_FW_ITEMS_SET, &items->state, 1, &response); + + if (ret > 0) { + hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", + __func__, ret); + return -EPROTO; + } + if (ret) + return ret; + + items->presence = params[0]; + items->desired_state = params[1]; + items->state = params[2]; + items->persistent = params[3]; + + return 0; +} + +/* -------------------------------------------------------------------------- */ /* 0x6100: TouchPadRawXY */ /* -------------------------------------------------------------------------- */ @@ -1136,6 +1188,75 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, return -1; } +/* ------------------------------------------------------------------------- */ +/* Logitech K400 devices */ +/* ------------------------------------------------------------------------- */ + +/* + * The Logitech K400 keyboard has an embedded touchpad which is seen + * as a mouse from the OS point of view. There is a hardware shortcut to disable + * tap-to-click but the setting is not remembered accross reset, annoying some + * users. + * + * We can toggle this feature from the host by using the feature 0x6010: + * Touchpad FW items + */ + +struct k400_private_data { + u8 feature_index; +}; + +static int k400_disable_tap_to_click(struct hidpp_device *hidpp) +{ + struct k400_private_data *k400 = hidpp->private_data; + struct hidpp_touchpad_fw_items items = {}; + int ret; + u8 feature_type; + + if (!k400->feature_index) { + ret = hidpp_root_get_feature(hidpp, + HIDPP_PAGE_TOUCHPAD_FW_ITEMS, + &k400->feature_index, &feature_type); + if (ret) + /* means that the device is not powered up */ + return ret; + } + + ret = hidpp_touchpad_fw_items_set(hidpp, k400->feature_index, &items); + if (ret) + return ret; + + return 0; +} + +static int k400_allocate(struct hid_device *hdev) +{ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + struct k400_private_data *k400; + + k400 = devm_kzalloc(&hdev->dev, sizeof(struct k400_private_data), + GFP_KERNEL); + if (!k400) + return -ENOMEM; + + hidpp->private_data = k400; + + return 0; +}; + +static int k400_connect(struct hid_device *hdev, bool connected) +{ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + + if (!connected) + return 0; + + if (!disable_tap_to_click) + return 0; + + return k400_disable_tap_to_click(hidpp); +} + /* -------------------------------------------------------------------------- */ /* Generic HID++ devices */ /* -------------------------------------------------------------------------- */ @@ -1332,6 +1453,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) ret = m560_send_config_command(hdev, connected); if (ret) return; + } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) { + ret = k400_connect(hdev, connected); + if (ret) + return; } if (!connected || hidpp->delayed_input) @@ -1416,6 +1541,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) ret = m560_allocate(hdev); if (ret) goto allocate_fail; + } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_K400) { + ret = k400_allocate(hdev); + if (ret) + goto allocate_fail; } INIT_WORK(&hidpp->work, delayed_work_cb); @@ -1510,6 +1639,10 @@ static const struct hid_device_id hidpp_devices[] = { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, 0x402d), .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, + { /* Keyboard logitech K400 */ + HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, + USB_VENDOR_ID_LOGITECH, 0x4024), + .driver_data = HIDPP_QUIRK_CONNECT_EVENTS | HIDPP_QUIRK_CLASS_K400 }, { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},