From: "Rémi Bernon" Subject: [PATCH 1/6] hidclass.sys: Create link collection caps during parsing. Message-Id: <20210618073940.3507834-1-rbernon@codeweavers.com> Date: Fri, 18 Jun 2021 09:39:35 +0200 Signed-off-by: Rémi Bernon --- dlls/hidclass.sys/descriptor.c | 67 ++++++++++++++++++------------ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 25 ++++++----- 2 files changed, 56 insertions(+), 36 deletions(-) diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 86b68863308..f7fcccf55d4 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -306,6 +306,9 @@ struct hid_parser_state DWORD stack_size; DWORD global_idx; DWORD collection_idx; + + struct hid_value_caps *collections; + DWORD collections_size; }; static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index ) @@ -390,12 +393,24 @@ static BOOL parse_new_collection( struct hid_parser_state *state ) return FALSE; } + if (!array_reserve( &state->collections, &state->collections_size, state->caps.NumberLinkCollectionNodes )) + { + ERR( "HID parser collections overflow!\n" ); + return FALSE; + } + copy_collection_items( state->stack + state->collection_idx, &state->items ); state->collection_idx++; + state->collections[state->caps.NumberLinkCollectionNodes] = state->items; state->items.link_collection = state->caps.NumberLinkCollectionNodes; state->items.link_usage_page = state->items.usage_page; state->items.link_usage = state->items.usage_min; + if (!state->caps.NumberLinkCollectionNodes) + { + state->caps.UsagePage = state->items.usage_page; + state->caps.Usage = state->items.usage_min; + } state->caps.NumberLinkCollectionNodes++; reset_local_items( state ); @@ -421,6 +436,7 @@ static void free_parser_state( struct hid_parser_state *state ) if (state->global_idx) ERR( "%u unpopped device caps on the stack\n", state->global_idx ); if (state->collection_idx) ERR( "%u unpopped device collection on the stack\n", state->collection_idx ); free( state->stack ); + free( state->collections ); free( state ); } @@ -727,10 +743,8 @@ static void preparse_collection(const struct collection *root, const struct coll WINE_HIDP_PREPARSED_DATA *data, struct preparse_ctx *ctx) { WINE_HID_ELEMENT *elem = HID_ELEMS(data); - WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data); struct feature *f; struct collection *c; - struct list *entry; LIST_FOR_EACH_ENTRY(f, &base->features, struct feature, entry) { @@ -775,33 +789,18 @@ static void preparse_collection(const struct collection *root, const struct coll } } - if (root != base) - { - nodes[base->index].LinkUsagePage = base->caps.UsagePage; - nodes[base->index].LinkUsage = base->caps.NotRange.Usage; - nodes[base->index].Parent = base->parent == root ? 0 : base->parent->index; - nodes[base->index].CollectionType = base->type; - nodes[base->index].IsAlias = 0; - - if ((entry = list_head(&base->collections))) - nodes[base->index].FirstChild = LIST_ENTRY(entry, struct collection, entry)->index; - } - LIST_FOR_EACH_ENTRY(c, &base->collections, struct collection, entry) - { preparse_collection(root, c, data, ctx); - - if ((entry = list_next(&base->collections, &c->entry))) - nodes[c->index].NextSibling = LIST_ENTRY(entry, struct collection, entry)->index; - if (root != base) nodes[base->index].NumberOfChildren++; - } } -static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_collection, unsigned int node_count) +static WINE_HIDP_PREPARSED_DATA *build_preparsed_data( struct collection *base_collection, + struct hid_parser_state *state ) { + WINE_HID_LINK_COLLECTION_NODE *nodes; WINE_HIDP_PREPARSED_DATA *data; unsigned int report_count; unsigned int size; + DWORD i; struct preparse_ctx ctx; unsigned int element_off; @@ -816,18 +815,34 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_coll size = element_off + (ctx.elem_count * sizeof(WINE_HID_ELEMENT)); nodes_offset = size; - size += node_count * sizeof(WINE_HID_LINK_COLLECTION_NODE); + size += state->caps.NumberLinkCollectionNodes * sizeof(WINE_HID_LINK_COLLECTION_NODE); if (!(data = calloc(1, size))) return NULL; data->magic = HID_MAGIC; data->dwSize = size; - data->caps.Usage = base_collection->caps.NotRange.Usage; - data->caps.UsagePage = base_collection->caps.UsagePage; - data->caps.NumberLinkCollectionNodes = node_count; + data->caps = state->caps; data->elementOffset = element_off; data->nodesOffset = nodes_offset; preparse_collection(base_collection, base_collection, data, &ctx); + + nodes = HID_NODES( data ); + for (i = 0; i < data->caps.NumberLinkCollectionNodes; ++i) + { + nodes[i].LinkUsagePage = state->collections[i].usage_page; + nodes[i].LinkUsage = state->collections[i].usage_min; + nodes[i].Parent = state->collections[i].link_collection; + nodes[i].CollectionType = state->collections[i].bit_field; + nodes[i].IsAlias = 0; + + if (i > 0) + { + nodes[i].NextSibling = nodes[nodes[i].Parent].FirstChild; + nodes[nodes[i].Parent].FirstChild = i; + nodes[nodes[i].Parent].NumberOfChildren++; + } + } + return data; } @@ -889,7 +904,7 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) debug_collection(base); - if ((data = build_PreparseData(base, cidx))) + if ((data = build_preparsed_data( base, state ))) debug_print_preparsed(data); free_collection(base); diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 5453af8ff1c..19099a5a19c 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1500,6 +1500,20 @@ static void test_pnp_driver(struct testsign_context *ctx) (val).member, (exp).member) #define check_member(val, exp, fmt, member) check_member_(__FILE__, __LINE__, val, exp, fmt, member) +#define check_hidp_link_collection_node(a, b) check_hidp_link_collection_node_(__LINE__, a, b) +static inline void check_hidp_link_collection_node_(int line, HIDP_LINK_COLLECTION_NODE *node, + const HIDP_LINK_COLLECTION_NODE *exp) +{ + check_member_(__FILE__, line, *node, *exp, "%04x", LinkUsage); + check_member_(__FILE__, line, *node, *exp, "%04x", LinkUsagePage); + check_member_(__FILE__, line, *node, *exp, "%d", Parent); + check_member_(__FILE__, line, *node, *exp, "%d", NumberOfChildren); + check_member_(__FILE__, line, *node, *exp, "%d", NextSibling); + check_member_(__FILE__, line, *node, *exp, "%d", FirstChild); + check_member_(__FILE__, line, *node, *exp, "%d", CollectionType); + check_member_(__FILE__, line, *node, *exp, "%d", IsAlias); +} + #define check_hidp_button_caps(a, b) check_hidp_button_caps_(__LINE__, a, b) static inline void check_hidp_button_caps_(int line, HIDP_BUTTON_CAPS *caps, const HIDP_BUTTON_CAPS *exp) { @@ -1850,16 +1864,7 @@ static void test_hidp(HANDLE file, int report_id) for (i = 0; i < ARRAY_SIZE(expect_collections); ++i) { winetest_push_context("collections[%d]", i); - check_member(collections[i], expect_collections[i], "%04x", LinkUsage); - check_member(collections[i], expect_collections[i], "%04x", LinkUsagePage); - check_member(collections[i], expect_collections[i], "%d", Parent); - check_member(collections[i], expect_collections[i], "%d", NumberOfChildren); - todo_wine_if(i == 1) - check_member(collections[i], expect_collections[i], "%d", NextSibling); - todo_wine_if(i == 0) - check_member(collections[i], expect_collections[i], "%d", FirstChild); - check_member(collections[i], expect_collections[i], "%d", CollectionType); - check_member(collections[i], expect_collections[i], "%d", IsAlias); + check_hidp_link_collection_node(&collections[i], &expect_collections[i]); winetest_pop_context(); } -- 2.31.0