From patchwork Tue Jan 17 14:35:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Tissoires X-Patchwork-Id: 9521237 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 163F3601C3 for ; Tue, 17 Jan 2017 14:37:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0DDE727F8C for ; Tue, 17 Jan 2017 14:37:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 01B042855D; Tue, 17 Jan 2017 14:37:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable 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 8DD2727F8C for ; Tue, 17 Jan 2017 14:37:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751539AbdAQOhh (ORCPT ); Tue, 17 Jan 2017 09:37:37 -0500 Received: from mx1.redhat.com ([209.132.183.28]:39968 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751537AbdAQOgd (ORCPT ); Tue, 17 Jan 2017 09:36:33 -0500 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B1A3161B97; Tue, 17 Jan 2017 14:36:28 +0000 (UTC) Received: from plouf.banquise.eu.com (ovpn-116-139.ams2.redhat.com [10.36.116.139]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v0HEZpSd002921; Tue, 17 Jan 2017 09:36:26 -0500 From: Benjamin Tissoires To: Jiri Kosina , Bastien Nocera , Peter Hutterer , Nestor Lopez Casado , Olivier Gay , Simon Wood Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 15/17] HID: logitech-hidpp: rework probe path for unifying devices Date: Tue, 17 Jan 2017 15:35:45 +0100 Message-Id: <20170117143547.30488-16-benjamin.tissoires@redhat.com> In-Reply-To: <20170117143547.30488-1-benjamin.tissoires@redhat.com> References: <20170117143547.30488-1-benjamin.tissoires@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 17 Jan 2017 14:36:28 +0000 (UTC) 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 Unifying devices are different from others because they can probed while not connected. So we need to talk to the receiver to get some extra information like the device name and the serial. Instead of having conditionals while attempting to read the device name from HID++ 2.0, have a special init path for them. Store the retrieved serial in hdev->uniq. Signed-off-by: Benjamin Tissoires --- drivers/hid/hid-logitech-hidpp.c | 81 +++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 17dd569..2293898 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -65,6 +65,7 @@ MODULE_PARM_DESC(disable_tap_to_click, #define HIDPP_QUIRK_FORCE_OUTPUT_REPORTS BIT(24) #define HIDPP_QUIRK_HIDPP20_BATTERY BIT(25) #define HIDPP_QUIRK_HIDPP10_BATTERY BIT(26) +#define HIDPP_QUIRK_UNIFYING BIT(27) #define HIDPP_QUIRK_DELAYED_INIT HIDPP_QUIRK_NO_HIDINPUT @@ -586,14 +587,14 @@ static int hidpp10_battery_event(struct hidpp_device *hidpp, u8 *data, int size) } #define HIDPP_REG_PAIRING_INFORMATION 0xB5 -#define DEVICE_NAME 0x40 +#define HIDPP_EXTENDED_PAIRING 0x30 +#define HIDPP_DEVICE_NAME 0x40 -static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev) +static char *hidpp_unifying_get_name(struct hidpp_device *hidpp_dev) { struct hidpp_report response; int ret; - /* hid-logitech-dj is in charge of setting the right device index */ - u8 params[1] = { DEVICE_NAME }; + u8 params[1] = { HIDPP_DEVICE_NAME }; char *name; int len; @@ -622,6 +623,52 @@ static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev) return name; } +static u32 hidpp_unifying_get_serial(struct hidpp_device *hidpp) +{ + struct hidpp_report response; + int ret; + u8 params[1] = { HIDPP_EXTENDED_PAIRING }; + + ret = hidpp_send_rap_command_sync(hidpp, + REPORT_ID_HIDPP_SHORT, + HIDPP_GET_LONG_REGISTER, + HIDPP_REG_PAIRING_INFORMATION, + params, 1, &response); + if (ret) + return 0; + + /* + * We don't care about LE or BE, we will output it as a string + * with %4phD, so we need to keep the order. + */ + return *((u32 *)&response.rap.params[1]); +} + +static int hidpp_unifying_init(struct hidpp_device *hidpp) +{ + struct hid_device *hdev = hidpp->hid_dev; + const char *name; + u32 serial; + + serial = hidpp_unifying_get_serial(hidpp); + if (serial == 0) + return -EIO; + + name = hidpp_unifying_get_name(hidpp); + if (!name) + return -EIO; + + snprintf(hdev->name, sizeof(hdev->name), "%s", name); + dbg_hid("HID++ Unifying: Got name: %s\n", name); + + snprintf(hdev->uniq, sizeof(hdev->uniq), "%04x-%4phD", + hdev->product, &serial); + dbg_hid("HID++ Unifying: Got serial: %s\n", hdev->uniq); + + kfree(name); + return 0; +} + /* -------------------------------------------------------------------------- */ /* 0x0000: Root */ /* -------------------------------------------------------------------------- */ @@ -2600,22 +2647,15 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp) return ret; } -static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying) +static void hidpp_overwrite_name(struct hid_device *hdev) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); char *name; - if (use_unifying) - /* - * the device is connected through an Unifying receiver, and - * might not be already connected. - * Ask the receiver for its name. - */ - name = hidpp_get_unifying_name(hidpp); - else if (hidpp->protocol_major < 2) + if (hidpp->protocol_major < 2) return; - else - name = hidpp_get_device_name(hidpp); + + name = hidpp_get_device_name(hidpp); if (!name) { hid_err(hdev, "unable to retrieve the name of the device"); @@ -2837,6 +2877,9 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) hidpp->quirks = id->driver_data; + if (id->group == HID_GROUP_LOGITECH_DJ_DEVICE) + hidpp->quirks |= HIDPP_QUIRK_UNIFYING; + if (disable_raw_mode) { hidpp->quirks &= ~HIDPP_QUIRK_CLASS_WTP; hidpp->quirks &= ~HIDPP_QUIRK_NO_HIDINPUT; @@ -2887,8 +2930,11 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) /* Allow incoming packets */ hid_device_io_start(hdev); + if (hidpp->quirks & HIDPP_QUIRK_UNIFYING) + hidpp_unifying_init(hidpp); + connected = hidpp_is_connected(hidpp); - if (id->group != HID_GROUP_LOGITECH_DJ_DEVICE) { + if (!(hidpp->quirks & HIDPP_QUIRK_UNIFYING)) { if (!connected) { ret = -ENODEV; hid_err(hdev, "Device not connected"); @@ -2899,7 +2945,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) hidpp->protocol_major, hidpp->protocol_minor); } - hidpp_overwrite_name(hdev, id->group == HID_GROUP_LOGITECH_DJ_DEVICE); + if (connected) + hidpp_overwrite_name(hdev); atomic_set(&hidpp->connected, connected); if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {