From: Aric Stewart Subject: [4/11]hid: Implement HidP_GetUsages Message-Id: <55928E20.1020806@codeweavers.com> Date: Tue, 30 Jun 2015 07:40:00 -0500 --- dlls/hid/hid.spec | 2 +- dlls/hid/hidp.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ddk/hidpi.h | 1 + 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/dlls/hid/hid.spec b/dlls/hid/hid.spec index 214fa9e..5b63267 100644 --- a/dlls/hid/hid.spec +++ b/dlls/hid/hid.spec @@ -28,7 +28,7 @@ @ stub HidP_GetSpecificValueCaps @ stub HidP_GetUsageValue @ stub HidP_GetUsageValueArray -@ stub HidP_GetUsages +@ stdcall HidP_GetUsages(long long long ptr ptr ptr ptr long) @ stub HidP_GetUsagesEx @ stdcall HidP_GetValueCaps(long ptr ptr ptr) @ stub HidP_InitializeReportForID diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index ce8f6df..1115160 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -37,6 +37,46 @@ WINE_DEFAULT_DEBUG_CHANNEL(hidp); +static NTSTATUS GetReportData(BYTE *report, INT reportLength, INT startBit, INT valueSize, PULONG value) +{ + + if ((startBit + valueSize) / 8 > reportLength) + return HIDP_STATUS_INVALID_REPORT_LENGTH; + + if (valueSize == 1) + { + ULONG byte_index = startBit / 8; + ULONG bit_index = startBit - (byte_index * 8); + INT mask = (1 << bit_index); + *value = (report[byte_index] & mask); + } + else + { + ULONG byte_index = (startBit + valueSize - 1) / 8; + ULONG data = 0; + ULONG remainingBits = valueSize; + while (remainingBits) + { + data <<= 8; + + if (remainingBits >= 8) + { + data |= report[byte_index]; + byte_index --; + remainingBits -= 8; + } + else if (remainingBits > 0) + { + BYTE mask = ~(0xff << (8-remainingBits)); + data |= report[byte_index] & mask; + remainingBits = 0; + } + } + *value = data; + } + return HIDP_STATUS_SUCCESS; +} + NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData) { PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; @@ -110,6 +150,89 @@ NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData, } +NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength) +{ + PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; + WINE_HID_REPORT *report = NULL; + BOOL found = FALSE; + USHORT b_count = 0, r_count = 0; + int i,uCount; + + TRACE("(%i, %x, %i, %p, %p, %p, %p, %i)\n", ReportType, UsagePage, LinkCollection, UsageList, UsageLength, PreparsedData, Report, ReportLength); + + if (data->magic != HID_MAGIC) + return HIDP_STATUS_INVALID_PREPARSED_DATA; + + switch(ReportType) + { + case HidP_Input: + b_count = data->caps.NumberInputButtonCaps; + r_count = data->dwInputReportCount; + report = HID_INPUT_REPORTS(data); + break; + case HidP_Output: + b_count = data->caps.NumberOutputButtonCaps; + r_count = data->dwOutputReportCount; + report = HID_OUTPUT_REPORTS(data); + break; + case HidP_Feature: + b_count = data->caps.NumberFeatureButtonCaps; + r_count = data->dwFeatureReportCount; + report = HID_FEATURE_REPORTS(data); + break; + default: + return HIDP_STATUS_INVALID_REPORT_TYPE; + } + + if (!r_count || !b_count || !report) + return HIDP_STATUS_USAGE_NOT_FOUND; + + for (i = 0; i < r_count; i++) + { + if (!report->reportID || report->reportID == Report[0]) + break; + report = HID_NEXT_REPORT(data, report); + } + + if (i == r_count) + return HIDP_STATUS_REPORT_DOES_NOT_EXIST; + + uCount = 0; + for (i = 0; i < report->elementCount && uCount < *UsageLength; i++) + { + if (report->Elements[i].ElementType == ButtonElement && + report->Elements[i].caps.button.UsagePage == UsagePage) + { + int k; + WINE_HID_ELEMENT *element = &report->Elements[i]; + for (k=0; k < element->bitCount; k++) + { + UINT v = 0; + NTSTATUS rc = GetReportData((BYTE*)Report, ReportLength, + element->valueStartBit + k, 1, &v); + if (rc != HIDP_STATUS_SUCCESS) + return rc; + found = TRUE; + if (v) + { + if (uCount == *UsageLength) + return HIDP_STATUS_BUFFER_TOO_SMALL; + UsageList[uCount] = element->caps.button.u.Range.UsageMin + k; + uCount++; + } + } + } + } + + if (!found) + return HIDP_STATUS_USAGE_NOT_FOUND; + + *UsageLength = uCount; + + return HIDP_STATUS_SUCCESS; +} + + NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData) { PWINE_HIDP_PREPARSED_DATA data = (PWINE_HIDP_PREPARSED_DATA)PreparsedData; diff --git a/include/ddk/hidpi.h b/include/ddk/hidpi.h index c63d3e3..fddfa02 100644 --- a/include/ddk/hidpi.h +++ b/include/ddk/hidpi.h @@ -138,6 +138,7 @@ typedef struct _HIDP_CAPS NTSTATUS WINAPI HidP_GetButtonCaps(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData); NTSTATUS WINAPI HidP_GetCaps(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities); +NTSTATUS WINAPI HidP_GetUsages(HIDP_REPORT_TYPE ReportType, USAGE UsagePage, USHORT LinkCollection, PUSAGE UsageList, PULONG UsageLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength); NTSTATUS WINAPI HidP_GetValueCaps(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);