|
1 | 1 | /* |
2 | | - * Copyright (c) 2019-2022, Jacques Gagnon |
| 2 | + * Copyright (c) 2019-2023, Jacques Gagnon |
3 | 3 | * SPDX-License-Identifier: Apache-2.0 |
4 | 4 | */ |
5 | 5 |
|
@@ -27,6 +27,7 @@ struct hid_fingerprint { |
27 | 27 | uint8_t fp[REPORT_MAX_USAGE*2]; |
28 | 28 | }; |
29 | 29 |
|
| 30 | +static struct hid_report wip_report[HID_TAG_CNT] = {0}; |
30 | 31 | static const struct hid_fingerprint hid_fp[] = { |
31 | 32 | #ifndef CONFIG_BLUERETRO_GENERIC_HID_DEBUG |
32 | 33 | { |
@@ -265,51 +266,64 @@ static void hid_device_fingerprint(struct hid_report *report, int32_t *type, uin |
265 | 266 | return; |
266 | 267 | } |
267 | 268 |
|
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) { |
269 | 270 | int32_t report_type = REPORT_NONE; |
270 | 271 | int32_t dev_type = BT_NONE; |
271 | 272 | uint32_t dev_subtype = BT_SUBTYPE_DEFAULT; |
272 | 273 |
|
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); |
277 | 284 | } |
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 |
279 | 293 | 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])); |
282 | 296 | #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", |
284 | 298 | report_type, dev_type, dev_subtype); |
285 | 299 | #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); |
287 | 301 | #endif |
288 | 302 | if (bt_data->base.pids->type <= BT_HID_GENERIC && dev_type > BT_HID_GENERIC) { |
289 | 303 | bt_type_update(bt_data->base.pids->id, dev_type, dev_subtype); |
290 | 304 | } |
291 | 305 | } |
292 | | - else { |
293 | 306 | #ifdef CONFIG_BLUERETRO_JSON_DBG |
294 | | - printf("}\n"); |
| 307 | + printf("}\n"); |
295 | 308 | #else |
296 | | - printf("\n"); |
| 309 | + printf("\n"); |
297 | 310 | #endif |
298 | | - } |
299 | 311 | } |
300 | 312 |
|
301 | 313 | void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) { |
302 | 314 | struct hid_stack_element hid_stack[HID_STACK_MAX] = {0}; |
303 | 315 | uint8_t hid_stack_idx = 0; |
304 | 316 | uint8_t usage_idx = 0; |
305 | | - struct hid_report wip_report = {0}; |
306 | 317 | uint16_t usage_list[REPORT_MAX_USAGE] = {0}; |
307 | 318 | uint8_t *end = data + len; |
308 | 319 | uint8_t *desc = data; |
309 | 320 | uint8_t report_id = 0; |
310 | 321 | 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)); |
313 | 327 |
|
314 | 328 | #ifdef CONFIG_BLUERETRO_DUMP_HID_DESC |
315 | 329 | data_dump(data, len); |
@@ -405,106 +419,75 @@ void hid_parser(struct bt_data *bt_data, uint8_t *data, uint32_t len) { |
405 | 419 | break; |
406 | 420 | case 0x7C: |
407 | 421 | break; |
408 | | - case HID_MI_INPUT: /* 0x81 */ |
409 | 422 | 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) { |
411 | 427 | 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]; |
435 | 437 | } |
436 | 438 | 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; |
438 | 440 | if (idx_end > REPORT_MAX_USAGE) { |
439 | 441 | idx_end = REPORT_MAX_USAGE; |
440 | 442 | } |
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; |
454 | 445 | 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]; |
461 | 447 | } |
462 | 448 | 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]; |
469 | 450 | } |
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; |
482 | 457 | } |
483 | 458 | } |
484 | 459 | } |
485 | 460 | 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; |
487 | 462 | } |
488 | 463 | usage_idx = 0; |
| 464 | + tag_idx = 0; |
489 | 465 | memset(usage_list, 0xFF, sizeof(usage_list)); |
490 | 466 | desc++; |
491 | 467 | break; |
492 | 468 | case HID_GI_REPORT_ID: /* 0x85 */ |
493 | 469 | /* process previous report fingerprint */ |
494 | 470 | 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 | + } |
496 | 482 | report_cnt++; |
497 | 483 | } |
498 | 484 | memset((void *)&wip_report, 0, sizeof(wip_report)); |
499 | 485 | 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 | + } |
508 | 491 | break; |
509 | 492 | case HID_GI_REPORT_COUNT: /* 0x95 */ |
510 | 493 | 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) { |
551 | 534 | return; |
552 | 535 | } |
553 | 536 | } |
554 | | - if (report_cnt == 0 && wip_report.id == 0) { |
| 537 | + if (report_cnt == 0 && wip_report[HID_IN].id == 0) { |
555 | 538 | report_id = 1; |
556 | | - wip_report.id = 1; |
| 539 | + wip_report[HID_IN].id = 1; |
| 540 | + wip_report[HID_OUT].id = 1; |
557 | 541 | } |
558 | 542 | 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 | + } |
560 | 554 | } |
561 | 555 | } |
0 commit comments