Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33797820 authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Jiri Kosina
Browse files

HID: logitech: allow the DJ device to request the unifying name



The names of the DJ devices are stored in the receiver. These names
can be retrieved through a HID++ command. However, the protocol says
that you have to ask the receiver for that, not the device iteself.

Introduce a special case in the DJ handling where a device can request
its unifying name, and when such a name is given, forward it also to
the corresponding device.

On the HID++ side, the receiver talks only HID++ 1.0, so we need to
implement this part of the protocol in the module.

Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Tested-by: default avatarAndrew de los Reyes <adlr@chromium.org>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 925f0f3e
Loading
Loading
Loading
Loading
+21 −3
Original line number Diff line number Diff line
@@ -667,6 +667,9 @@ static void logi_dj_ll_close(struct hid_device *hid)
	dbg_hid("%s:%s\n", __func__, hid->phys);
}

static u8 unifying_name_query[]  = {0x10, 0xff, 0x83, 0xb5, 0x40, 0x00, 0x00};
static u8 unifying_name_answer[] = {0x11, 0xff, 0x83, 0xb5};

static int logi_dj_ll_raw_request(struct hid_device *hid,
				  unsigned char reportnum, __u8 *buf,
				  size_t count, unsigned char report_type,
@@ -682,6 +685,12 @@ static int logi_dj_ll_raw_request(struct hid_device *hid,
		if (count < 2)
			return -EINVAL;

		/* special case where we should not overwrite
		 * the device_index */
		if (count == 7 && !memcmp(buf, unifying_name_query,
					  sizeof(unifying_name_query)))
			buf[4] |= djdev->device_index - 1;
		else
			buf[1] = djdev->device_index;
		return hid_hw_raw_request(djrcv_dev->hdev, reportnum, buf,
				count, report_type, reqtype);
@@ -873,8 +882,17 @@ static int logi_dj_hidpp_event(struct hid_device *hdev,
	unsigned long flags;
	u8 device_index = dj_report->device_index;

	if (device_index == HIDPP_RECEIVER_INDEX)
	if (device_index == HIDPP_RECEIVER_INDEX) {
		/* special case were the device wants to know its unifying
		 * name */
		if (size == HIDPP_REPORT_LONG_LENGTH &&
		    !memcmp(data, unifying_name_answer,
			    sizeof(unifying_name_answer)) &&
		    ((data[4] & 0xF0) == 0x40))
			device_index = (data[4] & 0x0F) + 1;
		else
			return false;
	}

	/*
	 * Data is from the HID++ collection, in this case, we forward the
+76 −4
Original line number Diff line number Diff line
@@ -205,6 +205,31 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
	return ret;
}

static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
	u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count,
	struct hidpp_report *response)
{
	struct hidpp_report *message = kzalloc(sizeof(struct hidpp_report),
			GFP_KERNEL);
	int ret;

	if ((report_id != REPORT_ID_HIDPP_SHORT) &&
	    (report_id != REPORT_ID_HIDPP_LONG))
		return -EINVAL;

	if (param_count > sizeof(message->rap.params))
		return -EINVAL;

	message->report_id = report_id;
	message->rap.sub_id = sub_id;
	message->rap.reg_address = reg_address;
	memcpy(&message->rap.params, params, param_count);

	ret = hidpp_send_message_sync(hidpp_dev, message, response);
	kfree(message);
	return ret;
}

static inline bool hidpp_match_answer(struct hidpp_report *question,
		struct hidpp_report *answer)
{
@@ -220,6 +245,45 @@ static inline bool hidpp_match_error(struct hidpp_report *question,
	    (answer->fap.params[0] == question->fap.funcindex_clientid);
}

/* -------------------------------------------------------------------------- */
/* HIDP++ 1.0 commands                                                        */
/* -------------------------------------------------------------------------- */

#define HIDPP_SET_REGISTER				0x80
#define HIDPP_GET_REGISTER				0x81
#define HIDPP_SET_LONG_REGISTER				0x82
#define HIDPP_GET_LONG_REGISTER				0x83

#define HIDPP_REG_PAIRING_INFORMATION			0xB5
#define DEVICE_NAME					0x40

static char *hidpp_get_unifying_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 };
	char *name;
	int len;

	ret = hidpp_send_rap_command_sync(hidpp_dev,
					REPORT_ID_HIDPP_SHORT,
					HIDPP_GET_LONG_REGISTER,
					HIDPP_REG_PAIRING_INFORMATION,
					params, 1, &response);
	if (ret)
		return NULL;

	len = response.rap.params[1];

	name = kzalloc(len + 1, GFP_KERNEL);
	if (!name)
		return NULL;

	memcpy(name, &response.rap.params[2], len);
	return name;
}

/* -------------------------------------------------------------------------- */
/* 0x0000: Root                                                               */
/* -------------------------------------------------------------------------- */
@@ -726,12 +790,20 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
	return 0;
}

static void hidpp_overwrite_name(struct hid_device *hdev)
static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
{
	struct hidpp_device *hidpp = hid_get_drvdata(hdev);
	char *name;
	u8 name_length;

	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
		name = hidpp_get_device_name(hidpp, &name_length);

	if (!name)
@@ -783,12 +855,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
			goto hid_parse_fail;
		}

		/* the device is connected, we can ask for its name */
		hid_info(hdev, "HID++ %u.%u device connected.\n",
			 hidpp->protocol_major, hidpp->protocol_minor);
		hidpp_overwrite_name(hdev);
	}

	hidpp_overwrite_name(hdev, id->group == HID_GROUP_LOGITECH_DJ_DEVICE);

	if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
		ret = wtp_get_config(hidpp);
		if (ret)