Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 109 ++++++++++++++------------------- 1 file changed, 46 insertions(+), 63 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 65c2f9aadae..cf0e8436b91 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -256,29 +256,6 @@ static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data) } }
-static int getValue(int bsize, int source, BOOL allow_negative) -{ - int mask = 0xff; - int negative = 0x80; - int outofrange = 0x100; - int value; - unsigned int i; - - if (bsize == 4) - return source; - - for (i = 1; i < bsize; i++) - { - mask = (mask<<8) + 0xff; - negative = (negative<<8); - outofrange = (outofrange<<8); - } - value = (source&mask); - if (allow_negative && value&negative) - value = -1 * (outofrange - value); - return value; -} - static void parse_io_feature(unsigned int bSize, int itemVal, int bTag, unsigned int *feature_index, struct feature *feature) @@ -342,17 +319,35 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l int usages_top = 0; USAGE usages[256]; int i; + UINT32 value; + INT32 signed_value;
for (i = index; i < length;) { BYTE b0 = descriptor[i++]; - int bSize = b0 & 0x03; + int size = b0 & 0x03; int bType = (b0 >> 2) & 0x03; int bTag = (b0 >> 4) & 0x0F;
- bSize = (bSize == 3) ? 4 : bSize; - if (bType == TAG_TYPE_RESERVED && bTag == 0x0F && bSize == 2 && - i + 2 < length) + if (size == 3) size = 4; + if (length - i < size) + { + ERR("Need %d bytes to read item value\n", size); + return -1; + } + + if (size == 0) signed_value = value = 0; + else if (size == 1) signed_value = (INT8)(value = *(UINT8 *)(descriptor + i)); + else if (size == 2) signed_value = (INT16)(value = *(UINT16 *)(descriptor + i)); + else if (size == 4) signed_value = (INT32)(value = *(UINT32 *)(descriptor + i)); + else + { + ERR("Unexpected item value size %d.\n", size); + return -1; + } + i += size; + + if (bType == TAG_TYPE_RESERVED && bTag == 0x0F && size == 2) { /* Long data items: Should be unused */ ERR("Long Data Item, should be unused\n"); @@ -360,19 +355,9 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l } else { - int bSizeActual = 0; - int itemVal = 0; unsigned int j;
- for (j = 0; j < bSize; j++) - { - if (i + j < length) - { - itemVal += descriptor[i + j] << (8 * j); - bSizeActual++; - } - } - TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0,i-1,bType, bTag, bSize, itemVal ); + TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0,i-size-1,bType, bTag, size, value );
if (bType == TAG_TYPE_MAIN) { @@ -392,7 +377,7 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l feature->type = HidP_Output; else feature->type = HidP_Feature; - parse_io_feature(bSize, itemVal, bTag, feature_index, feature); + parse_io_feature(size, value, bTag, feature_index, feature); if (j < usages_top) caps->NotRange.Usage = usages[j]; feature->caps = *caps; @@ -429,9 +414,9 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l list_init(&subcollection->collections); new_caps(caps);
- parse_collection(bSize, itemVal, subcollection); + parse_collection(size, value, subcollection);
- if ((i = parse_descriptor(descriptor, i+1, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; + if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; continue; } case TAG_MAIN_END_COLLECTION: @@ -446,34 +431,34 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l switch(bTag) { case TAG_GLOBAL_USAGE_PAGE: - caps->UsagePage = getValue(bSize, itemVal, FALSE); + caps->UsagePage = value; break; case TAG_GLOBAL_LOGICAL_MINIMUM: - caps->LogicalMin = getValue(bSize, itemVal, TRUE); + caps->LogicalMin = signed_value; break; case TAG_GLOBAL_LOGICAL_MAXIMUM: - caps->LogicalMax = getValue(bSize, itemVal, TRUE); + caps->LogicalMax = signed_value; break; case TAG_GLOBAL_PHYSICAL_MINIMUM: - caps->PhysicalMin = getValue(bSize, itemVal, TRUE); + caps->PhysicalMin = signed_value; break; case TAG_GLOBAL_PHYSICAL_MAXIMUM: - caps->PhysicalMax = getValue(bSize, itemVal, TRUE); + caps->PhysicalMax = signed_value; break; case TAG_GLOBAL_UNIT_EXPONENT: - caps->UnitsExp = getValue(bSize, itemVal, TRUE); + caps->UnitsExp = signed_value; break; case TAG_GLOBAL_UNIT: - caps->Units = getValue(bSize, itemVal, TRUE); + caps->Units = signed_value; break; case TAG_GLOBAL_REPORT_SIZE: - caps->BitSize = getValue(bSize, itemVal, FALSE); + caps->BitSize = value; break; case TAG_GLOBAL_REPORT_ID: - caps->ReportID = getValue(bSize, itemVal, FALSE); + caps->ReportID = value; break; case TAG_GLOBAL_REPORT_COUNT: - caps->ReportCount = getValue(bSize, itemVal, FALSE); + caps->ReportCount = value; break; case TAG_GLOBAL_PUSH: { @@ -521,44 +506,44 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l } else { - usages[usages_top++] = getValue(bSize, itemVal, FALSE); + usages[usages_top++] = value; caps->IsRange = FALSE; } break; case TAG_LOCAL_USAGE_MINIMUM: - caps->Range.UsageMin = getValue(bSize, itemVal, FALSE); + caps->Range.UsageMin = value; caps->IsRange = TRUE; break; case TAG_LOCAL_USAGE_MAXIMUM: - caps->Range.UsageMax = getValue(bSize, itemVal, FALSE); + caps->Range.UsageMax = value; caps->IsRange = TRUE; break; case TAG_LOCAL_DESIGNATOR_INDEX: - caps->NotRange.DesignatorIndex = getValue(bSize, itemVal, FALSE); + caps->NotRange.DesignatorIndex = value; caps->IsDesignatorRange = FALSE; break; case TAG_LOCAL_DESIGNATOR_MINIMUM: - caps->Range.DesignatorMin = getValue(bSize, itemVal, FALSE); + caps->Range.DesignatorMin = value; caps->IsDesignatorRange = TRUE; break; case TAG_LOCAL_DESIGNATOR_MAXIMUM: - caps->Range.DesignatorMax = getValue(bSize, itemVal, FALSE); + caps->Range.DesignatorMax = value; caps->IsDesignatorRange = TRUE; break; case TAG_LOCAL_STRING_INDEX: - caps->NotRange.StringIndex = getValue(bSize, itemVal, FALSE); + caps->NotRange.StringIndex = value; caps->IsStringRange = FALSE; break; case TAG_LOCAL_STRING_MINIMUM: - caps->Range.StringMin = getValue(bSize, itemVal, FALSE); + caps->Range.StringMin = value; caps->IsStringRange = TRUE; break; case TAG_LOCAL_STRING_MAXIMUM: - caps->Range.StringMax = getValue(bSize, itemVal, FALSE); + caps->Range.StringMax = value; caps->IsStringRange = TRUE; break; case TAG_LOCAL_DELIMITER: - FIXME("delimiter %d not implemented!\n", itemVal); + FIXME("delimiter %d not implemented!\n", value); return -1; default: ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); @@ -570,8 +555,6 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); return -1; } - - i += bSize; } } return i;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 365 +++++++++++++++------------------ 1 file changed, 165 insertions(+), 200 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index cf0e8436b91..c1e9b93bed5 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -318,16 +318,16 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l { int usages_top = 0; USAGE usages[256]; - int i; + int i, j; UINT32 value; INT32 signed_value; + struct feature *feature;
for (i = index; i < length;) { - BYTE b0 = descriptor[i++]; - int size = b0 & 0x03; - int bType = (b0 >> 2) & 0x03; - int bTag = (b0 >> 4) & 0x0F; + BYTE item = descriptor[i++]; + BYTE tag = item >> 4; + int size = item & 0x03;
if (size == 3) size = 4; if (length - i < size) @@ -347,215 +347,180 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l } i += size;
- if (bType == TAG_TYPE_RESERVED && bTag == 0x0F && size == 2) +#define SHORT_ITEM(tag,type) (((tag)<<4)|((type)<<2)) + switch (item & SHORT_ITEM(0xf,0x3)) { - /* Long data items: Should be unused */ - ERR("Long Data Item, should be unused\n"); - return -1; - } - else - { - unsigned int j; - - TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0,i-size-1,bType, bTag, size, value ); - - if (bType == TAG_TYPE_MAIN) + case SHORT_ITEM(TAG_MAIN_INPUT, TAG_TYPE_MAIN): + case SHORT_ITEM(TAG_MAIN_OUTPUT, TAG_TYPE_MAIN): + case SHORT_ITEM(TAG_MAIN_FEATURE, TAG_TYPE_MAIN): + for (j = 0; j < caps->ReportCount; j++) { - struct feature *feature; - switch(bTag) + if (!(feature = calloc(1, sizeof(*feature)))) return -1; + list_add_tail(&collection->features, &feature->entry); + if (tag == TAG_MAIN_INPUT) + feature->type = HidP_Input; + else if (tag == TAG_MAIN_OUTPUT) + feature->type = HidP_Output; + else + feature->type = HidP_Feature; + parse_io_feature(size, value, tag, feature_index, feature); + if (j < usages_top) + caps->NotRange.Usage = usages[j]; + feature->caps = *caps; + feature->caps.ReportCount = 1; + feature->collection = collection; + if (j+1 >= usages_top) { - case TAG_MAIN_INPUT: - case TAG_MAIN_OUTPUT: - case TAG_MAIN_FEATURE: - for (j = 0; j < caps->ReportCount; j++) - { - if (!(feature = calloc(1, sizeof(*feature)))) return -1; - list_add_tail(&collection->features, &feature->entry); - if (bTag == TAG_MAIN_INPUT) - feature->type = HidP_Input; - else if (bTag == TAG_MAIN_OUTPUT) - feature->type = HidP_Output; - else - feature->type = HidP_Feature; - parse_io_feature(size, value, bTag, feature_index, feature); - if (j < usages_top) - caps->NotRange.Usage = usages[j]; - feature->caps = *caps; - feature->caps.ReportCount = 1; - feature->collection = collection; - if (j+1 >= usages_top) - { - feature->caps.ReportCount += caps->ReportCount - (j + 1); - break; - } - } - usages_top = 0; - new_caps(caps); - break; - case TAG_MAIN_COLLECTION: - { - struct collection *subcollection; - if (!(subcollection = calloc(1, sizeof(struct collection)))) return -1; - list_add_tail(&collection->collections, &subcollection->entry); - subcollection->parent = collection; - /* Only set our collection once... - We do not properly handle composite devices yet. */ - if (usages_top) - { - caps->NotRange.Usage = usages[usages_top-1]; - usages_top = 0; - } - if (*collection_index == 0) - collection->caps = *caps; - subcollection->caps = *caps; - subcollection->index = *collection_index; - *collection_index = *collection_index + 1; - list_init(&subcollection->features); - list_init(&subcollection->collections); - new_caps(caps); - - parse_collection(size, value, subcollection); - - if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; - continue; - } - case TAG_MAIN_END_COLLECTION: - return i; - default: - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); - return -1; + feature->caps.ReportCount += caps->ReportCount - (j + 1); + break; } } - else if (bType == TAG_TYPE_GLOBAL) + usages_top = 0; + new_caps(caps); + break; + case SHORT_ITEM(TAG_MAIN_COLLECTION, TAG_TYPE_MAIN): + { + struct collection *subcollection; + if (!(subcollection = calloc(1, sizeof(struct collection)))) return -1; + list_add_tail(&collection->collections, &subcollection->entry); + subcollection->parent = collection; + /* Only set our collection once... + We do not properly handle composite devices yet. */ + if (usages_top) { - switch(bTag) - { - case TAG_GLOBAL_USAGE_PAGE: - caps->UsagePage = value; - break; - case TAG_GLOBAL_LOGICAL_MINIMUM: - caps->LogicalMin = signed_value; - break; - case TAG_GLOBAL_LOGICAL_MAXIMUM: - caps->LogicalMax = signed_value; - break; - case TAG_GLOBAL_PHYSICAL_MINIMUM: - caps->PhysicalMin = signed_value; - break; - case TAG_GLOBAL_PHYSICAL_MAXIMUM: - caps->PhysicalMax = signed_value; - break; - case TAG_GLOBAL_UNIT_EXPONENT: - caps->UnitsExp = signed_value; - break; - case TAG_GLOBAL_UNIT: - caps->Units = signed_value; - break; - case TAG_GLOBAL_REPORT_SIZE: - caps->BitSize = value; - break; - case TAG_GLOBAL_REPORT_ID: - caps->ReportID = value; - break; - case TAG_GLOBAL_REPORT_COUNT: - caps->ReportCount = value; - break; - case TAG_GLOBAL_PUSH: - { - struct caps_stack *saved; - if (!(saved = malloc(sizeof(*saved)))) return -1; - saved->caps = *caps; - TRACE("Push\n"); - list_add_tail(stack, &saved->entry); - break; - } - case TAG_GLOBAL_POP: - { - struct list *tail; - struct caps_stack *saved; - TRACE("Pop\n"); - tail = list_tail(stack); - if (tail) - { - saved = LIST_ENTRY(tail, struct caps_stack, entry); - *caps = saved->caps; - list_remove(tail); - free(saved); - } - else - { - ERR("Pop but no stack!\n"); - return -1; - } - break; - } - default: - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); - return -1; - } + caps->NotRange.Usage = usages[usages_top-1]; + usages_top = 0; } - else if (bType == TAG_TYPE_LOCAL) + if (*collection_index == 0) + collection->caps = *caps; + subcollection->caps = *caps; + subcollection->index = *collection_index; + *collection_index = *collection_index + 1; + list_init(&subcollection->features); + list_init(&subcollection->collections); + new_caps(caps); + + parse_collection(size, value, subcollection); + + if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; + continue; + } + case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN): + return i; + + case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL): + caps->UsagePage = value; + break; + case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MINIMUM, TAG_TYPE_GLOBAL): + caps->LogicalMin = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MAXIMUM, TAG_TYPE_GLOBAL): + caps->LogicalMax = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MINIMUM, TAG_TYPE_GLOBAL): + caps->PhysicalMin = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MAXIMUM, TAG_TYPE_GLOBAL): + caps->PhysicalMax = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_UNIT_EXPONENT, TAG_TYPE_GLOBAL): + caps->UnitsExp = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_UNIT, TAG_TYPE_GLOBAL): + caps->Units = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_REPORT_SIZE, TAG_TYPE_GLOBAL): + caps->BitSize = value; + break; + case SHORT_ITEM(TAG_GLOBAL_REPORT_ID, TAG_TYPE_GLOBAL): + caps->ReportID = value; + break; + case SHORT_ITEM(TAG_GLOBAL_REPORT_COUNT, TAG_TYPE_GLOBAL): + caps->ReportCount = value; + break; + case SHORT_ITEM(TAG_GLOBAL_PUSH, TAG_TYPE_GLOBAL): + { + struct caps_stack *saved; + if (!(saved = malloc(sizeof(*saved)))) return -1; + saved->caps = *caps; + TRACE("Push\n"); + list_add_tail(stack, &saved->entry); + break; + } + case SHORT_ITEM(TAG_GLOBAL_POP, TAG_TYPE_GLOBAL): + { + struct list *tail; + struct caps_stack *saved; + TRACE("Pop\n"); + tail = list_tail(stack); + if (tail) { - switch(bTag) - { - case TAG_LOCAL_USAGE: - if (usages_top == sizeof(usages)) - { - ERR("More than 256 individual usages defined\n"); - return -1; - } - else - { - usages[usages_top++] = value; - caps->IsRange = FALSE; - } - break; - case TAG_LOCAL_USAGE_MINIMUM: - caps->Range.UsageMin = value; - caps->IsRange = TRUE; - break; - case TAG_LOCAL_USAGE_MAXIMUM: - caps->Range.UsageMax = value; - caps->IsRange = TRUE; - break; - case TAG_LOCAL_DESIGNATOR_INDEX: - caps->NotRange.DesignatorIndex = value; - caps->IsDesignatorRange = FALSE; - break; - case TAG_LOCAL_DESIGNATOR_MINIMUM: - caps->Range.DesignatorMin = value; - caps->IsDesignatorRange = TRUE; - break; - case TAG_LOCAL_DESIGNATOR_MAXIMUM: - caps->Range.DesignatorMax = value; - caps->IsDesignatorRange = TRUE; - break; - case TAG_LOCAL_STRING_INDEX: - caps->NotRange.StringIndex = value; - caps->IsStringRange = FALSE; - break; - case TAG_LOCAL_STRING_MINIMUM: - caps->Range.StringMin = value; - caps->IsStringRange = TRUE; - break; - case TAG_LOCAL_STRING_MAXIMUM: - caps->Range.StringMax = value; - caps->IsStringRange = TRUE; - break; - case TAG_LOCAL_DELIMITER: - FIXME("delimiter %d not implemented!\n", value); - return -1; - default: - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); - return -1; - } + saved = LIST_ENTRY(tail, struct caps_stack, entry); + *caps = saved->caps; + list_remove(tail); + free(saved); } else { - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); + ERR("Pop but no stack!\n"); + return -1; + } + break; + } + + case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL): + if (usages_top == sizeof(usages)) + { + ERR("More than 256 individual usages defined\n"); return -1; } + else + { + usages[usages_top++] = value; + caps->IsRange = FALSE; + } + break; + case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL): + caps->Range.UsageMin = value; + caps->IsRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL): + caps->Range.UsageMax = value; + caps->IsRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL): + caps->NotRange.DesignatorIndex = value; + caps->IsDesignatorRange = FALSE; + break; + case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MINIMUM, TAG_TYPE_LOCAL): + caps->Range.DesignatorMin = value; + caps->IsDesignatorRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MAXIMUM, TAG_TYPE_LOCAL): + caps->Range.DesignatorMax = value; + caps->IsDesignatorRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_STRING_INDEX, TAG_TYPE_LOCAL): + caps->NotRange.StringIndex = value; + caps->IsStringRange = FALSE; + break; + case SHORT_ITEM(TAG_LOCAL_STRING_MINIMUM, TAG_TYPE_LOCAL): + caps->Range.StringMin = value; + caps->IsStringRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_STRING_MAXIMUM, TAG_TYPE_LOCAL): + caps->Range.StringMax = value; + caps->IsStringRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_DELIMITER, TAG_TYPE_LOCAL): + FIXME("delimiter %d not implemented!\n", value); + return -1; + + default: + FIXME("item type %x not implemented!\n", item); + return -1; } +#undef SHORT_ITEM } return i; }
And internal hid_value_caps struct, and use them to store items and usages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 194 ++++++++++++++++++++------------- include/wine/hid.h | 23 ++++ 2 files changed, 141 insertions(+), 76 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index c1e9b93bed5..b66e9deb9a0 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -130,7 +130,7 @@ struct collection {
struct caps_stack { struct list entry; - HIDP_VALUE_CAPS caps; + struct hid_value_caps caps; };
static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps ) @@ -145,6 +145,42 @@ static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps ) caps->Units, caps->UnitsExp, caps->LogicalMin, caps->LogicalMax, caps->PhysicalMin, caps->PhysicalMax ); }
+static void copy_hidp_value_caps( HIDP_VALUE_CAPS *out, const struct hid_value_caps *in ) +{ + out->UsagePage = in->usage_page; + out->ReportID = in->report_id; + out->IsAlias = FALSE; + out->BitSize = in->bit_size; + out->ReportCount = in->report_count; + out->UnitsExp = in->units_exp; + out->Units = in->units; + out->LogicalMin = in->logical_min; + out->LogicalMax = in->logical_max; + out->PhysicalMin = in->physical_min; + out->PhysicalMax = in->physical_max; + if (!(out->IsRange = in->is_range)) + out->NotRange.Usage = in->usage_min; + else + { + out->Range.UsageMin = in->usage_min; + out->Range.UsageMax = in->usage_max; + } + if (!(out->IsStringRange = in->is_string_range)) + out->NotRange.StringIndex = in->string_min; + else + { + out->Range.StringMin = in->string_min; + out->Range.StringMax = in->string_max; + } + if ((out->IsDesignatorRange = in->is_designator_range)) + out->NotRange.DesignatorIndex = in->designator_min; + else + { + out->Range.DesignatorMin = in->designator_min; + out->Range.DesignatorMax = in->designator_max; + } +} + static void debug_feature(struct feature *feature) { if (!feature) @@ -256,6 +292,31 @@ static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data) } }
+struct hid_parser_state +{ + USAGE usages[256]; + DWORD usages_size; + + struct hid_value_caps items; +}; + +static void reset_local_items( struct hid_parser_state *state ) +{ + state->items.is_range = FALSE; + state->items.is_string_range = FALSE; + state->items.is_designator_range = FALSE; + state->items.usage_min = FALSE; + state->usages_size = 0; +} + +static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage ) +{ + state->usages[state->usages_size] = usage; + state->items.is_range = FALSE; + if (state->usages_size++ == 255) ERR( "HID parser usages stack overflow!\n" ); + return state->usages_size <= 255; +} + static void parse_io_feature(unsigned int bSize, int itemVal, int bTag, unsigned int *feature_index, struct feature *feature) @@ -303,21 +364,10 @@ static void parse_collection(unsigned int bSize, int itemVal, } }
-static void new_caps(HIDP_VALUE_CAPS *caps) -{ - caps->IsRange = 0; - caps->IsStringRange = 0; - caps->IsDesignatorRange = 0; - caps->NotRange.Usage = 0; -} - -static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int length, - unsigned int *feature_index, unsigned int *collection_index, - struct collection *collection, HIDP_VALUE_CAPS *caps, - struct list *stack) +static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int length, + unsigned int *feature_index, unsigned int *collection_index, + struct collection *collection, struct hid_parser_state *state, struct list *stack ) { - int usages_top = 0; - USAGE usages[256]; int i, j; UINT32 value; INT32 signed_value; @@ -353,7 +403,7 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l case SHORT_ITEM(TAG_MAIN_INPUT, TAG_TYPE_MAIN): case SHORT_ITEM(TAG_MAIN_OUTPUT, TAG_TYPE_MAIN): case SHORT_ITEM(TAG_MAIN_FEATURE, TAG_TYPE_MAIN): - for (j = 0; j < caps->ReportCount; j++) + for (j = 0; j < state->items.report_count; j++) { if (!(feature = calloc(1, sizeof(*feature)))) return -1; list_add_tail(&collection->features, &feature->entry); @@ -364,19 +414,17 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l else feature->type = HidP_Feature; parse_io_feature(size, value, tag, feature_index, feature); - if (j < usages_top) - caps->NotRange.Usage = usages[j]; - feature->caps = *caps; + if (j < state->usages_size) state->items.usage_min = state->usages[j]; + copy_hidp_value_caps( &feature->caps, &state->items ); feature->caps.ReportCount = 1; feature->collection = collection; - if (j+1 >= usages_top) + if (j + 1 >= state->usages_size) { - feature->caps.ReportCount += caps->ReportCount - (j + 1); + feature->caps.ReportCount += state->items.report_count - (j + 1); break; } } - usages_top = 0; - new_caps(caps); + reset_local_items( state ); break; case SHORT_ITEM(TAG_MAIN_COLLECTION, TAG_TYPE_MAIN): { @@ -386,63 +434,60 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l subcollection->parent = collection; /* Only set our collection once... We do not properly handle composite devices yet. */ - if (usages_top) - { - caps->NotRange.Usage = usages[usages_top-1]; - usages_top = 0; - } - if (*collection_index == 0) - collection->caps = *caps; - subcollection->caps = *caps; + if (state->usages_size) state->items.usage_min = state->usages[state->usages_size - 1]; + if (*collection_index == 0) copy_hidp_value_caps( &collection->caps, &state->items ); + copy_hidp_value_caps( &subcollection->caps, &state->items ); subcollection->index = *collection_index; *collection_index = *collection_index + 1; list_init(&subcollection->features); list_init(&subcollection->collections); - new_caps(caps); - parse_collection(size, value, subcollection); + reset_local_items( state );
- if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; + if ((i = parse_descriptor( descriptor, i, length, feature_index, collection_index, + subcollection, state, stack )) < 0) + return i; continue; } case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN): + reset_local_items( state ); return i;
case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL): - caps->UsagePage = value; + state->items.usage_page = value; break; case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MINIMUM, TAG_TYPE_GLOBAL): - caps->LogicalMin = signed_value; + state->items.logical_min = signed_value; break; case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MAXIMUM, TAG_TYPE_GLOBAL): - caps->LogicalMax = signed_value; + state->items.logical_max = signed_value; break; case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MINIMUM, TAG_TYPE_GLOBAL): - caps->PhysicalMin = signed_value; + state->items.physical_min = signed_value; break; case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MAXIMUM, TAG_TYPE_GLOBAL): - caps->PhysicalMax = signed_value; + state->items.physical_max = signed_value; break; case SHORT_ITEM(TAG_GLOBAL_UNIT_EXPONENT, TAG_TYPE_GLOBAL): - caps->UnitsExp = signed_value; + state->items.units_exp = signed_value; break; case SHORT_ITEM(TAG_GLOBAL_UNIT, TAG_TYPE_GLOBAL): - caps->Units = signed_value; + state->items.units = signed_value; break; case SHORT_ITEM(TAG_GLOBAL_REPORT_SIZE, TAG_TYPE_GLOBAL): - caps->BitSize = value; + state->items.bit_size = value; break; case SHORT_ITEM(TAG_GLOBAL_REPORT_ID, TAG_TYPE_GLOBAL): - caps->ReportID = value; + state->items.report_id = value; break; case SHORT_ITEM(TAG_GLOBAL_REPORT_COUNT, TAG_TYPE_GLOBAL): - caps->ReportCount = value; + state->items.report_count = value; break; case SHORT_ITEM(TAG_GLOBAL_PUSH, TAG_TYPE_GLOBAL): { struct caps_stack *saved; if (!(saved = malloc(sizeof(*saved)))) return -1; - saved->caps = *caps; + saved->caps = state->items; TRACE("Push\n"); list_add_tail(stack, &saved->entry); break; @@ -456,7 +501,7 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l if (tail) { saved = LIST_ENTRY(tail, struct caps_stack, entry); - *caps = saved->caps; + state->items = saved->caps; list_remove(tail); free(saved); } @@ -469,48 +514,39 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l }
case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL): - if (usages_top == sizeof(usages)) - { - ERR("More than 256 individual usages defined\n"); - return -1; - } - else - { - usages[usages_top++] = value; - caps->IsRange = FALSE; - } + if (!parse_local_usage( state, value )) return -1; break; case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL): - caps->Range.UsageMin = value; - caps->IsRange = TRUE; + state->items.usage_min = value; + state->items.is_range = TRUE; break; case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL): - caps->Range.UsageMax = value; - caps->IsRange = TRUE; + state->items.usage_max = value; + state->items.is_range = TRUE; break; case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL): - caps->NotRange.DesignatorIndex = value; - caps->IsDesignatorRange = FALSE; + state->items.designator_min = state->items.designator_max = value; + state->items.is_designator_range = FALSE; break; case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MINIMUM, TAG_TYPE_LOCAL): - caps->Range.DesignatorMin = value; - caps->IsDesignatorRange = TRUE; + state->items.designator_min = value; + state->items.is_designator_range = TRUE; break; case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MAXIMUM, TAG_TYPE_LOCAL): - caps->Range.DesignatorMax = value; - caps->IsDesignatorRange = TRUE; + state->items.designator_max = value; + state->items.is_designator_range = TRUE; break; case SHORT_ITEM(TAG_LOCAL_STRING_INDEX, TAG_TYPE_LOCAL): - caps->NotRange.StringIndex = value; - caps->IsStringRange = FALSE; + state->items.string_min = state->items.string_max = value; + state->items.is_string_range = FALSE; break; case SHORT_ITEM(TAG_LOCAL_STRING_MINIMUM, TAG_TYPE_LOCAL): - caps->Range.StringMin = value; - caps->IsStringRange = TRUE; + state->items.string_min = value; + state->items.is_string_range = TRUE; break; case SHORT_ITEM(TAG_LOCAL_STRING_MAXIMUM, TAG_TYPE_LOCAL): - caps->Range.StringMax = value; - caps->IsStringRange = TRUE; + state->items.string_max = value; + state->items.is_string_range = TRUE; break; case SHORT_ITEM(TAG_LOCAL_DELIMITER, TAG_TYPE_LOCAL): FIXME("delimiter %d not implemented!\n", value); @@ -735,8 +771,8 @@ static void free_collection(struct collection *collection) WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) { WINE_HIDP_PREPARSED_DATA *data = NULL; + struct hid_parser_state *state; struct collection *base; - HIDP_VALUE_CAPS caps; int i;
struct list caps_stack; @@ -757,16 +793,21 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
list_init(&caps_stack);
- if (!(base = calloc(1, sizeof(*base)))) return NULL; + if (!(state = calloc( 1, sizeof(*state) ))) return NULL; + if (!(base = calloc( 1, sizeof(*base) ))) + { + free( state ); + return NULL; + } base->index = 1; list_init(&base->features); list_init(&base->collections); - memset(&caps, 0, sizeof(caps));
cidx = 0; - if (parse_descriptor(descriptor, 0, length, &feature_count, &cidx, base, &caps, &caps_stack) < 0) + if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state, &caps_stack ) < 0) { free_collection(base); + free( state ); return NULL; }
@@ -787,5 +828,6 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) debug_print_preparsed(data); free_collection(base);
+ free( state ); return data; } diff --git a/include/wine/hid.h b/include/wine/hid.h index cfb4f389eb9..50b1493ab62 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -68,6 +68,29 @@ C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.StringIndex) == offsetof(HIDP_VALU C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.DesignatorIndex) == offsetof(HIDP_VALUE_CAPS, NotRange.DesignatorIndex) ); C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.DataIndex) == offsetof(HIDP_VALUE_CAPS, NotRange.DataIndex) );
+struct hid_value_caps +{ + USAGE usage_page; + USAGE usage_min; + USAGE usage_max; + USHORT string_min; + USHORT string_max; + USHORT designator_min; + USHORT designator_max; + BOOLEAN is_range; + BOOLEAN is_string_range; + BOOLEAN is_designator_range; + UCHAR report_id; + USHORT bit_size; + USHORT report_count; + LONG logical_min; + LONG logical_max; + LONG physical_min; + LONG physical_max; + ULONG units; + ULONG units_exp; +}; + typedef struct __WINE_HID_REPORT { UCHAR reportID;
This adds a todo_wine, because although Wine didn't get the correct caps, some transient value was used incorrectly in Range.UsageMax, this is resetting local items as it should.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 124 ++++++++++++++++------------- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 1 + 2 files changed, 71 insertions(+), 54 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index b66e9deb9a0..b57ab2a7da8 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -128,11 +128,6 @@ struct collection { struct list collections; };
-struct caps_stack { - struct list entry; - struct hid_value_caps caps; -}; - static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps ) { if (!caps) return "(null)"; @@ -298,17 +293,69 @@ struct hid_parser_state DWORD usages_size;
struct hid_value_caps items; + + struct hid_value_caps *stack; + DWORD stack_size; + DWORD global_idx; };
+static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index ) +{ + if (index < *array_size) return TRUE; + if ((*array_size = *array_size ? (*array_size * 3 / 2) : 32) <= index) return FALSE; + if (!(*array = realloc( *array, *array_size * sizeof(**array) ))) return FALSE; + return TRUE; +} + +static void copy_global_items( struct hid_value_caps *dst, const struct hid_value_caps *src ) +{ + dst->usage_page = src->usage_page; + dst->logical_min = src->logical_min; + dst->logical_max = src->logical_max; + dst->physical_min = src->physical_min; + dst->physical_max = src->physical_max; + dst->units_exp = src->units_exp; + dst->units = src->units; + dst->bit_size = src->bit_size; + dst->report_id = src->report_id; + dst->report_count = src->report_count; +} + static void reset_local_items( struct hid_parser_state *state ) { - state->items.is_range = FALSE; - state->items.is_string_range = FALSE; - state->items.is_designator_range = FALSE; - state->items.usage_min = FALSE; + struct hid_value_caps tmp; + copy_global_items( &tmp, &state->items ); + memset( &state->items, 0, sizeof(state->items) ); + copy_global_items( &state->items, &tmp ); state->usages_size = 0; }
+static BOOL parse_global_push( struct hid_parser_state *state ) +{ + if (!array_reserve( &state->stack, &state->stack_size, state->global_idx )) + { + ERR( "HID parser stack overflow!\n" ); + return FALSE; + } + + copy_global_items( state->stack + state->global_idx, &state->items ); + state->global_idx++; + return TRUE; +} + +static BOOL parse_global_pop( struct hid_parser_state *state ) +{ + if (!state->global_idx) + { + ERR( "HID parser global stack underflow!\n" ); + return FALSE; + } + + state->global_idx--; + copy_global_items( &state->items, state->stack + state->global_idx ); + return TRUE; +} + static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage ) { state->usages[state->usages_size] = usage; @@ -317,6 +364,13 @@ static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage ) return state->usages_size <= 255; }
+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 ); + free( state->stack ); + free( state ); +} + static void parse_io_feature(unsigned int bSize, int itemVal, int bTag, unsigned int *feature_index, struct feature *feature) @@ -366,7 +420,7 @@ static void parse_collection(unsigned int bSize, int itemVal,
static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int length, unsigned int *feature_index, unsigned int *collection_index, - struct collection *collection, struct hid_parser_state *state, struct list *stack ) + struct collection *collection, struct hid_parser_state *state ) { int i, j; UINT32 value; @@ -445,7 +499,7 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int reset_local_items( state );
if ((i = parse_descriptor( descriptor, i, length, feature_index, collection_index, - subcollection, state, stack )) < 0) + subcollection, state )) < 0) return i; continue; } @@ -484,34 +538,11 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int state->items.report_count = value; break; case SHORT_ITEM(TAG_GLOBAL_PUSH, TAG_TYPE_GLOBAL): - { - struct caps_stack *saved; - if (!(saved = malloc(sizeof(*saved)))) return -1; - saved->caps = state->items; - TRACE("Push\n"); - list_add_tail(stack, &saved->entry); + if (!parse_global_push( state )) return -1; break; - } case SHORT_ITEM(TAG_GLOBAL_POP, TAG_TYPE_GLOBAL): - { - struct list *tail; - struct caps_stack *saved; - TRACE("Pop\n"); - tail = list_tail(stack); - if (tail) - { - saved = LIST_ENTRY(tail, struct caps_stack, entry); - state->items = saved->caps; - list_remove(tail); - free(saved); - } - else - { - ERR("Pop but no stack!\n"); - return -1; - } + if (!parse_global_pop( state )) return -1; break; - }
case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL): if (!parse_local_usage( state, value )) return -1; @@ -775,8 +806,6 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) struct collection *base; int i;
- struct list caps_stack; - unsigned int feature_count = 0; unsigned int cidx;
@@ -791,8 +820,6 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) } }
- list_init(&caps_stack); - if (!(state = calloc( 1, sizeof(*state) ))) return NULL; if (!(base = calloc( 1, sizeof(*base) ))) { @@ -804,30 +831,19 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) list_init(&base->collections);
cidx = 0; - if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state, &caps_stack ) < 0) + if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state ) < 0) { free_collection(base); - free( state ); + free_parser_state( state ); return NULL; }
debug_collection(base);
- if (!list_empty(&caps_stack)) - { - struct caps_stack *entry, *cursor; - ERR("%i unpopped device caps on the stack\n", list_count(&caps_stack)); - LIST_FOR_EACH_ENTRY_SAFE(entry, cursor, &caps_stack, struct caps_stack, entry) - { - list_remove(&entry->entry); - free(entry); - } - } - if ((data = build_PreparseData(base, cidx))) debug_print_preparsed(data); free_collection(base);
- free( state ); + free_parser_state( state ); return data; } diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 735d1a0d996..ff1db96a06a 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -2093,6 +2093,7 @@ static void test_hidp(HANDLE file, int report_id) check_member(value_caps[4], value_caps[3], "%d", PhysicalMax); todo_wine check_member(value_caps[4], value_caps[3], "%04x", Range.UsageMin); + todo_wine check_member(value_caps[4], value_caps[3], "%04x", Range.UsageMax); check_member(value_caps[4], value_caps[3], "%d", Range.StringMin); check_member(value_caps[4], value_caps[3], "%d", Range.StringMax);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=92660
Your paranoid android.
=== debiant2 (32 bit Arabic:Egypt report) ===
Report validation errors: ntoskrnl.exe:ntoskrnl prints too much data (32779 bytes)
=== debiant2 (32 bit Japanese:Japan report) ===
Report validation errors: ntoskrnl.exe:ntoskrnl prints too much data (32779 bytes)
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 57 +++++++++++++++++++++++++++++++--- include/wine/hid.h | 3 ++ 2 files changed, 55 insertions(+), 5 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index b57ab2a7da8..19f12d77ded 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -144,6 +144,9 @@ static void copy_hidp_value_caps( HIDP_VALUE_CAPS *out, const struct hid_value_c { out->UsagePage = in->usage_page; out->ReportID = in->report_id; + out->LinkCollection = in->link_collection; + out->LinkUsagePage = in->link_usage_page; + out->LinkUsage = in->link_usage; out->IsAlias = FALSE; out->BitSize = in->bit_size; out->ReportCount = in->report_count; @@ -289,6 +292,8 @@ static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data)
struct hid_parser_state { + HIDP_CAPS caps; + USAGE usages[256]; DWORD usages_size;
@@ -297,6 +302,7 @@ struct hid_parser_state struct hid_value_caps *stack; DWORD stack_size; DWORD global_idx; + DWORD collection_idx; };
static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index ) @@ -321,12 +327,21 @@ static void copy_global_items( struct hid_value_caps *dst, const struct hid_valu dst->report_count = src->report_count; }
+static void copy_collection_items( struct hid_value_caps *dst, const struct hid_value_caps *src ) +{ + dst->link_collection = src->link_collection; + dst->link_usage_page = src->link_usage_page; + dst->link_usage = src->link_usage; +} + static void reset_local_items( struct hid_parser_state *state ) { struct hid_value_caps tmp; copy_global_items( &tmp, &state->items ); + copy_collection_items( &tmp, &state->items ); memset( &state->items, 0, sizeof(state->items) ); copy_global_items( &state->items, &tmp ); + copy_collection_items( &state->items, &tmp ); state->usages_size = 0; }
@@ -364,9 +379,44 @@ static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage ) return state->usages_size <= 255; }
+static BOOL parse_new_collection( struct hid_parser_state *state ) +{ + if (!array_reserve( &state->stack, &state->stack_size, state->collection_idx )) + { + ERR( "HID parser stack overflow!\n" ); + return FALSE; + } + + copy_collection_items( state->stack + state->collection_idx, &state->items ); + state->collection_idx++; + + state->items.link_collection = state->caps.NumberLinkCollectionNodes; + state->items.link_usage_page = state->items.usage_page; + state->items.link_usage = state->items.usage_min; + state->caps.NumberLinkCollectionNodes++; + + reset_local_items( state ); + return TRUE; +} + +static BOOL parse_end_collection( struct hid_parser_state *state ) +{ + if (!state->collection_idx) + { + ERR( "HID parser collection stack underflow!\n" ); + return FALSE; + } + + state->collection_idx--; + copy_collection_items( &state->items, state->stack + state->collection_idx ); + reset_local_items( state ); + return TRUE; +} + 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 ); } @@ -496,7 +546,7 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int list_init(&subcollection->features); list_init(&subcollection->collections); parse_collection(size, value, subcollection); - reset_local_items( state ); + if (!parse_new_collection( state )) return -1;
if ((i = parse_descriptor( descriptor, i, length, feature_index, collection_index, subcollection, state )) < 0) @@ -504,7 +554,7 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int continue; } case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN): - reset_local_items( state ); + if (!parse_end_collection( state )) return -1; return i;
case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL): @@ -611,9 +661,6 @@ static void build_elements(WINE_HID_REPORT *wine_report, WINE_HID_ELEMENT *elems
wine_element->caps = feature->caps; wine_element->caps.BitField = feature->BitField; - wine_element->caps.LinkCollection = feature->collection->index; - wine_element->caps.LinkUsage = feature->collection->caps.NotRange.Usage; - wine_element->caps.LinkUsagePage = feature->collection->caps.UsagePage; wine_element->caps.IsAbsolute = feature->IsAbsolute; wine_element->caps.HasNull = feature->HasNull;
diff --git a/include/wine/hid.h b/include/wine/hid.h index 50b1493ab62..47aeda5575c 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -81,6 +81,9 @@ struct hid_value_caps BOOLEAN is_string_range; BOOLEAN is_designator_range; UCHAR report_id; + USHORT link_collection; + USAGE link_usage_page; + USAGE link_usage; USHORT bit_size; USHORT report_count; LONG logical_min;
As documented on MSDN, and as testing shows.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 8 +++++--- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 4 ++-- include/wine/hid.h | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 19f12d77ded..86b68863308 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -147,7 +147,10 @@ static void copy_hidp_value_caps( HIDP_VALUE_CAPS *out, const struct hid_value_c out->LinkCollection = in->link_collection; out->LinkUsagePage = in->link_usage_page; out->LinkUsage = in->link_usage; + out->BitField = in->bit_field; out->IsAlias = FALSE; + out->IsAbsolute = HID_VALUE_CAPS_IS_ABSOLUTE( in ); + out->HasNull = HID_VALUE_CAPS_HAS_NULL( in ); out->BitSize = in->bit_size; out->ReportCount = in->report_count; out->UnitsExp = in->units_exp; @@ -501,6 +504,8 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int } i += size;
+ state->items.bit_field = value; + #define SHORT_ITEM(tag,type) (((tag)<<4)|((type)<<2)) switch (item & SHORT_ITEM(0xf,0x3)) { @@ -660,9 +665,6 @@ static void build_elements(WINE_HID_REPORT *wine_report, WINE_HID_ELEMENT *elems wine_report->bitSize += wine_element->bitCount;
wine_element->caps = feature->caps; - wine_element->caps.BitField = feature->BitField; - wine_element->caps.IsAbsolute = feature->IsAbsolute; - wine_element->caps.HasNull = feature->HasNull;
if (wine_element->caps.IsRange) { diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index ff1db96a06a..5453af8ff1c 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1892,7 +1892,7 @@ static void test_hidp(HANDLE file, int report_id) check_member(button_caps[i], expect_button_caps[i], "%04x", UsagePage); check_member(button_caps[i], expect_button_caps[i], "%d", ReportID); check_member(button_caps[i], expect_button_caps[i], "%d", IsAlias); - todo_wine + todo_wine_if(i == 1 || i == 2) check_member(button_caps[i], expect_button_caps[i], "%d", BitField); todo_wine_if(i >= 2) check_member(button_caps[i], expect_button_caps[i], "%d", LinkCollection); @@ -1994,7 +1994,7 @@ static void test_hidp(HANDLE file, int report_id) check_member(value_caps[i], expect_value_caps[i], "%04x", UsagePage); check_member(value_caps[i], expect_value_caps[i], "%d", ReportID); check_member(value_caps[i], expect_value_caps[i], "%d", IsAlias); - todo_wine + todo_wine_if(i == 2) check_member(value_caps[i], expect_value_caps[i], "%d", BitField); check_member(value_caps[i], expect_value_caps[i], "%d", LinkCollection); check_member(value_caps[i], expect_value_caps[i], "%04x", LinkUsage); diff --git a/include/wine/hid.h b/include/wine/hid.h index 47aeda5575c..185015a52d9 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -84,6 +84,7 @@ struct hid_value_caps USHORT link_collection; USAGE link_usage_page; USAGE link_usage; + USHORT bit_field; USHORT bit_size; USHORT report_count; LONG logical_min; @@ -94,6 +95,9 @@ struct hid_value_caps ULONG units_exp; };
+#define HID_VALUE_CAPS_IS_ABSOLUTE(x) (((x)->bit_field & 0x04) == 0) +#define HID_VALUE_CAPS_HAS_NULL(x) (((x)->bit_field & 0x40) != 0) + typedef struct __WINE_HID_REPORT { UCHAR reportID;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=92662
Your paranoid android.
=== w8 (32 bit report) ===
ntoskrnl.exe: driver.c:272: Test failed: Got unexpected test_load_image_notify_count 0.