From cafebc058bf86e63fff5354864781d3de11e41d3 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 5 Feb 2014 16:33:22 -0500 Subject: HID: remove hid_get_raw_report in struct hid_device dev->hid_get_raw_report(X) and hid_hw_raw_request(X, HID_REQ_GET_REPORT) are strictly equivalent. Switch the hid subsystem to the hid_hw notation and remove the field .hid_get_raw_report in struct hid_device. Reviewed-by: David Herrmann Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/hid/i2c-hid/i2c-hid.c') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index e914f27..f4ea734 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1005,7 +1005,6 @@ static int i2c_hid_probe(struct i2c_client *client, hid->driver_data = client; hid->ll_driver = &i2c_hid_ll_driver; - hid->hid_get_raw_report = i2c_hid_get_raw_report; hid->hid_output_raw_report = i2c_hid_output_raw_report; hid->dev.parent = &client->dev; ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); -- cgit v1.1 From 9b5a9ae88573884224a26fda0e3eb6a6ec48686d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 10 Feb 2014 12:58:49 -0500 Subject: 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 Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 69 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 9 deletions(-) (limited to 'drivers/hid/i2c-hid/i2c-hid.c') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index f4ea734..b48f49d 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, return 0; } -static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, - u8 reportID, unsigned char *buf, size_t data_len) +/** + * i2c_hid_set_or_send_report: forward an incoming report to the device + * @client: the i2c_client of the device + * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT + * @reportID: the report ID + * @buf: the actual data to transfer, without the report ID + * @len: size of buf + * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report + */ +static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, + u8 reportID, unsigned char *buf, size_t data_len, bool use_data) { struct i2c_hid *ihid = i2c_get_clientdata(client); u8 *args = ihid->argsbuf; - const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd; + const struct i2c_hid_cmd *hidcmd; int ret; u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); @@ -278,6 +287,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, i2c_hid_dbg(ihid, "%s\n", __func__); + if (!use_data && maxOutputLength == 0) + return -ENOSYS; + if (reportID >= 0x0F) { args[index++] = reportID; reportID = 0x0F; @@ -287,9 +299,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, * use the data register for feature reports or if the device does not * support the output register */ - if (reportType == 0x03 || maxOutputLength == 0) { + if (use_data) { args[index++] = dataRegister & 0xFF; args[index++] = dataRegister >> 8; + hidcmd = &hid_set_report_cmd; } else { args[index++] = outputRegister & 0xFF; args[index++] = outputRegister >> 8; @@ -550,7 +563,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, } static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, - size_t count, unsigned char report_type) + size_t count, unsigned char report_type, bool use_data) { struct i2c_client *client = hid->driver_data; int report_id = buf[0]; @@ -564,9 +577,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, count--; } - ret = i2c_hid_set_report(client, + ret = i2c_hid_set_or_send_report(client, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, - report_id, buf, count); + report_id, buf, count, use_data); if (report_id && ret >= 0) 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, return ret; } +static int __i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, + size_t count, unsigned char report_type) +{ + struct i2c_client *client = hid->driver_data; + struct i2c_hid *ihid = i2c_get_clientdata(client); + bool data = true; /* SET_REPORT */ + + if (report_type == HID_OUTPUT_REPORT) + data = le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0; + + return i2c_hid_output_raw_report(hid, buf, count, report_type, data); +} + +static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf, + size_t count) +{ + return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT, + false); +} + +static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum, + __u8 *buf, size_t len, unsigned char rtype, + int reqtype) +{ + switch (reqtype) { + case HID_REQ_GET_REPORT: + return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype); + case HID_REQ_SET_REPORT: + if (buf[0] != reportnum) + return -EINVAL; + return i2c_hid_output_raw_report(hid, buf, len, rtype, true); + default: + return -EIO; + } +} + static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype) { @@ -597,7 +646,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, break; case HID_REQ_SET_REPORT: hid_output_report(rep, buf); - i2c_hid_output_raw_report(hid, buf, len, rep->type); + i2c_hid_output_raw_report(hid, buf, len, rep->type, true); break; } @@ -761,6 +810,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = { .close = i2c_hid_close, .power = i2c_hid_power, .request = i2c_hid_request, + .output_report = i2c_hid_output_report, + .raw_request = i2c_hid_raw_request, }; static int i2c_hid_init_irq(struct i2c_client *client) @@ -1005,7 +1056,7 @@ static int i2c_hid_probe(struct i2c_client *client, hid->driver_data = client; hid->ll_driver = &i2c_hid_ll_driver; - hid->hid_output_raw_report = i2c_hid_output_raw_report; + hid->hid_output_raw_report = __i2c_hid_output_raw_report; hid->dev.parent = &client->dev; ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); hid->bus = BUS_I2C; -- cgit v1.1 From 649f94790314b502bc4e905e005d89c3b693d60a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 10 Feb 2014 12:58:50 -0500 Subject: HID: i2c-hid: use generic .request() implementation Having our own .request() implementation does not give anything, so use the generic binding. Signed-off-by: Benjamin Tissoires Reviewed-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 31 ------------------------------- 1 file changed, 31 deletions(-) (limited to 'drivers/hid/i2c-hid/i2c-hid.c') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index b48f49d..5308656 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -623,36 +623,6 @@ static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum, } } -static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, - int reqtype) -{ - struct i2c_client *client = hid->driver_data; - char *buf; - int ret; - int len = i2c_hid_get_report_length(rep) - 2; - - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - return; - - switch (reqtype) { - case HID_REQ_GET_REPORT: - ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type); - if (ret < 0) - dev_err(&client->dev, "%s: unable to get report: %d\n", - __func__, ret); - else - hid_input_report(hid, rep->type, buf, ret, 0); - break; - case HID_REQ_SET_REPORT: - hid_output_report(rep, buf); - i2c_hid_output_raw_report(hid, buf, len, rep->type, true); - break; - } - - kfree(buf); -} - static int i2c_hid_parse(struct hid_device *hid) { struct i2c_client *client = hid->driver_data; @@ -809,7 +779,6 @@ static struct hid_ll_driver i2c_hid_ll_driver = { .open = i2c_hid_open, .close = i2c_hid_close, .power = i2c_hid_power, - .request = i2c_hid_request, .output_report = i2c_hid_output_report, .raw_request = i2c_hid_raw_request, }; -- cgit v1.1 From 5318251744b2c8a288f91f4e53ed69f2a01d6412 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 10 Feb 2014 12:58:59 -0500 Subject: HID: core: check parameters when sending/receiving data from the device It is better to check them soon enough before triggering any kernel panic. Signed-off-by: Benjamin Tissoires Reviewed-by: David Herrmann Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid/i2c-hid/i2c-hid.c') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 5308656..1a95531 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -276,7 +276,7 @@ static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType, 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 */ + /* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */ u16 size = 2 /* size */ + (reportID ? 1 : 0) /* reportID */ + data_len /* buf */; -- cgit v1.1 From 6fd182028c43baf1c7d017d52b0134ecadbdc447 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Sat, 8 Mar 2014 22:52:43 -0500 Subject: HID: remove hid_output_raw_report transport implementations Nobody calls hid_output_raw_report anymore, and nobody should. We can now remove the various implementation in the different transport drivers and the declarations. Reviewed-by: David Herrmann Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers/hid/i2c-hid/i2c-hid.c') diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 1a95531..2de2b8e 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -587,19 +587,6 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, return ret; } -static int __i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, - size_t count, unsigned char report_type) -{ - struct i2c_client *client = hid->driver_data; - struct i2c_hid *ihid = i2c_get_clientdata(client); - bool data = true; /* SET_REPORT */ - - if (report_type == HID_OUTPUT_REPORT) - data = le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0; - - return i2c_hid_output_raw_report(hid, buf, count, report_type, data); -} - static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf, size_t count) { @@ -1025,7 +1012,6 @@ static int i2c_hid_probe(struct i2c_client *client, hid->driver_data = client; hid->ll_driver = &i2c_hid_ll_driver; - hid->hid_output_raw_report = __i2c_hid_output_raw_report; hid->dev.parent = &client->dev; ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); hid->bus = BUS_I2C; -- cgit v1.1