Commit cf5b2fb0 authored by Angela Czubak's avatar Angela Czubak Committed by Jiri Kosina
Browse files

HID: i2c-hid: fix handling numbered reports with IDs of 15 and above



Special handling of numbered reports with IDs of 15 and above is only
needed when executing what HID-I2C spec is calling "Class Specific
Requests", and not when simply sending output reports.

Additionally, our mangling of report ID in i2c_hid_set_or_send_report()
resulted in incorrect report ID being written into SET_REPORT command
payload.

To solve it let's move all the report ID manipulation into
__i2c_hid_command() where we form the command data structure.

Signed-off-by: default avatarAngela Czubak <acz@semihalf.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Tested-by: default avatarBenjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 9b57f458
Loading
Loading
Loading
Loading
+10 −14
Original line number Original line Diff line number Diff line
@@ -97,6 +97,7 @@ union command {
		__le16 reg;
		__le16 reg;
		__u8 reportTypeID;
		__u8 reportTypeID;
		__u8 opcode;
		__u8 opcode;
		__u8 reportID;
	} __packed c;
	} __packed c;
};
};


@@ -232,7 +233,13 @@ static int __i2c_hid_command(struct i2c_client *client,


	if (length > 2) {
	if (length > 2) {
		cmd->c.opcode = command->opcode;
		cmd->c.opcode = command->opcode;
		cmd->c.reportTypeID = reportID | reportType << 4;
		if (reportID < 0x0F) {
			cmd->c.reportTypeID = reportType << 4 | reportID;
		} else {
			cmd->c.reportTypeID = reportType << 4 | 0x0F;
			cmd->c.reportID = reportID;
			length++;
		}
	}
	}


	memcpy(cmd->data + length, args, args_len);
	memcpy(cmd->data + length, args, args_len);
@@ -293,18 +300,13 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
		u8 reportID, unsigned char *buf_recv, int data_len)
		u8 reportID, unsigned char *buf_recv, int data_len)
{
{
	struct i2c_hid *ihid = i2c_get_clientdata(client);
	struct i2c_hid *ihid = i2c_get_clientdata(client);
	u8 args[3];
	u8 args[2];
	int ret;
	int ret;
	int args_len = 0;
	int args_len = 0;
	u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
	u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister);


	i2c_hid_dbg(ihid, "%s\n", __func__);
	i2c_hid_dbg(ihid, "%s\n", __func__);


	if (reportID >= 0x0F) {
		args[args_len++] = reportID;
		reportID = 0x0F;
	}

	args[args_len++] = readRegister & 0xFF;
	args[args_len++] = readRegister & 0xFF;
	args[args_len++] = readRegister >> 8;
	args[args_len++] = readRegister >> 8;


@@ -350,18 +352,12 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
	size =		2			/* size */ +
	size =		2			/* size */ +
			(reportID ? 1 : 0)	/* reportID */ +
			(reportID ? 1 : 0)	/* reportID */ +
			data_len		/* buf */;
			data_len		/* buf */;
	args_len =	(reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
	args_len =	2			/* dataRegister */ +
			2			/* dataRegister */ +
			size			/* args */;
			size			/* args */;


	if (!use_data && maxOutputLength == 0)
	if (!use_data && maxOutputLength == 0)
		return -ENOSYS;
		return -ENOSYS;


	if (reportID >= 0x0F) {
		args[index++] = reportID;
		reportID = 0x0F;
	}

	/*
	/*
	 * use the data register for feature reports or if the device does not
	 * use the data register for feature reports or if the device does not
	 * support the output register
	 * support the output register