From 31eba10bd283c7fa315e4d346408c03b54d109c1 Mon Sep 17 00:00:00 2001 From: Werner Sembach Date: Wed, 28 May 2025 23:03:32 +0200 Subject: [PATCH] linux/hidraw: Parse Report ID Some reports have an optional and/or device specific Report ID that someone sending the report need to prefix to the actual report when sending one. This adds an easy way on Linux to retrieve that ID. Signed-off-by: Werner Sembach --- hidapi/hidapi.h | 3 +++ linux/hid.c | 13 ++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/hidapi/hidapi.h b/hidapi/hidapi.h index cbc3107d..95a515fb 100644 --- a/hidapi/hidapi.h +++ b/hidapi/hidapi.h @@ -176,6 +176,9 @@ extern "C" { /** Usage for this Device/Interface (Windows/Mac/hidraw only) */ unsigned short usage; + /** Report ID for this Device/Interface + (hidraw only) */ + unsigned char report_id; /** The USB interface which this logical device represents. diff --git a/linux/hid.c b/linux/hid.c index e212a70d..e3dfed20 100644 --- a/linux/hid.c +++ b/linux/hid.c @@ -347,7 +347,7 @@ struct hid_usage_iterator { * 1 when finished processing descriptor. * -1 on a malformed report. */ -static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct hid_usage_iterator *ctx, unsigned short *usage_page, unsigned short *usage) +static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct hid_usage_iterator *ctx, unsigned short *usage_page, unsigned short *usage, unsigned char *report_id) { int data_len, key_size; int initial = ctx->pos == 0; /* Used to handle case where no top-level application collection is defined */ @@ -381,6 +381,10 @@ static int get_next_hid_usage(const __u8 *report_descriptor, __u32 size, struct } break; + case 0x84: /* Report ID 6.2.2.7 (Global) */ + *report_id = get_hid_report_bytes(report_descriptor, size, data_len, ctx->pos); + break; + case 0xa0: /* Collection 6.2.2.4 (Main) */ if (!hid_iterate_over_collection(report_descriptor, size, &ctx->pos, &data_len, &key_size)) { return -1; @@ -805,6 +809,7 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device if (result >= 0) { unsigned short page = 0, usage = 0; + unsigned char report_id = 0; struct hid_usage_iterator usage_iterator; memset(&usage_iterator, 0, sizeof(usage_iterator)); @@ -812,16 +817,17 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device * Parse the first usage and usage page * out of the report descriptor. */ - if (!get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage)) { + if (!get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage, &report_id)) { cur_dev->usage_page = page; cur_dev->usage = usage; + cur_dev->report_id = report_id; } /* * Parse any additional usage and usage pages * out of the report descriptor. */ - while (!get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage)) { + while (!get_next_hid_usage(report_desc.value, report_desc.size, &usage_iterator, &page, &usage, &report_id)) { /* Create new record for additional usage pairs */ struct hid_device_info *tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); struct hid_device_info *prev_dev = cur_dev; @@ -842,6 +848,7 @@ static struct hid_device_info * create_device_info_for_device(struct udev_device cur_dev->product_string = prev_dev->product_string? wcsdup(prev_dev->product_string): NULL; cur_dev->usage_page = page; cur_dev->usage = usage; + cur_dev->report_id = report_id; cur_dev->bus_type = prev_dev->bus_type; } }