HID: core: replace the collection tree pointers with indices
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 9 Jan 2019 03:50:18 +0000 (13:50 +1000)
committerJiri Kosina <jkosina@suse.cz>
Thu, 10 Jan 2019 06:08:18 +0000 (07:08 +0100)
Previously, the pointer to the parent collection was stored. If a device
exceeds 16 collections (HID_DEFAULT_NUM_COLLECTIONS), the array to store
the collections is reallocated, the pointer to the parent collection becomes
invalid.

Replace the pointers with an index-based lookup into the collections array.

Fixes: c53431eb696f3c ("HID: core: store the collections as a basic tree")
Reported-by: Pandruvada, Srinivas <srinivas.pandruvada@intel.com>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Tested-by: Kyle Pelton <kyle.d.pelton@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-core.c
include/linux/hid.h

index f41d5fe51abe3b812b600c7fa79d789f350ef3ce..f9093dedf647cf1825f99918b9554076fcd887fa 100644 (file)
@@ -125,6 +125,7 @@ static int open_collection(struct hid_parser *parser, unsigned type)
 {
        struct hid_collection *collection;
        unsigned usage;
+       int collection_index;
 
        usage = parser->local.usage[0];
 
@@ -167,13 +168,13 @@ static int open_collection(struct hid_parser *parser, unsigned type)
        parser->collection_stack[parser->collection_stack_ptr++] =
                parser->device->maxcollection;
 
-       collection = parser->device->collection +
-               parser->device->maxcollection++;
+       collection_index = parser->device->maxcollection++;
+       collection = parser->device->collection + collection_index;
        collection->type = type;
        collection->usage = usage;
        collection->level = parser->collection_stack_ptr - 1;
-       collection->parent = parser->active_collection;
-       parser->active_collection = collection;
+       collection->parent_idx = parser->active_collection_idx;
+       parser->active_collection_idx = collection_index;
 
        if (type == HID_COLLECTION_APPLICATION)
                parser->device->maxapplication++;
@@ -192,8 +193,13 @@ static int close_collection(struct hid_parser *parser)
                return -EINVAL;
        }
        parser->collection_stack_ptr--;
-       if (parser->active_collection)
-               parser->active_collection = parser->active_collection->parent;
+       if (parser->active_collection_idx != -1) {
+               struct hid_device *device = parser->device;
+               struct hid_collection *c;
+
+               c = &device->collection[parser->active_collection_idx];
+               parser->active_collection_idx = c->parent_idx;
+       }
        return 0;
 }
 
@@ -819,6 +825,7 @@ static int hid_scan_report(struct hid_device *hid)
                return -ENOMEM;
 
        parser->device = hid;
+       parser->active_collection_idx = -1;
        hid->group = HID_GROUP_GENERIC;
 
        /*
@@ -1006,10 +1013,12 @@ static void hid_apply_multiplier_to_field(struct hid_device *hid,
                usage = &field->usage[i];
 
                collection = &hid->collection[usage->collection_index];
-               while (collection && collection != multiplier_collection)
-                       collection = collection->parent;
+               while (collection->parent_idx != -1 &&
+                      collection != multiplier_collection)
+                       collection = &hid->collection[collection->parent_idx];
 
-               if (collection || multiplier_collection == NULL)
+               if (collection->parent_idx != -1 ||
+                   multiplier_collection == NULL)
                        usage->resolution_multiplier = effective_multiplier;
 
        }
@@ -1044,9 +1053,9 @@ static void hid_apply_multiplier(struct hid_device *hid,
         * applicable fields later.
         */
        multiplier_collection = &hid->collection[multiplier->usage->collection_index];
-       while (multiplier_collection &&
+       while (multiplier_collection->parent_idx != -1 &&
               multiplier_collection->type != HID_COLLECTION_LOGICAL)
-               multiplier_collection = multiplier_collection->parent;
+               multiplier_collection = &hid->collection[multiplier_collection->parent_idx];
 
        effective_multiplier = hid_calculate_multiplier(hid, multiplier);
 
@@ -1170,6 +1179,7 @@ int hid_open_report(struct hid_device *device)
        }
 
        parser->device = device;
+       parser->active_collection_idx = -1;
 
        end = start + size;
 
index d99287327ef23f630e321d4705da2ef0248a257a..992bbb7196df43343db3b25ce0259a07964c2070 100644 (file)
@@ -430,7 +430,7 @@ struct hid_local {
  */
 
 struct hid_collection {
-       struct hid_collection *parent;
+       int parent_idx; /* device->collection */
        unsigned type;
        unsigned usage;
        unsigned level;
@@ -658,7 +658,7 @@ struct hid_parser {
        unsigned int         *collection_stack;
        unsigned int          collection_stack_ptr;
        unsigned int          collection_stack_size;
-       struct hid_collection *active_collection;
+       int                   active_collection_idx; /* device->collection */
        struct hid_device    *device;
        unsigned int          scan_flags;
 };