HID: vivaldi: fix handling devices not using numbered reports
commit 3fe6acd4dc922237b30e55473c9349c6ce0690f3 upstream.
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: 14c9c014ba
("HID: add vivaldi HID driver")
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Tested-by: Stephen Boyd <swboyd@chromium.org> # CoachZ
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
d7544cf693
commit
8b8ff4c793
@ -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,
|
|||||||
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,
|
|||||||
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",
|
||||||
|
Loading…
Reference in New Issue
Block a user