Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/Makefile.in | 3 +- dlls/hidclass.sys/descriptor.c | 602 --------------------------------- dlls/hidclass.sys/device.c | 88 ++--- dlls/hidclass.sys/hid.h | 6 +- dlls/hidclass.sys/pnp.c | 27 +- 5 files changed, 65 insertions(+), 661 deletions(-) delete mode 100644 dlls/hidclass.sys/descriptor.c
diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in index 344fd10bc86..a6a131df87e 100644 --- a/dlls/hidclass.sys/Makefile.in +++ b/dlls/hidclass.sys/Makefile.in @@ -1,10 +1,9 @@ MODULE = hidclass.sys IMPORTLIB = hidclass -IMPORTS = hal ntoskrnl user32 +IMPORTS = hal ntoskrnl user32 hidparse
EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ - descriptor.c \ device.c \ pnp.c diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c deleted file mode 100644 index 546e589d01b..00000000000 --- a/dlls/hidclass.sys/descriptor.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * HID descriptor parsing - * - * Copyright (C) 2015 Aric Stewart - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include <stdarg.h> -#include <stdlib.h> -#include <stdio.h> -#include "hid.h" - -#include "wine/debug.h" -#include "wine/list.h" - -WINE_DEFAULT_DEBUG_CHANNEL(hid); - -/* Flags that are defined in the document - "Device Class Definition for Human Interface Devices" */ -enum { - INPUT_DATA_CONST = 0x01, /* Data (0) | Constant (1) */ - INPUT_ARRAY_VAR = 0x02, /* Array (0) | Variable (1) */ - INPUT_ABS_REL = 0x04, /* Absolute (0) | Relative (1) */ - INPUT_WRAP = 0x08, /* No Wrap (0) | Wrap (1) */ - INPUT_LINEAR = 0x10, /* Linear (0) | Non Linear (1) */ - INPUT_PREFSTATE = 0x20, /* Preferred State (0) | No Preferred (1) */ - INPUT_NULL = 0x40, /* No Null position (0) | Null state(1) */ - INPUT_VOLATILE = 0x80, /* Non Volatile (0) | Volatile (1) */ - INPUT_BITFIELD = 0x100 /* Bit Field (0) | Buffered Bytes (1) */ -}; - -enum { - TAG_TYPE_MAIN = 0x0, - TAG_TYPE_GLOBAL, - TAG_TYPE_LOCAL, - TAG_TYPE_RESERVED, -}; - -enum { - TAG_MAIN_INPUT = 0x08, - TAG_MAIN_OUTPUT = 0x09, - TAG_MAIN_FEATURE = 0x0B, - TAG_MAIN_COLLECTION = 0x0A, - TAG_MAIN_END_COLLECTION = 0x0C -}; - -enum { - TAG_GLOBAL_USAGE_PAGE = 0x0, - TAG_GLOBAL_LOGICAL_MINIMUM, - TAG_GLOBAL_LOGICAL_MAXIMUM, - TAG_GLOBAL_PHYSICAL_MINIMUM, - TAG_GLOBAL_PHYSICAL_MAXIMUM, - TAG_GLOBAL_UNIT_EXPONENT, - TAG_GLOBAL_UNIT, - TAG_GLOBAL_REPORT_SIZE, - TAG_GLOBAL_REPORT_ID, - TAG_GLOBAL_REPORT_COUNT, - TAG_GLOBAL_PUSH, - TAG_GLOBAL_POP -}; - -enum { - TAG_LOCAL_USAGE = 0x0, - TAG_LOCAL_USAGE_MINIMUM, - TAG_LOCAL_USAGE_MAXIMUM, - TAG_LOCAL_DESIGNATOR_INDEX, - TAG_LOCAL_DESIGNATOR_MINIMUM, - TAG_LOCAL_DESIGNATOR_MAXIMUM, - TAG_LOCAL_STRING_INDEX, - TAG_LOCAL_STRING_MINIMUM, - TAG_LOCAL_STRING_MAXIMUM, - TAG_LOCAL_DELIMITER -}; - -static inline const char *debugstr_hid_value_caps( struct hid_value_caps *caps ) -{ - if (!caps) return "(null)"; - return wine_dbg_sprintf( "RId %d, Usg %02x:%02x-%02x Dat %02x-%02x (%d), Str %d-%d (%d), Des %d-%d (%d), " - "Bits %02x, LCol %d LUsg %02x:%02x, BitSz %d, RCnt %d, Unit %x E%+d, Log %+d-%+d, Phy %+d-%+d", - caps->report_id, caps->usage_page, caps->usage_min, caps->usage_max, caps->data_index_min, caps->data_index_max, caps->is_range, - caps->string_min, caps->string_max, caps->is_string_range, caps->designator_min, caps->designator_max, caps->is_designator_range, - caps->bit_field, caps->link_collection, caps->link_usage_page, caps->link_usage, caps->bit_size, caps->report_count, - caps->units, caps->units_exp, caps->logical_min, caps->logical_max, caps->physical_min, caps->physical_max ); -} - -static void debug_print_preparsed( struct hid_preparsed_data *data ) -{ - unsigned int i, end; - if (TRACE_ON(hid)) - { - TRACE( "START PREPARSED Data <<< Usage: %i, UsagePage: %i, " - "InputReportByteLength: %i, tOutputReportByteLength: %i, " - "FeatureReportByteLength: %i, NumberLinkCollectionNodes: %i, " - "NumberInputButtonCaps: %i, NumberInputValueCaps: %i, " - "NumberInputDataIndices: %i, NumberOutputButtonCaps: %i, " - "NumberOutputValueCaps: %i, NumberOutputDataIndices: %i, " - "NumberFeatureButtonCaps: %i, NumberFeatureValueCaps: %i, " - "NumberFeatureDataIndices: %i\n", - data->caps.Usage, data->caps.UsagePage, data->caps.InputReportByteLength, - data->caps.OutputReportByteLength, data->caps.FeatureReportByteLength, - data->caps.NumberLinkCollectionNodes, data->caps.NumberInputButtonCaps, - data->caps.NumberInputValueCaps, data->caps.NumberInputDataIndices, - data->caps.NumberOutputButtonCaps, data->caps.NumberOutputValueCaps, - data->caps.NumberOutputDataIndices, data->caps.NumberFeatureButtonCaps, - data->caps.NumberFeatureValueCaps, data->caps.NumberFeatureDataIndices ); - end = data->value_caps_count[HidP_Input]; - for (i = 0; i < end; i++) TRACE( "INPUT: %s\n", debugstr_hid_value_caps( HID_INPUT_VALUE_CAPS( data ) + i ) ); - end = data->value_caps_count[HidP_Output]; - for (i = 0; i < end; i++) TRACE( "OUTPUT: %s\n", debugstr_hid_value_caps( HID_OUTPUT_VALUE_CAPS( data ) + i ) ); - end = data->value_caps_count[HidP_Feature]; - for (i = 0; i < end; i++) TRACE( "FEATURE: %s\n", debugstr_hid_value_caps( HID_FEATURE_VALUE_CAPS( data ) + i ) ); - end = data->caps.NumberLinkCollectionNodes; - for (i = 0; i < end; i++) TRACE( "COLLECTION: %s\n", debugstr_hid_value_caps( HID_COLLECTION_VALUE_CAPS( data ) + i ) ); - TRACE(">>> END Preparsed Data\n"); - } -} - -struct hid_parser_state -{ - HIDP_CAPS caps; - - USAGE usages_page[256]; - USAGE usages_min[256]; - USAGE usages_max[256]; - DWORD usages_size; - - struct hid_value_caps items; - - struct hid_value_caps *stack; - DWORD stack_size; - DWORD global_idx; - DWORD collection_idx; - - 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 ) -{ - 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 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 ); - 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; -} - -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_page, USAGE 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 )) - { - ERR( "HID parser stack overflow!\n" ); - return FALSE; - } - - if (!array_reserve( &state->collections, &state->collections_size, state->caps.NumberLinkCollectionNodes )) - { - ERR( "HID parser collections overflow!\n" ); - return FALSE; - } - - 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; - state->items.link_usage = state->items.usage_min; - if (!state->caps.NumberLinkCollectionNodes) - { - state->caps.UsagePage = state->items.usage_page; - state->caps.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 BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TYPE type ) -{ - 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]; - BOOL is_array; - - 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 ); - state->items.start_bit = *bit_size; - - 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.start_index = 0; - if (!(is_array = HID_VALUE_CAPS_IS_ARRAY( &state->items ))) state->items.report_count -= usages_size - 1; - else state->items.start_bit -= state->items.report_count * state->items.bit_size; - - while (usages_size--) - { - if (!is_array) state->items.start_bit -= state->items.report_count * state->items.bit_size; - else state->items.start_index += 1; - 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; - if (!is_array) state->items.report_count = 1; - } - - state->items.usage_page = usage_page; - 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; - - 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 ) -{ - 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->collections ); - free( state->values[HidP_Input] ); - free( state->values[HidP_Output] ); - free( state->values[HidP_Feature] ); - free( state ); -} - -static struct hid_preparsed_data *build_preparsed_data( struct hid_parser_state *state ) -{ - struct hid_preparsed_data *data; - struct hid_value_caps *caps; - DWORD i, button, filler, caps_len, size; - - caps_len = state->caps.NumberInputValueCaps + state->caps.NumberOutputValueCaps + - state->caps.NumberFeatureValueCaps + state->caps.NumberLinkCollectionNodes; - size = FIELD_OFFSET( struct hid_preparsed_data, value_caps[caps_len] ); - - if (!(data = calloc( 1, size ))) return NULL; - data->magic = HID_MAGIC; - data->size = size; - data->caps = state->caps; - 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; - - /* fixup value vs button vs filler counts */ - - caps = HID_INPUT_VALUE_CAPS( data ); - memcpy( caps, state->values[0], data->caps.NumberInputValueCaps * sizeof(*caps) ); - for (i = 0, button = 0, filler = 0; i < data->caps.NumberInputValueCaps; ++i) - { - if (!caps[i].usage_min && !caps[i].usage_max) filler++; - else if (HID_VALUE_CAPS_IS_BUTTON( caps + i )) button++; - } - data->caps.NumberInputButtonCaps = button; - data->caps.NumberInputValueCaps -= filler + button; - - caps = HID_OUTPUT_VALUE_CAPS( data ); - memcpy( caps, state->values[1], data->caps.NumberOutputValueCaps * sizeof(*caps) ); - for (i = 0, button = 0, filler = 0; i < data->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->caps.NumberOutputValueCaps; - data->caps.NumberOutputButtonCaps = button; - data->caps.NumberOutputValueCaps -= filler + button; - - caps = HID_FEATURE_VALUE_CAPS( data ); - memcpy( caps, state->values[2], data->caps.NumberFeatureValueCaps * sizeof(*caps) ); - for (i = 0, button = 0, filler = 0; i < data->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->caps.NumberFeatureValueCaps; - data->caps.NumberFeatureButtonCaps = button; - data->caps.NumberFeatureValueCaps -= filler + button; - - caps = HID_COLLECTION_VALUE_CAPS( data ); - memcpy( caps, state->collections, data->caps.NumberLinkCollectionNodes * sizeof(*caps) ); - - return data; -} - -struct hid_preparsed_data *parse_descriptor( BYTE *descriptor, unsigned int length ) -{ - struct hid_preparsed_data *data = NULL; - struct hid_parser_state *state; - UINT32 size, value; - INT32 signed_value; - BYTE *ptr, *end; - int i; - - if (TRACE_ON( hid )) - { - TRACE( "descriptor %p, length %u:\n", descriptor, length ); - for (i = 0; i < length;) - { - TRACE( "%08x ", i ); - do { TRACE( " %02x", descriptor[i] ); } while (++i % 16 && i < length); - TRACE( "\n" ); - } - } - - if (!(state = calloc( 1, sizeof(*state) ))) return NULL; - init_parser_state( state ); - - for (ptr = descriptor, end = descriptor + length; ptr != end; ptr += size + 1) - { - size = (*ptr & 0x03); - if (size == 3) size = 4; - if (ptr + size > end) - { - ERR("Need %d bytes to read item value\n", size); - goto done; - } - - if (size == 0) signed_value = value = 0; - else if (size == 1) signed_value = (INT8)(value = *(UINT8 *)(ptr + 1)); - else if (size == 2) signed_value = (INT16)(value = *(UINT16 *)(ptr + 1)); - else if (size == 4) signed_value = (INT32)(value = *(UINT32 *)(ptr + 1)); - else - { - ERR("Unexpected item value size %d.\n", size); - goto done; - } - - state->items.bit_field = value; - -#define SHORT_ITEM(tag,type) (((tag)<<4)|((type)<<2)) - switch (*ptr & SHORT_ITEM(0xf,0x3)) - { - case SHORT_ITEM(TAG_MAIN_INPUT, TAG_TYPE_MAIN): - if (!parse_new_value_caps( state, HidP_Input )) goto done; - break; - case SHORT_ITEM(TAG_MAIN_OUTPUT, TAG_TYPE_MAIN): - if (!parse_new_value_caps( state, HidP_Output )) goto done; - break; - case SHORT_ITEM(TAG_MAIN_FEATURE, TAG_TYPE_MAIN): - if (!parse_new_value_caps( state, HidP_Feature )) goto done; - break; - case SHORT_ITEM(TAG_MAIN_COLLECTION, TAG_TYPE_MAIN): - if (!parse_new_collection( state )) goto done; - break; - case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN): - if (!parse_end_collection( state )) goto done; - break; - - case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL): - state->items.usage_page = value; - break; - case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MINIMUM, TAG_TYPE_GLOBAL): - state->items.logical_min = signed_value; - break; - case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MAXIMUM, TAG_TYPE_GLOBAL): - state->items.logical_max = signed_value; - break; - case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MINIMUM, TAG_TYPE_GLOBAL): - state->items.physical_min = signed_value; - break; - case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MAXIMUM, TAG_TYPE_GLOBAL): - state->items.physical_max = signed_value; - break; - case SHORT_ITEM(TAG_GLOBAL_UNIT_EXPONENT, TAG_TYPE_GLOBAL): - state->items.units_exp = signed_value; - break; - case SHORT_ITEM(TAG_GLOBAL_UNIT, TAG_TYPE_GLOBAL): - state->items.units = signed_value; - break; - case SHORT_ITEM(TAG_GLOBAL_REPORT_SIZE, TAG_TYPE_GLOBAL): - state->items.bit_size = value; - break; - case SHORT_ITEM(TAG_GLOBAL_REPORT_ID, TAG_TYPE_GLOBAL): - state->items.report_id = value; - break; - case SHORT_ITEM(TAG_GLOBAL_REPORT_COUNT, TAG_TYPE_GLOBAL): - state->items.report_count = value; - break; - case SHORT_ITEM(TAG_GLOBAL_PUSH, TAG_TYPE_GLOBAL): - if (!parse_global_push( state )) goto done; - break; - case SHORT_ITEM(TAG_GLOBAL_POP, TAG_TYPE_GLOBAL): - if (!parse_global_pop( state )) goto done; - break; - - case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL): - if (!parse_local_usage( state, value >> 16, value & 0xffff )) goto done; - break; - case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL): - parse_local_usage_min( state, value >> 16, value & 0xffff ); - break; - case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL): - 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; - state->items.is_designator_range = FALSE; - break; - case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MINIMUM, TAG_TYPE_LOCAL): - state->items.designator_min = value; - state->items.is_designator_range = TRUE; - break; - case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MAXIMUM, TAG_TYPE_LOCAL): - state->items.designator_max = value; - state->items.is_designator_range = TRUE; - break; - case SHORT_ITEM(TAG_LOCAL_STRING_INDEX, TAG_TYPE_LOCAL): - 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): - state->items.string_min = value; - state->items.is_string_range = TRUE; - break; - case SHORT_ITEM(TAG_LOCAL_STRING_MAXIMUM, TAG_TYPE_LOCAL): - 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); - goto done; - - default: - FIXME( "item type %x not implemented!\n", *ptr ); - goto done; - } -#undef SHORT_ITEM - } - - if ((data = build_preparsed_data( state ))) debug_print_preparsed( data ); - -done: - free_parser_state( state ); - return data; -} diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 84eda78019c..ed7cd76fcde 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -181,7 +181,7 @@ static struct hid_report *hid_report_queue_pop( struct hid_report_queue *queue ) static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *packet ) { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - struct hid_preparsed_data *preparsed = ext->u.pdo.preparsed_data; + HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; struct hid_report *last_report, *report; struct hid_report_queue *queue; RAWINPUT *rawinput; @@ -228,7 +228,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack queue = irp->Tail.Overlay.OriginalFileObject->FsContext;
if (!(report = hid_report_queue_pop( queue ))) hid_report_incref( (report = last_report) ); - memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, preparsed->caps.InputReportByteLength ); + memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length; irp->IoStatus.Status = STATUS_SUCCESS; hid_report_decref( report ); @@ -243,25 +243,34 @@ static DWORD CALLBACK hid_device_thread(void *args) { DEVICE_OBJECT *device = (DEVICE_OBJECT*)args; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - struct hid_preparsed_data *preparsed = ext->u.pdo.preparsed_data; - BYTE report_id = HID_INPUT_VALUE_CAPS( preparsed )->report_id; - ULONG buffer_len = preparsed->caps.InputReportByteLength; + HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; + HIDP_REPORT_IDS *reports = ext->u.pdo.device_desc.ReportIDs; + ULONG report_count = ext->u.pdo.device_desc.ReportIDsLength; + ULONG i, report_id = 0, poll_interval = 0; HID_XFER_PACKET *packet; - ULONG poll_interval = 0; IO_STATUS_BLOCK io; BYTE *buffer; DWORD res;
- packet = malloc( sizeof(*packet) + buffer_len ); + packet = malloc( sizeof(*packet) + desc->InputLength ); buffer = (BYTE *)(packet + 1); packet->reportBuffer = buffer;
if (ext->u.pdo.information.Polled) poll_interval = ext->u.pdo.poll_interval;
+ for (i = 0; i < report_count; ++i) + { + if (!reports[i].ReportID || reports[i].InputLength) + break; + } + + if (i == report_count) WARN("no input report found.\n"); + else report_id = reports[i].ReportID; + do { packet->reportId = buffer[0] = report_id; - packet->reportBufferLen = buffer_len; + packet->reportBufferLen = desc->InputLength;
if (!report_id) { @@ -318,18 +327,18 @@ static void handle_IOCTL_HID_GET_COLLECTION_INFORMATION( IRP *irp, BASE_DEVICE_E
static void handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( IRP *irp, BASE_DEVICE_EXTENSION *ext ) { + HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp ); - struct hid_preparsed_data *preparsed = ext->u.pdo.preparsed_data;
- if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < preparsed->size) + if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < desc->PreparsedDataLength) { irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE; irp->IoStatus.Information = 0; } else { - memcpy( irp->UserBuffer, preparsed, preparsed->size ); - irp->IoStatus.Information = preparsed->size; + memcpy( irp->UserBuffer, desc->PreparsedData, desc->PreparsedDataLength ); + irp->IoStatus.Information = desc->PreparsedDataLength; irp->IoStatus.Status = STATUS_SUCCESS; } } @@ -357,10 +366,10 @@ static void handle_minidriver_string( BASE_DEVICE_EXTENSION *ext, IRP *irp, SHOR
static void hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP *irp ) { - struct hid_preparsed_data *preparsed = ext->u.pdo.preparsed_data; + HIDP_REPORT_IDS *reports = ext->u.pdo.device_desc.ReportIDs; + ULONG report_count = ext->u.pdo.device_desc.ReportIDsLength; IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp ); - struct hid_value_caps *caps = NULL, *caps_end = NULL; - ULONG report_len = 0, buffer_len = 0; + ULONG i, report_len = 0, buffer_len = 0; HID_XFER_PACKET packet; BYTE *buffer = NULL;
@@ -381,51 +390,48 @@ static void hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP buffer = irp->AssociatedIrp.SystemBuffer; break; } + if (!buffer || !buffer_len) + { + irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; + return; + } + + for (i = 0; i < report_count; ++i) + { + if (!reports[i].ReportID || reports[i].ReportID == buffer[0]) + break; + } + if (i == report_count) + { + irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + return; + }
switch (code) { case IOCTL_HID_GET_INPUT_REPORT: - report_len = preparsed->caps.InputReportByteLength; - caps = HID_INPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->value_caps_count[HidP_Input]; + report_len = reports[i].InputLength; break; case IOCTL_HID_SET_OUTPUT_REPORT: case IOCTL_HID_WRITE_REPORT: - report_len = preparsed->caps.OutputReportByteLength; - caps = HID_OUTPUT_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->value_caps_count[HidP_Output]; + report_len = reports[i].OutputLength; break; case IOCTL_HID_GET_FEATURE: case IOCTL_HID_SET_FEATURE: - report_len = preparsed->caps.FeatureReportByteLength; - caps = HID_FEATURE_VALUE_CAPS( preparsed ); - caps_end = caps + preparsed->value_caps_count[HidP_Feature]; + report_len = reports[i].FeatureLength; break; } - - if (!buffer || !buffer_len) - { - irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; - return; - } if (buffer_len < report_len) { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; return; }
- for (; caps != caps_end; ++caps) if (!caps->report_id || caps->report_id == buffer[0]) break; - if (caps == caps_end) - { - irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - return; - } - packet.reportId = buffer[0]; packet.reportBuffer = buffer; packet.reportBufferLen = buffer_len;
- if (!caps->report_id) + if (!reports[i].ReportID) { packet.reportId = 0; packet.reportBuffer++; @@ -575,7 +581,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) { struct hid_report_queue *queue = irp->Tail.Overlay.OriginalFileObject->FsContext; BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; - struct hid_preparsed_data *preparsed = ext->u.pdo.preparsed_data; + HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); struct hid_report *report; NTSTATUS status; @@ -593,7 +599,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) return STATUS_DELETE_PENDING; }
- if (irpsp->Parameters.Read.Length < preparsed->caps.InputReportByteLength) + if (irpsp->Parameters.Read.Length < desc->InputLength) { irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE; IoCompleteRequest( irp, IO_NO_INCREMENT ); @@ -603,7 +609,7 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) irp->IoStatus.Information = 0; if ((report = hid_report_queue_pop( queue ))) { - memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, preparsed->caps.InputReportByteLength ); + memcpy( irp->AssociatedIrp.SystemBuffer, report->buffer, desc->InputLength ); irp->IoStatus.Information = report->length; irp->IoStatus.Status = STATUS_SUCCESS; hid_report_decref( report ); diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 2dfdfe4d0f7..1ca6a926872 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -27,6 +27,7 @@ #include "ddk/hidport.h" #include "ddk/hidclass.h" #include "ddk/hidpi.h" +#include "ddk/hidpddi.h" #include "cfgmgr32.h" #include "wine/list.h" #include "wine/hid.h" @@ -54,7 +55,7 @@ typedef struct _BASE_DEVICE_EXTENSION DEVICE_OBJECT *parent_fdo;
HID_COLLECTION_INFORMATION information; - struct hid_preparsed_data *preparsed_data; + HIDP_DEVICE_DESC device_desc;
ULONG poll_interval; HANDLE halt_event; @@ -129,6 +130,3 @@ NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp) DECLSPEC_HIDDEN; - -/* Parsing HID Report Descriptors into preparsed data */ -struct hid_preparsed_data *parse_descriptor( BYTE *descriptor, unsigned int length ) DECLSPEC_HIDDEN; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 9752a47326f..db45aea2fd3 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -109,6 +109,7 @@ C_ASSERT(offsetof(RAWINPUT, data.hid.bRawData[2 * sizeof(USAGE)]) < sizeof(RAWIN
static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param) { + HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; RAWINPUT rawinput; INPUT input;
@@ -118,8 +119,8 @@ static void send_wm_input_device_change(BASE_DEVICE_EXTENSION *ext, LPARAM param rawinput.header.wParam = param; rawinput.data.hid.dwCount = 0; rawinput.data.hid.dwSizeHid = 0; - ((USAGE *)rawinput.data.hid.bRawData)[0] = ext->u.pdo.preparsed_data->caps.UsagePage; - ((USAGE *)rawinput.data.hid.bRawData)[1] = ext->u.pdo.preparsed_data->caps.Usage; + ((USAGE *)rawinput.data.hid.bRawData)[0] = desc->UsagePage; + ((USAGE *)rawinput.data.hid.bRawData)[1] = desc->Usage;
input.type = INPUT_HARDWARE; input.hi.uMsg = WM_INPUT_DEVICE_CHANGE; @@ -183,6 +184,7 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) { BASE_DEVICE_EXTENSION *fdo_ext = fdo->DeviceExtension, *pdo_ext; HID_DEVICE_ATTRIBUTES attr = {0}; + HIDP_COLLECTION_DESC *desc; HID_DESCRIPTOR descriptor; DEVICE_OBJECT *child_pdo; BYTE *reportDescriptor; @@ -253,19 +255,21 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) return; }
- pdo_ext->u.pdo.preparsed_data = parse_descriptor( reportDescriptor, descriptor.DescriptorList[i].wReportLength ); + io.Status = HidP_GetCollectionDescription( reportDescriptor, descriptor.DescriptorList[i].wReportLength, + PagedPool, &pdo_ext->u.pdo.device_desc ); free(reportDescriptor); - if (!pdo_ext->u.pdo.preparsed_data) + if (io.Status != HIDP_STATUS_SUCCESS) { ERR("Cannot parse Report Descriptor\n"); IoDeleteDevice(child_pdo); return; }
- pdo_ext->u.pdo.information.DescriptorSize = pdo_ext->u.pdo.preparsed_data->size; + desc = pdo_ext->u.pdo.device_desc.CollectionDesc; + pdo_ext->u.pdo.information.DescriptorSize = desc->PreparsedDataLength;
- page = pdo_ext->u.pdo.preparsed_data->caps.UsagePage; - usage = pdo_ext->u.pdo.preparsed_data->caps.Usage; + page = desc->UsagePage; + usage = desc->Usage; if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE) pdo_ext->u.pdo.rawinput_handle = WINE_MOUSE_HANDLE; else if (page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD) @@ -374,6 +378,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) { IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp); BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + HIDP_COLLECTION_DESC *desc = ext->u.pdo.device_desc.CollectionDesc; NTSTATUS status = irp->IoStatus.Status; KIRQL irql;
@@ -447,14 +452,12 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) }
/* FIXME: This should probably be done in mouhid.sys. */ - if (ext->u.pdo.preparsed_data->caps.UsagePage == HID_USAGE_PAGE_GENERIC - && ext->u.pdo.preparsed_data->caps.Usage == HID_USAGE_GENERIC_MOUSE) + if (desc->UsagePage == HID_USAGE_PAGE_GENERIC && desc->Usage == HID_USAGE_GENERIC_MOUSE) { if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_MOUSE, NULL, &ext->u.pdo.mouse_link_name)) ext->u.pdo.is_mouse = TRUE; } - if (ext->u.pdo.preparsed_data->caps.UsagePage == HID_USAGE_PAGE_GENERIC - && ext->u.pdo.preparsed_data->caps.Usage == HID_USAGE_GENERIC_KEYBOARD) + if (desc->UsagePage == HID_USAGE_PAGE_GENERIC && desc->Usage == HID_USAGE_GENERIC_KEYBOARD) { if (!IoRegisterDeviceInterface(device, &GUID_DEVINTERFACE_KEYBOARD, NULL, &ext->u.pdo.keyboard_link_name)) ext->u.pdo.is_keyboard = TRUE; @@ -488,7 +491,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device, IRP *irp) } CloseHandle(ext->u.pdo.halt_event);
- free(ext->u.pdo.preparsed_data); + HidP_FreeCollectionDescription(&ext->u.pdo.device_desc);
RtlFreeUnicodeString(&ext->u.pdo.link_name);