Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Don't access IRP fields after IoCompleteRequest calls in PATCH 2.
dlls/hid/hidp.c | 62 +++++++++++++++++++++++++++++- dlls/hidclass.sys/descriptor.c | 11 ++++-- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 16 +++----- include/wine/hid.h | 1 + 4 files changed, 75 insertions(+), 15 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index 6a9fba6e425..a4e5afbbfcc 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -286,6 +286,18 @@ static NTSTATUS get_usage( const struct hid_value_caps *caps, void *user ) { struct get_usage_params *params = user; ULONG bit, last; + BYTE index; + + if (HID_VALUE_CAPS_IS_ARRAY( caps )) + { + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) + { + if (!(index = params->report_buf[bit / 8])) continue; + if (params->usages < params->usages_end) *params->usages = caps->usage_min + index - caps->start_index; + params->usages++; + } + return HIDP_STATUS_SUCCESS; + }
for (bit = caps->start_bit, last = bit + caps->usage_max - caps->usage_min; bit <= last; ++bit) { @@ -423,7 +435,22 @@ struct set_usage_params static NTSTATUS set_usage( const struct hid_value_caps *caps, void *user ) { struct set_usage_params *params = user; - ULONG bit = caps->start_bit + params->usage - caps->usage_min; + ULONG bit, last; + + if (HID_VALUE_CAPS_IS_ARRAY( caps )) + { + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) + { + if (params->report_buf[bit / 8]) continue; + params->report_buf[bit / 8] = caps->start_index + params->usage - caps->usage_min; + break; + } + + if (bit > last) return HIDP_STATUS_BUFFER_TOO_SMALL; + return HIDP_STATUS_NULL; + } + + bit = caps->start_bit + params->usage - caps->usage_min; params->report_buf[bit / 8] |= (1 << (bit % 8)); return HIDP_STATUS_NULL; } @@ -595,6 +622,22 @@ static NTSTATUS get_usage_and_page( const struct hid_value_caps *caps, void *use { struct get_usage_and_page_params *params = user; ULONG bit, last; + BYTE index; + + if (HID_VALUE_CAPS_IS_ARRAY( caps )) + { + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) + { + if (!(index = params->report_buf[bit / 8])) continue; + if (params->usages < params->usages_end) + { + params->usages->UsagePage = caps->usage_page; + params->usages->Usage = caps->usage_min + index - caps->start_index; + } + params->usages++; + } + return HIDP_STATUS_SUCCESS; + }
for (bit = caps->start_bit, last = bit + caps->usage_max - caps->usage_min; bit <= last; bit++) { @@ -667,9 +710,24 @@ static NTSTATUS find_all_data( const struct hid_value_caps *caps, void *user ) HIDP_DATA *data = params->data, *data_end = params->data_end; ULONG bit, last, bit_count = caps->bit_size * caps->report_count; char *report_buf = params->report_buf; + BYTE index;
if (!caps->bit_size) return HIDP_STATUS_SUCCESS; - if (caps->bit_size == 1) + + if (HID_VALUE_CAPS_IS_ARRAY( caps )) + { + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) + { + if (!(index = report_buf[bit / 8])) continue; + if (data < data_end) + { + data->DataIndex = caps->data_index_min + index - caps->start_index; + data->On = 1; + } + data++; + } + } + else if (HID_VALUE_CAPS_IS_BUTTON( caps )) { for (bit = caps->start_bit, last = bit + caps->usage_max - caps->usage_min; bit <= last; bit++) { diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index 986912990a7..f8bacbbbc1a 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -460,6 +460,7 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY USHORT *data_idx = state->data_idx[type]; ULONG *bit_size = &state->bit_size[type][state->items.report_id]; struct feature *feature; + BOOL is_array; int j;
for (j = 0; j < state->items.report_count; j++) @@ -496,10 +497,14 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY } value = state->values[type] + *value_idx;
- state->items.report_count -= usages_size - 1; + 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--) { - state->items.start_bit -= state->items.report_count * state->items.bit_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]; @@ -508,7 +513,7 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY 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; + if (!is_array) state->items.report_count = 1; }
state->items.usage_page = usage_page; diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 401401bbffe..892e839fa56 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -2229,10 +2229,10 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled memcpy(buffer, report, caps.InputReportByteLength); status = HidP_SetUsages(HidP_Input, HID_USAGE_PAGE_KEYBOARD, 0, usages, &value, preparsed_data, report, caps.InputReportByteLength); - todo_wine ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_SetUsages returned %#x\n", status); + ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_SetUsages returned %#x\n", status); buffer[6] = 2; buffer[7] = 4; - todo_wine ok(!memcmp(buffer, report, caps.InputReportByteLength), "unexpected report data\n"); + ok(!memcmp(buffer, report, caps.InputReportByteLength), "unexpected report data\n");
status = HidP_SetUsageValue(HidP_Input, HID_USAGE_PAGE_LED, 0, 6, 1, preparsed_data, report, caps.InputReportByteLength); @@ -2272,7 +2272,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled status = HidP_GetUsagesEx(HidP_Input, 0, usage_and_pages, &value, preparsed_data, report, caps.InputReportByteLength); ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsagesEx returned %#x\n", status); - todo_wine ok(value == 6, "got usage count %d, expected %d\n", value, 4); + ok(value == 6, "got usage count %d, expected %d\n", value, 4); 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); ok(usage_and_pages[1].UsagePage == HID_USAGE_PAGE_BUTTON, "got usage_and_pages[1] UsagePage %x, expected %x\n", @@ -2281,7 +2281,6 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled usage_and_pages[2].UsagePage, HID_USAGE_PAGE_KEYBOARD); ok(usage_and_pages[3].UsagePage == HID_USAGE_PAGE_KEYBOARD, "got usage_and_pages[3] UsagePage %x, expected %x\n", usage_and_pages[3].UsagePage, HID_USAGE_PAGE_KEYBOARD); - todo_wine ok(usage_and_pages[4].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[4] UsagePage %x, expected %x\n", usage_and_pages[4].UsagePage, HID_USAGE_PAGE_LED); ok(usage_and_pages[5].UsagePage == HID_USAGE_PAGE_LED, "got usage_and_pages[5] UsagePage %x, expected %x\n", @@ -2292,13 +2291,10 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled usage_and_pages[1].Usage, 6); ok(usage_and_pages[2].Usage == 9, "got usage_and_pages[2] Usage %x, expected %x\n", usage_and_pages[2].Usage, 9); - todo_wine ok(usage_and_pages[3].Usage == 11, "got usage_and_pages[3] Usage %x, expected %x\n", usage_and_pages[3].Usage, 11); - todo_wine ok(usage_and_pages[4].Usage == 6, "got usage_and_pages[4] Usage %x, expected %x\n", usage_and_pages[4].Usage, 6); - todo_wine ok(usage_and_pages[5].Usage == 4, "got usage_and_pages[5] Usage %x, expected %x\n", usage_and_pages[5].Usage, 4);
@@ -2314,15 +2310,15 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled value = 1; status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength); ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_GetData returned %#x\n", status); - todo_wine ok(value == 11, "got data count %d, expected %d\n", value, 11); + ok(value == 11, "got data count %d, expected %d\n", value, 11); memset(data, 0, sizeof(data)); status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength); ok(status == HIDP_STATUS_SUCCESS, "HidP_GetData returned %#x\n", status); for (i = 0; i < ARRAY_SIZE(expect_data); ++i) { winetest_push_context("data[%d]", i); - todo_wine_if(i >= 4) check_member(data[i], expect_data[i], "%d", DataIndex); - todo_wine_if(i >= 4) check_member(data[i], expect_data[i], "%d", RawValue); + check_member(data[i], expect_data[i], "%d", DataIndex); + check_member(data[i], expect_data[i], "%d", RawValue); winetest_pop_context(); }
diff --git a/include/wine/hid.h b/include/wine/hid.h index b15b26474a0..ade9681ab7d 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -60,6 +60,7 @@ struct hid_value_caps USHORT bit_size; USHORT report_count; ULONG start_bit; + ULONG start_index; LONG logical_min; LONG logical_max; LONG physical_min;