[PATCH 1/5] hid: Introduce new copy_bits helper for HidP_SetUsageValueArray.
Rémi Bernon
rbernon at codeweavers.com
Fri Jun 25 03:06:48 CDT 2021
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/hid/hidp.c | 70 ++++++++++++++++++++++++++++--
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 6 +--
2 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c
index 8d893f6327d..827de20c634 100644
--- a/dlls/hid/hidp.c
+++ b/dlls/hid/hidp.c
@@ -70,6 +70,7 @@ struct caps_filter
{
BOOLEAN buttons;
BOOLEAN values;
+ BOOLEAN array;
USAGE usage_page;
USHORT collection;
USAGE usage;
@@ -102,6 +103,7 @@ static NTSTATUS enum_value_caps( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_REPOR
{
if (!match_value_caps( caps, filter )) continue;
if (filter->report_id && caps->report_id != filter->report_id) continue;
+ else if (filter->array && (caps->is_range || caps->report_count <= 1)) return HIDP_STATUS_NOT_VALUE_ARRAY;
else if (remaining-- > 0) status = callback( caps, user );
}
@@ -114,6 +116,44 @@ static NTSTATUS enum_value_caps( WINE_HIDP_PREPARSED_DATA *preparsed, HIDP_REPOR
return HIDP_STATUS_SUCCESS;
}
+/* copy count bits from src, starting at (-shift) bit if < 0, to dst starting at (shift) bit if > 0 */
+static void copy_bits( unsigned char *dst, const unsigned char *src, int count, int shift )
+{
+ unsigned char bits, mask;
+ size_t src_shift = shift < 0 ? (-shift & 7) : 0;
+ size_t dst_shift = shift > 0 ? (shift & 7) : 0;
+ if (shift < 0) src += -shift / 8;
+ if (shift > 0) dst += shift / 8;
+
+ if (src_shift == 0 && dst_shift == 0)
+ {
+ memcpy( dst, src, count / 8 );
+ dst += count / 8;
+ src += count / 8;
+ count &= 7;
+ }
+
+ if (!count) return;
+
+ bits = *dst << (8 - dst_shift);
+ count += dst_shift;
+
+ while (count > 8)
+ {
+ *dst = bits >> (8 - dst_shift);
+ bits = *(unsigned short *)src++ >> src_shift;
+ *dst++ |= bits << dst_shift;
+ count -= 8;
+ }
+
+ bits >>= (8 - dst_shift);
+ if (count <= 8 - src_shift) bits |= (*src >> src_shift) << dst_shift;
+ else bits |= (*(unsigned short *)src >> src_shift) << dst_shift;
+
+ mask = (1 << count) - 1;
+ *dst = (bits & mask) | (*dst & ~mask);
+}
+
static NTSTATUS get_report_data(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value)
{
@@ -323,6 +363,13 @@ static NTSTATUS find_usage(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT
return HIDP_STATUS_USAGE_NOT_FOUND;
}
+struct usage_value_params
+{
+ void *value_buf;
+ USHORT value_len;
+ void *report_buf;
+};
+
static LONG sign_extend(ULONG value, const WINE_HID_ELEMENT *element)
{
UINT bit_count = element->bitCount;
@@ -514,6 +561,15 @@ ULONG WINAPI HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type, USAGE usage_
return count;
}
+static NTSTATUS set_usage_value( const struct hid_value_caps *caps, void *user )
+{
+ struct usage_value_params *params = user;
+ ULONG bit_count = caps->bit_size * caps->report_count;
+ if ((bit_count + 7) / 8 > params->value_len) return HIDP_STATUS_BUFFER_TOO_SMALL;
+ copy_bits( params->report_buf, params->value_buf, bit_count, caps->start_bit );
+ return HIDP_STATUS_NULL;
+}
+
NTSTATUS WINAPI HidP_SetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
USAGE Usage, ULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData,
CHAR *Report, ULONG ReportLength)
@@ -539,11 +595,19 @@ NTSTATUS WINAPI HidP_SetUsageValueArray( HIDP_REPORT_TYPE report_type, USAGE usa
USAGE usage, char *value_buf, USHORT value_len,
PHIDP_PREPARSED_DATA preparsed_data, char *report_buf, ULONG report_len )
{
- FIXME( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
- "preparsed_data %p, report_buf %p, report_len %u stub!\n",
+ struct usage_value_params params = {.value_buf = value_buf, .value_len = value_len, .report_buf = report_buf};
+ WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
+ struct caps_filter filter = {.values = TRUE, .array = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage};
+ USHORT count = 1;
+
+ TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value_buf %p, value_len %u, "
+ "preparsed_data %p, report_buf %p, report_len %u.\n",
report_type, usage_page, collection, usage, value_buf, value_len, preparsed_data, report_buf, report_len );
- return HIDP_STATUS_NOT_IMPLEMENTED;
+ if (!report_len) return HIDP_STATUS_INVALID_REPORT_LENGTH;
+
+ filter.report_id = report_buf[0];
+ return enum_value_caps( preparsed, report_type, report_len, &filter, set_usage_value, ¶ms, &count );
}
struct set_usage_params
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index ca030599299..3185b0f7893 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -2021,15 +2021,14 @@ static void test_hidp(HANDLE file, int report_id)
status = HidP_SetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, buffer,
sizeof(buffer), preparsed_data, report, caps.InputReportByteLength);
- todo_wine
ok(status == HIDP_STATUS_NOT_VALUE_ARRAY, "HidP_SetUsageValueArray returned %#x\n", status);
memset(buffer, 0xcd, sizeof(buffer));
status = HidP_SetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, buffer,
0, preparsed_data, report, caps.InputReportByteLength);
- todo_wine
ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_SetUsageValueArray returned %#x\n", status);
status = HidP_SetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, buffer,
8, preparsed_data, report, caps.InputReportByteLength);
+ todo_wine
ok(status == HIDP_STATUS_NOT_IMPLEMENTED, "HidP_SetUsageValueArray returned %#x\n", status);
status = HidP_GetUsageValueArray(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, buffer,
@@ -2365,13 +2364,10 @@ static void test_hidp(HANDLE file, int report_id)
memset(buffer, 0xff, sizeof(buffer));
status = HidP_SetUsageValueArray(HidP_Feature, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME, buffer,
0, preparsed_data, report, caps.FeatureReportByteLength);
- todo_wine
ok(status == HIDP_STATUS_BUFFER_TOO_SMALL, "HidP_SetUsageValueArray returned %#x\n", status);
status = HidP_SetUsageValueArray(HidP_Feature, HID_USAGE_PAGE_HAPTICS, 0, HID_USAGE_HAPTICS_WAVEFORM_CUTOFF_TIME, buffer,
64, preparsed_data, report, caps.FeatureReportByteLength);
- todo_wine
ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValueArray returned %#x\n", status);
- todo_wine
ok(!memcmp(report + 9, buffer, 8), "unexpected report data\n");
memset(buffer, 0, sizeof(buffer));
--
2.32.0
More information about the wine-devel
mailing list