[PATCH 4/4] hid: Implement HidP_SetScaledUsageValue.
Rémi Bernon
rbernon at codeweavers.com
Wed Aug 25 11:08:33 CDT 2021
The function seems to actually do overflows and rounding errors.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
It's so nasty that I'm not even sure anymore that I'll use it, but here
we go anyway.
dlls/hid/hid.spec | 2 +-
dlls/hid/hidp.c | 47 +++++++++++++++
dlls/ntoskrnl.exe/tests/driver_hid.c | 10 ++++
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 86 +++++++++++++++++++++++++---
include/ddk/hidpi.h | 1 +
5 files changed, 138 insertions(+), 8 deletions(-)
diff --git a/dlls/hid/hid.spec b/dlls/hid/hid.spec
index 5d4706e3727..37dfdbce307 100644
--- a/dlls/hid/hid.spec
+++ b/dlls/hid/hid.spec
@@ -35,7 +35,7 @@
@ stdcall HidP_MaxDataListLength(long ptr)
@ stdcall HidP_MaxUsageListLength(long long ptr)
@ stub HidP_SetData
-@ stub HidP_SetScaledUsageValue
+@ stdcall HidP_SetScaledUsageValue(long long long long long ptr ptr long)
@ stdcall HidP_SetUsageValue(long long long long long ptr ptr long)
@ stdcall HidP_SetUsageValueArray(long long long long ptr long ptr ptr long)
@ stdcall HidP_SetUsages(long long long ptr ptr ptr ptr long)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c
index 8c43d27f252..cd9de2148c2 100644
--- a/dlls/hid/hidp.c
+++ b/dlls/hid/hidp.c
@@ -380,6 +380,53 @@ ULONG WINAPI HidP_MaxUsageListLength( HIDP_REPORT_TYPE report_type, USAGE usage_
return count;
}
+static NTSTATUS set_scaled_usage_value( const struct hid_value_caps *caps, void *user )
+{
+ ULONG bit_count = caps->bit_size * caps->report_count;
+ struct usage_value_params *params = user;
+ LONG value, log_range, phy_range;
+
+ if (caps->logical_min > caps->logical_max) return HIDP_STATUS_BAD_LOG_PHY_VALUES;
+ if (caps->physical_min > caps->physical_max) return HIDP_STATUS_BAD_LOG_PHY_VALUES;
+
+ if ((bit_count + 7) / 8 > sizeof(value)) return HIDP_STATUS_BUFFER_TOO_SMALL;
+ if (sizeof(LONG) > params->value_len) return HIDP_STATUS_BUFFER_TOO_SMALL;
+ value = *(LONG *)params->value_buf;
+
+ if (caps->physical_min || caps->physical_max)
+ {
+ /* testing shows that this is what the function does, including all
+ * the overflows and rounding errors... */
+ log_range = (caps->logical_max - caps->logical_min + 1) / 2;
+ phy_range = (caps->physical_max - caps->physical_min + 1) / 2;
+ value = value - caps->physical_min;
+ value = (log_range * value) / phy_range;
+ value = caps->logical_min + value;
+ }
+
+ copy_bits( params->report_buf, (unsigned char *)&value, bit_count, caps->start_bit );
+
+ return HIDP_STATUS_NULL;
+}
+
+NTSTATUS WINAPI HidP_SetScaledUsageValue( HIDP_REPORT_TYPE report_type, USAGE usage_page, USHORT collection,
+ USAGE usage, LONG value, PHIDP_PREPARSED_DATA preparsed_data,
+ char *report_buf, ULONG report_len )
+{
+ struct usage_value_params params = {.value_buf = &value, .value_len = sizeof(value), .report_buf = report_buf};
+ struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)preparsed_data;
+ struct caps_filter filter = {.values = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage };
+ USHORT count = 1;
+
+ TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %d, preparsed_data %p, report_buf %p, report_len %u.\n",
+ report_type, usage_page, collection, usage, value, preparsed_data, report_buf, report_len );
+
+ 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_scaled_usage_value, ¶ms, &count );
+}
+
static NTSTATUS set_usage_value( const struct hid_value_caps *caps, void *user )
{
struct usage_value_params *params = user;
diff --git a/dlls/ntoskrnl.exe/tests/driver_hid.c b/dlls/ntoskrnl.exe/tests/driver_hid.c
index ce942815dcb..ed0767877ac 100644
--- a/dlls/ntoskrnl.exe/tests/driver_hid.c
+++ b/dlls/ntoskrnl.exe/tests/driver_hid.c
@@ -356,6 +356,16 @@ static NTSTATUS WINAPI driver_internal_ioctl(DEVICE_OBJECT *device, IRP *irp)
/* reset global items */
UNIT(1, 0), /* None */
UNIT_EXPONENT(1, 0),
+
+ USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC),
+ USAGE(1, HID_USAGE_GENERIC_Z),
+ LOGICAL_MINIMUM(4, 0x0000),
+ LOGICAL_MAXIMUM(4, 0x7fff),
+ PHYSICAL_MINIMUM(4, 0xfff90000),
+ PHYSICAL_MAXIMUM(4, 0x0003ffff),
+ REPORT_SIZE(1, 32),
+ REPORT_COUNT(1, 1),
+ FEATURE(1, Data|Var|Abs),
END_COLLECTION,
USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC),
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 34491500423..84711f75b33 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -1686,14 +1686,14 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
.UsagePage = HID_USAGE_PAGE_GENERIC,
.InputReportByteLength = 26,
.OutputReportByteLength = 3,
- .FeatureReportByteLength = 18,
+ .FeatureReportByteLength = 22,
.NumberLinkCollectionNodes = 10,
.NumberInputButtonCaps = 17,
.NumberInputValueCaps = 7,
.NumberInputDataIndices = 47,
.NumberFeatureButtonCaps = 1,
- .NumberFeatureValueCaps = 5,
- .NumberFeatureDataIndices = 7,
+ .NumberFeatureValueCaps = 6,
+ .NumberFeatureDataIndices = 8,
},
/* with report id */
{
@@ -1701,14 +1701,14 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
.UsagePage = HID_USAGE_PAGE_GENERIC,
.InputReportByteLength = 25,
.OutputReportByteLength = 2,
- .FeatureReportByteLength = 17,
+ .FeatureReportByteLength = 21,
.NumberLinkCollectionNodes = 10,
.NumberInputButtonCaps = 17,
.NumberInputValueCaps = 7,
.NumberInputDataIndices = 47,
.NumberFeatureButtonCaps = 1,
- .NumberFeatureValueCaps = 5,
- .NumberFeatureDataIndices = 7,
+ .NumberFeatureValueCaps = 6,
+ .NumberFeatureDataIndices = 8,
},
};
const HIDP_BUTTON_CAPS expect_button_caps[] =
@@ -2182,6 +2182,10 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
(LONG *)&value, preparsed_data, report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_BAD_LOG_PHY_VALUES, "HidP_GetScaledUsageValue returned %#x\n", status);
ok(value == 0, "got value %x, expected %#x\n", value, 0);
+ status = HidP_SetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY,
+ 0, preparsed_data, report, caps.InputReportByteLength);
+ ok(status == HIDP_STATUS_BAD_LOG_PHY_VALUES, "HidP_GetScaledUsageValue returned %#x\n", status);
+ ok(value == 0, "got value %x, expected %#x\n", value, 0);
value = HidP_MaxUsageListLength(HidP_Feature + 1, 0, preparsed_data);
ok(value == 0, "HidP_MaxUsageListLength(HidP_Feature + 1, 0) returned %d, expected %d\n", value, 0);
@@ -2311,7 +2315,7 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
value = HidP_MaxDataListLength(HidP_Output, preparsed_data);
ok(value == 0, "HidP_MaxDataListLength(HidP_Output) returned %d, expected %d\n", value, 0);
value = HidP_MaxDataListLength(HidP_Feature, preparsed_data);
- ok(value == 13, "HidP_MaxDataListLength(HidP_Feature) returned %d, expected %d\n", value, 13);
+ ok(value == 14, "HidP_MaxDataListLength(HidP_Feature) returned %d, expected %d\n", value, 14);
value = 1;
status = HidP_GetData(HidP_Input, data, &value, preparsed_data, report, caps.InputReportByteLength);
@@ -2474,6 +2478,74 @@ static void test_hidp(HANDLE file, HANDLE async_file, int report_id, BOOL polled
ok(!memcmp(buffer, buffer + 16, 16), "unexpected report value\n");
+ value = 0x7fffffff;
+ status = HidP_SetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status);
+ value = 0xdeadbeef;
+ status = HidP_GetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ (LONG *)&value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_VALUE_OUT_OF_RANGE, "HidP_GetScaledUsageValue returned %#x\n", status);
+ ok(value == 0, "got value %x, expected %#x\n", value, 0);
+ value = 0xdeadbeef;
+ status = HidP_GetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ &value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status);
+ ok(value == 0x7fffffff, "got value %x, expected %#x\n", value, 0x7fffffff);
+
+ value = 0x7fff;
+ status = HidP_SetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status);
+ value = 0xdeadbeef;
+ status = HidP_GetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ (LONG *)&value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status);
+ ok(value == 0x0003ffff, "got value %x, expected %#x\n", value, 0x0003ffff);
+
+ value = 0;
+ status = HidP_SetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetUsageValue returned %#x\n", status);
+ value = 0xdeadbeef;
+ status = HidP_GetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ (LONG *)&value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status);
+ ok(value == 0xfff90000, "got value %x, expected %#x\n", value, 0xfff90000);
+ status = HidP_SetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ 0x1000, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetScaledUsageValue returned %#x\n", status);
+ value = 0;
+ status = HidP_GetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ &value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status);
+ ok(value == 0xfffff518, "got value %x, expected %#x\n", value, 0xfffff518);
+ status = HidP_SetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ 0, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetScaledUsageValue returned %#x\n", status);
+ value = 0;
+ status = HidP_GetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ &value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status);
+ ok(value == 0xfffff45e, "got value %x, expected %#x\n", value, 0xfffff45e);
+ status = HidP_SetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ 0xdead, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetScaledUsageValue returned %#x\n", status);
+ value = 0;
+ status = HidP_GetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ &value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status);
+ ok(value == 0xfffffe7d, "got value %x, expected %#x\n", value, 0xfffffe7d);
+ status = HidP_SetScaledUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ 0xbeef, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_SetScaledUsageValue returned %#x\n", status);
+ value = 0;
+ status = HidP_GetUsageValue(HidP_Feature, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
+ &value, preparsed_data, report, caps.FeatureReportByteLength);
+ ok(status == HIDP_STATUS_SUCCESS, "HidP_GetUsageValue returned %#x\n", status);
+ ok(value == 0xfffffd0b, "got value %x, expected %#x\n", value, 0xfffffd0b);
+
+
memset(report, 0xcd, sizeof(report));
status = HidP_InitializeReportForID(HidP_Input, report_id, preparsed_data, report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_SUCCESS, "HidP_InitializeReportForID returned %#x\n", status);
diff --git a/include/ddk/hidpi.h b/include/ddk/hidpi.h
index 305c38a95d3..e2e2bd2229b 100644
--- a/include/ddk/hidpi.h
+++ b/include/ddk/hidpi.h
@@ -202,6 +202,7 @@ NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS
NTSTATUS WINAPI HidP_InitializeReportForID(HIDP_REPORT_TYPE ReportType, UCHAR ReportID, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
ULONG WINAPI HidP_MaxUsageListLength(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, PHIDP_PREPARSED_DATA PreparsedData);
NTSTATUS WINAPI HidP_GetScaledUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, PLONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
+NTSTATUS WINAPI HidP_SetScaledUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, LONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
NTSTATUS WINAPI HidP_SetUsageValue(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, USAGE Usage, ULONG UsageValue, PHIDP_PREPARSED_DATA PreparsedData, CHAR *Report, ULONG ReportLength);
NTSTATUS WINAPI HidP_SetUsageValueArray( HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
USAGE Usage, PCHAR UsageValue, USHORT UsageValueByteLength,
--
2.33.0
More information about the wine-devel
mailing list