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

Commit a5ce8f5b authored by Simon Wood's avatar Simon Wood Committed by Jiri Kosina
Browse files

HID: hid-logitech-hidpp: Add support for very long packets



Patch add support for the 'very long' HID++ packets, which are
64 bytes in length.

Signed-off-by: default avatarSimon Wood <simon@mungewell.org>
Reviewed-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 2f239858
Loading
Loading
Loading
Loading
+48 −11
Original line number Original line Diff line number Diff line
@@ -40,9 +40,11 @@ MODULE_PARM_DESC(disable_tap_to_click,


#define REPORT_ID_HIDPP_SHORT			0x10
#define REPORT_ID_HIDPP_SHORT			0x10
#define REPORT_ID_HIDPP_LONG			0x11
#define REPORT_ID_HIDPP_LONG			0x11
#define REPORT_ID_HIDPP_VERY_LONG		0x12


#define HIDPP_REPORT_SHORT_LENGTH		7
#define HIDPP_REPORT_SHORT_LENGTH		7
#define HIDPP_REPORT_LONG_LENGTH		20
#define HIDPP_REPORT_LONG_LENGTH		20
#define HIDPP_REPORT_VERY_LONG_LENGTH		64


#define HIDPP_QUIRK_CLASS_WTP			BIT(0)
#define HIDPP_QUIRK_CLASS_WTP			BIT(0)
#define HIDPP_QUIRK_CLASS_M560			BIT(1)
#define HIDPP_QUIRK_CLASS_M560			BIT(1)
@@ -81,13 +83,13 @@ MODULE_PARM_DESC(disable_tap_to_click,
struct fap {
struct fap {
	u8 feature_index;
	u8 feature_index;
	u8 funcindex_clientid;
	u8 funcindex_clientid;
	u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
	u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
};


struct rap {
struct rap {
	u8 sub_id;
	u8 sub_id;
	u8 reg_address;
	u8 reg_address;
	u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
	u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
};


struct hidpp_report {
struct hidpp_report {
@@ -153,6 +155,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
	case REPORT_ID_HIDPP_LONG:
	case REPORT_ID_HIDPP_LONG:
		fields_count = HIDPP_REPORT_LONG_LENGTH;
		fields_count = HIDPP_REPORT_LONG_LENGTH;
		break;
		break;
	case REPORT_ID_HIDPP_VERY_LONG:
		fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
		break;
	default:
	default:
		return -ENODEV;
		return -ENODEV;
	}
	}
@@ -217,7 +222,8 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
		goto exit;
		goto exit;
	}
	}


	if (response->report_id == REPORT_ID_HIDPP_LONG &&
	if ((response->report_id == REPORT_ID_HIDPP_LONG ||
			response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
			response->fap.feature_index == HIDPP20_ERROR) {
			response->fap.feature_index == HIDPP20_ERROR) {
		ret = response->fap.params[1];
		ret = response->fap.params[1];
		dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
		dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
@@ -243,6 +249,10 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
	message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
	message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
	if (!message)
	if (!message)
		return -ENOMEM;
		return -ENOMEM;

	if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
		message->report_id = REPORT_ID_HIDPP_VERY_LONG;
	else
		message->report_id = REPORT_ID_HIDPP_LONG;
		message->report_id = REPORT_ID_HIDPP_LONG;
	message->fap.feature_index = feat_index;
	message->fap.feature_index = feat_index;
	message->fap.funcindex_clientid = funcindex_clientid;
	message->fap.funcindex_clientid = funcindex_clientid;
@@ -258,13 +268,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
	struct hidpp_report *response)
	struct hidpp_report *response)
{
{
	struct hidpp_report *message;
	struct hidpp_report *message;
	int ret;
	int ret, max_count;


	if ((report_id != REPORT_ID_HIDPP_SHORT) &&
	switch (report_id) {
	    (report_id != REPORT_ID_HIDPP_LONG))
	case REPORT_ID_HIDPP_SHORT:
		max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
		break;
	case REPORT_ID_HIDPP_LONG:
		max_count = HIDPP_REPORT_LONG_LENGTH - 4;
		break;
	case REPORT_ID_HIDPP_VERY_LONG:
		max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
		break;
	default:
		return -EINVAL;
		return -EINVAL;
	}


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


	message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
	message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
@@ -508,10 +528,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
	if (ret)
	if (ret)
		return ret;
		return ret;


	if (response.report_id == REPORT_ID_HIDPP_LONG)
	switch (response.report_id) {
	case REPORT_ID_HIDPP_VERY_LONG:
		count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
		break;
	case REPORT_ID_HIDPP_LONG:
		count = HIDPP_REPORT_LONG_LENGTH - 4;
		count = HIDPP_REPORT_LONG_LENGTH - 4;
	else
		break;
	case REPORT_ID_HIDPP_SHORT:
		count = HIDPP_REPORT_SHORT_LENGTH - 4;
		count = HIDPP_REPORT_SHORT_LENGTH - 4;
		break;
	default:
		return -EPROTO;
	}


	if (len_buf < count)
	if (len_buf < count)
		count = len_buf;
		count = len_buf;
@@ -1347,6 +1376,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,


	/* Generic HID++ processing. */
	/* Generic HID++ processing. */
	switch (data[0]) {
	switch (data[0]) {
	case REPORT_ID_HIDPP_VERY_LONG:
		if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
			hid_err(hdev, "received hid++ report of bad size (%d)",
				size);
			return 1;
		}
		ret = hidpp_raw_hidpp_event(hidpp, data, size);
		break;
	case REPORT_ID_HIDPP_LONG:
	case REPORT_ID_HIDPP_LONG:
		if (size != HIDPP_REPORT_LONG_LENGTH) {
		if (size != HIDPP_REPORT_LONG_LENGTH) {
			hid_err(hdev, "received hid++ report of bad size (%d)",
			hid_err(hdev, "received hid++ report of bad size (%d)",