]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/hid/hid-core.c
drm/amdgpu/smu: add metrics table lock
[linux.git] / drivers / hid / hid-core.c
index 63fdbf09b044f3c8b0211d7e46c25ffa39776eb0..e0b241bd3070c5a15e9ac90ecc81573aad6452ec 100644 (file)
@@ -211,6 +211,18 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
        return 0; /* we know nothing about this usage type */
 }
 
+/*
+ * Concatenate usage which defines 16 bits or less with the
+ * currently defined usage page to form a 32 bit usage
+ */
+
+static void complete_usage(struct hid_parser *parser, unsigned int index)
+{
+       parser->local.usage[index] &= 0xFFFF;
+       parser->local.usage[index] |=
+               (parser->global.usage_page & 0xFFFF) << 16;
+}
+
 /*
  * Add a usage to the temporary parser table.
  */
@@ -222,6 +234,14 @@ static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
                return -1;
        }
        parser->local.usage[parser->local.usage_index] = usage;
+
+       /*
+        * If Usage item only includes usage id, concatenate it with
+        * currently defined usage page
+        */
+       if (size <= 2)
+               complete_usage(parser, parser->local.usage_index);
+
        parser->local.usage_size[parser->local.usage_index] = size;
        parser->local.collection_index[parser->local.usage_index] =
                parser->collection_stack_ptr ?
@@ -543,13 +563,32 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
  * usage value."
  */
 
-static void hid_concatenate_usage_page(struct hid_parser *parser)
+static void hid_concatenate_last_usage_page(struct hid_parser *parser)
 {
        int i;
+       unsigned int usage_page;
+       unsigned int current_page;
+
+       if (!parser->local.usage_index)
+               return;
 
-       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;
+       usage_page = parser->global.usage_page;
+
+       /*
+        * Concatenate usage page again only if last declared Usage Page
+        * has not been already used in previous usages concatenation
+        */
+       for (i = parser->local.usage_index - 1; i >= 0; i--) {
+               if (parser->local.usage_size[i] > 2)
+                       /* Ignore extended usages */
+                       continue;
+
+               current_page = parser->local.usage[i] >> 16;
+               if (current_page == usage_page)
+                       break;
+
+               complete_usage(parser, i);
+       }
 }
 
 /*
@@ -561,7 +600,7 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
        __u32 data;
        int ret;
 
-       hid_concatenate_usage_page(parser);
+       hid_concatenate_last_usage_page(parser);
 
        data = item_udata(item);
 
@@ -742,6 +781,10 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
        if (usage == 0xff0000c5 && parser->global.report_count == 256 &&
            parser->global.report_size == 8)
                parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
+
+       if (usage == 0xff0000c6 && parser->global.report_count == 1 &&
+           parser->global.report_size == 8)
+               parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8;
 }
 
 static void hid_scan_collection(struct hid_parser *parser, unsigned type)
@@ -772,7 +815,7 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
        __u32 data;
        int i;
 
-       hid_concatenate_usage_page(parser);
+       hid_concatenate_last_usage_page(parser);
 
        data = item_udata(item);