From: Matthias Gorzellik matthias.gorzellik@gmail.com
--- dlls/hidparse.sys/main.c | 165 +++++++++++++++++++++++-------------- dlls/winexinput.sys/main.c | 4 +- include/ddk/hidpddi.h | 23 +++--- 3 files changed, 116 insertions(+), 76 deletions(-)
diff --git a/dlls/hidparse.sys/main.c b/dlls/hidparse.sys/main.c index feb5b3531a4..d56c1a93860 100644 --- a/dlls/hidparse.sys/main.c +++ b/dlls/hidparse.sys/main.c @@ -647,83 +647,123 @@ done: NTSTATUS WINAPI HidP_GetCollectionDescription( PHIDP_REPORT_DESCRIPTOR report_desc, ULONG report_desc_len, POOL_TYPE pool_type, HIDP_DEVICE_DESC *device_desc ) { - ULONG i, len, report_count = 0, input_len[256] = {0}, output_len[256] = {0}, feature_len[256] = {0}; + ULONG i, j; struct hid_value_caps *caps, *caps_end; struct hid_preparsed_data *preparsed; + BYTE *ptr, *end; + UINT32 size, depth = 0; + // FIXME: how many TLCs are allowed? + BYTE *toplevel_collections[10];
TRACE( "report_desc %p, report_desc_len %lu, pool_type %u, device_desc %p.\n", report_desc, report_desc_len, pool_type, device_desc );
memset( device_desc, 0, sizeof(*device_desc) );
- if (!(preparsed = parse_descriptor( report_desc, report_desc_len, pool_type ))) - return HIDP_STATUS_INTERNAL_ERROR; - - if (!(device_desc->CollectionDesc = ExAllocatePool( pool_type, sizeof(*device_desc->CollectionDesc) ))) + toplevel_collections[0] = report_desc; + for (ptr = report_desc, end = report_desc + report_desc_len; ptr != end; ptr += size + 1) { - free( preparsed ); - return STATUS_NO_MEMORY; - } + size = (*ptr & 0x03); + if (size == 3) size = 4; + if (ptr + size > end) + { + ERR( "Need %d bytes to read item value\n", size ); + return HIDP_STATUS_INTERNAL_ERROR; + }
- len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + - preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node); - - device_desc->CollectionDescLength = 1; - device_desc->CollectionDesc[0].UsagePage = preparsed->usage_page; - device_desc->CollectionDesc[0].Usage = preparsed->usage; - device_desc->CollectionDesc[0].CollectionNumber = 1; - device_desc->CollectionDesc[0].InputLength = preparsed->input_report_byte_length; - device_desc->CollectionDesc[0].OutputLength = preparsed->output_report_byte_length; - device_desc->CollectionDesc[0].FeatureLength = preparsed->feature_report_byte_length; - device_desc->CollectionDesc[0].PreparsedDataLength = len; - device_desc->CollectionDesc[0].PreparsedData = (PHIDP_PREPARSED_DATA)preparsed; - - caps = HID_INPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->input_caps_end - preparsed->input_caps_start; - for (; caps != caps_end; ++caps) - { - len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; - if (!input_len[caps->report_id]) report_count++; - input_len[caps->report_id] = max(input_len[caps->report_id], len); +#define SHORT_ITEM( tag, type ) (((tag) << 4) | ((type) << 2)) + switch (*ptr & SHORT_ITEM( 0xf, 0x3 )) + { + case SHORT_ITEM( TAG_MAIN_COLLECTION, TAG_TYPE_MAIN ): + depth++; + break; + case SHORT_ITEM( TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN ): + if (--depth == 0) { + device_desc->CollectionDescLength++; + if (device_desc->CollectionDescLength < ARRAY_SIZE(toplevel_collections)) + toplevel_collections[device_desc->CollectionDescLength] = ptr + size + 1; + else { + ERR( "Too many toplevel collections." ); + return HIDP_STATUS_INTERNAL_ERROR; + } + } + break; + default: + break; + } }
- caps = HID_OUTPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->output_caps_end - preparsed->output_caps_start; - for (; caps != caps_end; ++caps) - { - len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; - if (!input_len[caps->report_id] && !output_len[caps->report_id]) report_count++; - output_len[caps->report_id] = max(output_len[caps->report_id], len); - } + if (!(device_desc->CollectionDesc = ExAllocatePool( pool_type, device_desc->CollectionDescLength * sizeof(*device_desc->CollectionDesc) ))) + return STATUS_NO_MEMORY;
- caps = HID_FEATURE_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->feature_caps_end - preparsed->feature_caps_start; - for (; caps != caps_end; ++caps) - { - len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; - if (!input_len[caps->report_id] && !output_len[caps->report_id] && !feature_len[caps->report_id]) report_count++; - feature_len[caps->report_id] = max(feature_len[caps->report_id], len); - } + for (i = 0; i < device_desc->CollectionDescLength; ++i) { + ULONG report_count = 0, input_len[256] = {0}, output_len[256] = {0}, feature_len[256] = {0}, len;
- if (!(device_desc->ReportIDs = ExAllocatePool( pool_type, sizeof(*device_desc->ReportIDs) * report_count ))) - { - free( preparsed ); - ExFreePool( device_desc->CollectionDesc ); - return STATUS_NO_MEMORY; - } + TRACE( "num tlcs %lu, tlc %lu, start %p, end %p\n", device_desc->CollectionDescLength, i, toplevel_collections[i], toplevel_collections[i+1]);
- for (i = 0, report_count = 0; i < 256; ++i) - { - if (!input_len[i] && !output_len[i] && !feature_len[i]) continue; - device_desc->ReportIDs[report_count].ReportID = i; - device_desc->ReportIDs[report_count].CollectionNumber = 1; - device_desc->ReportIDs[report_count].InputLength = (input_len[i] + 7) / 8; - device_desc->ReportIDs[report_count].OutputLength = (output_len[i] + 7) / 8; - device_desc->ReportIDs[report_count].FeatureLength = (feature_len[i] + 7) / 8; - report_count++; - } - device_desc->ReportIDsLength = report_count; + if (!(preparsed = parse_descriptor( toplevel_collections[i], toplevel_collections[i+1] - toplevel_collections[i], pool_type ))) + return HIDP_STATUS_INTERNAL_ERROR; + + len = preparsed->caps_size + FIELD_OFFSET(struct hid_preparsed_data, value_caps[0]) + + preparsed->number_link_collection_nodes * sizeof(struct hid_collection_node); + + device_desc->CollectionDesc[i].UsagePage = preparsed->usage_page; + device_desc->CollectionDesc[i].Usage = preparsed->usage; + device_desc->CollectionDesc[i].CollectionNumber = i+1; + device_desc->CollectionDesc[i].InputLength = preparsed->input_report_byte_length; + device_desc->CollectionDesc[i].OutputLength = preparsed->output_report_byte_length; + device_desc->CollectionDesc[i].FeatureLength = preparsed->feature_report_byte_length; + device_desc->CollectionDesc[i].PreparsedDataLength = len; + device_desc->CollectionDesc[i].PreparsedData = (PHIDP_PREPARSED_DATA)preparsed; + + caps = HID_INPUT_VALUE_CAPS( preparsed ); + caps_end = caps + preparsed->input_caps_end - preparsed->input_caps_start; + for (; caps != caps_end; ++caps) + { + len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; + if (!input_len[caps->report_id]) report_count++; + input_len[caps->report_id] = max(input_len[caps->report_id], len); + }
+ caps = HID_OUTPUT_VALUE_CAPS( preparsed ); + caps_end = caps + preparsed->output_caps_end - preparsed->output_caps_start; + for (; caps != caps_end; ++caps) + { + len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; + if (!input_len[caps->report_id] && !output_len[caps->report_id]) report_count++; + output_len[caps->report_id] = max(output_len[caps->report_id], len); + } + + caps = HID_FEATURE_VALUE_CAPS( preparsed ); + caps_end = caps + preparsed->feature_caps_end - preparsed->feature_caps_start; + for (; caps != caps_end; ++caps) + { + len = caps->start_byte * 8 + caps->start_bit + caps->bit_size * caps->report_count; + if (!input_len[caps->report_id] && !output_len[caps->report_id] && !feature_len[caps->report_id]) report_count++; + feature_len[caps->report_id] = max(feature_len[caps->report_id], len); + } + + if (!(device_desc->CollectionDesc[i].ReportIDs = ExAllocatePool( pool_type, sizeof(*device_desc->CollectionDesc[i].ReportIDs) * report_count ))) + { + for (j = 0; j < i; ++j) { + free( device_desc->CollectionDesc[j].PreparsedData ); + ExFreePool( device_desc->CollectionDesc[j].ReportIDs ); + } + ExFreePool( device_desc->CollectionDesc ); + return STATUS_NO_MEMORY; + } + + for (j = 0, report_count = 0; j < 256; ++j) + { + if (!input_len[j] && !output_len[j] && !feature_len[j]) continue; + device_desc->CollectionDesc[i].ReportIDs[report_count].ReportID = j; + device_desc->CollectionDesc[i].ReportIDs[report_count].InputLength = (input_len[j] + 7) / 8; + device_desc->CollectionDesc[i].ReportIDs[report_count].OutputLength = (output_len[j] + 7) / 8; + device_desc->CollectionDesc[i].ReportIDs[report_count].FeatureLength = (feature_len[j] + 7) / 8; + report_count++; + } + device_desc->CollectionDesc[i].ReportIDsLength = report_count; + } return HIDP_STATUS_SUCCESS; }
@@ -731,6 +771,7 @@ void WINAPI HidP_FreeCollectionDescription( HIDP_DEVICE_DESC *device_desc ) { TRACE( "device_desc %p.\n", device_desc );
+ for ( UINT i = 0; i < device_desc->CollectionDescLength; i++) + ExFreePool( device_desc->CollectionDesc[i].ReportIDs ); ExFreePool( device_desc->CollectionDesc ); - ExFreePool( device_desc->ReportIDs ); } diff --git a/dlls/winexinput.sys/main.c b/dlls/winexinput.sys/main.c index 5a5c6ca8f00..e11ab5b7303 100644 --- a/dlls/winexinput.sys/main.c +++ b/dlls/winexinput.sys/main.c @@ -700,8 +700,8 @@ static NTSTATUS initialize_device(DEVICE_OBJECT *device) if (!fdo->ry_caps.UsagePage) WARN("missing ry axis\n"); if (!fdo->rt_caps.UsagePage) WARN("missing rt axis\n");
- reports = fdo->device_desc.ReportIDs; - report_count = fdo->device_desc.ReportIDsLength; + reports = fdo->device_desc.CollectionDesc->ReportIDs; + report_count = fdo->device_desc.CollectionDesc->ReportIDsLength; for (i = 0; i < report_count; ++i) if (!reports[i].ReportID || reports[i].InputLength) break; if (i == report_count) i = 0; /* no input report?!, just use first ID */
diff --git a/include/ddk/hidpddi.h b/include/ddk/hidpddi.h index 87e68e31869..57ac02f61ee 100644 --- a/include/ddk/hidpddi.h +++ b/include/ddk/hidpddi.h @@ -22,6 +22,14 @@ #include <hidusage.h> #include <ddk/hidpi.h>
+typedef struct _HIDP_REPORT_IDS +{ + UCHAR ReportID; + USHORT InputLength; + USHORT OutputLength; + USHORT FeatureLength; +} HIDP_REPORT_IDS, *PHIDP_REPORT_IDS; + typedef struct _HIDP_COLLECTION_DESC { USAGE UsagePage; @@ -33,16 +41,10 @@ typedef struct _HIDP_COLLECTION_DESC USHORT FeatureLength; USHORT PreparsedDataLength; PHIDP_PREPARSED_DATA PreparsedData; -} HIDP_COLLECTION_DESC, *PHIDP_COLLECTION_DESC;
-typedef struct _HIDP_REPORT_IDS -{ - UCHAR ReportID; - UCHAR CollectionNumber; - USHORT InputLength; - USHORT OutputLength; - USHORT FeatureLength; -} HIDP_REPORT_IDS, *PHIDP_REPORT_IDS; + HIDP_REPORT_IDS *ReportIDs; + ULONG ReportIDsLength; +} HIDP_COLLECTION_DESC, *PHIDP_COLLECTION_DESC;
typedef struct _HIDP_GETCOLDESC_DBG { @@ -56,9 +58,6 @@ typedef struct _HIDP_DEVICE_DESC HIDP_COLLECTION_DESC *CollectionDesc; ULONG CollectionDescLength;
- HIDP_REPORT_IDS *ReportIDs; - ULONG ReportIDsLength; - HIDP_GETCOLDESC_DBG Dbg; } HIDP_DEVICE_DESC, *PHIDP_DEVICE_DESC;