Skip to content

Commit fe3ee1e

Browse files
committed
HID: logitech-hidpp: allow non HID++ devices to be handled by this module
On the gaming mice, there are 2 interfaces, one for the mouse and one for the macros. Better allow everybody to go through hid-logitech-hidpp than trying to be smarter. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
1 parent f2113c3 commit fe3ee1e

File tree

1 file changed

+68
-8
lines changed

1 file changed

+68
-8
lines changed

drivers/hid/hid-logitech-hidpp.c

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2783,6 +2783,9 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
27832783
{
27842784
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
27852785

2786+
if (!hidpp)
2787+
return 0;
2788+
27862789
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
27872790
return wtp_input_mapping(hdev, hi, field, usage, bit, max);
27882791
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560 &&
@@ -2798,6 +2801,9 @@ static int hidpp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
27982801
{
27992802
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
28002803

2804+
if (!hidpp)
2805+
return 0;
2806+
28012807
/* Ensure that Logitech G920 is not given a default fuzz/flat value */
28022808
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
28032809
if (usage->type == EV_ABS && (usage->code == ABS_X ||
@@ -2829,6 +2835,9 @@ static int hidpp_input_configured(struct hid_device *hdev,
28292835
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
28302836
struct input_dev *input = hidinput->input;
28312837

2838+
if (!hidpp)
2839+
return 0;
2840+
28322841
hidpp_populate_input(hidpp, input, true);
28332842

28342843
return 0;
@@ -2898,6 +2907,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
28982907
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
28992908
int ret = 0;
29002909

2910+
if (!hidpp)
2911+
return 0;
2912+
29012913
/* Generic HID++ processing. */
29022914
switch (data[0]) {
29032915
case REPORT_ID_HIDPP_VERY_LONG:
@@ -2946,7 +2958,12 @@ static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
29462958
* restriction imposed in hidpp_usages.
29472959
*/
29482960
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
2949-
struct hidpp_scroll_counter *counter = &hidpp->vertical_wheel_counter;
2961+
struct hidpp_scroll_counter *counter;
2962+
2963+
if (!hidpp)
2964+
return 0;
2965+
2966+
counter = &hidpp->vertical_wheel_counter;
29502967
/* A scroll event may occur before the multiplier has been retrieved or
29512968
* the input device set, or high-res scroll enabling may fail. In such
29522969
* cases we must return early (falling back to default behaviour) to
@@ -3202,13 +3219,60 @@ static const struct attribute_group ps_attribute_group = {
32023219
.attrs = sysfs_attrs
32033220
};
32043221

3222+
static bool hidpp_validate_report(struct hid_device *hdev, int id, int size,
3223+
bool optional)
3224+
{
3225+
struct hid_report_enum *re;
3226+
struct hid_report *report;
3227+
3228+
if (id >= HID_MAX_IDS || id < 0) {
3229+
hid_err(hdev, "invalid HID report id %u\n", id);
3230+
return false;
3231+
}
3232+
3233+
re = &(hdev->report_enum[HID_OUTPUT_REPORT]);
3234+
report = re->report_id_hash[id];
3235+
3236+
if (!report)
3237+
return optional;
3238+
3239+
if (report->field[0]->report_count < size) {
3240+
hid_warn(hdev, "not enough values in hidpp report %d\n", id);
3241+
return false;
3242+
}
3243+
3244+
return true;
3245+
}
3246+
3247+
static bool hidpp_validate_device(struct hid_device *hdev)
3248+
{
3249+
return hidpp_validate_report(hdev, REPORT_ID_HIDPP_SHORT,
3250+
HIDPP_REPORT_SHORT_LENGTH - 1, false) &&
3251+
hidpp_validate_report(hdev, REPORT_ID_HIDPP_LONG,
3252+
HIDPP_REPORT_LONG_LENGTH - 1, true) &&
3253+
hidpp_validate_report(hdev, REPORT_ID_HIDPP_VERY_LONG,
3254+
HIDPP_REPORT_VERY_LONG_LENGTH - 1, true);
3255+
}
3256+
32053257
static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
32063258
{
32073259
struct hidpp_device *hidpp;
32083260
int ret;
32093261
bool connected;
32103262
unsigned int connect_mask = HID_CONNECT_DEFAULT;
32113263

3264+
ret = hid_parse(hdev);
3265+
if (ret) {
3266+
hid_err(hdev, "%s:parse failed\n", __func__);
3267+
return ret;
3268+
}
3269+
3270+
/*
3271+
* Make sure the device is HID++ capable, otherwise treat as generic HID
3272+
*/
3273+
if (!hidpp_validate_device(hdev))
3274+
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
3275+
32123276
hidpp = devm_kzalloc(&hdev->dev, sizeof(struct hidpp_device),
32133277
GFP_KERNEL);
32143278
if (!hidpp)
@@ -3252,12 +3316,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
32523316
hid_warn(hdev, "Cannot allocate sysfs group for %s\n",
32533317
hdev->name);
32543318

3255-
ret = hid_parse(hdev);
3256-
if (ret) {
3257-
hid_err(hdev, "%s:parse failed\n", __func__);
3258-
goto hid_parse_fail;
3259-
}
3260-
32613319
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
32623320
connect_mask &= ~HID_CONNECT_HIDINPUT;
32633321

@@ -3330,7 +3388,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
33303388
hid_hw_stop(hdev);
33313389
}
33323390
hid_hw_start_fail:
3333-
hid_parse_fail:
33343391
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
33353392
cancel_work_sync(&hidpp->work);
33363393
mutex_destroy(&hidpp->send_mutex);
@@ -3341,6 +3398,9 @@ static void hidpp_remove(struct hid_device *hdev)
33413398
{
33423399
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
33433400

3401+
if (!hidpp)
3402+
return hid_hw_stop(hdev);
3403+
33443404
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
33453405

33463406
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {

0 commit comments

Comments
 (0)