aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Duggan <aduggan@synaptics.com>2013-06-17 19:15:06 -0400
committerJiri Kosina <jkosina@suse.cz>2013-07-04 09:00:11 -0400
commit811adb9622de310efbb661531c3ec0ae5d2b2bc0 (patch)
treecec9cf37020101df3f4342cb204afb7abd27bea1
parent26e04462c8b78d079d3231396ec72d58a14f114b (diff)
HID: i2c-hid: support sending HID output reports using the output register
The current i2c hid driver does not support sending HID output reports using the output register for devices which support receiving reports through this method. This patch determines which method to use to send output reports based on the value of wMaxOutputLength in the device's HID descriptor. Signed-off-by: Andrew Duggan <aduggan@synaptics.com> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 2b1799a3b212..879b0ed701a3 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),
108static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) }; 108static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) };
109static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) }; 109static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) };
110static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) }; 110static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) };
111static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 };
111 112
112/* 113/*
113 * These definitions are not used here, but are defined by the spec. 114 * 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,
259{ 260{
260 struct i2c_hid *ihid = i2c_get_clientdata(client); 261 struct i2c_hid *ihid = i2c_get_clientdata(client);
261 u8 *args = ihid->argsbuf; 262 u8 *args = ihid->argsbuf;
263 const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd;
262 int ret; 264 int ret;
263 u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); 265 u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
266 u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
267 u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
264 268
265 /* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */ 269 /* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */
266 u16 size = 2 /* size */ + 270 u16 size = 2 /* size */ +
@@ -278,8 +282,18 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
278 reportID = 0x0F; 282 reportID = 0x0F;
279 } 283 }
280 284
281 args[index++] = dataRegister & 0xFF; 285 /*
282 args[index++] = dataRegister >> 8; 286 * use the data register for feature reports or if the device does not
287 * support the output register
288 */
289 if (reportType == 0x03 || maxOutputLength == 0) {
290 args[index++] = dataRegister & 0xFF;
291 args[index++] = dataRegister >> 8;
292 } else {
293 args[index++] = outputRegister & 0xFF;
294 args[index++] = outputRegister >> 8;
295 hidcmd = &hid_no_cmd;
296 }
283 297
284 args[index++] = size & 0xFF; 298 args[index++] = size & 0xFF;
285 args[index++] = size >> 8; 299 args[index++] = size >> 8;
@@ -289,7 +303,7 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
289 303
290 memcpy(&args[index], buf, data_len); 304 memcpy(&args[index], buf, data_len);
291 305
292 ret = __i2c_hid_command(client, &hid_set_report_cmd, reportID, 306 ret = __i2c_hid_command(client, hidcmd, reportID,
293 reportType, args, args_len, NULL, 0); 307 reportType, args, args_len, NULL, 0);
294 if (ret) { 308 if (ret) {
295 dev_err(&client->dev, "failed to set a report to device.\n"); 309 dev_err(&client->dev, "failed to set a report to device.\n");