hidclass.sys: Create link collection caps during parsing.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-06-18 09:39:35 +02:00 committed by Alexandre Julliard
parent 4940d2ada2
commit f266b2b5d4
2 changed files with 56 additions and 36 deletions

View file

@ -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);

View file

@ -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();
}