OSDN Git Service

HID: generic: create one input report per application type
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Tue, 24 Apr 2018 08:04:33 +0000 (10:04 +0200)
committerJiri Kosina <jkosina@suse.cz>
Thu, 26 Apr 2018 12:17:31 +0000 (14:17 +0200)
It is not a good idea to try to fit all types of applications in the
same input report. There are a lot of devices that are needing
the quirk HID_MULTI_INPUT but this quirk doesn't match the actual HID
description as it is based on the report ID.

Given that most devices with MULTI_INPUT I can think of split nicely
the devices inputs into application, it is a good thing to split the
devices by default based on this assumption.

Also make hid-multitouch following this rule, to not have to deal
with too many input created.

While we are at it, fix some checkpatch complaints about converting
'unsigned' to 'unsigned int'.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-core.c
drivers/hid/hid-generic.c
drivers/hid/hid-gfrm.c
drivers/hid/hid-input.c
drivers/hid/hid-magicmouse.c
include/linux/hid.h

index 5d7cc6b..6881910 100644 (file)
@@ -57,7 +57,9 @@ MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle
  * Register a new report for a device.
  */
 
-struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+struct hid_report *hid_register_report(struct hid_device *device,
+                                      unsigned int type, unsigned int id,
+                                      unsigned int application)
 {
        struct hid_report_enum *report_enum = device->report_enum + type;
        struct hid_report *report;
@@ -78,6 +80,7 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
        report->type = type;
        report->size = 0;
        report->device = device;
+       report->application = application;
        report_enum->report_id_hash[id] = report;
 
        list_add_tail(&report->list, &report_enum->report_list);
@@ -221,11 +224,15 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 {
        struct hid_report *report;
        struct hid_field *field;
-       unsigned usages;
-       unsigned offset;
-       unsigned i;
+       unsigned int usages;
+       unsigned int offset;
+       unsigned int i;
+       unsigned int application;
+
+       application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
 
-       report = hid_register_report(parser->device, report_type, parser->global.report_id);
+       report = hid_register_report(parser->device, report_type,
+                                    parser->global.report_id, application);
        if (!report) {
                hid_err(parser->device, "hid_register_report failed\n");
                return -1;
@@ -259,7 +266,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 
        field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
        field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
-       field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
+       field->application = application;
 
        for (i = 0; i < usages; i++) {
                unsigned j = i;
index c25b471..3b6eccb 100644 (file)
@@ -56,6 +56,20 @@ static bool hid_generic_match(struct hid_device *hdev,
        return true;
 }
 
+static int hid_generic_probe(struct hid_device *hdev,
+                            const struct hid_device_id *id)
+{
+       int ret;
+
+       hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
+
+       ret = hid_parse(hdev);
+       if (ret)
+               return ret;
+
+       return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
 static const struct hid_device_id hid_table[] = {
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
        { }
@@ -66,6 +80,7 @@ static struct hid_driver hid_generic = {
        .name = "hid-generic",
        .id_table = hid_table,
        .match = hid_generic_match,
+       .probe = hid_generic_probe,
 };
 module_hid_driver(hid_generic);
 
index 075b1c0..cf477f8 100644 (file)
@@ -116,7 +116,7 @@ static int gfrm_probe(struct hid_device *hdev, const struct hid_device_id *id)
                 * those reports reach gfrm_raw_event() from hid_input_report().
                 */
                if (!hid_register_report(hdev, HID_INPUT_REPORT,
-                                        GFRM100_SEARCH_KEY_REPORT_ID)) {
+                                        GFRM100_SEARCH_KEY_REPORT_ID, 0)) {
                        ret = -ENOMEM;
                        goto done;
                }
index fd1c4fe..7463ee2 100644 (file)
@@ -1610,6 +1610,20 @@ static struct hid_input *hidinput_match(struct hid_report *report)
        return NULL;
 }
 
+static struct hid_input *hidinput_match_application(struct hid_report *report)
+{
+       struct hid_device *hid = report->device;
+       struct hid_input *hidinput;
+
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+               if (hidinput->report &&
+                   hidinput->report->application == report->application)
+                       return hidinput;
+       }
+
+       return NULL;
+}
+
 static inline void hidinput_configure_usages(struct hid_input *hidinput,
                                             struct hid_report *report)
 {
@@ -1670,6 +1684,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
                         */
                        if (hid->quirks & HID_QUIRK_MULTI_INPUT)
                                hidinput = hidinput_match(report);
+                       else if (hid->maxapplication > 1 &&
+                                (hid->quirks & HID_QUIRK_INPUT_PER_APP))
+                               hidinput = hidinput_match_application(report);
 
                        if (!hidinput) {
                                hidinput = hidinput_allocate(hid);
index 42ed887..b454c43 100644 (file)
@@ -531,12 +531,12 @@ static int magicmouse_probe(struct hid_device *hdev,
 
        if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
                report = hid_register_report(hdev, HID_INPUT_REPORT,
-                       MOUSE_REPORT_ID);
+                       MOUSE_REPORT_ID, 0);
        else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
                report = hid_register_report(hdev, HID_INPUT_REPORT,
-                       TRACKPAD_REPORT_ID);
+                       TRACKPAD_REPORT_ID, 0);
                report = hid_register_report(hdev, HID_INPUT_REPORT,
-                       DOUBLE_REPORT_ID);
+                       DOUBLE_REPORT_ID, 0);
        }
 
        if (!report) {
index 396068c..bcc91bf 100644 (file)
@@ -341,6 +341,7 @@ struct hid_item {
 /* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */
 /* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */
 #define HID_QUIRK_ALWAYS_POLL                  BIT(10)
+#define HID_QUIRK_INPUT_PER_APP                        BIT(11)
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS          BIT(16)
 #define HID_QUIRK_SKIP_OUTPUT_REPORT_ID                BIT(17)
 #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18)
@@ -465,8 +466,9 @@ struct hid_field {
 struct hid_report {
        struct list_head list;
        struct list_head hidinput_list;
-       unsigned id;                                    /* id of this report */
-       unsigned type;                                  /* report type */
+       unsigned int id;                                /* id of this report */
+       unsigned int type;                              /* report type */
+       unsigned int application;                       /* application usage for this report */
        struct hid_field *field[HID_MAX_FIELDS];        /* fields of the report */
        unsigned maxfield;                              /* maximum valid field index */
        unsigned size;                                  /* size of the report (bits) */
@@ -861,7 +863,9 @@ void hid_output_report(struct hid_report *report, __u8 *data);
 void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
 u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
 struct hid_device *hid_allocate_device(void);
-struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
+struct hid_report *hid_register_report(struct hid_device *device,
+                                      unsigned int type, unsigned int id,
+                                      unsigned int application);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
 struct hid_report *hid_validate_values(struct hid_device *hid,
                                       unsigned int type, unsigned int id,