Merge branches 'for-5.1/upstream-fixes', 'for-5.2/core', 'for-5.2/ish', 'for-5.2...
[sfrench/cifs-2.6.git] / drivers / hid / hid-core.c
index bff8186e1ea5aec651e8d936f530a10a3e0a5f1a..92387fc0bf180e730d606556b018fe34dd916de6 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #include <linux/semaphore.h>
+#include <linux/async.h>
 
 #include <linux/hid.h>
 #include <linux/hiddev.h>
@@ -218,13 +219,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
  * Add a usage to the temporary parser table.
  */
 
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
 {
        if (parser->local.usage_index >= HID_MAX_USAGES) {
                hid_err(parser->device, "usage index exceeded\n");
                return -1;
        }
        parser->local.usage[parser->local.usage_index] = usage;
+       parser->local.usage_size[parser->local.usage_index] = size;
        parser->local.collection_index[parser->local.usage_index] =
                parser->collection_stack_ptr ?
                parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
@@ -486,10 +488,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                        return 0;
                }
 
-               if (item->size <= 2)
-                       data = (parser->global.usage_page << 16) + data;
-
-               return hid_add_usage(parser, data);
+               return hid_add_usage(parser, data, item->size);
 
        case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
 
@@ -498,9 +497,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                        return 0;
                }
 
-               if (item->size <= 2)
-                       data = (parser->global.usage_page << 16) + data;
-
                parser->local.usage_minimum = data;
                return 0;
 
@@ -511,9 +507,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                        return 0;
                }
 
-               if (item->size <= 2)
-                       data = (parser->global.usage_page << 16) + data;
-
                count = data - parser->local.usage_minimum;
                if (count + parser->local.usage_index >= HID_MAX_USAGES) {
                        /*
@@ -533,7 +526,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
                }
 
                for (n = parser->local.usage_minimum; n <= data; n++)
-                       if (hid_add_usage(parser, n)) {
+                       if (hid_add_usage(parser, n, item->size)) {
                                dbg_hid("hid_add_usage failed\n");
                                return -1;
                        }
@@ -547,6 +540,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
        return 0;
 }
 
+/*
+ * Concatenate Usage Pages into Usages where relevant:
+ * As per specification, 6.2.2.8: "When the parser encounters a main item it
+ * concatenates the last declared Usage Page with a Usage to form a complete
+ * usage value."
+ */
+
+static void hid_concatenate_usage_page(struct hid_parser *parser)
+{
+       int i;
+
+       for (i = 0; i < parser->local.usage_index; i++)
+               if (parser->local.usage_size[i] <= 2)
+                       parser->local.usage[i] += parser->global.usage_page << 16;
+}
+
 /*
  * Process a main item.
  */
@@ -556,6 +565,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
        __u32 data;
        int ret;
 
+       hid_concatenate_usage_page(parser);
+
        data = item_udata(item);
 
        switch (item->tag) {
@@ -765,6 +776,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
        __u32 data;
        int i;
 
+       hid_concatenate_usage_page(parser);
+
        data = item_udata(item);
 
        switch (item->tag) {
@@ -2352,6 +2365,15 @@ int hid_add_device(struct hid_device *hdev)
        dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
                     hdev->vendor, hdev->product, atomic_inc_return(&id));
 
+       /*
+        * Try loading the module for the device before the add, so that we do
+        * not first have hid-generic binding only to have it replaced
+        * immediately afterwards with a specialized driver.
+        */
+       if (!current_is_async())
+               request_module("hid:b%04Xg%04Xv%08Xp%08X", hdev->bus,
+                              hdev->group, hdev->vendor, hdev->product);
+
        hid_debug_register(hdev, dev_name(&hdev->dev));
        ret = device_add(&hdev->dev);
        if (!ret)