From 51560aabcb259cb89659d96654d8ad38edbb528d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Bernon?= Date: Mon, 21 Jun 2021 09:05:20 +0200 Subject: [PATCH] hidclass.sys: Build an alternate value array. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RĂ©mi Bernon Signed-off-by: Alexandre Julliard --- dlls/hidclass.sys/descriptor.c | 99 +++++++++++++++++++++++++++++++++- include/wine/hid.h | 11 ++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index e1f1b0bd4f9..e319519ca90 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -287,8 +287,13 @@ struct hid_parser_state struct hid_value_caps *collections; DWORD collections_size; + struct hid_value_caps *values[3]; + ULONG values_size[3]; + ULONG bit_size[3][256]; USHORT *byte_size[3]; /* pointers to caps */ + USHORT *value_idx[3]; /* pointers to caps */ + USHORT *data_idx[3]; /* pointers to caps */ }; static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index ) @@ -447,7 +452,12 @@ static BOOL parse_end_collection( struct hid_parser_state *state ) static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TYPE type, struct collection *collection ) { + struct hid_value_caps *value; + USAGE usage_page = state->items.usage_page; + DWORD usages_size = max(1, state->usages_size); USHORT *byte_size = state->byte_size[type]; + USHORT *value_idx = state->value_idx[type]; + USHORT *data_idx = state->data_idx[type]; ULONG *bit_size = &state->bit_size[type][state->items.report_id]; struct feature *feature; int j; @@ -472,6 +482,34 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY *bit_size += state->items.bit_size * state->items.report_count; *byte_size = max( *byte_size, (*bit_size + 7) / 8 ); + if (!state->items.report_count) + { + reset_local_items( state ); + return TRUE; + } + + if (!array_reserve( &state->values[type], &state->values_size[type], *value_idx + usages_size )) + { + ERR( "HID parser values overflow!\n" ); + return FALSE; + } + value = state->values[type] + *value_idx; + + state->items.report_count -= usages_size - 1; + while (usages_size--) + { + state->items.usage_page = state->usages_page[usages_size]; + state->items.usage_min = state->usages_min[usages_size]; + state->items.usage_max = state->usages_max[usages_size]; + state->items.data_index_min = *data_idx; + state->items.data_index_max = *data_idx + state->items.usage_max - state->items.usage_min; + if (state->items.usage_max || state->items.usage_min) *data_idx = state->items.data_index_max + 1; + *value++ = state->items; + *value_idx += 1; + state->items.report_count = 1; + } + + state->items.usage_page = usage_page; reset_local_items( state ); return TRUE; } @@ -482,6 +520,14 @@ static void init_parser_state( struct hid_parser_state *state ) state->byte_size[HidP_Input] = &state->caps.InputReportByteLength; state->byte_size[HidP_Output] = &state->caps.OutputReportByteLength; state->byte_size[HidP_Feature] = &state->caps.FeatureReportByteLength; + + state->value_idx[HidP_Input] = &state->caps.NumberInputValueCaps; + state->value_idx[HidP_Output] = &state->caps.NumberOutputValueCaps; + state->value_idx[HidP_Feature] = &state->caps.NumberFeatureValueCaps; + + state->data_idx[HidP_Input] = &state->caps.NumberInputDataIndices; + state->data_idx[HidP_Output] = &state->caps.NumberOutputDataIndices; + state->data_idx[HidP_Feature] = &state->caps.NumberFeatureDataIndices; } static void free_parser_state( struct hid_parser_state *state ) @@ -490,6 +536,9 @@ static void free_parser_state( struct hid_parser_state *state ) if (state->collection_idx) ERR( "%u unpopped device collection on the stack\n", state->collection_idx ); free( state->stack ); free( state->collections ); + free( state->values[HidP_Input] ); + free( state->values[HidP_Output] ); + free( state->values[HidP_Feature] ); free( state ); } @@ -785,9 +834,10 @@ static WINE_HIDP_PREPARSED_DATA *build_preparsed_data( struct collection *base_c { WINE_HID_LINK_COLLECTION_NODE *nodes; WINE_HIDP_PREPARSED_DATA *data; + struct hid_value_caps *caps; unsigned int report_count; unsigned int size; - DWORD i; + DWORD i, button, filler, caps_len, caps_off; struct preparse_ctx ctx; unsigned int element_off; @@ -804,13 +854,26 @@ static WINE_HIDP_PREPARSED_DATA *build_preparsed_data( struct collection *base_c nodes_offset = size; size += state->caps.NumberLinkCollectionNodes * sizeof(WINE_HID_LINK_COLLECTION_NODE); + caps_len = state->caps.NumberInputValueCaps + state->caps.NumberOutputValueCaps + state->caps.NumberFeatureValueCaps; + caps_off = size; + size += caps_len * sizeof(*caps); + if (!(data = calloc(1, size))) return NULL; data->magic = HID_MAGIC; data->dwSize = size; data->caps = state->caps; + data->new_caps = state->caps; data->elementOffset = element_off; data->nodesOffset = nodes_offset; + data->value_caps_offset = caps_off; + data->value_caps_count[HidP_Input] = state->caps.NumberInputValueCaps; + data->value_caps_count[HidP_Output] = state->caps.NumberOutputValueCaps; + data->value_caps_count[HidP_Feature] = state->caps.NumberFeatureValueCaps; + + data->caps.NumberInputValueCaps = data->caps.NumberInputButtonCaps = data->caps.NumberInputDataIndices = 0; + data->caps.NumberOutputValueCaps = data->caps.NumberOutputButtonCaps = data->caps.NumberOutputDataIndices = 0; + data->caps.NumberFeatureValueCaps = data->caps.NumberFeatureButtonCaps = data->caps.NumberFeatureDataIndices = 0; preparse_collection(base_collection, base_collection, data, &ctx); nodes = HID_NODES( data ); @@ -830,6 +893,40 @@ static WINE_HIDP_PREPARSED_DATA *build_preparsed_data( struct collection *base_c } } + /* fixup value vs button vs filler counts */ + + caps = HID_INPUT_VALUE_CAPS( data ); + memcpy( caps, state->values[0], data->new_caps.NumberInputValueCaps * sizeof(*caps) ); + for (i = 0, button = 0, filler = 0; i < data->new_caps.NumberInputValueCaps; ++i) + { + if (!caps[i].usage_min && !caps[i].usage_max) filler++; + else if (HID_VALUE_CAPS_IS_BUTTON( caps + i )) button++; + } + data->new_caps.NumberInputButtonCaps = button; + data->new_caps.NumberInputValueCaps -= filler + button; + + caps = HID_OUTPUT_VALUE_CAPS( data ); + memcpy( caps, state->values[1], data->new_caps.NumberOutputValueCaps * sizeof(*caps) ); + for (i = 0, button = 0, filler = 0; i < data->new_caps.NumberOutputValueCaps; ++i) + { + if (!caps[i].usage_min && !caps[i].usage_max) filler++; + else if (HID_VALUE_CAPS_IS_BUTTON( caps + i )) button++; + } + caps += data->new_caps.NumberOutputValueCaps; + data->new_caps.NumberOutputButtonCaps = button; + data->new_caps.NumberOutputValueCaps -= filler + button; + + caps = HID_FEATURE_VALUE_CAPS( data ); + memcpy( caps, state->values[2], data->new_caps.NumberFeatureValueCaps * sizeof(*caps) ); + for (i = 0, button = 0, filler = 0; i < data->new_caps.NumberFeatureValueCaps; ++i) + { + if (!caps[i].usage_min && !caps[i].usage_max) filler++; + else if (HID_VALUE_CAPS_IS_BUTTON( caps + i )) button++; + } + caps += data->new_caps.NumberFeatureValueCaps; + data->new_caps.NumberFeatureButtonCaps = button; + data->new_caps.NumberFeatureValueCaps -= filler + button; + return data; } diff --git a/include/wine/hid.h b/include/wine/hid.h index 185015a52d9..5609adec11f 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -73,6 +73,8 @@ struct hid_value_caps USAGE usage_page; USAGE usage_min; USAGE usage_max; + USHORT data_index_min; + USHORT data_index_max; USHORT string_min; USHORT string_max; USHORT designator_min; @@ -97,6 +99,8 @@ struct hid_value_caps #define HID_VALUE_CAPS_IS_ABSOLUTE(x) (((x)->bit_field & 0x04) == 0) #define HID_VALUE_CAPS_HAS_NULL(x) (((x)->bit_field & 0x40) != 0) +#define HID_VALUE_CAPS_IS_ARRAY(c) (((c)->bit_field & 2) == 0) +#define HID_VALUE_CAPS_IS_BUTTON(c) ((c)->bit_size == 1 || HID_VALUE_CAPS_IS_ARRAY(c)) typedef struct __WINE_HID_REPORT { @@ -122,12 +126,15 @@ typedef struct __WINE_HIDP_PREPARSED_DATA DWORD magic; DWORD dwSize; HIDP_CAPS caps; + HIDP_CAPS new_caps; DWORD elementOffset; DWORD nodesOffset; DWORD reportCount[3]; BYTE reportIdx[3][256]; + DWORD value_caps_offset; + USHORT value_caps_count[3]; WINE_HID_REPORT reports[1]; } WINE_HIDP_PREPARSED_DATA, *PWINE_HIDP_PREPARSED_DATA; @@ -137,4 +144,8 @@ typedef struct __WINE_HIDP_PREPARSED_DATA #define HID_ELEMS(d) ((WINE_HID_ELEMENT*)((BYTE*)(d) + (d)->elementOffset)) #define HID_NODES(d) ((WINE_HID_LINK_COLLECTION_NODE*)((BYTE*)(d) + (d)->nodesOffset)) +#define HID_INPUT_VALUE_CAPS(d) ((struct hid_value_caps*)((char *)(d) + (d)->value_caps_offset)) +#define HID_OUTPUT_VALUE_CAPS(d) (HID_INPUT_VALUE_CAPS(d) + (d)->value_caps_count[0]) +#define HID_FEATURE_VALUE_CAPS(d) (HID_OUTPUT_VALUE_CAPS(d) + (d)->value_caps_count[1]) + #endif /* __WINE_PARSE_H */