Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 53 +++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 10 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 930dcd52715..646f6eaa492 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -272,7 +272,9 @@ struct hid_parser_state { HIDP_CAPS caps;
- USAGE usages[256]; + USAGE usages_page[256]; + USAGE usages_min[256]; + USAGE usages_max[256]; DWORD usages_size;
struct hid_value_caps items; @@ -323,6 +325,9 @@ static void reset_local_items( struct hid_parser_state *state ) memset( &state->items, 0, sizeof(state->items) ); copy_global_items( &state->items, &tmp ); copy_collection_items( &state->items, &tmp ); + memset( &state->usages_page, 0, sizeof(state->usages_page) ); + memset( &state->usages_min, 0, sizeof(state->usages_min) ); + memset( &state->usages_max, 0, sizeof(state->usages_max) ); state->usages_size = 0; }
@@ -352,14 +357,42 @@ static BOOL parse_global_pop( struct hid_parser_state *state ) return TRUE; }
-static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage ) +static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage_page, USAGE usage ) { - state->usages[state->usages_size] = usage; + if (!usage_page) usage_page = state->items.usage_page; + if (state->items.is_range) state->usages_size = 0; + state->usages_page[state->usages_size] = usage_page; + state->usages_min[state->usages_size] = usage; + state->usages_max[state->usages_size] = usage; + state->items.usage_min = usage; + state->items.usage_max = 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_local_usage_min( struct hid_parser_state *state, USAGE usage_page, USAGE usage ) +{ + if (!usage_page) usage_page = state->items.usage_page; + if (!state->items.is_range) state->usages_max[0] = 0; + state->usages_page[0] = usage_page; + state->usages_min[0] = usage; + state->items.usage_min = usage; + state->items.is_range = TRUE; + state->usages_size = 1; +} + +static void parse_local_usage_max( struct hid_parser_state *state, USAGE usage_page, USAGE usage ) +{ + if (!usage_page) usage_page = state->items.usage_page; + if (!state->items.is_range) state->usages_min[0] = 0; + state->usages_page[0] = usage_page; + state->usages_max[0] = usage; + state->items.usage_max = usage; + state->items.is_range = TRUE; + state->usages_size = 1; +} + static BOOL parse_new_collection( struct hid_parser_state *state ) { if (!array_reserve( &state->stack, &state->stack_size, state->collection_idx )) @@ -377,6 +410,9 @@ static BOOL parse_new_collection( struct hid_parser_state *state ) copy_collection_items( state->stack + state->collection_idx, &state->items ); state->collection_idx++;
+ state->items.usage_min = state->usages_min[0]; + state->items.usage_max = state->usages_max[0]; + state->collections[state->caps.NumberLinkCollectionNodes] = state->items; state->items.link_collection = state->caps.NumberLinkCollectionNodes; state->items.link_usage_page = state->items.usage_page; @@ -417,8 +453,8 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY list_add_tail( &collection->features, &feature->entry ); feature->type = type; feature->isData = ((state->items.bit_field & INPUT_DATA_CONST) == 0); - if (j < state->usages_size) state->items.usage_min = state->usages[j]; copy_hidp_value_caps( &feature->caps, &state->items ); + if (j < state->usages_size) feature->caps.NotRange.Usage = state->usages_min[j]; feature->caps.ReportCount = 1; if (j + 1 >= state->usages_size) { @@ -508,7 +544,6 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int subcollection->parent = collection; /* Only set our collection once... We do not properly handle composite devices yet. */ - if (state->usages_size) state->items.usage_min = state->usages[state->usages_size - 1]; list_init(&subcollection->features); list_init(&subcollection->collections); parse_collection(size, value, subcollection); @@ -559,15 +594,13 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int break;
case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL): - if (!parse_local_usage( state, value )) return -1; + if (!parse_local_usage( state, value >> 16, value & 0xffff )) return -1; break; case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL): - state->items.usage_min = value; - state->items.is_range = TRUE; + parse_local_usage_min( state, value >> 16, value & 0xffff ); break; case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL): - state->items.usage_max = value; - state->items.is_range = TRUE; + parse_local_usage_max( state, value >> 16, value & 0xffff ); break; case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL): state->items.designator_min = state->items.designator_max = value;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/descriptor.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 646f6eaa492..e1f1b0bd4f9 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -286,6 +286,9 @@ struct hid_parser_state
struct hid_value_caps *collections; DWORD collections_size; + + ULONG bit_size[3][256]; + USHORT *byte_size[3]; /* pointers to caps */ };
static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index ) @@ -444,6 +447,8 @@ 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 ) { + USHORT *byte_size = state->byte_size[type]; + ULONG *bit_size = &state->bit_size[type][state->items.report_id]; struct feature *feature; int j;
@@ -463,10 +468,22 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY } }
+ if (!*bit_size) *bit_size = 8; + *bit_size += state->items.bit_size * state->items.report_count; + *byte_size = max( *byte_size, (*bit_size + 7) / 8 ); + reset_local_items( state ); return TRUE; }
+static void init_parser_state( struct hid_parser_state *state ) +{ + memset( state, 0, sizeof(*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; +} + 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 ); @@ -747,20 +764,14 @@ static void preparse_collection(const struct collection *root, const struct coll case HidP_Input: build_elements(report, elem, f, &data->caps.NumberInputDataIndices); count_elements(f, &data->caps.NumberInputButtonCaps, &data->caps.NumberInputValueCaps); - data->caps.InputReportByteLength = - max(data->caps.InputReportByteLength, (report->bitSize + 7) / 8); break; case HidP_Output: build_elements(report, elem, f, &data->caps.NumberOutputDataIndices); count_elements(f, &data->caps.NumberOutputButtonCaps, &data->caps.NumberOutputValueCaps); - data->caps.OutputReportByteLength = - max(data->caps.OutputReportByteLength, (report->bitSize + 7) / 8); break; case HidP_Feature: build_elements(report, elem, f, &data->caps.NumberFeatureDataIndices); count_elements(f, &data->caps.NumberFeatureButtonCaps, &data->caps.NumberFeatureValueCaps); - data->caps.FeatureReportByteLength = - max(data->caps.FeatureReportByteLength, (report->bitSize + 7) / 8); break; } } @@ -865,6 +876,7 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length) } list_init(&base->features); list_init(&base->collections); + init_parser_state( state );
if (parse_descriptor( descriptor, 0, length, base, state ) < 0) {
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- 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 */
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hid/hidp.c | 113 +++--------------------------------------------- 1 file changed, 6 insertions(+), 107 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index 9eedf12b694..168461d99c9 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -156,63 +156,12 @@ static NTSTATUS get_report_data_array(BYTE *report, UINT reportLength, UINT star return HIDP_STATUS_SUCCESS; }
- -NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, - PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData) +NTSTATUS WINAPI HidP_GetButtonCaps( HIDP_REPORT_TYPE report_type, HIDP_BUTTON_CAPS *caps, USHORT *caps_count, + PHIDP_PREPARSED_DATA preparsed_data ) { - PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; - WINE_HID_ELEMENT *elems = HID_ELEMS(data); - WINE_HID_REPORT *report = NULL; - USHORT b_count = 0, r_count = 0; - int i,j,u; - - TRACE("(%i, %p, %p, %p)\n",ReportType, ButtonCaps, ButtonCapsLength, PreparsedData); - - if (data->magic != HID_MAGIC) - return HIDP_STATUS_INVALID_PREPARSED_DATA; - - switch(ReportType) - { - case HidP_Input: - b_count = data->caps.NumberInputButtonCaps; - report = HID_INPUT_REPORTS(data); - break; - case HidP_Output: - b_count = data->caps.NumberOutputButtonCaps; - report = HID_OUTPUT_REPORTS(data); - break; - case HidP_Feature: - b_count = data->caps.NumberFeatureButtonCaps; - report = HID_FEATURE_REPORTS(data); - break; - default: - return HIDP_STATUS_INVALID_REPORT_TYPE; - } - r_count = data->reportCount[ReportType]; - - if (!r_count || !b_count) - { - *ButtonCapsLength = 0; - return HIDP_STATUS_SUCCESS; - } - - b_count = min(b_count, *ButtonCapsLength); - - u = 0; - for (j = 0; j < r_count && u < b_count; j++) - { - for (i = 0; i < report[j].elementCount && u < b_count; i++) - { - if (elems[report[j].elementIdx + i].caps.BitSize == 1) - ButtonCaps[u++] = *(HIDP_BUTTON_CAPS *)&elems[report[j].elementIdx + i].caps; - } - } - - *ButtonCapsLength = b_count; - return HIDP_STATUS_SUCCESS; + return HidP_GetSpecificButtonCaps( report_type, 0, 0, 0, caps, caps_count, preparsed_data ); }
- NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities) { @@ -467,60 +416,10 @@ NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USH return HIDP_STATUS_SUCCESS; }
- -NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, - PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData) +NTSTATUS WINAPI HidP_GetValueCaps( HIDP_REPORT_TYPE report_type, HIDP_VALUE_CAPS *caps, USHORT *caps_count, + PHIDP_PREPARSED_DATA preparsed_data ) { - PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; - WINE_HID_ELEMENT *elems = HID_ELEMS(data); - WINE_HID_REPORT *report = NULL; - USHORT v_count = 0, r_count = 0; - int i,j,u; - - TRACE("(%i, %p, %p, %p)\n", ReportType, ValueCaps, ValueCapsLength, PreparsedData); - - if (data->magic != HID_MAGIC) - return HIDP_STATUS_INVALID_PREPARSED_DATA; - - switch(ReportType) - { - case HidP_Input: - v_count = data->caps.NumberInputValueCaps; - report = HID_INPUT_REPORTS(data); - break; - case HidP_Output: - v_count = data->caps.NumberOutputValueCaps; - report = HID_OUTPUT_REPORTS(data); - break; - case HidP_Feature: - v_count = data->caps.NumberFeatureValueCaps; - report = HID_FEATURE_REPORTS(data); - break; - default: - return HIDP_STATUS_INVALID_REPORT_TYPE; - } - r_count = data->reportCount[ReportType]; - - if (!r_count || !v_count) - { - *ValueCapsLength = 0; - return HIDP_STATUS_SUCCESS; - } - - v_count = min(v_count, *ValueCapsLength); - - u = 0; - for (j = 0; j < r_count && u < v_count; j++) - { - for (i = 0; i < report[j].elementCount && u < v_count; i++) - { - if (elems[report[j].elementIdx + i].caps.BitSize != 1) - ValueCaps[u++] = elems[report[j].elementIdx + i].caps; - } - } - - *ValueCapsLength = v_count; - return HIDP_STATUS_SUCCESS; + return HidP_GetSpecificValueCaps( report_type, 0, 0, 0, caps, caps_count, preparsed_data ); }
NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID,
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hid/hidp.c | 80 ++++++++++++++++-------------- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 56 +-------------------- 2 files changed, 45 insertions(+), 91 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index 168461d99c9..bdf03a652f4 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -36,6 +36,36 @@
WINE_DEFAULT_DEBUG_CHANNEL(hidp);
+static NTSTATUS get_value_caps_range( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_REPORT_TYPE report_type, ULONG report_len, + const struct hid_value_caps **caps, const struct hid_value_caps **caps_end ) +{ + if (preparsed->magic != HID_MAGIC) return HIDP_STATUS_INVALID_PREPARSED_DATA; + + switch (report_type) + { + case HidP_Input: + if (report_len && report_len != preparsed->caps.InputReportByteLength) + return HIDP_STATUS_INVALID_REPORT_LENGTH; + *caps = HID_INPUT_VALUE_CAPS( preparsed ); + break; + case HidP_Output: + if (report_len && report_len != preparsed->caps.OutputReportByteLength) + return HIDP_STATUS_INVALID_REPORT_LENGTH; + *caps = HID_OUTPUT_VALUE_CAPS( preparsed ); + break; + case HidP_Feature: + if (report_len && report_len != preparsed->caps.FeatureReportByteLength) + return HIDP_STATUS_INVALID_REPORT_LENGTH; + *caps = HID_FEATURE_VALUE_CAPS( preparsed ); + break; + default: + return HIDP_STATUS_INVALID_REPORT_TYPE; + } + + *caps_end = *caps + preparsed->value_caps_count[report_type]; + return HIDP_STATUS_SUCCESS; +} + static NTSTATUS get_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value) {
@@ -422,48 +452,26 @@ NTSTATUS WINAPI HidP_GetValueCaps( HIDP_REPORT_TYPE report_type, HIDP_VALUE_CAPS return HidP_GetSpecificValueCaps( report_type, 0, 0, 0, caps, caps_count, preparsed_data ); }
-NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID, - PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, - ULONG ReportLength) +NTSTATUS WINAPI HidP_InitializeReportForID( HIDP_REPORT_TYPE report_type, UCHAR report_id, + PHIDP_PREPARSED_DATA preparsed_data, char *report_buf, ULONG report_len ) { - int size; - PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; - WINE_HID_REPORT *report = NULL; - int r_count; + WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data; + const struct hid_value_caps *caps, *end; + NTSTATUS status;
- TRACE("(%i, %i, %p, %p, %i)\n",ReportType, ReportID, PreparsedData, Report, ReportLength); + TRACE( "report_type %d, report_id %x, preparsed_data %p, report_buf %p, report_len %u.\n", report_type, + report_id, preparsed_data, report_buf, report_len );
- if (data->magic != HID_MAGIC) - return HIDP_STATUS_INVALID_PREPARSED_DATA; + if (!report_len) return HIDP_STATUS_INVALID_REPORT_LENGTH;
- switch(ReportType) - { - case HidP_Input: - size = data->caps.InputReportByteLength; - break; - case HidP_Output: - size = data->caps.OutputReportByteLength; - break; - case HidP_Feature: - size = data->caps.FeatureReportByteLength; - break; - default: - return HIDP_STATUS_INVALID_REPORT_TYPE; - } - r_count = data->reportCount[ReportType]; - report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]]; - - if (!r_count || !size) - return HIDP_STATUS_REPORT_DOES_NOT_EXIST; + status = get_value_caps_range( preparsed, report_type, report_len, &caps, &end ); + if (status != HIDP_STATUS_SUCCESS) return status;
- if (size != ReportLength) - return HIDP_STATUS_INVALID_REPORT_LENGTH; - - if (report->reportID && report->reportID != Report[0]) - return HIDP_STATUS_REPORT_DOES_NOT_EXIST; + while (caps != end && (caps->report_id != report_id || (!caps->usage_min && !caps->usage_max))) caps++; + if (caps == end) return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
- ZeroMemory(Report, size); - Report[0] = ReportID; + memset( report_buf, 0, report_len ); + report_buf[0] = report_id; return HIDP_STATUS_SUCCESS; }
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 19099a5a19c..ff3749569ff 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -2134,18 +2134,15 @@ static void test_hidp(HANDLE file, int report_id) status = HidP_InitializeReportForID(HidP_Input, 0, preparsed_data, report, caps.InputReportByteLength + 1); ok(status == HIDP_STATUS_INVALID_REPORT_LENGTH, "HidP_InitializeReportForID returned %#x\n", status); status = HidP_InitializeReportForID(HidP_Input, 1 - report_id, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(!report_id) ok(status == HIDP_STATUS_REPORT_DOES_NOT_EXIST, "HidP_InitializeReportForID returned %#x\n", status);
memset(report, 0xcd, sizeof(report)); status = HidP_InitializeReportForID(HidP_Input, report_id, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_InitializeReportForID returned %#x\n", status);
memset(buffer, 0xcd, sizeof(buffer)); memset(buffer, 0, caps.InputReportByteLength); buffer[0] = report_id; - todo_wine_if(report_id) ok(!memcmp(buffer, report, sizeof(buffer)), "unexpected report data\n");
status = HidP_SetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, buffer, @@ -2163,12 +2160,10 @@ static void test_hidp(HANDLE file, int report_id)
status = HidP_GetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, buffer, sizeof(buffer), preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_NOT_VALUE_ARRAY, "HidP_GetUsageValueArray returned %#x\n", status); memset(buffer, 0xcd, sizeof(buffer)); status = HidP_GetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, buffer, 0, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetUsageValueArray returned %#x\n", status); status = HidP_GetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, buffer, 8, preparsed_data, report, caps.InputReportByteLength); @@ -2178,53 +2173,41 @@ static void test_hidp(HANDLE file, int report_id) value = -128; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == 0x80, "got value %x, expected %#x\n", value, 0x80); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == -128, "got value %x, expected %#x\n", value, -128);
value = 127; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == 127, "got value %x, expected %#x\n", value, 127);
value = 0; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == 0, "got value %x, expected %#x\n", value, 0);
value = 0x7fffffff; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, @@ -2236,7 +2219,6 @@ static void test_hidp(HANDLE file, int report_id) value = 0xdeadbeef; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status); todo_wine ok(value == 0x7fffffff, "got value %x, expected %#x\n", value, 0x7fffffff); @@ -2244,12 +2226,10 @@ static void test_hidp(HANDLE file, int report_id) value = 0x3fffffff; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status); todo_wine ok(value == 0x7fffffff, "got value %x, expected %#x\n", value, 0x7fffffff); @@ -2257,40 +2237,32 @@ static void test_hidp(HANDLE file, int report_id) value = 0; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == 0x80000000, "got value %x, expected %#x\n", value, 0x80000000);
value = 0; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == 0, "got value %x, expected %#x\n", value, 0);
value = 0xfeedcafe; status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status); value = 0xdeadbeef; status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, (LONG *)&value, preparsed_data, report, caps.InputReportByteLength); todo_wine ok(status == HIDP_STATUS_BAD_LOG_PHY_VALUES, "HidP_GetScaledUsageValue returned %#x\n", status); - todo_wine_if(report_id) ok(value == 0, "got value %x, expected %#x\n", value, 0);
value = HidP_MaxUsageListLength(HidP_Feature + 1, 0, preparsed_data); @@ -2314,46 +2286,39 @@ static void test_hidp(HANDLE file, int report_id) value = 1; status = HidP_SetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_SetUsages returned %#x\n", status); usages[1] = 2; usages[2] = 0xff; value = 3; status = HidP_SetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_SetUsages returned %#x\n", status); usages[0] = 4; usages[1] = 6; value = 2; status = HidP_SetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsages returned %#x\n", status); usages[0] = 4; usages[1] = 6; value = 2; status = HidP_SetUsages(HidP_Input, HID_USAGE_PAGE_LED, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsages returned %#x\n", status);
status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_LED, 0, 6, 1, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_SetUsageValue returned %#x\n", status);
value = 0xdeadbeef; status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_LED, 0, 6, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_SetUsageValue returned %#x\n", status); ok(value == 0xdeadbeef, "got value %x, expected %#x\n", value, 0xdeadbeef);
value = 1; status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetUsages returned %#x\n", status); todo_wine ok(value == 2, "got usage count %d, expected %d\n", value, 2); @@ -2361,22 +2326,16 @@ static void test_hidp(HANDLE file, int report_id) memset(usages, 0xcd, sizeof(usages)); status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsages returned %#x\n", status); - todo_wine_if(report_id) ok(value == 2, "got usage count %d, expected %d\n", value, 2); - todo_wine_if(report_id) ok(usages[0] == 4, "got usages[0] %x, expected %x\n", usages[0], 4); - todo_wine_if(report_id) ok(usages[1] == 6, "got usages[1] %x, expected %x\n", usages[1], 6);
value = ARRAY_SIZE(usages); memset(usages, 0xcd, sizeof(usages)); status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_LED, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsages returned %#x\n", status); - todo_wine_if(report_id) ok(value == 2, "got usage count %d, expected %d\n", value, 2); todo_wine ok(usages[0] == 6, "got usages[0] %x, expected %x\n", usages[0], 6); @@ -2387,26 +2346,18 @@ static void test_hidp(HANDLE file, int report_id) memset(usage_and_pages, 0xcd, sizeof(usage_and_pages)); status = HidP_GetUsagesEx(HidP_Input, 0, usage_and_pages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsagesEx returned %#x\n", status); - todo_wine_if(report_id) ok(value == 4, "got usage count %d, expected %d\n", value, 4); - todo_wine_if(report_id) ok(usage_and_pages[0].UsagePage == HID_USAGE_PAGE_BUTTON, "got usage_and_pages[0] UsagePage %x, expected %x\n", usage_and_pages[0].UsagePage, HID_USAGE_PAGE_BUTTON); - todo_wine_if(report_id) ok(usage_and_pages[1].UsagePage == HID_USAGE_PAGE_BUTTON, "got usage_and_pages[1] UsagePage %x, expected %x\n", usage_and_pages[1].UsagePage, HID_USAGE_PAGE_BUTTON); - todo_wine_if(report_id) ok(usage_and_pages[2].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[2] UsagePage %x, expected %x\n", usage_and_pages[2].UsagePage, HID_USAGE_PAGE_LED); - todo_wine_if(report_id) ok(usage_and_pages[3].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[3] UsagePage %x, expected %x\n", usage_and_pages[3].UsagePage, HID_USAGE_PAGE_LED); - todo_wine_if(report_id) ok(usage_and_pages[0].Usage == 4, "got usage_and_pages[0] Usage %x, expected %x\n", usage_and_pages[0].Usage, 4); - todo_wine_if(report_id) ok(usage_and_pages[1].Usage == 6, "got usage_and_pages[1] Usage %x, expected %x\n", usage_and_pages[1].Usage, 6); todo_wine @@ -2428,15 +2379,13 @@ static void test_hidp(HANDLE file, int report_id)
value = 1; status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetData returned %#x\n", status); todo_wine ok(value == 9, "got data count %d, expected %d\n", value, 9); memset(data, 0, sizeof(data)); status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_GetData returned %#x\n", status); - if (status == HIDP_STATUS_SUCCESS) for (i = 0; i < ARRAY_SIZE(expect_data); ++i) + for (i = 0; i < ARRAY_SIZE(expect_data); ++i) { winetest_push_context("data[%d]", i); todo_wine_if(i >= 4) @@ -2448,18 +2397,15 @@ static void test_hidp(HANDLE file, int report_id)
memset(report, 0xcd, sizeof(report)); status = HidP_InitializeReportForID(HidP_Feature, 3, preparsed_data, report, caps.FeatureReportByteLength); - todo_wine_if(!report_id) ok(status == HIDP_STATUS_REPORT_DOES_NOT_EXIST, "HidP_InitializeReportForID returned %#x\n", status);
memset(report, 0xcd, sizeof(report)); status = HidP_InitializeReportForID(HidP_Feature, report_id, preparsed_data, report, caps.FeatureReportByteLength); - todo_wine_if(report_id) ok(status == HIDP_STATUS_SUCCESS, "HidP_InitializeReportForID returned %#x\n", status);
memset(buffer, 0xcd, sizeof(buffer)); memset(buffer, 0, caps.FeatureReportByteLength); buffer[0] = report_id; - todo_wine_if(report_id) ok(!memcmp(buffer, report, sizeof(buffer)), "unexpected report data\n");
for (i = 0; i < caps.NumberLinkCollectionNodes; ++i)
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=92824
Your paranoid android.
=== w7u_el (32 bit report) ===
ntoskrnl.exe: driver.c:759: Test failed: got 0
=== w1064_tsign (64 bit report) ===
ntoskrnl.exe: driver.c:272: Test failed: Got unexpected test_load_image_notify_count 0.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hid/hidp.c | 160 +++++++++++++++++------------ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 41 +------- include/wine/hid.h | 30 ------ 3 files changed, 95 insertions(+), 136 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index bdf03a652f4..301c367d37a 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -66,6 +66,49 @@ static NTSTATUS get_value_caps_range( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_ return HIDP_STATUS_SUCCESS; }
+struct caps_filter +{ + BOOLEAN buttons; + USAGE usage_page; + USHORT collection; + USAGE usage; +}; + +static BOOL match_value_caps( const struct hid_value_caps *caps, const struct caps_filter *filter ) +{ + if (!caps->usage_min && !caps->usage_max) return FALSE; + if (filter->buttons && !HID_VALUE_CAPS_IS_BUTTON( caps )) return FALSE; + if (filter->usage_page && filter->usage_page != caps->usage_page) return FALSE; + if (filter->collection && filter->collection != caps->link_collection) return FALSE; + if (!filter->usage) return TRUE; + return caps->usage_min <= filter->usage && caps->usage_max >= filter->usage; +} + +typedef NTSTATUS (*enum_value_caps_callback)( const struct hid_value_caps *caps, void *user ); + +static NTSTATUS enum_value_caps( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_REPORT_TYPE report_type, + const struct caps_filter *filter, enum_value_caps_callback callback, + void *user, USHORT *count ) +{ + const struct hid_value_caps *caps, *caps_end; + NTSTATUS status; + LONG remaining = *count; + + for (status = get_value_caps_range( preparsed, report_type, 0, &caps, &caps_end ); + status == HIDP_STATUS_SUCCESS && caps != caps_end; caps++) + { + if (!match_value_caps( caps, filter )) continue; + if (remaining-- > 0) status = callback( caps, user ); + } + + if (status != HIDP_STATUS_SUCCESS) return status; + + *count -= remaining; + if (*count == 0) return HIDP_STATUS_USAGE_NOT_FOUND; + if (remaining < 0) return HIDP_STATUS_BUFFER_TOO_SMALL; + return HIDP_STATUS_SUCCESS; +} + static NTSTATUS get_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value) {
@@ -192,17 +235,18 @@ NTSTATUS WINAPI HidP_GetButtonCaps( HIDP_REPORT_TYPE report_type, HIDP_BUTTON_CA return HidP_GetSpecificButtonCaps( report_type, 0, 0, 0, caps, caps_count, preparsed_data ); }
-NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData, - PHIDP_CAPS Capabilities) +NTSTATUS WINAPI HidP_GetCaps( PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps ) { - PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; + WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
- TRACE("(%p, %p)\n",PreparsedData, Capabilities); + TRACE( "preparsed_data %p, caps %p.\n", preparsed_data, caps );
- if (data->magic != HID_MAGIC) - return HIDP_STATUS_INVALID_PREPARSED_DATA; + if (preparsed->magic != HID_MAGIC) return HIDP_STATUS_INVALID_PREPARSED_DATA;
- *Capabilities = data->caps; + *caps = preparsed->caps; + caps->NumberInputButtonCaps = preparsed->new_caps.NumberInputButtonCaps; + caps->NumberOutputButtonCaps = preparsed->new_caps.NumberOutputButtonCaps; + caps->NumberFeatureButtonCaps = preparsed->new_caps.NumberFeatureButtonCaps;
return HIDP_STATUS_SUCCESS; } @@ -603,75 +647,59 @@ NTSTATUS WINAPI HidP_TranslateUsagesToI8042ScanCodes(USAGE *ChangedUsageList, return STATUS_NOT_IMPLEMENTED; }
-NTSTATUS WINAPI HidP_GetSpecificButtonCaps(HIDP_REPORT_TYPE ReportType, - USAGE UsagePage, USHORT LinkCollection, USAGE Usage, - HIDP_BUTTON_CAPS *ButtonCaps, USHORT *ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData) +static NTSTATUS get_button_caps( const struct hid_value_caps *caps, void *user ) { - WINE_HIDP_PREPARSED_DATA *data = (WINE_HIDP_PREPARSED_DATA*)PreparsedData; - WINE_HID_ELEMENT *elems = HID_ELEMS(data); - WINE_HID_REPORT *report = NULL; - USHORT b_count = 0, r_count = 0; - int i,j,u; - - TRACE("(%i, 0x%x, %i, 0x%x, %p %p %p)\n", ReportType, UsagePage, LinkCollection, - Usage, ButtonCaps, ButtonCapsLength, PreparsedData); - - if (data->magic != HID_MAGIC) - return HIDP_STATUS_INVALID_PREPARSED_DATA; - - switch(ReportType) + HIDP_BUTTON_CAPS **iter = user, *dst = *iter; + dst->UsagePage = caps->usage_page; + dst->ReportID = caps->report_id; + dst->LinkCollection = caps->link_collection; + dst->LinkUsagePage = caps->link_usage_page; + dst->LinkUsage = caps->link_usage; + dst->BitField = caps->bit_field; + dst->IsAlias = FALSE; + dst->IsAbsolute = HID_VALUE_CAPS_IS_ABSOLUTE( caps ); + if (!(dst->IsRange = caps->is_range)) { - case HidP_Input: - b_count = data->caps.NumberInputButtonCaps; - report = HID_INPUT_REPORTS(data); - break; - case HidP_Output: - b_count = data->caps.NumberOutputButtonCaps; - report = HID_OUTPUT_REPORTS(data); - break; - case HidP_Feature: - b_count = data->caps.NumberFeatureButtonCaps; - report = HID_FEATURE_REPORTS(data); - break; - default: - return HIDP_STATUS_INVALID_REPORT_TYPE; + dst->NotRange.Usage = caps->usage_min; + dst->NotRange.DataIndex = caps->data_index_min; } - r_count = data->reportCount[ReportType]; - - if (!r_count || !b_count) + else { - *ButtonCapsLength = 0; - return HIDP_STATUS_SUCCESS; + dst->Range.UsageMin = caps->usage_min; + dst->Range.UsageMax = caps->usage_max; + dst->Range.DataIndexMin = caps->data_index_min; + dst->Range.DataIndexMax = caps->data_index_max; } - - b_count = min(b_count, *ButtonCapsLength); - - u = 0; - for (j = 0; j < r_count && u < b_count; j++) + if (!(dst->IsStringRange = caps->is_string_range)) + dst->NotRange.StringIndex = caps->string_min; + else { - for (i = 0; i < report[j].elementCount && u < b_count; i++) - { - if (elems[report[j].elementIdx + i].caps.BitSize == 1 && - (UsagePage == 0 || UsagePage == elems[report[j].elementIdx + i].caps.UsagePage) && - (LinkCollection == 0 || LinkCollection == elems[report[j].elementIdx + i].caps.LinkCollection) && - (Usage == 0 || ( - (!elems[report[j].elementIdx + i].caps.IsRange && - Usage == elems[report[j].elementIdx + i].caps.NotRange.Usage)) || - (elems[report[j].elementIdx + i].caps.IsRange && - Usage >= elems[report[j].elementIdx + i].caps.Range.UsageMin && - Usage <= elems[report[j].elementIdx + i].caps.Range.UsageMax))) - { - ButtonCaps[u++] = *(HIDP_BUTTON_CAPS *)&elems[report[j].elementIdx + i].caps; - } - } + dst->Range.StringMin = caps->string_min; + dst->Range.StringMax = caps->string_max; } - TRACE("Matched %i usages\n", u); - - *ButtonCapsLength = u; - + if ((dst->IsDesignatorRange = caps->is_designator_range)) + dst->NotRange.DesignatorIndex = caps->designator_min; + else + { + dst->Range.DesignatorMin = caps->designator_min; + dst->Range.DesignatorMax = caps->designator_max; + } + *iter += 1; return HIDP_STATUS_SUCCESS; }
+NTSTATUS WINAPI HidP_GetSpecificButtonCaps( HIDP_REPORT_TYPE report_type, USAGE usage_page, USHORT collection, + USAGE usage, HIDP_BUTTON_CAPS *caps, USHORT *caps_count, + PHIDP_PREPARSED_DATA preparsed_data ) +{ + WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data; + const struct caps_filter filter = {.buttons = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage}; + + TRACE( "report_type %d, usage_page %x, collection %d, usage %x, caps %p, caps_count %p, preparsed_data %p.\n", + report_type, usage_page, collection, usage, caps, caps_count, preparsed_data ); + + return enum_value_caps( preparsed, report_type, &filter, get_button_caps, &caps, caps_count ); +}
NTSTATUS WINAPI HidP_GetSpecificValueCaps(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index ff3749569ff..11779daf684 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -1833,7 +1833,6 @@ static void test_hidp(HANDLE file, int report_id) check_member(caps, expect_hidp_caps[report_id], "%d", OutputReportByteLength); check_member(caps, expect_hidp_caps[report_id], "%d", FeatureReportByteLength); check_member(caps, expect_hidp_caps[report_id], "%d", NumberLinkCollectionNodes); - todo_wine check_member(caps, expect_hidp_caps[report_id], "%d", NumberInputButtonCaps); todo_wine check_member(caps, expect_hidp_caps[report_id], "%d", NumberInputValueCaps); @@ -1870,15 +1869,12 @@ static void test_hidp(HANDLE file, int report_id)
count = ARRAY_SIZE(button_caps); status = HidP_GetButtonCaps(HidP_Output, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetButtonCaps returned %#x\n", status); status = HidP_GetButtonCaps(HidP_Feature + 1, button_caps, &count, preparsed_data); ok(status == HIDP_STATUS_INVALID_REPORT_TYPE, "HidP_GetButtonCaps returned %#x\n", status); count = 0; status = HidP_GetButtonCaps(HidP_Input, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetButtonCaps returned %#x\n", status); - todo_wine ok(count == caps.NumberInputButtonCaps, "HidP_GetButtonCaps returned count %d, expected %d\n", count, caps.NumberInputButtonCaps); count = ARRAY_SIZE(button_caps); @@ -1893,50 +1889,18 @@ static void test_hidp(HANDLE file, int report_id) for (i = 0; i < ARRAY_SIZE(expect_button_caps); ++i) { winetest_push_context("button_caps[%d]", i); - todo_wine_if(i >= 2) - 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_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); - todo_wine_if(i >= (report_id ? 2 : 3)) - check_member(button_caps[i], expect_button_caps[i], "%04x", LinkUsage); - todo_wine_if(i >= (report_id ? 2 : 3)) - check_member(button_caps[i], expect_button_caps[i], "%04x", LinkUsagePage); - todo_wine_if(i >= 1 && i <= (report_id ? 2 : 1)) - check_member(button_caps[i], expect_button_caps[i], "%d", IsRange); - check_member(button_caps[i], expect_button_caps[i], "%d", IsStringRange); - check_member(button_caps[i], expect_button_caps[i], "%d", IsDesignatorRange); - todo_wine_if(i == 2) - check_member(button_caps[i], expect_button_caps[i], "%d", IsAbsolute); - todo_wine_if(i >= 1) - check_member(button_caps[i], expect_button_caps[i], "%04x", Range.UsageMin); - todo_wine_if(i >= 1) - check_member(button_caps[i], expect_button_caps[i], "%04x", Range.UsageMax); - check_member(button_caps[i], expect_button_caps[i], "%d", Range.StringMin); - check_member(button_caps[i], expect_button_caps[i], "%d", Range.StringMax); - check_member(button_caps[i], expect_button_caps[i], "%d", Range.DesignatorMin); - check_member(button_caps[i], expect_button_caps[i], "%d", Range.DesignatorMax); - todo_wine_if(i >= 1) - check_member(button_caps[i], expect_button_caps[i], "%d", Range.DataIndexMin); - todo_wine_if(i >= 1) - check_member(button_caps[i], expect_button_caps[i], "%d", Range.DataIndexMax); + check_hidp_button_caps(&button_caps[i], &expect_button_caps[i]); winetest_pop_context(); }
count = ARRAY_SIZE(button_caps) - 1; status = HidP_GetSpecificButtonCaps(HidP_Output, 0, 0, 0, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetSpecificButtonCaps returned %#x\n", status); status = HidP_GetSpecificButtonCaps(HidP_Feature + 1, 0, 0, 0, button_caps, &count, preparsed_data); ok(status == HIDP_STATUS_INVALID_REPORT_TYPE, "HidP_GetSpecificButtonCaps returned %#x\n", status); count = 0; status = HidP_GetSpecificButtonCaps(HidP_Input, 0, 0, 0, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetSpecificButtonCaps returned %#x\n", status); - todo_wine ok(count == caps.NumberInputButtonCaps, "HidP_GetSpecificButtonCaps returned count %d, expected %d\n", count, caps.NumberInputButtonCaps); count = ARRAY_SIZE(button_caps) - 1; @@ -1957,17 +1921,14 @@ static void test_hidp(HANDLE file, int report_id)
count = 0xbeef; status = HidP_GetSpecificButtonCaps(HidP_Input, 0xfffe, 0, 0, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetSpecificButtonCaps returned %#x\n", status); ok(count == 0, "HidP_GetSpecificButtonCaps returned count %d, expected %d\n", count, 0); count = 0xbeef; status = HidP_GetSpecificButtonCaps(HidP_Input, 0, 0xfffe, 0, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetSpecificButtonCaps returned %#x\n", status); ok(count == 0, "HidP_GetSpecificButtonCaps returned count %d, expected %d\n", count, 0); count = 0xbeef; status = HidP_GetSpecificButtonCaps(HidP_Input, 0, 0, 0xfffe, button_caps, &count, preparsed_data); - todo_wine ok(status == HIDP_STATUS_USAGE_NOT_FOUND, "HidP_GetSpecificButtonCaps returned %#x\n", status); ok(count == 0, "HidP_GetSpecificButtonCaps returned count %d, expected %d\n", count, 0);
diff --git a/include/wine/hid.h b/include/wine/hid.h index 5609adec11f..ceb07069b52 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -38,36 +38,6 @@ typedef struct __WINE_ELEMENT HIDP_VALUE_CAPS caps; } WINE_HID_ELEMENT;
-/* make sure HIDP_BUTTON_CAPS is a subset of HIDP_VALUE_CAPS */ -C_ASSERT( sizeof(HIDP_BUTTON_CAPS) == sizeof(HIDP_VALUE_CAPS) ); - -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, UsagePage) == offsetof(HIDP_VALUE_CAPS, UsagePage) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, ReportID) == offsetof(HIDP_VALUE_CAPS, ReportID) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, IsAlias) == offsetof(HIDP_VALUE_CAPS, IsAlias) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, BitField) == offsetof(HIDP_VALUE_CAPS, BitField) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, LinkCollection) == offsetof(HIDP_VALUE_CAPS, LinkCollection) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, LinkUsage) == offsetof(HIDP_VALUE_CAPS, LinkUsage) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, LinkUsagePage) == offsetof(HIDP_VALUE_CAPS, LinkUsagePage) ); - -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, IsRange) == offsetof(HIDP_VALUE_CAPS, IsRange) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, IsStringRange) == offsetof(HIDP_VALUE_CAPS, IsStringRange) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, IsDesignatorRange) == offsetof(HIDP_VALUE_CAPS, IsDesignatorRange) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, IsAbsolute) == offsetof(HIDP_VALUE_CAPS, IsAbsolute) ); - -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.UsageMin) == offsetof(HIDP_VALUE_CAPS, Range.UsageMin) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.UsageMax) == offsetof(HIDP_VALUE_CAPS, Range.UsageMax) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.StringMin) == offsetof(HIDP_VALUE_CAPS, Range.StringMin) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.StringMax) == offsetof(HIDP_VALUE_CAPS, Range.StringMax) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.DesignatorMin) == offsetof(HIDP_VALUE_CAPS, Range.DesignatorMin) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.DesignatorMax) == offsetof(HIDP_VALUE_CAPS, Range.DesignatorMax) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.DataIndexMin) == offsetof(HIDP_VALUE_CAPS, Range.DataIndexMin) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, Range.DataIndexMax) == offsetof(HIDP_VALUE_CAPS, Range.DataIndexMax) ); - -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.Usage) == offsetof(HIDP_VALUE_CAPS, NotRange.Usage) ); -C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.StringIndex) == offsetof(HIDP_VALUE_CAPS, NotRange.StringIndex) ); -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;
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=92825
Your paranoid android.
=== debiant2 (32 bit German report) ===
ntoskrnl.exe: ntoskrnl: Timeout
On 6/21/21 9:35 AM, Marvin wrote:
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=92825
Your paranoid android.
=== debiant2 (32 bit German report) ===
ntoskrnl.exe: ntoskrnl: Timeout
I don't think this is related to the changes, the tests randomly (but infrequently) get stuck after:
ntoskrnl.c:2718: Test marked todo: Got unexpected value 0.
Or is there something else wrong with the series?
On 6/23/21 2:42 AM, Rémi Bernon wrote:
On 6/21/21 9:35 AM, Marvin wrote:
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=92825
Your paranoid android.
=== debiant2 (32 bit German report) ===
ntoskrnl.exe: ntoskrnl: Timeout
I don't think this is related to the changes, the tests randomly (but infrequently) get stuck after:
ntoskrnl.c:2718: Test marked todo: Got unexpected value 0.
Or is there something else wrong with the series?
Yes, I believe this is https://bugs.winehq.org/show_bug.cgi?id=51295.