Skip to content

Commit ff67c77

Browse files
Reconstruction logic for padding bytes at the end of Reports (only possible for devices without ReportID) (#707)
-Add reconstruction logic of const padding bytes at the end of a report for devices which don't use ReportIDs -Enhanced padding logic to distinguish between byte and bit padding. -Add a new test case for Razer Cobra mouse `1532_00A3_0002_0001` which has a completly con feature report of 90 bytes. -Modified expected report descriptor reference file `045E_02FF_0005_0001_expected.rpt_desc` to include additional padding bytes.
1 parent 750bf20 commit ff67c77

File tree

6 files changed

+415
-6
lines changed

6 files changed

+415
-6
lines changed

windows/hidapi_descriptor_reconstruct.c

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,10 @@ int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned cha
537537
}
538538
}
539539

540+
BOOLEAN devicehasReportIDs = FALSE;
540541
struct rd_main_item_node *list = main_item_list; // List root;
542+
// Windows pp_data are per top-level collection, therefore top level coll end is unique
543+
struct rd_main_item_node* node_before_top_level_coll_end = NULL;
541544

542545
while (list->next != NULL)
543546
{
@@ -552,12 +555,20 @@ int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned cha
552555
struct rd_main_item_node *list_node = rd_search_main_item_list_for_bit_position(last_bit_position[list->MainItemType][list->ReportID], list->MainItemType, list->ReportID, &last_report_item_lookup[list->MainItemType][list->ReportID]);
553556
rd_insert_main_item_node(last_bit_position[list->MainItemType][list->ReportID] + 1, list->FirstBit - 1, rd_item_node_padding, -1, 0, list->MainItemType, list->ReportID, &list_node);
554557
}
558+
if (list->ReportID != 0) {
559+
devicehasReportIDs = TRUE;
560+
}
555561
last_bit_position[list->MainItemType][list->ReportID] = list->LastBit;
556562
last_report_item_lookup[list->MainItemType][list->ReportID] = list;
557563
}
558564
}
565+
if (list->next->MainItemType == rd_collection_end) {
566+
// Store the node before the collection end - the last occurence is the end of the top level collection
567+
node_before_top_level_coll_end = list;
568+
}
559569
list = list->next;
560570
}
571+
561572
// Add 8 bit padding at each report end
562573
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
563574
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
@@ -566,10 +577,31 @@ int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned cha
566577
if (padding < 8) {
567578
// Insert padding item after item referenced in last_report_item_lookup
568579
rd_insert_main_item_node(last_bit_position[rt_idx][reportid_idx] + 1, last_bit_position[rt_idx][reportid_idx] + padding, rd_item_node_padding, -1, 0, (rd_main_items) rt_idx, (unsigned char) reportid_idx, &last_report_item_lookup[rt_idx][reportid_idx]);
580+
if (last_report_item_lookup[rt_idx][reportid_idx] == node_before_top_level_coll_end) {
581+
// If this padding item is at the end of the top level collection, update node_before_top_level_coll_end
582+
node_before_top_level_coll_end = last_report_item_lookup[rt_idx][reportid_idx]->next;
583+
}
584+
last_bit_position[rt_idx][reportid_idx] += padding;
569585
}
570586
}
571587
}
572588
}
589+
590+
// Add full byte padding at the end of the report descriptor (only reconstructable, for devices without Report IDs)
591+
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
592+
if (!devicehasReportIDs && pp_data->caps_info[rt_idx].NumberOfCaps > 0 && pp_data->caps_info[rt_idx].ReportByteLength > 0) {
593+
// ReportID 0 means this device uses not Report IDs
594+
// => Maximum one report per type possible, so we can take the size from the buffer size for the report type
595+
const unsigned char reportId = 0;
596+
// ReportByteLength is the report length in bytes plus the one byte for the optional ReportID
597+
int padding = (pp_data->caps_info[rt_idx].ReportByteLength - 1) * 8 - (last_bit_position[rt_idx][reportId] + 1);
598+
599+
if (padding > 0) {
600+
// Insert padding item after item referenced in last_report_item_lookup
601+
rd_insert_main_item_node(last_bit_position[rt_idx][reportId] + 1, last_bit_position[rt_idx][reportId] + padding, rd_item_node_padding, -1, 0, (rd_main_items)rt_idx, reportId, &node_before_top_level_coll_end);
602+
}
603+
}
604+
}
573605
}
574606

575607

@@ -652,13 +684,25 @@ int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned cha
652684
else if (main_item_list->TypeOfNode == rd_item_node_padding) {
653685
// Padding
654686
// The preparsed data doesn't contain any information about padding. Therefore all undefined gaps
655-
// in the reports are filled with the same style of constant padding.
687+
// in the reports are filled with the same style of constant bit or byte padding.
688+
689+
if ((main_item_list->LastBit - main_item_list->FirstBit + 1) % 8 == 0) {
690+
// Padding in full bytes
656691

657-
// Write "Report Size" with number of padding bits
658-
rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc);
692+
// Write "Report Size" for padding bytes is 8
693+
rd_write_short_item(rd_global_report_size, 8, &rpt_desc);
659694

660-
// Write "Report Count" for padding always as 1
661-
rd_write_short_item(rd_global_report_count, 1, &rpt_desc);
695+
// Write "Report Count" with number of padding bytes
696+
rd_write_short_item(rd_global_report_count, (main_item_list->LastBit - main_item_list->FirstBit + 1) / 8, &rpt_desc);
697+
} else {
698+
// Padding in bits
699+
700+
// Write "Report Size" with number of padding bits
701+
rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc);
702+
703+
// Write "Report Count" for padding bits is 1
704+
rd_write_short_item(rd_global_report_count, 1, &rpt_desc);
705+
}
662706

663707
if (rt_idx == HidP_Input) {
664708
// Write "Input" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const

windows/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ set(HID_DESCRIPTOR_RECONSTRUCT_TEST_CASES
4040
047F_C056_0003_FFA0
4141
047F_C056_0005_000B
4242
045E_02FF_0005_0001
43+
1532_00A3_0002_0001
4344
)
4445

4546
set(CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION "3.22")

windows/test/data/045E_02FF_0005_0001_expected.rpt_desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
0x00, 0x81, 0x02, 0x05, 0x01, 0x09, 0x39, 0x15, 0x01, 0x25,
1010
0x08, 0x35, 0x00, 0x46, 0x3B, 0x10, 0x65, 0x0E, 0x75, 0x04,
1111
0x95, 0x01, 0x81, 0x42, 0x75, 0x04, 0x95, 0x01, 0x81, 0x03,
12-
0xC0,
12+
0x75, 0x08, 0x95, 0x02, 0x81, 0x03, 0xC0,

0 commit comments

Comments
 (0)