Commit 3fe6acd4 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Jiri Kosina

HID: vivaldi: fix handling devices not using numbered reports

Unfortunately details of USB HID transport bled into HID core and
handling of numbered/unnumbered reports is quite a mess, with
hid_report_len() calculating the length according to USB rules,
and hid_hw_raw_request() adding report ID to the buffer for both
numbered and unnumbered reports.

Untangling it all requres a lot of changes in HID, so for now let's
handle this in the driver.

[jkosina@suse.cz: microoptimize field->report->id to report->id]
Fixes: 14c9c014 ("HID: add vivaldi HID driver")
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
Tested-by: Stephen Boyd <swboyd@chromium.org> # CoachZ
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent f3193ea1
...@@ -74,10 +74,11 @@ static void vivaldi_feature_mapping(struct hid_device *hdev, ...@@ -74,10 +74,11 @@ static void vivaldi_feature_mapping(struct hid_device *hdev,
struct hid_usage *usage) struct hid_usage *usage)
{ {
struct vivaldi_data *drvdata = hid_get_drvdata(hdev); struct vivaldi_data *drvdata = hid_get_drvdata(hdev);
struct hid_report *report = field->report;
int fn_key; int fn_key;
int ret; int ret;
u32 report_len; u32 report_len;
u8 *buf; u8 *report_data, *buf;
if (field->logical != HID_USAGE_FN_ROW_PHYSMAP || if (field->logical != HID_USAGE_FN_ROW_PHYSMAP ||
(usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL) (usage->hid & HID_USAGE_PAGE) != HID_UP_ORDINAL)
...@@ -89,12 +90,24 @@ static void vivaldi_feature_mapping(struct hid_device *hdev, ...@@ -89,12 +90,24 @@ static void vivaldi_feature_mapping(struct hid_device *hdev,
if (fn_key > drvdata->max_function_row_key) if (fn_key > drvdata->max_function_row_key)
drvdata->max_function_row_key = fn_key; drvdata->max_function_row_key = fn_key;
buf = hid_alloc_report_buf(field->report, GFP_KERNEL); report_data = buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf) if (!report_data)
return; return;
report_len = hid_report_len(field->report); report_len = hid_report_len(report);
ret = hid_hw_raw_request(hdev, field->report->id, buf, if (!report->id) {
/*
* hid_hw_raw_request() will stuff report ID (which will be 0)
* into the first byte of the buffer even for unnumbered
* reports, so we need to account for this to avoid getting
* -EOVERFLOW in return.
* Note that hid_alloc_report_buf() adds 7 bytes to the size
* so we can safely say that we have space for an extra byte.
*/
report_len++;
}
ret = hid_hw_raw_request(hdev, report->id, report_data,
report_len, HID_FEATURE_REPORT, report_len, HID_FEATURE_REPORT,
HID_REQ_GET_REPORT); HID_REQ_GET_REPORT);
if (ret < 0) { if (ret < 0) {
...@@ -103,7 +116,16 @@ static void vivaldi_feature_mapping(struct hid_device *hdev, ...@@ -103,7 +116,16 @@ static void vivaldi_feature_mapping(struct hid_device *hdev,
goto out; goto out;
} }
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, buf, if (!report->id) {
/*
* Undo the damage from hid_hw_raw_request() for unnumbered
* reports.
*/
report_data++;
report_len--;
}
ret = hid_report_raw_event(hdev, HID_FEATURE_REPORT, report_data,
report_len, 0); report_len, 0);
if (ret) { if (ret) {
dev_warn(&hdev->dev, "failed to report feature %d\n", dev_warn(&hdev->dev, "failed to report feature %d\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment