All of lore.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Tissoires <benjamin.tissoires@redhat.com>
To: Jiri Kosina <jikos@kernel.org>,
	Bastien Nocera <hadess@hadess.net>,
	Peter Hutterer <peter.hutterer@who-t.net>,
	Nestor Lopez Casado <nlopezcasad@logitech.com>,
	Olivier Gay <ogay@logitech.com>, Simon Wood <simon@mungewell.org>
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 17/17] HID: logitech-hidpp: retrieve the name of the gaming mice over wireless
Date: Tue, 17 Jan 2017 15:35:47 +0100	[thread overview]
Message-ID: <20170117143547.30488-18-benjamin.tissoires@redhat.com> (raw)
In-Reply-To: <20170117143547.30488-1-benjamin.tissoires@redhat.com>

The G700 and the G900 present both a wireless receiver with almost unifying
protocol. We handle them as bypass for the mouse and keyboard nodes, but
they appear in the system as "Logitech USB Receiver".

We can do better by retrieving the name from one of the nodes, the HID++
one of the receiver. To get the valid values in the non-HID++ nodes, we
delay their probing until the HID++ node has been found. This way, we
can retrieve the shared names and overwrite the USB provided ones.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
 drivers/hid/hid-logitech-hidpp.c | 106 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 103 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 99caec4..3412101 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -123,6 +123,17 @@ struct hidpp_battery {
 	int level;
 };
 
+struct hidpp_shared {
+	struct list_head list;
+	int count;
+	char name[128];		/* Device name */
+	char phys[64];		/* Device physical location */
+	char uniq[64];		/* Device unique identifier (serial #) */
+};
+
+static LIST_HEAD(hidpp_shared_list);
+static DEFINE_MUTEX(hidpp_shared_list_lock);
+
 struct hidpp_device {
 	struct hid_device *hid_dev;
 	struct mutex send_mutex;
@@ -144,6 +155,8 @@ struct hidpp_device {
 	unsigned long quirks;
 
 	struct hidpp_battery battery;
+
+	struct hidpp_shared *shared;
 };
 
 /* HID++ 1.0 error codes */
@@ -2849,6 +2862,78 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
 	hidpp->delayed_input = input;
 }
 
+static void hidpp_remove_shared_data(void *res)
+{
+	struct hidpp_device *hidpp = res;
+
+	mutex_lock(&hidpp_shared_list_lock);
+
+	if (hidpp->shared && !--hidpp->shared->count) {
+		list_del(&hidpp->shared->list);
+		kfree(hidpp->shared);
+	}
+	hidpp->shared = NULL;
+
+	mutex_unlock(&hidpp_shared_list_lock);
+}
+
+static bool hidpp_compare_device_paths(const char *hdev_a, const char *hdev_b)
+{
+	const char separator = '/';
+	int n1 = strrchr(hdev_a, separator) - hdev_a;
+	int n2 = strrchr(hdev_b, separator) - hdev_b;
+
+	if (n1 != n2 || n1 <= 0 || n2 <= 0)
+		return false;
+
+	return !strncmp(hdev_a, hdev_b, n1);
+}
+
+static int hidpp_get_shared_data(struct hidpp_device *hidpp)
+{
+	struct hid_device *hdev = hidpp->hid_dev;
+	struct hidpp_shared *s, *shared = NULL;
+	int ret;
+
+	mutex_lock(&hidpp_shared_list_lock);
+
+	if (hidpp->device_index != 0xff) {
+		shared = kzalloc(sizeof(struct hidpp_shared), GFP_KERNEL);
+		if (!shared) {
+			mutex_unlock(&hidpp_shared_list_lock);
+			return -ENOMEM;
+		}
+		memcpy(shared->name, hdev->name, sizeof(shared->name));
+		memcpy(shared->uniq, hdev->uniq, sizeof(shared->uniq));
+		memcpy(shared->phys, hdev->phys, sizeof(shared->phys));
+		list_add_tail(&shared->list, &hidpp_shared_list);
+	} else {
+		list_for_each_entry(s, &hidpp_shared_list, list) {
+			if (hidpp_compare_device_paths(s->phys, hdev->phys))
+				shared = s;
+		}
+	}
+
+	if (!shared) {
+		mutex_unlock(&hidpp_shared_list_lock);
+		return -EPROBE_DEFER;
+	}
+
+	hidpp->shared = shared;
+	shared->count++;
+
+	mutex_unlock(&hidpp_shared_list_lock);
+
+	ret = devm_add_action_or_reset(&hidpp->hid_dev->dev,
+					hidpp_remove_shared_data, hidpp);
+	if (ret)
+		return ret;
+
+	memcpy(hdev->name, shared->name, sizeof(hdev->name));
+	memcpy(hdev->uniq, shared->uniq, sizeof(hdev->uniq));
+	return 0;
+}
+
 static DEVICE_ATTR(builtin_power_supply, 0000, NULL, NULL);
 
 static struct attribute *sysfs_attrs[] = {
@@ -2910,8 +2995,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 	/*
 	 * Make sure the device is HID++ capable, otherwise treat as generic HID
+	 * Special case for manually affected Unifying receiver where we want to
+	 * link the interfaces together to have a proper name instead of
+	 * "Logitech USB Receiver".
 	 */
-	if (!hidpp_validate_device(hdev))
+	if (!(id->driver_data & HIDPP_QUIRK_UNIFYING) &&
+	    !hidpp_validate_device(hdev))
 		return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 
 	/*
@@ -2995,8 +3084,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);
+	if (hidpp->quirks & HIDPP_QUIRK_UNIFYING) {
+		ret = hidpp_unifying_init(hidpp);
+		if (ret)
+			goto start;
+	}
 
 	connected = hidpp_is_connected(hidpp);
 	if (!(hidpp->quirks & HIDPP_QUIRK_UNIFYING)) {
@@ -3026,6 +3118,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
 	hidpp_connect_event(hidpp);
 
+start:
 	/* Reset the HID node state */
 	hid_device_io_stop(hdev);
 	hid_hw_close(hdev);
@@ -3034,6 +3127,13 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
 	if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
 		connect_mask &= ~HID_CONNECT_HIDINPUT;
 
+	if ((hidpp->quirks & HIDPP_QUIRK_UNIFYING) &&
+	    id->group != HID_GROUP_LOGITECH_DJ_DEVICE) {
+		ret = hidpp_get_shared_data(hidpp);
+		if (ret)
+			goto hid_hw_start_fail;
+	}
+
 	/* Now export the actual inputs and hidraw nodes to the world */
 	ret = hid_hw_start(hdev, connect_mask);
 	if (ret) {
-- 
2.9.3

  parent reply	other threads:[~2017-01-17 14:37 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-01-17 14:35 [PATCH 00/17] Report power supply from hid-logitech-dj and others Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 01/17] HID: logitech-dj: allow devices to request full pairing information Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 02/17] HID: logitech-hidpp: Add scope to battery Benjamin Tissoires
2017-01-18 11:35   ` Bastien Nocera
2017-01-20 13:11   ` Jiri Kosina
2017-01-20 14:25     ` Benjamin Tissoires
2017-01-20 14:26       ` Jiri Kosina
2017-01-17 14:35 ` [PATCH 03/17] HID: logitech-hidpp: make sure we only register one battery per device Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 04/17] HID: logitech-hidpp: battery: remove overloads and provide ONLINE Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 05/17] HID: logitech-hidpp: forward device info in power_supply Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 06/17] HID: logitech-hidpp: create the battery for all types of HID++ devices Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 07/17] HID: logitech-hidpp: return an error if the feature is not present Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 08/17] HID: logitech-hidpp: add support for battery status for the K750 Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 09/17] HID: logitech-hidpp: enable HID++ 1.0 battery reporting Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 10/17] HID: logitech-hidpp: notify battery on connect Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 11/17] HID: logitech-hidpp: add a sysfs file to tell we support power_supply Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 12/17] HID: logitech-hidpp: allow non HID++ devices to be handled by this module Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 13/17] HID: logitech-hidpp: make .probe usbhid capable Benjamin Tissoires
2017-01-18  9:26   ` Benjamin Tissoires
2017-01-19 10:56     ` Jiri Kosina
2017-01-19 11:11       ` Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 14/17] HID: logitech-hidpp: do not query the name through HID++ for 1.0 devices Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 15/17] HID: logitech-hidpp: rework probe path for unifying devices Benjamin Tissoires
2017-01-17 14:35 ` [PATCH 16/17] HID: logitech-hidpp: report battery for the G700 over wireless Benjamin Tissoires
2017-01-17 14:35 ` Benjamin Tissoires [this message]
2017-01-23 14:35 ` [PATCH 00/17] Report power supply from hid-logitech-dj and others Bastien Nocera
2017-01-23 15:22   ` Benjamin Tissoires
2017-01-24 17:11   ` Bastien Nocera

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170117143547.30488-18-benjamin.tissoires@redhat.com \
    --to=benjamin.tissoires@redhat.com \
    --cc=hadess@hadess.net \
    --cc=jikos@kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nlopezcasad@logitech.com \
    --cc=ogay@logitech.com \
    --cc=peter.hutterer@who-t.net \
    --cc=simon@mungewell.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.