diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2019-01-08 22:50:18 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2019-01-10 01:08:18 -0500 |
commit | ee46967fc6e74d412fe1ec15f77fdb8624bde2b0 (patch) | |
tree | 586d3468d91b7059e2f8e9b200c95894501cd4a6 | |
parent | cf26057a9441173ad552e90cea3344607075c9ad (diff) |
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) | |||
125 | { | 125 | { |
126 | struct hid_collection *collection; | 126 | struct hid_collection *collection; |
127 | unsigned usage; | 127 | unsigned usage; |
128 | int collection_index; | ||
128 | 129 | ||
129 | usage = parser->local.usage[0]; | 130 | usage = parser->local.usage[0]; |
130 | 131 | ||
@@ -167,13 +168,13 @@ static int open_collection(struct hid_parser *parser, unsigned type) | |||
167 | parser->collection_stack[parser->collection_stack_ptr++] = | 168 | parser->collection_stack[parser->collection_stack_ptr++] = |
168 | parser->device->maxcollection; | 169 | parser->device->maxcollection; |
169 | 170 | ||
170 | collection = parser->device->collection + | 171 | collection_index = parser->device->maxcollection++; |
171 | parser->device->maxcollection++; | 172 | collection = parser->device->collection + collection_index; |
172 | collection->type = type; | 173 | collection->type = type; |
173 | collection->usage = usage; | 174 | collection->usage = usage; |
174 | collection->level = parser->collection_stack_ptr - 1; | 175 | collection->level = parser->collection_stack_ptr - 1; |
175 | collection->parent = parser->active_collection; | 176 | collection->parent_idx = parser->active_collection_idx; |
176 | parser->active_collection = collection; | 177 | parser->active_collection_idx = collection_index; |
177 | 178 | ||
178 | if (type == HID_COLLECTION_APPLICATION) | 179 | if (type == HID_COLLECTION_APPLICATION) |
179 | parser->device->maxapplication++; | 180 | parser->device->maxapplication++; |
@@ -192,8 +193,13 @@ static int close_collection(struct hid_parser *parser) | |||
192 | return -EINVAL; | 193 | return -EINVAL; |
193 | } | 194 | } |
194 | parser->collection_stack_ptr--; | 195 | parser->collection_stack_ptr--; |
195 | if (parser->active_collection) | 196 | if (parser->active_collection_idx != -1) { |
196 | parser->active_collection = parser->active_collection->parent; | 197 | struct hid_device *device = parser->device; |
198 | struct hid_collection *c; | ||
199 | |||
200 | c = &device->collection[parser->active_collection_idx]; | ||
201 | parser->active_collection_idx = c->parent_idx; | ||
202 | } | ||
197 | return 0; | 203 | return 0; |
198 | } | 204 | } |
199 | 205 | ||
@@ -819,6 +825,7 @@ static int hid_scan_report(struct hid_device *hid) | |||
819 | return -ENOMEM; | 825 | return -ENOMEM; |
820 | 826 | ||
821 | parser->device = hid; | 827 | parser->device = hid; |
828 | parser->active_collection_idx = -1; | ||
822 | hid->group = HID_GROUP_GENERIC; | 829 | hid->group = HID_GROUP_GENERIC; |
823 | 830 | ||
824 | /* | 831 | /* |
@@ -1006,10 +1013,12 @@ static void hid_apply_multiplier_to_field(struct hid_device *hid, | |||
1006 | usage = &field->usage[i]; | 1013 | usage = &field->usage[i]; |
1007 | 1014 | ||
1008 | collection = &hid->collection[usage->collection_index]; | 1015 | collection = &hid->collection[usage->collection_index]; |
1009 | while (collection && collection != multiplier_collection) | 1016 | while (collection->parent_idx != -1 && |
1010 | collection = collection->parent; | 1017 | collection != multiplier_collection) |
1018 | collection = &hid->collection[collection->parent_idx]; | ||
1011 | 1019 | ||
1012 | if (collection || multiplier_collection == NULL) | 1020 | if (collection->parent_idx != -1 || |
1021 | multiplier_collection == NULL) | ||
1013 | usage->resolution_multiplier = effective_multiplier; | 1022 | usage->resolution_multiplier = effective_multiplier; |
1014 | 1023 | ||
1015 | } | 1024 | } |
@@ -1044,9 +1053,9 @@ static void hid_apply_multiplier(struct hid_device *hid, | |||
1044 | * applicable fields later. | 1053 | * applicable fields later. |
1045 | */ | 1054 | */ |
1046 | multiplier_collection = &hid->collection[multiplier->usage->collection_index]; | 1055 | multiplier_collection = &hid->collection[multiplier->usage->collection_index]; |
1047 | while (multiplier_collection && | 1056 | while (multiplier_collection->parent_idx != -1 && |
1048 | multiplier_collection->type != HID_COLLECTION_LOGICAL) | 1057 | multiplier_collection->type != HID_COLLECTION_LOGICAL) |
1049 | multiplier_collection = multiplier_collection->parent; | 1058 | multiplier_collection = &hid->collection[multiplier_collection->parent_idx]; |
1050 | 1059 | ||
1051 | effective_multiplier = hid_calculate_multiplier(hid, multiplier); | 1060 | effective_multiplier = hid_calculate_multiplier(hid, multiplier); |
1052 | 1061 | ||
@@ -1170,6 +1179,7 @@ int hid_open_report(struct hid_device *device) | |||
1170 | } | 1179 | } |
1171 | 1180 | ||
1172 | parser->device = device; | 1181 | parser->device = device; |
1182 | parser->active_collection_idx = -1; | ||
1173 | 1183 | ||
1174 | end = start + size; | 1184 | end = start + size; |
1175 | 1185 | ||
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 { | |||
430 | */ | 430 | */ |
431 | 431 | ||
432 | struct hid_collection { | 432 | struct hid_collection { |
433 | struct hid_collection *parent; | 433 | int parent_idx; /* device->collection */ |
434 | unsigned type; | 434 | unsigned type; |
435 | unsigned usage; | 435 | unsigned usage; |
436 | unsigned level; | 436 | unsigned level; |
@@ -658,7 +658,7 @@ struct hid_parser { | |||
658 | unsigned int *collection_stack; | 658 | unsigned int *collection_stack; |
659 | unsigned int collection_stack_ptr; | 659 | unsigned int collection_stack_ptr; |
660 | unsigned int collection_stack_size; | 660 | unsigned int collection_stack_size; |
661 | struct hid_collection *active_collection; | 661 | int active_collection_idx; /* device->collection */ |
662 | struct hid_device *device; | 662 | struct hid_device *device; |
663 | unsigned int scan_flags; | 663 | unsigned int scan_flags; |
664 | }; | 664 | }; |