diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2019-01-09 13:50:18 +1000 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2019-01-10 07:08:18 +0100 |
commit | ee46967fc6e74d412fe1ec15f77fdb8624bde2b0 (patch) | |
tree | 586d3468d91b7059e2f8e9b200c95894501cd4a6 | |
parent | Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid (diff) | |
download | linux-dev-ee46967fc6e74d412fe1ec15f77fdb8624bde2b0.tar.xz linux-dev-ee46967fc6e74d412fe1ec15f77fdb8624bde2b0.zip |
HID: core: replace the collection tree pointers with indices
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>
-rw-r--r-- | drivers/hid/hid-core.c | 32 | ||||
-rw-r--r-- | include/linux/hid.h | 4 |
2 files changed, 23 insertions, 13 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f41d5fe51abe..f9093dedf647 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -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; diff --git a/include/linux/hid.h b/include/linux/hid.h index d99287327ef2..992bbb7196df 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -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; }; |