From 1cda5082f89d3e8a10fb35bdba74440241d7d822 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 11 Feb 2010 21:02:54 +0000 Subject: added detection of HID report IDs for interrupt transfers processing of HID report IDs in hid_open using HidP_GetValueCaps added corresponding DLL call --- libusb/os/windows_usb.c | 64 +++++++++++++++++++++++++++++++++++++++++++------ libusb/os/windows_usb.h | 49 ++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 8 deletions(-) diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c index dadbb4f..a16b140 100644 --- a/libusb/os/windows_usb.c +++ b/libusb/os/windows_usb.c @@ -3025,7 +3025,7 @@ static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int i return LIBUSB_ERROR_NO_MEM; } buf[0] = (uint8_t)id; - usbi_dbg("report ID: %02X", buf[0]); + usbi_dbg("report ID: 0x%02X", buf[0]); // NB: HidD_GetInputReport returns the last Input Report read whereas ReadFile // waits for input to be generated => in case your HID device requires human // action to generate a report, it may wait indefinitely. @@ -3092,7 +3092,7 @@ static int _hid_set_report(struct hid_device_priv* dev, HANDLE hid_handle, int i } buf[0] = (uint8_t)id; - usbi_dbg("report ID: %02X", buf[0]); + usbi_dbg("report ID: 0x%02X", buf[0]); memcpy(buf + 1, data, *size); #if !defined(USE_HIDD_FOR_REPORTS) @@ -3211,6 +3211,7 @@ static int hid_init(struct libusb_context *ctx) DLL_LOAD(hid.dll, HidD_GetInputReport, FALSE); DLL_LOAD(hid.dll, HidD_SetOutputReport, FALSE); DLL_LOAD(hid.dll, HidD_FlushQueue, TRUE); + DLL_LOAD(hid.dll, HidP_GetValueCaps, TRUE); api_hid_available = true; return LIBUSB_SUCCESS; @@ -3233,8 +3234,10 @@ static int hid_open(struct libusb_device_handle *dev_handle) HIDD_ATTRIBUTES hid_attributes; PHIDP_PREPARSED_DATA preparsed_data = NULL; HIDP_CAPS capabilities; + HIDP_VALUE_CAPS *value_caps; HANDLE hid_handle = INVALID_HANDLE_VALUE; + ULONG size; int i; CHECK_HID_AVAILABLE; @@ -3298,6 +3301,54 @@ static int hid_open(struct libusb_device_handle *dev_handle) usbi_err(ctx, "could not parse HID capabilities (HidP_GetCaps)"); break; } + // Get the default input and output report IDs to use with interrupt + size = capabilities.NumberInputValueCaps; + usbi_dbg("%d HID input report value(s) found", size); + priv->hid->input_report_id = 0; + if (size > 0) { + value_caps = malloc(size * sizeof(HIDP_VALUE_CAPS)); + if ( (value_caps != NULL) + && (HidP_GetValueCaps(HidP_Input, value_caps, &size, preparsed_data) == HIDP_STATUS_SUCCESS) + && (size >= 1) ) { + priv->hid->input_report_id = value_caps[0].ReportID; + for (i=1; i<(int)size; i++) { + if (value_caps[i].ReportID != priv->hid->input_report_id) { + usbi_warn(ctx, "multiple input report IDs found for HID"); + usbi_warn(ctx, " will only handle report ID 0x%02X for interrupt transfers", + priv->hid->input_report_id); + break; + } + } + usbi_dbg("will use report ID 0x%02X for interrupt transfers", priv->hid->input_report_id); + } else { + usbi_warn(ctx, "could process input report IDs"); + } + safe_free(value_caps); + } + + size = capabilities.NumberOutputValueCaps; + usbi_dbg("%d HID output report value(s) found", size); + priv->hid->output_report_id = 0; + if (size > 0) { + value_caps = malloc(size * sizeof(HIDP_VALUE_CAPS)); + if ( (value_caps != NULL) + && (HidP_GetValueCaps(HidP_Output, value_caps, &size, preparsed_data) == HIDP_STATUS_SUCCESS) + && (size >= 1) ) { + priv->hid->output_report_id = value_caps[0].ReportID; + for (i=1; i<(int)size; i++) { + if (value_caps[i].ReportID != priv->hid->output_report_id) { + usbi_warn(ctx, "multiple output report IDs found for HID"); + usbi_warn(ctx, " will only handle report ID 0x%02X for interrupt transfers", + priv->hid->output_report_id); + break; + } + } + usbi_dbg("will use report ID 0x%02X for interrupt transfers", priv->hid->output_report_id); + } else { + usbi_warn(ctx, "could process output report IDs"); + } + safe_free(value_caps); + } priv->hid->output_report_size = capabilities.OutputReportByteLength; priv->hid->input_report_size = capabilities.InputReportByteLength; priv->hid->feature_report_size = capabilities.FeatureReportByteLength; @@ -3554,14 +3605,13 @@ static int hid_submit_bulk_transfer(struct usbi_transfer *itransfer) { if (transfer_priv->hid_buffer == NULL) { return LIBUSB_ERROR_NO_MEM; } - // TODO: can we figure out report ID here? - transfer_priv->hid_buffer[0] = 0; - if (direction_in) { - usbi_dbg("reading %d bytes", transfer->length+1); + transfer_priv->hid_buffer[0] = priv->hid->input_report_id; + usbi_dbg("reading %d bytes (report ID: 0x%02X)", transfer->length+1, transfer_priv->hid_buffer[0]); ret = ReadFile(hid_handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped); } else { - usbi_dbg("writing %d bytes", transfer->length+1); + transfer_priv->hid_buffer[0] = priv->hid->output_report_id; + usbi_dbg("writing %d bytes (report ID: 0x%02X)", transfer->length+1, transfer_priv->hid_buffer[0]); transfer_priv->hid_buffer[0] = 0; ret = WriteFile(hid_handle, transfer_priv->hid_buffer, transfer->length+1, &size, wfd.overlapped); } diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h index 90aa879..cd74e22 100644 --- a/libusb/os/windows_usb.h +++ b/libusb/os/windows_usb.h @@ -213,8 +213,11 @@ struct hid_device_priv { uint16_t vid; uint16_t pid; uint8_t config; - uint16_t output_report_size; + uint8_t input_report_id; + uint8_t output_report_id; + uint8_t feature_report_id; uint16_t input_report_size; + uint16_t output_report_size; uint16_t feature_report_size; WCHAR man_string[MAX_USB_STRING_LENGTH]; WCHAR prod_string[MAX_USB_STRING_LENGTH]; @@ -721,6 +724,49 @@ typedef struct { USHORT NumberFeatureDataIndices; } HIDP_CAPS, *PHIDP_CAPS; +typedef enum _HIDP_REPORT_TYPE { + HidP_Input, + HidP_Output, + HidP_Feature +} HIDP_REPORT_TYPE; + +typedef struct _HIDP_VALUE_CAPS { + USAGE UsagePage; + UCHAR ReportID; + BOOLEAN IsAlias; + USHORT BitField; + USHORT LinkCollection; + USAGE LinkUsage; + USAGE LinkUsagePage; + BOOLEAN IsRange; + BOOLEAN IsStringRange; + BOOLEAN IsDesignatorRange; + BOOLEAN IsAbsolute; + BOOLEAN HasNull; + UCHAR Reserved; + USHORT BitSize; + USHORT ReportCount; + USHORT Reserved2[5]; + ULONG UnitsExp; + ULONG Units; + LONG LogicalMin, LogicalMax; + LONG PhysicalMin, PhysicalMax; + union { + struct { + USAGE UsageMin, UsageMax; + USHORT StringMin, StringMax; + USHORT DesignatorMin, DesignatorMax; + USHORT DataIndexMin, DataIndexMax; + } Range; + struct { + USAGE Usage, Reserved1; + USHORT StringIndex, Reserved2; + USHORT DesignatorIndex, Reserved3; + USHORT DataIndex, Reserved4; + } NotRange; + }; +} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS; + DLL_DECLARE(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES)); DLL_DECLARE(WINAPI, VOID, HidD_GetHidGuid, (LPGUID)); DLL_DECLARE(WINAPI, BOOL, HidD_GetPreparsedData, (HANDLE, PHIDP_PREPARSED_DATA *)); @@ -736,3 +782,4 @@ DLL_DECLARE(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG)); DLL_DECLARE(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG)); DLL_DECLARE(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG)); DLL_DECLARE(WINAPI, BOOL, HidD_FlushQueue, (HANDLE)); +DLL_DECLARE(WINAPI, BOOL, HidP_GetValueCaps, (HIDP_REPORT_TYPE, PHIDP_VALUE_CAPS, PULONG, PHIDP_PREPARSED_DATA)); -- cgit v1.2.1