diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2014-02-10 12:58:49 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-02-17 08:53:09 -0500 |
commit | 9b5a9ae88573884224a26fda0e3eb6a6ec48686d (patch) | |
tree | 073210d6f79259918a9fd76ff8fe91c2d2ddd3d4 /drivers/hid/i2c-hid/i2c-hid.c | |
parent | 4fa5a7f76cc7b6ac87f57741edd2b124851d119f (diff) |
HID: i2c-hid: implement ll_driver transport-layer callbacks
Add output_report and raw_request to i2c-hid.
The current implementation of i2c_hid_output_raw_report decides
by itself if it should use a direct send of the output report
or use the data register (SET_REPORT). Split that by reimplement
the logic in __i2c_hid_output_raw_report() which will be dropped
soon.
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/i2c-hid/i2c-hid.c')
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid.c | 69 |
1 files changed, 60 insertions, 9 deletions
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index f4ea7343e823..b48f49d1f0dd 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c | |||
@@ -256,12 +256,21 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, | |||
256 | return 0; | 256 | return 0; |
257 | } | 257 | } |
258 | 258 | ||
259 | static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, | 259 | /** |
260 | u8 reportID, unsigned char *buf, size_t data_len) | 260 | * i2c_hid_set_or_send_report: forward an incoming report to the device |
261 | * @client: the i2c_client of the device | ||
262 | * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT | ||
263 | * @reportID: the report ID | ||
264 | * @buf: the actual data to transfer, without the report ID | ||
265 | * @len: size of buf | ||
266 | * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report | ||
267 | */ | ||
268 | static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, | ||
269 | u8 reportID, unsigned char *buf, size_t data_len, bool use_data) | ||
261 | { | 270 | { |
262 | struct i2c_hid *ihid = i2c_get_clientdata(client); | 271 | struct i2c_hid *ihid = i2c_get_clientdata(client); |
263 | u8 *args = ihid->argsbuf; | 272 | u8 *args = ihid->argsbuf; |
264 | const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd; | 273 | const struct i2c_hid_cmd *hidcmd; |
265 | int ret; | 274 | int ret; |
266 | u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); | 275 | u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); |
267 | u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); | 276 | u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); |
@@ -278,6 +287,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, | |||
278 | 287 | ||
279 | i2c_hid_dbg(ihid, "%s\n", __func__); | 288 | i2c_hid_dbg(ihid, "%s\n", __func__); |
280 | 289 | ||
290 | if (!use_data && maxOutputLength == 0) | ||
291 | return -ENOSYS; | ||
292 | |||
281 | if (reportID >= 0x0F) { | 293 | if (reportID >= 0x0F) { |
282 | args[index++] = reportID; | 294 | args[index++] = reportID; |
283 | reportID = 0x0F; | 295 | reportID = 0x0F; |
@@ -287,9 +299,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, | |||
287 | * use the data register for feature reports or if the device does not | 299 | * use the data register for feature reports or if the device does not |
288 | * support the output register | 300 | * support the output register |
289 | */ | 301 | */ |
290 | if (reportType == 0x03 || maxOutputLength == 0) { | 302 | if (use_data) { |
291 | args[index++] = dataRegister & 0xFF; | 303 | args[index++] = dataRegister & 0xFF; |
292 | args[index++] = dataRegister >> 8; | 304 | args[index++] = dataRegister >> 8; |
305 | hidcmd = &hid_set_report_cmd; | ||
293 | } else { | 306 | } else { |
294 | args[index++] = outputRegister & 0xFF; | 307 | args[index++] = outputRegister & 0xFF; |
295 | args[index++] = outputRegister >> 8; | 308 | args[index++] = outputRegister >> 8; |
@@ -550,7 +563,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, | |||
550 | } | 563 | } |
551 | 564 | ||
552 | static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, | 565 | static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, |
553 | size_t count, unsigned char report_type) | 566 | size_t count, unsigned char report_type, bool use_data) |
554 | { | 567 | { |
555 | struct i2c_client *client = hid->driver_data; | 568 | struct i2c_client *client = hid->driver_data; |
556 | int report_id = buf[0]; | 569 | int report_id = buf[0]; |
@@ -564,9 +577,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, | |||
564 | count--; | 577 | count--; |
565 | } | 578 | } |
566 | 579 | ||
567 | ret = i2c_hid_set_report(client, | 580 | ret = i2c_hid_set_or_send_report(client, |
568 | report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, | 581 | report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, |
569 | report_id, buf, count); | 582 | report_id, buf, count, use_data); |
570 | 583 | ||
571 | if (report_id && ret >= 0) | 584 | if (report_id && ret >= 0) |
572 | ret++; /* add report_id to the number of transfered bytes */ | 585 | ret++; /* add report_id to the number of transfered bytes */ |
@@ -574,6 +587,42 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, | |||
574 | return ret; | 587 | return ret; |
575 | } | 588 | } |
576 | 589 | ||
590 | static int __i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, | ||
591 | size_t count, unsigned char report_type) | ||
592 | { | ||
593 | struct i2c_client *client = hid->driver_data; | ||
594 | struct i2c_hid *ihid = i2c_get_clientdata(client); | ||
595 | bool data = true; /* SET_REPORT */ | ||
596 | |||
597 | if (report_type == HID_OUTPUT_REPORT) | ||
598 | data = le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0; | ||
599 | |||
600 | return i2c_hid_output_raw_report(hid, buf, count, report_type, data); | ||
601 | } | ||
602 | |||
603 | static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf, | ||
604 | size_t count) | ||
605 | { | ||
606 | return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT, | ||
607 | false); | ||
608 | } | ||
609 | |||
610 | static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum, | ||
611 | __u8 *buf, size_t len, unsigned char rtype, | ||
612 | int reqtype) | ||
613 | { | ||
614 | switch (reqtype) { | ||
615 | case HID_REQ_GET_REPORT: | ||
616 | return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype); | ||
617 | case HID_REQ_SET_REPORT: | ||
618 | if (buf[0] != reportnum) | ||
619 | return -EINVAL; | ||
620 | return i2c_hid_output_raw_report(hid, buf, len, rtype, true); | ||
621 | default: | ||
622 | return -EIO; | ||
623 | } | ||
624 | } | ||
625 | |||
577 | static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, | 626 | static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, |
578 | int reqtype) | 627 | int reqtype) |
579 | { | 628 | { |
@@ -597,7 +646,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, | |||
597 | break; | 646 | break; |
598 | case HID_REQ_SET_REPORT: | 647 | case HID_REQ_SET_REPORT: |
599 | hid_output_report(rep, buf); | 648 | hid_output_report(rep, buf); |
600 | i2c_hid_output_raw_report(hid, buf, len, rep->type); | 649 | i2c_hid_output_raw_report(hid, buf, len, rep->type, true); |
601 | break; | 650 | break; |
602 | } | 651 | } |
603 | 652 | ||
@@ -761,6 +810,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = { | |||
761 | .close = i2c_hid_close, | 810 | .close = i2c_hid_close, |
762 | .power = i2c_hid_power, | 811 | .power = i2c_hid_power, |
763 | .request = i2c_hid_request, | 812 | .request = i2c_hid_request, |
813 | .output_report = i2c_hid_output_report, | ||
814 | .raw_request = i2c_hid_raw_request, | ||
764 | }; | 815 | }; |
765 | 816 | ||
766 | static int i2c_hid_init_irq(struct i2c_client *client) | 817 | static int i2c_hid_init_irq(struct i2c_client *client) |
@@ -1005,7 +1056,7 @@ static int i2c_hid_probe(struct i2c_client *client, | |||
1005 | 1056 | ||
1006 | hid->driver_data = client; | 1057 | hid->driver_data = client; |
1007 | hid->ll_driver = &i2c_hid_ll_driver; | 1058 | hid->ll_driver = &i2c_hid_ll_driver; |
1008 | hid->hid_output_raw_report = i2c_hid_output_raw_report; | 1059 | hid->hid_output_raw_report = __i2c_hid_output_raw_report; |
1009 | hid->dev.parent = &client->dev; | 1060 | hid->dev.parent = &client->dev; |
1010 | ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); | 1061 | ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); |
1011 | hid->bus = BUS_I2C; | 1062 | hid->bus = BUS_I2C; |