From 56d529694be78e0b4e99055c332169494e4f5f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Tue, 11 Feb 2020 19:13:46 +0100 Subject: [PATCH] hid: Implement HidP_GetLinkCollectionNodes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RĂ©mi Bernon Signed-off-by: Aric Stewart Signed-off-by: Alexandre Julliard --- dlls/hid/hidp.c | 24 ++++++++++++++++++++--- dlls/hid/tests/device.c | 7 ------- dlls/hidclass.sys/descriptor.c | 36 +++++++++++++++++++++++++++++----- include/wine/hid.h | 13 ++++++++++++ 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index e0513af7fba..817e021fe4e 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -931,9 +931,27 @@ NTSTATUS WINAPI HidP_GetData(HIDP_REPORT_TYPE ReportType, HIDP_DATA *DataList, U NTSTATUS WINAPI HidP_GetLinkCollectionNodes(HIDP_LINK_COLLECTION_NODE *LinkCollectionNode, ULONG *LinkCollectionNodeLength, PHIDP_PREPARSED_DATA PreparsedData) { - FIXME("stub (%p, %p, %p)\n", LinkCollectionNode, LinkCollectionNodeLength, PreparsedData); + WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData; + WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data); + ULONG i; - *LinkCollectionNodeLength = 0; + TRACE("(%p, %p, %p)\n", LinkCollectionNode, LinkCollectionNodeLength, PreparsedData); - return STATUS_NOT_IMPLEMENTED; + if (*LinkCollectionNodeLength < data->caps.NumberLinkCollectionNodes) + return HIDP_STATUS_BUFFER_TOO_SMALL; + + for (i = 0; i < data->caps.NumberLinkCollectionNodes; ++i) + { + LinkCollectionNode[i].LinkUsage = nodes[i].LinkUsage; + LinkCollectionNode[i].LinkUsagePage = nodes[i].LinkUsagePage; + LinkCollectionNode[i].Parent = nodes[i].Parent; + LinkCollectionNode[i].NumberOfChildren = nodes[i].NumberOfChildren; + LinkCollectionNode[i].NextSibling = nodes[i].NextSibling; + LinkCollectionNode[i].FirstChild = nodes[i].FirstChild; + LinkCollectionNode[i].CollectionType = nodes[i].CollectionType; + LinkCollectionNode[i].IsAlias = nodes[i].IsAlias; + } + *LinkCollectionNodeLength = data->caps.NumberLinkCollectionNodes; + + return HIDP_STATUS_SUCCESS; } diff --git a/dlls/hid/tests/device.c b/dlls/hid/tests/device.c index b3e959d2594..24c307704fe 100644 --- a/dlls/hid/tests/device.c +++ b/dlls/hid/tests/device.c @@ -51,17 +51,14 @@ static void test_device_info(HANDLE device) trace("Found device %s (%02x, %02x)\n", wine_dbgstr_w(device_name), Caps.UsagePage, Caps.Usage); trace("LinkCollectionNodes: (%d)\n", Caps.NumberLinkCollectionNodes); - todo_wine ok(Caps.NumberLinkCollectionNodes > 0, "Expected at least one link collection\n"); nodes_count = 0; status = HidP_GetLinkCollectionNodes(nodes, &nodes_count, ppd); - todo_wine ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetLinkCollectionNodes succeeded:%x\n", status); nodes_count = ARRAY_SIZE(nodes); status = HidP_GetLinkCollectionNodes(nodes, &nodes_count, ppd); - todo_wine ok(status == HIDP_STATUS_SUCCESS, "HidP_GetLinkCollectionNodes failed:%x\n", status); for (i = 0; i < nodes_count; ++i) @@ -74,13 +71,9 @@ static void test_device_info(HANDLE device) nodes[i].CollectionType, nodes[i].IsAlias, nodes[i].UserContext); } - todo_wine ok(nodes_count > 0, "Unexpected number of link collection nodes:%u.\n", nodes_count); - todo_wine ok(nodes[0].LinkUsagePage == Caps.UsagePage, "Unexpected top collection usage page:%x\n", nodes[0].LinkUsagePage); - todo_wine ok(nodes[0].LinkUsage == Caps.Usage, "Unexpected top collection usage:%x\n", nodes[0].LinkUsage); - todo_wine ok(nodes[0].CollectionType == 1, "Unexpected top collection type:%x\n", nodes[0].CollectionType); rc = HidD_FreePreparsedData(ppd); diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index af1679d23b0..876369ad701 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -835,12 +835,14 @@ static void create_preparse_ctx(const struct collection *base, struct preparse_c create_preparse_ctx(c, ctx); } -static void preparse_collection(const struct collection *base, +static void preparse_collection(const struct collection *root, const struct collection *base, 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) { @@ -885,11 +887,29 @@ static void preparse_collection(const struct collection *base, } } + if (root != base) + { + nodes[base->index].LinkUsagePage = base->caps.UsagePage; + nodes[base->index].LinkUsage = base->caps.u.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(c, data, ctx); + { + 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) +static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_collection, unsigned int node_count) { WINE_HIDP_PREPARSED_DATA *data; unsigned int report_count; @@ -897,6 +917,7 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_coll struct preparse_ctx ctx; unsigned int element_off; + unsigned int nodes_offset; memset(&ctx, 0, sizeof(ctx)); create_preparse_ctx(base_collection, &ctx); @@ -906,14 +927,19 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_coll element_off = FIELD_OFFSET(WINE_HIDP_PREPARSED_DATA, reports[report_count]); size = element_off + (ctx.elem_count * sizeof(WINE_HID_ELEMENT)); + nodes_offset = size; + size += node_count * sizeof(WINE_HID_LINK_COLLECTION_NODE); + data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); data->magic = HID_MAGIC; data->dwSize = size; data->caps.Usage = base_collection->caps.u.NotRange.Usage; data->caps.UsagePage = base_collection->caps.UsagePage; + data->caps.NumberLinkCollectionNodes = node_count; data->elementOffset = element_off; + data->nodesOffset = nodes_offset; - preparse_collection(base_collection, data, &ctx); + preparse_collection(base_collection, base_collection, data, &ctx); return data; } @@ -981,7 +1007,7 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) } } - data = build_PreparseData(base); + data = build_PreparseData(base, cidx); debug_print_preparsed(data); free_collection(base); diff --git a/include/wine/hid.h b/include/wine/hid.h index 319105d286e..857dcae18fe 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -48,6 +48,17 @@ typedef struct __WINE_HID_REPORT DWORD elementIdx; } WINE_HID_REPORT; +typedef struct __WINE_HID_LINK_COLLECTION_NODE { + USAGE LinkUsage; + USAGE LinkUsagePage; + USHORT Parent; + USHORT NumberOfChildren; + USHORT NextSibling; + USHORT FirstChild; + BYTE CollectionType; + BYTE IsAlias; +} WINE_HID_LINK_COLLECTION_NODE; + typedef struct __WINE_HIDP_PREPARSED_DATA { DWORD magic; @@ -55,6 +66,7 @@ typedef struct __WINE_HIDP_PREPARSED_DATA HIDP_CAPS caps; DWORD elementOffset; + DWORD nodesOffset; DWORD reportCount[3]; BYTE reportIdx[3][256]; @@ -65,5 +77,6 @@ typedef struct __WINE_HIDP_PREPARSED_DATA #define HID_OUTPUT_REPORTS(d) ((d)->reports + (d)->reportCount[0]) #define HID_FEATURE_REPORTS(d) ((d)->reports + (d)->reportCount[0] + (d)->reportCount[1]) #define HID_ELEMS(d) ((WINE_HID_ELEMENT*)((BYTE*)(d) + (d)->elementOffset)) +#define HID_NODES(d) ((WINE_HID_LINK_COLLECTION_NODE*)((BYTE*)(d) + (d)->nodesOffset)) #endif /* __WINE_PARSE_H */