Commit 7ad1fe0d authored by Bastien Nocera's avatar Bastien Nocera Committed by Benjamin Tissoires
Browse files

HID: logitech-hidpp: Don't use the USB serial for USB devices



For devices that support the 0x0003 feature (Device Information) version 4,
set the serial based on the output of that feature, rather than relying
on the usbhid code setting the USB serial.

This should allow the serial when connected through USB to (nearly)
match the one when connected through a unifying receiver.

For example, on the serials on a G903 wired/wireless mouse:
- Unifying: 4067-e8-ce-cd-45
- USB before patch: 017C385C3837
- USB after patch: c086-e8-ce-cd-45

Signed-off-by: default avatarBastien Nocera <hadess@hadess.net>
Link: https://lore.kernel.org/r/20230302130117.3975-1-hadess@hadess.net


Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
parent 2653e3fe
Loading
Loading
Loading
Loading
+51 −0
Original line number Original line Diff line number Diff line
@@ -947,6 +947,55 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
	return 0;
	return 0;
}
}


/* -------------------------------------------------------------------------- */
/* 0x0003: Device Information                                                 */
/* -------------------------------------------------------------------------- */

#define HIDPP_PAGE_DEVICE_INFORMATION			0x0003

#define CMD_GET_DEVICE_INFO				0x00

static int hidpp_get_serial(struct hidpp_device *hidpp, u32 *serial)
{
	struct hidpp_report response;
	u8 feature_type;
	u8 feature_index;
	int ret;

	ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_DEVICE_INFORMATION,
				     &feature_index,
				     &feature_type);
	if (ret)
		return ret;

	ret = hidpp_send_fap_command_sync(hidpp, feature_index,
					  CMD_GET_DEVICE_INFO,
					  NULL, 0, &response);
	if (ret)
		return ret;

	/* See hidpp_unifying_get_serial() */
	*serial = *((u32 *)&response.rap.params[1]);
	return 0;
}

static int hidpp_serial_init(struct hidpp_device *hidpp)
{
	struct hid_device *hdev = hidpp->hid_dev;
	u32 serial;
	int ret;

	ret = hidpp_get_serial(hidpp, &serial);
	if (ret)
		return ret;

	snprintf(hdev->uniq, sizeof(hdev->uniq), "%04x-%4phD",
		 hdev->product, &serial);
	dbg_hid("HID++ DeviceInformation: Got serial: %s\n", hdev->uniq);

	return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* 0x0005: GetDeviceNameType                                                  */
/* 0x0005: GetDeviceNameType                                                  */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@@ -4210,6 +4259,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)


	if (hidpp->quirks & HIDPP_QUIRK_UNIFYING)
	if (hidpp->quirks & HIDPP_QUIRK_UNIFYING)
		hidpp_unifying_init(hidpp);
		hidpp_unifying_init(hidpp);
	else if (hid_is_usb(hidpp->hid_dev))
		hidpp_serial_init(hidpp);


	connected = hidpp_root_get_protocol_version(hidpp) == 0;
	connected = hidpp_root_get_protocol_version(hidpp) == 0;
	atomic_set(&hidpp->connected, connected);
	atomic_set(&hidpp->connected, connected);