hid: Implement HidP_SetScaledUsageValue.

The function seems to actually do overflows and rounding errors.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-08-25 18:08:33 +02:00 committed by Alexandre Julliard
parent 3b40a03267
commit 74b7845ff0
5 changed files with 138 additions and 8 deletions

View File

@ -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)

View File

@ -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, &params, &count );
}
static NTSTATUS set_usage_value( const struct hid_value_caps *caps, void *user )
{
struct usage_value_params *params = user;

View File

@ -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),

View File

@ -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);

View File

@ -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,