[PATCH v2 1/6] hidclass.sys: Implement button array value caps.

Rémi Bernon rbernon at codeweavers.com
Tue Aug 3 11:55:17 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at 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




More information about the wine-devel mailing list