Skip to content
This repository was archived by the owner on Dec 14, 2025. It is now read-only.

Commit dbd71dc

Browse files
committed
[HID] Split properly Input & Output report sharing same ID
1 parent e3fa81c commit dbd71dc

2 files changed

Lines changed: 96 additions & 94 deletions

File tree

main/adapter/adapter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,13 @@ enum {
377377
FB_TYPE_SYS_ID,
378378
};
379379

380+
enum {
381+
HID_IN = 0,
382+
HID_OUT,
383+
//HID_FTR,
384+
HID_TAG_CNT,
385+
};
386+
380387
struct ctrl_meta {
381388
int32_t neutral;
382389
int32_t deadzone;
@@ -458,6 +465,7 @@ struct hid_usage {
458465
struct hid_report {
459466
uint32_t id;
460467
uint32_t len;
468+
uint32_t tag;
461469
uint32_t usage_cnt;
462470
struct hid_usage usages[REPORT_MAX_USAGE];
463471
};

main/adapter/hid_parser.c

Lines changed: 88 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019-2022, Jacques Gagnon
2+
* Copyright (c) 2019-2023, Jacques Gagnon
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -27,6 +27,7 @@ struct hid_fingerprint {
2727
uint8_t fp[REPORT_MAX_USAGE*2];
2828
};
2929

30+
static struct hid_report wip_report[HID_TAG_CNT] = {0};
3031
static const struct hid_fingerprint hid_fp[] = {
3132
#ifndef CONFIG_BLUERETRO_GENERIC_HID_DEBUG
3233
{
@@ -265,51 +266,64 @@ static void hid_device_fingerprint(struct hid_report *report, int32_t *type, uin
265266
return;
266267
}
267268

268-
static void hid_process_report(struct bt_data *bt_data, struct hid_report *wip_report, uint32_t report_bit_offset, uint32_t report_usage_idx) {
269+
static void hid_process_report(struct bt_data *bt_data, struct hid_report *report) {
269270
int32_t report_type = REPORT_NONE;
270271
int32_t dev_type = BT_NONE;
271272
uint32_t dev_subtype = BT_SUBTYPE_DEFAULT;
272273

273-
wip_report->len = report_bit_offset / 8;
274-
wip_report->usage_cnt = report_usage_idx;
275-
if (report_bit_offset % 8) {
276-
wip_report->len++;
274+
report_type = hid_report_fingerprint(report);
275+
#ifdef CONFIG_BLUERETRO_JSON_DBG
276+
printf("{\"log_type\": \"parsed_hid_report\", \"report_id\": %ld, \"report_tag\": %ld, \"usages\": [", report->id, report->tag);
277+
for (uint32_t i = 0; i < report->usage_cnt; i++) {
278+
if (i) {
279+
printf(", ");
280+
}
281+
printf("{\"usage_page\": %ld, \"usage\": %ld, \"bit_offset\": %lu, \"bit_size\": %lu}",
282+
report->usages[i].usage_page, report->usages[i].usage, report->usages[i].bit_offset,
283+
report->usages[i].bit_size);
277284
}
278-
report_type = hid_report_fingerprint(wip_report);
285+
printf("]");
286+
#else
287+
printf("# %ld %c ", report->id, (report->tag) ? 'O' : 'I');
288+
for (uint32_t i = 0; i < report->usage_cnt; i++) {
289+
printf("%02lX%02lX %lu %lu ", report->usages[i].usage_page, report->usages[i].usage,
290+
report->usages[i].bit_offset, report->usages[i].bit_size);
291+
}
292+
#endif
279293
if (report_type != REPORT_NONE && bt_data->reports[report_type].id == 0) {
280-
hid_device_fingerprint(wip_report, &dev_type, &dev_subtype);
281-
memcpy(&bt_data->reports[report_type], wip_report, sizeof(bt_data->reports[0]));
294+
hid_device_fingerprint(report, &dev_type, &dev_subtype);
295+
memcpy(&bt_data->reports[report_type], report, sizeof(bt_data->reports[0]));
282296
#ifdef CONFIG_BLUERETRO_JSON_DBG
283-
printf("], \"report_type\": %ld, \"device_type\": %ld, \"device_subtype\": %ld}\n",
297+
printf(", \"report_type\": %ld, \"device_type\": %ld, \"device_subtype\": %ld",
284298
report_type, dev_type, dev_subtype);
285299
#else
286-
printf("rtype: %ld dtype: %ld sub: %ld\n", report_type, dev_type, dev_subtype);
300+
printf("rtype: %ld dtype: %ld sub: %ld", report_type, dev_type, dev_subtype);
287301
#endif
288302
if (bt_data->base.pids->type <= BT_HID_GENERIC && dev_type > BT_HID_GENERIC) {
289303
bt_type_update(bt_data->base.pids->id, dev_type, dev_subtype);
290304
}
291305
}
292-
else {
293306
#ifdef CONFIG_BLUERETRO_JSON_DBG
294-
printf("}\n");
307+
printf("}\n");
295308
#else
296-
printf("\n");
309+
printf("\n");
297310
#endif
298-
}
299311
}
300312

301313
void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) {
302314
struct hid_stack_element hid_stack[HID_STACK_MAX] = {0};
303315
uint8_t hid_stack_idx = 0;
304316
uint8_t usage_idx = 0;
305-
struct hid_report wip_report = {0};
306317
uint16_t usage_list[REPORT_MAX_USAGE] = {0};
307318
uint8_t *end = data + len;
308319
uint8_t *desc = data;
309320
uint8_t report_id = 0;
310321
uint8_t report_cnt = 0;
311-
uint32_t report_bit_offset = 0;
312-
uint32_t report_usage_idx = 0;
322+
uint8_t tag_idx = 0;
323+
uint32_t report_bit_offset[HID_TAG_CNT] = {0};
324+
uint32_t report_usage_idx[HID_TAG_CNT] = {0};
325+
326+
memset((void *)&wip_report, 0, sizeof(wip_report));
313327

314328
#ifdef CONFIG_BLUERETRO_DUMP_HID_DESC
315329
data_dump(data, len);
@@ -405,106 +419,75 @@ void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) {
405419
break;
406420
case 0x7C:
407421
break;
408-
case HID_MI_INPUT: /* 0x81 */
409422
case HID_MI_OUTPUT: /* 0x91 */
410-
if (!(*desc & 0x01) && hid_stack[hid_stack_idx].usage_page != 0xFF && usage_list[0] != 0xFF && report_usage_idx < REPORT_MAX_USAGE) {
423+
tag_idx = 1;
424+
/* Fallthrough */
425+
case HID_MI_INPUT: /* 0x81 */
426+
if (!(*desc & 0x01) && hid_stack[hid_stack_idx].usage_page != 0xFF && usage_list[0] != 0xFF && report_usage_idx[tag_idx] < REPORT_MAX_USAGE) {
411427
if (hid_stack[hid_stack_idx].report_size == 1) {
412-
wip_report.usages[report_usage_idx].usage_page = hid_stack[hid_stack_idx].usage_page;
413-
wip_report.usages[report_usage_idx].usage = usage_list[0];
414-
wip_report.usages[report_usage_idx].flags = *desc;
415-
wip_report.usages[report_usage_idx].bit_offset = report_bit_offset;
416-
wip_report.usages[report_usage_idx].bit_size = hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
417-
wip_report.usages[report_usage_idx].logical_min = hid_stack[hid_stack_idx].logical_min;
418-
wip_report.usages[report_usage_idx].logical_max = hid_stack[hid_stack_idx].logical_max;
419-
#ifdef CONFIG_BLUERETRO_JSON_DBG
420-
if (report_usage_idx) {
421-
printf(", ");
422-
}
423-
else if (!report_id) {
424-
printf("{\"log_type\": \"parsed_hid_report\", \"report_id\": 1, \"usages\": [");
425-
}
426-
printf("{\"usage_page\": %d, \"usage\": %d, \"bit_offset\": %lu, \"bit_size\": %lu}",
427-
hid_stack[hid_stack_idx].usage_page, usage_list[0], report_bit_offset,
428-
hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size);
429-
#else
430-
printf("%02X%02X %lu %lu ", hid_stack[hid_stack_idx].usage_page, usage_list[0], report_bit_offset,
431-
hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size);
432-
#endif
433-
report_bit_offset += hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
434-
++report_usage_idx;
428+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].usage_page = hid_stack[hid_stack_idx].usage_page;
429+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].usage = usage_list[0];
430+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].flags = *desc;
431+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].bit_offset = report_bit_offset[tag_idx];
432+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
433+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].logical_min = hid_stack[hid_stack_idx].logical_min;
434+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].logical_max = hid_stack[hid_stack_idx].logical_max;
435+
report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_cnt * hid_stack[hid_stack_idx].report_size;
436+
++report_usage_idx[tag_idx];
435437
}
436438
else {
437-
uint32_t idx_end = report_usage_idx + hid_stack[hid_stack_idx].report_cnt;
439+
uint32_t idx_end = report_usage_idx[tag_idx] + hid_stack[hid_stack_idx].report_cnt;
438440
if (idx_end > REPORT_MAX_USAGE) {
439441
idx_end = REPORT_MAX_USAGE;
440442
}
441-
for (uint32_t i = 0; report_usage_idx < idx_end; ++i, ++report_usage_idx) {
442-
wip_report.usages[report_usage_idx].usage_page = hid_stack[hid_stack_idx].usage_page;
443-
#ifdef CONFIG_BLUERETRO_JSON_DBG
444-
if (report_usage_idx) {
445-
printf(", ");
446-
}
447-
else if (!report_id) {
448-
printf("{\"log_type\": \"parsed_hid_report\", \"report_id\": 1, \"usages\": [");
449-
}
450-
printf("{\"usage_page\": %d", hid_stack[hid_stack_idx].usage_page);
451-
#else
452-
printf("%02X", hid_stack[hid_stack_idx].usage_page);
453-
#endif
443+
for (uint32_t i = 0; report_usage_idx[tag_idx] < idx_end; ++i, ++report_usage_idx[tag_idx]) {
444+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].usage_page = hid_stack[hid_stack_idx].usage_page;
454445
if (usage_idx < 2) {
455-
wip_report.usages[report_usage_idx].usage = usage_list[0];
456-
#ifdef CONFIG_BLUERETRO_JSON_DBG
457-
printf(", \"usage\": %d", usage_list[0]);
458-
#else
459-
printf("%02X ", usage_list[0]);
460-
#endif
446+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].usage = usage_list[0];
461447
}
462448
else {
463-
wip_report.usages[report_usage_idx].usage = usage_list[i];
464-
#ifdef CONFIG_BLUERETRO_JSON_DBG
465-
printf(", \"usage\": %d", usage_list[i]);
466-
#else
467-
printf("%02X ", usage_list[i]);
468-
#endif
449+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].usage = usage_list[i];
469450
}
470-
wip_report.usages[report_usage_idx].flags = *desc;
471-
wip_report.usages[report_usage_idx].bit_offset = report_bit_offset;
472-
wip_report.usages[report_usage_idx].bit_size = hid_stack[hid_stack_idx].report_size;
473-
wip_report.usages[report_usage_idx].logical_min = hid_stack[hid_stack_idx].logical_min;
474-
wip_report.usages[report_usage_idx].logical_max = hid_stack[hid_stack_idx].logical_max;
475-
#ifdef CONFIG_BLUERETRO_JSON_DBG
476-
printf(", \"bit_offset\": %lu, \"bit_size\": %lu}",
477-
report_bit_offset, hid_stack[hid_stack_idx].report_size);
478-
#else
479-
printf("%lu %lu, ", report_bit_offset, hid_stack[hid_stack_idx].report_size);
480-
#endif
481-
report_bit_offset += hid_stack[hid_stack_idx].report_size;
451+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].flags = *desc;
452+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].bit_offset = report_bit_offset[tag_idx];
453+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].bit_size = hid_stack[hid_stack_idx].report_size;
454+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].logical_min = hid_stack[hid_stack_idx].logical_min;
455+
wip_report[tag_idx].usages[report_usage_idx[tag_idx]].logical_max = hid_stack[hid_stack_idx].logical_max;
456+
report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_size;
482457
}
483458
}
484459
}
485460
else {
486-
report_bit_offset += hid_stack[hid_stack_idx].report_size * hid_stack[hid_stack_idx].report_cnt;
461+
report_bit_offset[tag_idx] += hid_stack[hid_stack_idx].report_size * hid_stack[hid_stack_idx].report_cnt;
487462
}
488463
usage_idx = 0;
464+
tag_idx = 0;
489465
memset(usage_list, 0xFF, sizeof(usage_list));
490466
desc++;
491467
break;
492468
case HID_GI_REPORT_ID: /* 0x85 */
493469
/* process previous report fingerprint */
494470
if (report_id) {
495-
hid_process_report(bt_data, &wip_report, report_bit_offset, report_usage_idx);
471+
for (uint32_t i = 0; i < HID_TAG_CNT; i++) {
472+
wip_report[i].tag = i;
473+
wip_report[i].usage_cnt = report_usage_idx[i];
474+
wip_report[i].len = report_bit_offset[i] / 8;
475+
if (report_bit_offset[i] % 8) {
476+
wip_report[i].len++;
477+
}
478+
if (wip_report[i].len) {
479+
hid_process_report(bt_data, &wip_report[i]);
480+
}
481+
}
496482
report_cnt++;
497483
}
498484
memset((void *)&wip_report, 0, sizeof(wip_report));
499485
report_id = *desc++;
500-
wip_report.id = report_id;
501-
report_usage_idx = 0;
502-
report_bit_offset = 0;
503-
#ifdef CONFIG_BLUERETRO_JSON_DBG
504-
printf("{\"log_type\": \"parsed_hid_report\", \"report_id\": %d, \"usages\": [", report_id);
505-
#else
506-
printf("# %d ", report_id);
507-
#endif
486+
for (uint32_t i = 0; i < HID_TAG_CNT; i++) {
487+
wip_report[i].id = report_id;
488+
report_usage_idx[i] = 0;
489+
report_bit_offset[i] = 0;
490+
}
508491
break;
509492
case HID_GI_REPORT_COUNT: /* 0x95 */
510493
hid_stack[hid_stack_idx].report_cnt = *desc++;
@@ -551,11 +534,22 @@ void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) {
551534
return;
552535
}
553536
}
554-
if (report_cnt == 0 && wip_report.id == 0) {
537+
if (report_cnt == 0 && wip_report[HID_IN].id == 0) {
555538
report_id = 1;
556-
wip_report.id = 1;
539+
wip_report[HID_IN].id = 1;
540+
wip_report[HID_OUT].id = 1;
557541
}
558542
if (report_id) {
559-
hid_process_report(bt_data, &wip_report, report_bit_offset, report_usage_idx);
543+
for (uint32_t i = 0; i < HID_TAG_CNT; i++) {
544+
wip_report[i].tag = i;
545+
wip_report[i].usage_cnt = report_usage_idx[i];
546+
wip_report[i].len = report_bit_offset[i] / 8;
547+
if (report_bit_offset[i] % 8) {
548+
wip_report[i].len++;
549+
}
550+
if (wip_report[i].len) {
551+
hid_process_report(bt_data, &wip_report[i]);
552+
}
553+
}
560554
}
561555
}

0 commit comments

Comments
 (0)