diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 2b1799a3b212d73e1bc9100be6092923a4bc8cb2..879b0ed701a3fb4109243a2642857c16518185b8 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -108,6 +108,7 @@ static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01), static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) }; static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; +static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 }; /* * These definitions are not used here, but are defined by the spec. @@ -259,8 +260,11 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, { struct i2c_hid *ihid = i2c_get_clientdata(client); u8 *args = ihid->argsbuf; + const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd; int ret; u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); + u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); + u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength); /* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */ u16 size = 2 /* size */ + @@ -278,8 +282,18 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, reportID = 0x0F; } - args[index++] = dataRegister & 0xFF; - args[index++] = dataRegister >> 8; + /* + * use the data register for feature reports or if the device does not + * support the output register + */ + if (reportType == 0x03 || maxOutputLength == 0) { + args[index++] = dataRegister & 0xFF; + args[index++] = dataRegister >> 8; + } else { + args[index++] = outputRegister & 0xFF; + args[index++] = outputRegister >> 8; + hidcmd = &hid_no_cmd; + } args[index++] = size & 0xFF; args[index++] = size >> 8; @@ -289,7 +303,7 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, memcpy(&args[index], buf, data_len); - ret = __i2c_hid_command(client, &hid_set_report_cmd, reportID, + ret = __i2c_hid_command(client, hidcmd, reportID, reportType, args, args_len, NULL, 0); if (ret) { dev_err(&client->dev, "failed to set a report to device.\n");