[PATCH 5/5] hid: Rewrite HidP_GetScaledUsageValue using enum_value_caps.
Rémi Bernon
rbernon at codeweavers.com
Fri Jun 25 03:06:52 CDT 2021
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/hid/hidp.c | 137 ++++++++---------------------
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 4 -
2 files changed, 36 insertions(+), 105 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c
index 948f0c7c4dc..59f18276b38 100644
--- a/dlls/hid/hidp.c
+++ b/dlls/hid/hidp.c
@@ -217,70 +217,6 @@ NTSTATUS WINAPI HidP_GetCaps( PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *ca
return HIDP_STATUS_SUCCESS;
}
-static NTSTATUS find_usage(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection,
- USAGE Usage, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report,
- USHORT bit_size, WINE_HID_ELEMENT *element)
-{
- PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData;
- WINE_HID_ELEMENT *elems = HID_ELEMS(data);
- WINE_HID_REPORT *report = NULL;
- USHORT v_count = 0, r_count = 0;
- int i;
-
- TRACE("(%i, %x, %i, %i, %p, %p)\n", ReportType, UsagePage, LinkCollection, Usage,
- PreparsedData, Report);
-
- if (data->magic != HID_MAGIC)
- return HIDP_STATUS_INVALID_PREPARSED_DATA;
- switch(ReportType)
- {
- case HidP_Input:
- v_count = data->caps.NumberInputValueCaps;
- break;
- case HidP_Output:
- v_count = data->caps.NumberOutputValueCaps;
- break;
- case HidP_Feature:
- v_count = data->caps.NumberFeatureValueCaps;
- break;
- default:
- return HIDP_STATUS_INVALID_REPORT_TYPE;
- }
- r_count = data->reportCount[ReportType];
- report = &data->reports[data->reportIdx[ReportType][(BYTE)Report[0]]];
-
- if (!r_count || !v_count)
- return HIDP_STATUS_USAGE_NOT_FOUND;
-
- if (report->reportID && report->reportID != Report[0])
- return HIDP_STATUS_REPORT_DOES_NOT_EXIST;
-
- for (i = 0; i < report->elementCount; i++)
- {
- HIDP_VALUE_CAPS *value = &elems[report->elementIdx + i].caps;
-
- if ((elems[report->elementIdx + i].caps.BitSize == 1) != (bit_size == 1) ||
- value->UsagePage != UsagePage)
- continue;
-
- if (value->IsRange && value->Range.UsageMin <= Usage && Usage <= value->Range.UsageMax)
- {
- *element = elems[report->elementIdx + i];
- element->valueStartBit += value->BitSize * (Usage - value->Range.UsageMin);
- element->bitCount = elems[report->elementIdx + i].caps.BitSize;
- return HIDP_STATUS_SUCCESS;
- }
- else if (value->NotRange.Usage == Usage)
- {
- *element = elems[report->elementIdx + i];
- element->bitCount = elems[report->elementIdx + i].caps.BitSize;
- return HIDP_STATUS_SUCCESS;
- }
- }
-
- return HIDP_STATUS_USAGE_NOT_FOUND;
-}
-
struct usage_value_params
{
void *value_buf;
@@ -288,53 +224,52 @@ struct usage_value_params
void *report_buf;
};
-static LONG sign_extend(ULONG value, const WINE_HID_ELEMENT *element)
+static LONG sign_extend( ULONG value, const struct hid_value_caps *caps )
{
- UINT bit_count = element->bitCount;
-
- if ((value & (1 << (bit_count - 1)))
- && element->caps.BitSize != 1
- && element->caps.LogicalMin < 0)
- {
- value -= (1 << bit_count);
- }
- return value;
+ UINT sign = 1 << (caps->bit_size - 1);
+ if (sign <= 1 || caps->logical_min >= 0) return value;
+ return value - ((value & sign) << 1);
}
-static LONG logical_to_physical(LONG value, const WINE_HID_ELEMENT *element)
+static NTSTATUS get_scaled_usage_value( const struct hid_value_caps *caps, void *user )
{
- if (element->caps.PhysicalMin || element->caps.PhysicalMax)
- {
- value = (((ULONGLONG)(value - element->caps.LogicalMin)
- * (element->caps.PhysicalMax - element->caps.PhysicalMin))
- / (element->caps.LogicalMax - element->caps.LogicalMin))
- + element->caps.PhysicalMin;
- }
- return value;
+ struct usage_value_params *params = user;
+ ULONG unsigned_value = 0, bit_count = caps->bit_size * caps->report_count;
+ LONG signed_value, *value = params->value_buf;
+
+ if ((bit_count + 7) / 8 > sizeof(unsigned_value)) return HIDP_STATUS_BUFFER_TOO_SMALL;
+ if (sizeof(LONG) > params->value_len) return HIDP_STATUS_BUFFER_TOO_SMALL;
+ copy_bits( (unsigned char *)&unsigned_value, params->report_buf, bit_count, -caps->start_bit );
+ signed_value = sign_extend( unsigned_value, caps );
+
+ if (caps->logical_min > caps->logical_max || caps->physical_min > caps->physical_max)
+ return HIDP_STATUS_BAD_LOG_PHY_VALUES;
+ if (caps->logical_min > signed_value || caps->logical_max < signed_value)
+ return HIDP_STATUS_VALUE_OUT_OF_RANGE;
+
+ if (!caps->physical_min && !caps->physical_max) *value = signed_value;
+ else *value = caps->physical_min + MulDiv( signed_value - caps->logical_min, caps->physical_max - caps->physical_min,
+ caps->logical_max - caps->logical_min );
+ return HIDP_STATUS_NULL;
}
-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_GetScaledUsageValue( 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 )
{
- NTSTATUS rc;
- WINE_HID_ELEMENT element;
- TRACE("(%i, %x, %i, %i, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, Usage, UsageValue,
- PreparsedData, Report, ReportLength);
+ struct usage_value_params params = {.value_buf = value, .value_len = sizeof(*value), .report_buf = report_buf};
+ WINE_HIDP_PREPARSED_DATA *preparsed = (WINE_HIDP_PREPARSED_DATA *)preparsed_data;
+ struct caps_filter filter = {.values = TRUE, .usage_page = usage_page, .collection = collection, .usage = usage };
+ USHORT count = 1;
- rc = find_usage(ReportType, UsagePage, LinkCollection, Usage, PreparsedData, Report, 0, &element);
+ TRACE( "report_type %d, usage_page %x, collection %d, usage %x, value %p, preparsed_data %p, report_buf %p, report_len %u.\n",
+ report_type, usage_page, collection, usage, value, preparsed_data, report_buf, report_len );
- if (rc == HIDP_STATUS_SUCCESS)
- {
- ULONG rawValue;
- rc = get_report_data((BYTE*)Report, ReportLength,
- element.valueStartBit, element.bitCount, &rawValue);
- if (rc != HIDP_STATUS_SUCCESS)
- return rc;
- *UsageValue = logical_to_physical(sign_extend(rawValue, &element), &element);
- }
+ *value = 0;
+ if (!report_len) return HIDP_STATUS_INVALID_REPORT_LENGTH;
- return rc;
+ filter.report_id = report_buf[0];
+ return enum_value_caps( preparsed, report_type, report_len, &filter, get_scaled_usage_value, ¶ms, &count );
}
static NTSTATUS get_usage_value( const struct hid_value_caps *caps, void *user )
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index b29660d4773..432bc168259 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -2085,9 +2085,7 @@ static void test_hidp(HANDLE file, int report_id)
value = 0xdeadbeef;
status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
(LONG *)&value, preparsed_data, report, caps.InputReportByteLength);
- todo_wine
ok(status == HIDP_STATUS_VALUE_OUT_OF_RANGE, "HidP_GetScaledUsageValue returned %#x\n", status);
- todo_wine
ok(value == 0, "got value %x, expected %#x\n", value, 0);
value = 0xdeadbeef;
status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
@@ -2103,7 +2101,6 @@ static void test_hidp(HANDLE file, int report_id)
status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z,
(LONG *)&value, preparsed_data, report, caps.InputReportByteLength);
ok(status == HIDP_STATUS_SUCCESS, "HidP_GetScaledUsageValue returned %#x\n", status);
- todo_wine
ok(value == 0x7fffffff, "got value %x, expected %#x\n", value, 0x7fffffff);
value = 0;
@@ -2133,7 +2130,6 @@ static void test_hidp(HANDLE file, int report_id)
value = 0xdeadbeef;
status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY,
(LONG *)&value, preparsed_data, report, caps.InputReportByteLength);
- todo_wine
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);
--
2.32.0
More information about the wine-devel
mailing list