Signed-off-by: Rémi Bernon <rbernon(a)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;
--
2.32.0