aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2019-01-09 13:50:18 +1000
committerJiri Kosina <jkosina@suse.cz>2019-01-10 07:08:18 +0100
commitee46967fc6e74d412fe1ec15f77fdb8624bde2b0 (patch)
tree586d3468d91b7059e2f8e9b200c95894501cd4a6
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid (diff)
downloadlinux-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.c32
-rw-r--r--include/linux/hid.h4
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;
};