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>
This commit is contained in:
parent
f2113c3020
commit
fe3ee1ec00
1 changed files with 68 additions and 8 deletions
|
@ -2783,6 +2783,9 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||||
{
|
{
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
|
if (!hidpp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
|
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
|
||||||
return wtp_input_mapping(hdev, hi, field, usage, bit, max);
|
return wtp_input_mapping(hdev, hi, field, usage, bit, max);
|
||||||
else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560 &&
|
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,
|
||||||
{
|
{
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
|
if (!hidpp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Ensure that Logitech G920 is not given a default fuzz/flat value */
|
/* Ensure that Logitech G920 is not given a default fuzz/flat value */
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
|
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
|
||||||
if (usage->type == EV_ABS && (usage->code == ABS_X ||
|
if (usage->type == EV_ABS && (usage->code == ABS_X ||
|
||||||
|
@ -2829,6 +2835,9 @@ static int hidpp_input_configured(struct hid_device *hdev,
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
struct input_dev *input = hidinput->input;
|
struct input_dev *input = hidinput->input;
|
||||||
|
|
||||||
|
if (!hidpp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
hidpp_populate_input(hidpp, input, true);
|
hidpp_populate_input(hidpp, input, true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2898,6 +2907,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!hidpp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Generic HID++ processing. */
|
/* Generic HID++ processing. */
|
||||||
switch (data[0]) {
|
switch (data[0]) {
|
||||||
case REPORT_ID_HIDPP_VERY_LONG:
|
case REPORT_ID_HIDPP_VERY_LONG:
|
||||||
|
@ -2946,7 +2958,12 @@ static int hidpp_event(struct hid_device *hdev, struct hid_field *field,
|
||||||
* restriction imposed in hidpp_usages.
|
* restriction imposed in hidpp_usages.
|
||||||
*/
|
*/
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
struct hidpp_scroll_counter *counter = &hidpp->vertical_wheel_counter;
|
struct hidpp_scroll_counter *counter;
|
||||||
|
|
||||||
|
if (!hidpp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
counter = &hidpp->vertical_wheel_counter;
|
||||||
/* A scroll event may occur before the multiplier has been retrieved or
|
/* A scroll event may occur before the multiplier has been retrieved or
|
||||||
* the input device set, or high-res scroll enabling may fail. In such
|
* the input device set, or high-res scroll enabling may fail. In such
|
||||||
* cases we must return early (falling back to default behaviour) to
|
* cases we must return early (falling back to default behaviour) to
|
||||||
|
@ -3202,6 +3219,41 @@ static const struct attribute_group ps_attribute_group = {
|
||||||
.attrs = sysfs_attrs
|
.attrs = sysfs_attrs
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool hidpp_validate_report(struct hid_device *hdev, int id, int size,
|
||||||
|
bool optional)
|
||||||
|
{
|
||||||
|
struct hid_report_enum *re;
|
||||||
|
struct hid_report *report;
|
||||||
|
|
||||||
|
if (id >= HID_MAX_IDS || id < 0) {
|
||||||
|
hid_err(hdev, "invalid HID report id %u\n", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
re = &(hdev->report_enum[HID_OUTPUT_REPORT]);
|
||||||
|
report = re->report_id_hash[id];
|
||||||
|
|
||||||
|
if (!report)
|
||||||
|
return optional;
|
||||||
|
|
||||||
|
if (report->field[0]->report_count < size) {
|
||||||
|
hid_warn(hdev, "not enough values in hidpp report %d\n", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hidpp_validate_device(struct hid_device *hdev)
|
||||||
|
{
|
||||||
|
return hidpp_validate_report(hdev, REPORT_ID_HIDPP_SHORT,
|
||||||
|
HIDPP_REPORT_SHORT_LENGTH - 1, false) &&
|
||||||
|
hidpp_validate_report(hdev, REPORT_ID_HIDPP_LONG,
|
||||||
|
HIDPP_REPORT_LONG_LENGTH - 1, true) &&
|
||||||
|
hidpp_validate_report(hdev, REPORT_ID_HIDPP_VERY_LONG,
|
||||||
|
HIDPP_REPORT_VERY_LONG_LENGTH - 1, true);
|
||||||
|
}
|
||||||
|
|
||||||
static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
{
|
{
|
||||||
struct hidpp_device *hidpp;
|
struct hidpp_device *hidpp;
|
||||||
|
@ -3209,6 +3261,18 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
bool connected;
|
bool connected;
|
||||||
unsigned int connect_mask = HID_CONNECT_DEFAULT;
|
unsigned int connect_mask = HID_CONNECT_DEFAULT;
|
||||||
|
|
||||||
|
ret = hid_parse(hdev);
|
||||||
|
if (ret) {
|
||||||
|
hid_err(hdev, "%s:parse failed\n", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the device is HID++ capable, otherwise treat as generic HID
|
||||||
|
*/
|
||||||
|
if (!hidpp_validate_device(hdev))
|
||||||
|
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
|
||||||
|
|
||||||
hidpp = devm_kzalloc(&hdev->dev, sizeof(struct hidpp_device),
|
hidpp = devm_kzalloc(&hdev->dev, sizeof(struct hidpp_device),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!hidpp)
|
if (!hidpp)
|
||||||
|
@ -3252,12 +3316,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||||
hid_warn(hdev, "Cannot allocate sysfs group for %s\n",
|
hid_warn(hdev, "Cannot allocate sysfs group for %s\n",
|
||||||
hdev->name);
|
hdev->name);
|
||||||
|
|
||||||
ret = hid_parse(hdev);
|
|
||||||
if (ret) {
|
|
||||||
hid_err(hdev, "%s:parse failed\n", __func__);
|
|
||||||
goto hid_parse_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
|
if (hidpp->quirks & HIDPP_QUIRK_NO_HIDINPUT)
|
||||||
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
connect_mask &= ~HID_CONNECT_HIDINPUT;
|
||||||
|
|
||||||
|
@ -3330,7 +3388,6 @@ hid_hw_open_failed:
|
||||||
hid_hw_stop(hdev);
|
hid_hw_stop(hdev);
|
||||||
}
|
}
|
||||||
hid_hw_start_fail:
|
hid_hw_start_fail:
|
||||||
hid_parse_fail:
|
|
||||||
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
|
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
|
||||||
cancel_work_sync(&hidpp->work);
|
cancel_work_sync(&hidpp->work);
|
||||||
mutex_destroy(&hidpp->send_mutex);
|
mutex_destroy(&hidpp->send_mutex);
|
||||||
|
@ -3341,6 +3398,9 @@ static void hidpp_remove(struct hid_device *hdev)
|
||||||
{
|
{
|
||||||
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
|
if (!hidpp)
|
||||||
|
return hid_hw_stop(hdev);
|
||||||
|
|
||||||
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
|
sysfs_remove_group(&hdev->dev.kobj, &ps_attribute_group);
|
||||||
|
|
||||||
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
|
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue