Atlas - hidapi_descriptor_reconstruct.c
Home / ext / SDL / src / hidapi / windows Lines: 1 | Size: 50700 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/******************************************************* 2 HIDAPI - Multi-Platform library for 3 communication with HID devices. 4 5 libusb/hidapi Team 6 7 Copyright 2022, All Rights Reserved. 8 9 At the discretion of the user of this library, 10 this software may be licensed under the terms of the 11 GNU General Public License v3, a BSD-Style license, or the 12 original HIDAPI license as outlined in the LICENSE.txt, 13 LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt 14 files located at the root of the source distribution. 15 These files may also be found in the public source 16 code repository located at: 17 https://github.com/libusb/hidapi . 18********************************************************/ 19#include "hidapi_descriptor_reconstruct.h" 20 21/** 22 * @brief References to report descriptor buffer. 23 * 24 */ 25struct rd_buffer { 26 unsigned char* buf; /* Pointer to the array which stores the reconstructed descriptor */ 27 size_t buf_size; /* Size of the buffer in bytes */ 28 size_t byte_idx; /* Index of the next report byte to write to buf array */ 29}; 30 31/** 32 * @brief Function that appends a byte to encoded report descriptor buffer. 33 * 34 * @param[in] byte Single byte to append. 35 * @param rpt_desc Pointer to report descriptor buffer struct. 36 */ 37static void rd_append_byte(unsigned char byte, struct rd_buffer* rpt_desc) { 38 if (rpt_desc->byte_idx < rpt_desc->buf_size) { 39 rpt_desc->buf[rpt_desc->byte_idx] = byte; 40 rpt_desc->byte_idx++; 41 } 42} 43 44/** 45 * @brief Writes a short report descriptor item according USB HID spec 1.11 chapter 6.2.2.2. 46 * 47 * @param[in] rd_item Enumeration identifying type (Main, Global, Local) and function (e.g Usage or Report Count) of the item. 48 * @param[in] data Data (Size depends on rd_item 0,1,2 or 4bytes). 49 * @param rpt_desc Pointer to report descriptor buffer struct. 50 * 51 * @return Returns 0 if successful, -1 for error. 52 */ 53static int rd_write_short_item(rd_items rd_item, LONG64 data, struct rd_buffer* rpt_desc) { 54 if (rd_item & 0x03) { 55 // Invalid input data, last to bits are reserved for data size 56 return -1; 57 } 58 59 if (rd_item == rd_main_collection_end) { 60 // Item without data (1Byte prefix only) 61 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x00; 62 rd_append_byte(oneBytePrefix, rpt_desc); 63 } 64 else if ((rd_item == rd_global_logical_minimum) || 65 (rd_item == rd_global_logical_maximum) || 66 (rd_item == rd_global_physical_minimum) || 67 (rd_item == rd_global_physical_maximum)) { 68 // Item with signed integer data 69 if ((data >= -128) && (data <= 127)) { 70 // 1Byte prefix + 1Byte data 71 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01; 72 char localData = (char)data; 73 rd_append_byte(oneBytePrefix, rpt_desc); 74 rd_append_byte(localData & 0xFF, rpt_desc); 75 } 76 else if ((data >= -32768) && (data <= 32767)) { 77 // 1Byte prefix + 2Byte data 78 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02; 79 INT16 localData = (INT16)data; 80 rd_append_byte(oneBytePrefix, rpt_desc); 81 rd_append_byte(localData & 0xFF, rpt_desc); 82 rd_append_byte(localData >> 8 & 0xFF, rpt_desc); 83 } 84 else if ((data >= -2147483648LL) && (data <= 2147483647)) { 85 // 1Byte prefix + 4Byte data 86 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03; 87 INT32 localData = (INT32)data; 88 rd_append_byte(oneBytePrefix, rpt_desc); 89 rd_append_byte(localData & 0xFF, rpt_desc); 90 rd_append_byte(localData >> 8 & 0xFF, rpt_desc); 91 rd_append_byte(localData >> 16 & 0xFF, rpt_desc); 92 rd_append_byte(localData >> 24 & 0xFF, rpt_desc); 93 } 94 else { 95 // Data out of 32 bit signed integer range 96 return -1; 97 } 98 } 99 else { 100 // Item with unsigned integer data 101 if ((data >= 0) && (data <= 0xFF)) { 102 // 1Byte prefix + 1Byte data 103 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01; 104 unsigned char localData = (unsigned char)data; 105 rd_append_byte(oneBytePrefix, rpt_desc); 106 rd_append_byte(localData & 0xFF, rpt_desc); 107 } 108 else if ((data >= 0) && (data <= 0xFFFF)) { 109 // 1Byte prefix + 2Byte data 110 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02; 111 UINT16 localData = (UINT16)data; 112 rd_append_byte(oneBytePrefix, rpt_desc); 113 rd_append_byte(localData & 0xFF, rpt_desc); 114 rd_append_byte(localData >> 8 & 0xFF, rpt_desc); 115 } 116 else if ((data >= 0) && (data <= 0xFFFFFFFF)) { 117 // 1Byte prefix + 4Byte data 118 unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03; 119 UINT32 localData = (UINT32)data; 120 rd_append_byte(oneBytePrefix, rpt_desc); 121 rd_append_byte(localData & 0xFF, rpt_desc); 122 rd_append_byte(localData >> 8 & 0xFF, rpt_desc); 123 rd_append_byte(localData >> 16 & 0xFF, rpt_desc); 124 rd_append_byte(localData >> 24 & 0xFF, rpt_desc); 125 } 126 else { 127 // Data out of 32 bit unsigned integer range 128 return -1; 129 } 130 } 131 return 0; 132} 133 134static struct rd_main_item_node * rd_append_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) { 135 struct rd_main_item_node *new_list_node; 136 137 // Determine last node in the list 138 while (*list != NULL) 139 { 140 list = &(*list)->next; 141 } 142 143 new_list_node = malloc(sizeof(*new_list_node)); // Create new list entry 144 new_list_node->FirstBit = first_bit; 145 new_list_node->LastBit = last_bit; 146 new_list_node->TypeOfNode = type_of_node; 147 new_list_node->CapsIndex = caps_index; 148 new_list_node->CollectionIndex = collection_index; 149 new_list_node->MainItemType = main_item_type; 150 new_list_node->ReportID = report_id; 151 new_list_node->next = NULL; // NULL marks last node in the list 152 153 *list = new_list_node; 154 return new_list_node; 155} 156 157static struct rd_main_item_node * rd_insert_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) { 158 // Insert item after the main item node referenced by list 159 struct rd_main_item_node *next_item = (*list)->next; 160 (*list)->next = NULL; 161 rd_append_main_item_node(first_bit, last_bit, type_of_node, caps_index, collection_index, main_item_type, report_id, list); 162 (*list)->next->next = next_item; 163 return (*list)->next; 164} 165 166static struct rd_main_item_node * rd_search_main_item_list_for_bit_position(int search_bit, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) { 167 // Determine first INPUT/OUTPUT/FEATURE main item, where the last bit position is equal or greater than the search bit position 168 169 while (((*list)->next->MainItemType != rd_collection) && 170 ((*list)->next->MainItemType != rd_collection_end) && 171 !(((*list)->next->LastBit >= search_bit) && 172 ((*list)->next->ReportID == report_id) && 173 ((*list)->next->MainItemType == main_item_type)) 174 ) 175 { 176 list = &(*list)->next; 177 } 178 return *list; 179} 180 181int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned char *buf, size_t buf_size) 182{ 183 hidp_preparsed_data *pp_data = (hidp_preparsed_data *) preparsed_data; 184 185 // Check if MagicKey is correct, to ensure that pp_data points to an valid preparse data structure 186 if (memcmp(pp_data->MagicKey, "HidP KDR", 8) != 0) { 187 return -1; 188 } 189 190 struct rd_buffer rpt_desc; 191 rpt_desc.buf = buf; 192 rpt_desc.buf_size = buf_size; 193 rpt_desc.byte_idx = 0; 194 195 // Set pointer to the first node of link_collection_nodes 196 phid_pp_link_collection_node link_collection_nodes = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray); 197 198 // **************************************************************************************************************************** 199 // Create lookup tables for the bit range of each report per collection (position of first bit and last bit in each collection) 200 // coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE] 201 // **************************************************************************************************************************** 202 203 // Allocate memory and initialize lookup table 204 rd_bit_range ****coll_bit_range; 205 coll_bit_range = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_bit_range)); 206 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) { 207 coll_bit_range[collection_node_idx] = malloc(256 * sizeof(*coll_bit_range[0])); // 256 possible report IDs (incl. 0x00) 208 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) { 209 coll_bit_range[collection_node_idx][reportid_idx] = malloc(NUM_OF_HIDP_REPORT_TYPES * sizeof(*coll_bit_range[0][0])); 210 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 211 coll_bit_range[collection_node_idx][reportid_idx][rt_idx] = malloc(sizeof(rd_bit_range)); 212 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = -1; 213 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = -1; 214 } 215 } 216 } 217 218 // Fill the lookup table where caps exist 219 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 220 for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) { 221 int first_bit, last_bit; 222 first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8 223 + pp_data->caps[caps_idx].BitPosition; 224 last_bit = first_bit + pp_data->caps[caps_idx].ReportSize 225 * pp_data->caps[caps_idx].ReportCount - 1; 226 if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit == -1 || 227 coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit > first_bit) { 228 coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit = first_bit; 229 } 230 if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit < last_bit) { 231 coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit = last_bit; 232 } 233 } 234 } 235 236 // ************************************************************************* 237 // -Determine hierarchy levels of each collections and store it in: 238 // coll_levels[COLLECTION_INDEX] 239 // -Determine number of direct childs of each collections and store it in: 240 // coll_number_of_direct_childs[COLLECTION_INDEX] 241 // ************************************************************************* 242 int max_coll_level = 0; 243 int *coll_levels = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_levels[0])); 244 int *coll_number_of_direct_childs = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_number_of_direct_childs[0])); 245 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) { 246 coll_levels[collection_node_idx] = -1; 247 coll_number_of_direct_childs[collection_node_idx] = 0; 248 } 249 250 { 251 int actual_coll_level = 0; 252 USHORT collection_node_idx = 0; 253 while (actual_coll_level >= 0) { 254 coll_levels[collection_node_idx] = actual_coll_level; 255 if ((link_collection_nodes[collection_node_idx].NumberOfChildren > 0) && 256 (coll_levels[link_collection_nodes[collection_node_idx].FirstChild] == -1)) { 257 actual_coll_level++; 258 coll_levels[collection_node_idx] = actual_coll_level; 259 if (max_coll_level < actual_coll_level) { 260 max_coll_level = actual_coll_level; 261 } 262 coll_number_of_direct_childs[collection_node_idx]++; 263 collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild; 264 } 265 else if (link_collection_nodes[collection_node_idx].NextSibling != 0) { 266 coll_number_of_direct_childs[link_collection_nodes[collection_node_idx].Parent]++; 267 collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling; 268 } 269 else { 270 actual_coll_level--; 271 if (actual_coll_level >= 0) { 272 collection_node_idx = link_collection_nodes[collection_node_idx].Parent; 273 } 274 } 275 } 276 } 277 278 // ********************************************************************************* 279 // Propagate the bit range of each report from the child collections to their parent 280 // and store the merged result for the parent 281 // ********************************************************************************* 282 for (int actual_coll_level = max_coll_level - 1; actual_coll_level >= 0; actual_coll_level--) { 283 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) { 284 if (coll_levels[collection_node_idx] == actual_coll_level) { 285 USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild; 286 while (child_idx) { 287 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) { 288 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 289 // Merge bit range from childs 290 if ((coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit != -1) && 291 (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit)) { 292 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit; 293 } 294 if (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit < coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit) { 295 coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit; 296 } 297 child_idx = link_collection_nodes[child_idx].NextSibling; 298 } 299 } 300 } 301 } 302 } 303 } 304 305 // ************************************************************************************************** 306 // Determine child collection order of the whole hierarchy, based on previously determined bit ranges 307 // and store it this index coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX] 308 // ************************************************************************************************** 309 USHORT **coll_child_order; 310 coll_child_order = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_child_order)); 311 { 312 BOOLEAN *coll_parsed_flag; 313 coll_parsed_flag = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_parsed_flag[0])); 314 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) { 315 coll_parsed_flag[collection_node_idx] = FALSE; 316 } 317 int actual_coll_level = 0; 318 USHORT collection_node_idx = 0; 319 while (actual_coll_level >= 0) { 320 if ((coll_number_of_direct_childs[collection_node_idx] != 0) && 321 (coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] == FALSE)) { 322 coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] = TRUE; 323 coll_child_order[collection_node_idx] = malloc((coll_number_of_direct_childs[collection_node_idx]) * sizeof(*coll_child_order[0])); 324 325 { 326 // Create list of child collection indices 327 // sorted reverse to the order returned to HidP_GetLinkCollectionNodeschild 328 // which seems to match the original order, as long as no bit position needs to be considered 329 USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild; 330 int child_count = coll_number_of_direct_childs[collection_node_idx] - 1; 331 coll_child_order[collection_node_idx][child_count] = child_idx; 332 while (link_collection_nodes[child_idx].NextSibling) { 333 child_count--; 334 child_idx = link_collection_nodes[child_idx].NextSibling; 335 coll_child_order[collection_node_idx][child_count] = child_idx; 336 } 337 } 338 339 if (coll_number_of_direct_childs[collection_node_idx] > 1) { 340 // Sort child collections indices by bit positions 341 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 342 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) { 343 for (int child_idx = 1; child_idx < coll_number_of_direct_childs[collection_node_idx]; child_idx++) { 344 // since the coll_bit_range array is not sorted, we need to reference the collection index in 345 // our sorted coll_child_order array, and look up the corresponding bit ranges for comparing values to sort 346 int prev_coll_idx = coll_child_order[collection_node_idx][child_idx - 1]; 347 int cur_coll_idx = coll_child_order[collection_node_idx][child_idx]; 348 if ((coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) && 349 (coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) && 350 (coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit)) { 351 // Swap position indices of the two compared child collections 352 USHORT idx_latch = coll_child_order[collection_node_idx][child_idx - 1]; 353 coll_child_order[collection_node_idx][child_idx - 1] = coll_child_order[collection_node_idx][child_idx]; 354 coll_child_order[collection_node_idx][child_idx] = idx_latch; 355 } 356 } 357 } 358 } 359 } 360 actual_coll_level++; 361 collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild; 362 } 363 else if (link_collection_nodes[collection_node_idx].NextSibling != 0) { 364 collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling; 365 } 366 else { 367 actual_coll_level--; 368 if (actual_coll_level >= 0) { 369 collection_node_idx = link_collection_nodes[collection_node_idx].Parent; 370 } 371 } 372 } 373 free(coll_parsed_flag); 374 } 375 376 377 // *************************************************************************************** 378 // Create sorted main_item_list containing all the Collection and CollectionEnd main items 379 // *************************************************************************************** 380 struct rd_main_item_node *main_item_list = NULL; // List root 381 // Lookup table to find the Collection items in the list by index 382 struct rd_main_item_node **coll_begin_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_begin_lookup)); 383 struct rd_main_item_node **coll_end_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_end_lookup)); 384 { 385 int *coll_last_written_child = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_last_written_child[0])); 386 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) { 387 coll_last_written_child[collection_node_idx] = -1; 388 } 389 390 int actual_coll_level = 0; 391 USHORT collection_node_idx = 0; 392 struct rd_main_item_node *firstDelimiterNode = NULL; 393 struct rd_main_item_node *delimiterCloseNode = NULL; 394 coll_begin_lookup[0] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list); 395 while (actual_coll_level >= 0) { 396 if ((coll_number_of_direct_childs[collection_node_idx] != 0) && 397 (coll_last_written_child[collection_node_idx] == -1)) { 398 // Collection has child collections, but none is written to the list yet 399 400 coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][0]; 401 collection_node_idx = coll_child_order[collection_node_idx][0]; 402 403 // In a HID Report Descriptor, the first usage declared is the most preferred usage for the control. 404 // While the order in the WIN32 capabiliy strutures is the opposite: 405 // Here the preferred usage is the last aliased usage in the sequence. 406 407 if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) { 408 // Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output) 409 firstDelimiterNode = main_item_list; 410 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list); 411 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list); 412 delimiterCloseNode = main_item_list; 413 } 414 else { 415 // Normal not aliased collection 416 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list); 417 actual_coll_level++; 418 } 419 420 421 } 422 else if ((coll_number_of_direct_childs[collection_node_idx] > 1) && 423 (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][coll_number_of_direct_childs[collection_node_idx] - 1])) { 424 // Collection has child collections, and this is not the first child 425 426 int nextChild = 1; 427 while (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][nextChild - 1]) { 428 nextChild++; 429 } 430 coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][nextChild]; 431 collection_node_idx = coll_child_order[collection_node_idx][nextChild]; 432 433 if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) { 434 // Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output) 435 firstDelimiterNode = main_item_list; 436 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list); 437 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list); 438 delimiterCloseNode = main_item_list; 439 } 440 else if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) { 441 coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode); 442 } 443 else if (!link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) { 444 coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode); 445 coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_open, 0, &firstDelimiterNode); 446 firstDelimiterNode = NULL; 447 main_item_list = delimiterCloseNode; 448 delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE 449 } 450 if (!link_collection_nodes[collection_node_idx].IsAlias) { 451 coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list); 452 actual_coll_level++; 453 } 454 } 455 else { 456 actual_coll_level--; 457 coll_end_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection_end, 0, &main_item_list); 458 collection_node_idx = link_collection_nodes[collection_node_idx].Parent; 459 } 460 } 461 free(coll_last_written_child); 462 } 463 464 465 // **************************************************************** 466 // Inserted Input/Output/Feature main items into the main_item_list 467 // in order of reconstructed bit positions 468 // **************************************************************** 469 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 470 // Add all value caps to node list 471 struct rd_main_item_node *firstDelimiterNode = NULL; 472 struct rd_main_item_node *delimiterCloseNode = NULL; 473 for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) { 474 struct rd_main_item_node *coll_begin = coll_begin_lookup[pp_data->caps[caps_idx].LinkCollection]; 475 int first_bit, last_bit; 476 first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8 + 477 pp_data->caps[caps_idx].BitPosition; 478 last_bit = first_bit + pp_data->caps[caps_idx].ReportSize * 479 pp_data->caps[caps_idx].ReportCount - 1; 480 481 for (int child_idx = 0; child_idx < coll_number_of_direct_childs[pp_data->caps[caps_idx].LinkCollection]; child_idx++) { 482 // Determine in which section before/between/after child collection the item should be inserted 483 if (first_bit < coll_bit_range[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit) 484 { 485 // Note, that the default value for undefined coll_bit_range is -1, which can't be greater than the bit position 486 break; 487 } 488 coll_begin = coll_end_lookup[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]]; 489 } 490 struct rd_main_item_node *list_node; 491 list_node = rd_search_main_item_list_for_bit_position(first_bit, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &coll_begin); 492 493 // In a HID Report Descriptor, the first usage declared is the most preferred usage for the control. 494 // While the order in the WIN32 capabiliy strutures is the opposite: 495 // Here the preferred usage is the last aliased usage in the sequence. 496 497 if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode == NULL)) { 498 // Alliased Usage (First node in pp_data->caps -> Last entry in report descriptor output) 499 firstDelimiterNode = list_node; 500 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node); 501 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_close, pp_data->caps[caps_idx].ReportID, &list_node); 502 delimiterCloseNode = list_node; 503 } else if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) { 504 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node); 505 } 506 else if (!pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) { 507 // Alliased Collection (Last node in pp_data->caps -> First entry in report descriptor output) 508 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node); 509 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_open, pp_data->caps[caps_idx].ReportID, &list_node); 510 firstDelimiterNode = NULL; 511 list_node = delimiterCloseNode; 512 delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE 513 } 514 if (!pp_data->caps[caps_idx].IsAlias) { 515 rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &list_node); 516 } 517 } 518 } 519 520 521 // *********************************************************** 522 // Add const main items for padding to main_item_list 523 // -To fill all bit gaps 524 // -At each report end for 8bit padding 525 // Note that information about the padding at the report end, 526 // is not stored in the preparsed data, but in practice all 527 // report descriptors seem to have it, as assumed here. 528 // *********************************************************** 529 { 530 int *last_bit_position[NUM_OF_HIDP_REPORT_TYPES]; 531 struct rd_main_item_node **last_report_item_lookup[NUM_OF_HIDP_REPORT_TYPES]; 532 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 533 last_bit_position[rt_idx] = malloc(256 * sizeof(*last_bit_position[rt_idx])); 534 last_report_item_lookup[rt_idx] = malloc(256 * sizeof(*last_report_item_lookup[rt_idx])); 535 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) { 536 last_bit_position[rt_idx][reportid_idx] = -1; 537 last_report_item_lookup[rt_idx][reportid_idx] = NULL; 538 } 539 } 540 541 struct rd_main_item_node *list = main_item_list; // List root; 542 543 while (list->next != NULL) 544 { 545 if ((list->MainItemType >= rd_input) && 546 (list->MainItemType <= rd_feature)) { 547 // INPUT, OUTPUT or FEATURE 548 if (list->FirstBit != -1) { 549 if ((last_bit_position[list->MainItemType][list->ReportID] + 1 != list->FirstBit) && 550 (last_report_item_lookup[list->MainItemType][list->ReportID] != NULL) && 551 (last_report_item_lookup[list->MainItemType][list->ReportID]->FirstBit != list->FirstBit) // Happens in case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array 552 ) { 553 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]); 554 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); 555 } 556 last_bit_position[list->MainItemType][list->ReportID] = list->LastBit; 557 last_report_item_lookup[list->MainItemType][list->ReportID] = list; 558 } 559 } 560 list = list->next; 561 } 562 // Add 8 bit padding at each report end 563 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 564 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) { 565 if (last_bit_position[rt_idx][reportid_idx] != -1) { 566 int padding = 8 - ((last_bit_position[rt_idx][reportid_idx] + 1) % 8); 567 if (padding < 8) { 568 // Insert padding item after item referenced in last_report_item_lookup 569 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]); 570 } 571 } 572 } 573 free(last_bit_position[rt_idx]); 574 free(last_report_item_lookup[rt_idx]); 575 } 576 } 577 578 579 // *********************************** 580 // Encode the report descriptor output 581 // *********************************** 582 UCHAR last_report_id = 0; 583 USAGE last_usage_page = 0; 584 LONG last_physical_min = 0;// If both, Physical Minimum and Physical Maximum are 0, the logical limits should be taken as physical limits according USB HID spec 1.11 chapter 6.2.2.7 585 LONG last_physical_max = 0; 586 ULONG last_unit_exponent = 0; // If Unit Exponent is Undefined it should be considered as 0 according USB HID spec 1.11 chapter 6.2.2.7 587 ULONG last_unit = 0; // If the first nibble is 7, or second nibble of Unit is 0, the unit is None according USB HID spec 1.11 chapter 6.2.2.7 588 BOOLEAN inhibit_write_of_usage = FALSE; // Needed in case of delimited usage print, before the normal collection or cap 589 int report_count = 0; 590 while (main_item_list != NULL) 591 { 592 int rt_idx = main_item_list->MainItemType; 593 int caps_idx = main_item_list->CapsIndex; 594 if (main_item_list->MainItemType == rd_collection) { 595 if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) { 596 // Write "Usage Page" at the begin of a collection - except it refers the same table as wrote last 597 rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc); 598 last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage; 599 } 600 if (inhibit_write_of_usage) { 601 // Inhibit only once after DELIMITER statement 602 inhibit_write_of_usage = FALSE; 603 } 604 else { 605 // Write "Usage" of collection 606 rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc); 607 } 608 // Write begin of "Collection" 609 rd_write_short_item(rd_main_collection, link_collection_nodes[main_item_list->CollectionIndex].CollectionType, &rpt_desc); 610 } 611 else if (main_item_list->MainItemType == rd_collection_end) { 612 // Write "End Collection" 613 rd_write_short_item(rd_main_collection_end, 0, &rpt_desc); 614 } 615 else if (main_item_list->MainItemType == rd_delimiter_open) { 616 if (main_item_list->CollectionIndex != -1) { 617 // Write "Usage Page" inside of a collection delmiter section 618 if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) { 619 rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc); 620 last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage; 621 } 622 } 623 else if (main_item_list->CapsIndex != 0) { 624 // Write "Usage Page" inside of a main item delmiter section 625 if (pp_data->caps[caps_idx].UsagePage != last_usage_page) { 626 rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc); 627 last_usage_page = pp_data->caps[caps_idx].UsagePage; 628 } 629 } 630 // Write "Delimiter Open" 631 rd_write_short_item(rd_local_delimiter, 1, &rpt_desc); // 1 = open set of aliased usages 632 } 633 else if (main_item_list->MainItemType == rd_delimiter_usage) { 634 if (main_item_list->CollectionIndex != -1) { 635 // Write aliased collection "Usage" 636 rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc); 637 } if (main_item_list->CapsIndex != 0) { 638 // Write aliased main item range from "Usage Minimum" to "Usage Maximum" 639 if (pp_data->caps[caps_idx].IsRange) { 640 rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc); 641 rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc); 642 } 643 else { 644 // Write single aliased main item "Usage" 645 rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc); 646 } 647 } 648 } 649 else if (main_item_list->MainItemType == rd_delimiter_close) { 650 // Write "Delimiter Close" 651 rd_write_short_item(rd_local_delimiter, 0, &rpt_desc); // 0 = close set of aliased usages 652 // Inhibit next usage write 653 inhibit_write_of_usage = TRUE; 654 } 655 else if (main_item_list->TypeOfNode == rd_item_node_padding) { 656 // Padding 657 // The preparsed data doesn't contain any information about padding. Therefore all undefined gaps 658 // in the reports are filled with the same style of constant padding. 659 660 // Write "Report Size" with number of padding bits 661 rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc); 662 663 // Write "Report Count" for padding always as 1 664 rd_write_short_item(rd_global_report_count, 1, &rpt_desc); 665 666 if (rt_idx == HidP_Input) { 667 // 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 668 rd_write_short_item(rd_main_input, 0x03, &rpt_desc); // Const / Abs 669 } 670 else if (rt_idx == HidP_Output) { 671 // Write "Output" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const 672 rd_write_short_item(rd_main_output, 0x03, &rpt_desc); // Const / Abs 673 } 674 else if (rt_idx == HidP_Feature) { 675 // Write "Feature" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const 676 rd_write_short_item(rd_main_feature, 0x03, &rpt_desc); // Const / Abs 677 } 678 report_count = 0; 679 } 680 else if (pp_data->caps[caps_idx].IsButtonCap) { 681 // Button 682 // (The preparsed data contain different data for 1 bit Button caps, than for parametric Value caps) 683 684 if (last_report_id != pp_data->caps[caps_idx].ReportID) { 685 // Write "Report ID" if changed 686 rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc); 687 last_report_id = pp_data->caps[caps_idx].ReportID; 688 } 689 690 // Write "Usage Page" when changed 691 if (pp_data->caps[caps_idx].UsagePage != last_usage_page) { 692 rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc); 693 last_usage_page = pp_data->caps[caps_idx].UsagePage; 694 } 695 696 // Write only local report items for each cap, if ReportCount > 1 697 if (pp_data->caps[caps_idx].IsRange) { 698 report_count += (pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin); 699 } 700 701 if (inhibit_write_of_usage) { 702 // Inhibit only once after Delimiter - Reset flag 703 inhibit_write_of_usage = FALSE; 704 } 705 else { 706 if (pp_data->caps[caps_idx].IsRange) { 707 // Write range from "Usage Minimum" to "Usage Maximum" 708 rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc); 709 rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc); 710 } 711 else { 712 // Write single "Usage" 713 rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc); 714 } 715 } 716 717 if (pp_data->caps[caps_idx].IsDesignatorRange) { 718 // Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum" 719 rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc); 720 rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc); 721 } 722 else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) { 723 // Designator set 0 is a special descriptor set (of the HID Physical Descriptor), 724 // that specifies the number of additional descriptor sets. 725 // Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it. 726 // Write single "Designator Index" 727 rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc); 728 } 729 730 if (pp_data->caps[caps_idx].IsStringRange) { 731 // Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum" 732 rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc); 733 rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc); 734 } 735 else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) { 736 // String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages, 737 // therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it. 738 // Write single "String Index" 739 rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc); 740 } 741 742 if ((main_item_list->next != NULL) && 743 ((int)main_item_list->next->MainItemType == rt_idx) && 744 (main_item_list->next->TypeOfNode == rd_item_node_cap) && 745 (pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) && 746 (!pp_data->caps[caps_idx].IsRange) && // This node in list is no array 747 (!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array 748 (pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) && 749 (pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) && 750 (pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField) 751 ) { 752 if (main_item_list->next->FirstBit != main_item_list->FirstBit) { 753 // In case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array, the report count should be incremented 754 755 // Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields 756 report_count++; 757 } 758 } 759 else { 760 761 if ((pp_data->caps[caps_idx].Button.LogicalMin == 0) && 762 (pp_data->caps[caps_idx].Button.LogicalMax == 0)) { 763 // While a HID report descriptor must always contain LogicalMinimum and LogicalMaximum, 764 // the preparsed data contain both fields set to zero, for the case of simple buttons 765 // Write "Logical Minimum" set to 0 and "Logical Maximum" set to 1 766 rd_write_short_item(rd_global_logical_minimum, 0, &rpt_desc); 767 rd_write_short_item(rd_global_logical_maximum, 1, &rpt_desc); 768 } 769 else { 770 // Write logical range from "Logical Minimum" to "Logical Maximum" 771 rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].Button.LogicalMin, &rpt_desc); 772 rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].Button.LogicalMax, &rpt_desc); 773 } 774 775 // Write "Report Size" 776 rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc); 777 778 // Write "Report Count" 779 if (!pp_data->caps[caps_idx].IsRange) { 780 // Variable bit field with one bit per button 781 // In case of multiple usages with the same items, only "Usage" is written per cap, and "Report Count" is incremented 782 rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc); 783 } 784 else { 785 // Button array of "Report Size" x "Report Count 786 rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount, &rpt_desc); 787 } 788 789 790 // Buttons have only 1 bit and therefore no physical limits/units -> Set to undefined state 791 if (last_physical_min != 0) { 792 // Write "Physical Minimum", but only if changed 793 last_physical_min = 0; 794 rd_write_short_item(rd_global_physical_minimum, last_physical_min, &rpt_desc); 795 } 796 if (last_physical_max != 0) { 797 // Write "Physical Maximum", but only if changed 798 last_physical_max = 0; 799 rd_write_short_item(rd_global_physical_maximum, last_physical_max, &rpt_desc); 800 } 801 if (last_unit_exponent != 0) { 802 // Write "Unit Exponent", but only if changed 803 last_unit_exponent = 0; 804 rd_write_short_item(rd_global_unit_exponent, last_unit_exponent, &rpt_desc); 805 } 806 if (last_unit != 0) { 807 // Write "Unit",but only if changed 808 last_unit = 0; 809 rd_write_short_item(rd_global_unit, last_unit, &rpt_desc); 810 } 811 812 // Write "Input" main item 813 if (rt_idx == HidP_Input) { 814 rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc); 815 } 816 // Write "Output" main item 817 else if (rt_idx == HidP_Output) { 818 rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc); 819 } 820 // Write "Feature" main item 821 else if (rt_idx == HidP_Feature) { 822 rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc); 823 } 824 report_count = 0; 825 } 826 } 827 else { 828 829 if (last_report_id != pp_data->caps[caps_idx].ReportID) { 830 // Write "Report ID" if changed 831 rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc); 832 last_report_id = pp_data->caps[caps_idx].ReportID; 833 } 834 835 // Write "Usage Page" if changed 836 if (pp_data->caps[caps_idx].UsagePage != last_usage_page) { 837 rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc); 838 last_usage_page = pp_data->caps[caps_idx].UsagePage; 839 } 840 841 if (inhibit_write_of_usage) { 842 // Inhibit only once after Delimiter - Reset flag 843 inhibit_write_of_usage = FALSE; 844 } 845 else { 846 if (pp_data->caps[caps_idx].IsRange) { 847 // Write usage range from "Usage Minimum" to "Usage Maximum" 848 rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc); 849 rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc); 850 } 851 else { 852 // Write single "Usage" 853 rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc); 854 } 855 } 856 857 if (pp_data->caps[caps_idx].IsDesignatorRange) { 858 // Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum" 859 rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc); 860 rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc); 861 } 862 else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) { 863 // Designator set 0 is a special descriptor set (of the HID Physical Descriptor), 864 // that specifies the number of additional descriptor sets. 865 // Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it. 866 // Write single "Designator Index" 867 rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc); 868 } 869 870 if (pp_data->caps[caps_idx].IsStringRange) { 871 // Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum" 872 rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc); 873 rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc); 874 } 875 else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) { 876 // String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages, 877 // therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it. 878 // Write single "String Index" 879 rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc); 880 } 881 882 if ((pp_data->caps[caps_idx].BitField & 0x02) != 0x02) { 883 // In case of an value array overwrite "Report Count" 884 pp_data->caps[caps_idx].ReportCount = pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin + 1; 885 } 886 887 888 // Print only local report items for each cap, if ReportCount > 1 889 if ((main_item_list->next != NULL) && 890 ((int) main_item_list->next->MainItemType == rt_idx) && 891 (main_item_list->next->TypeOfNode == rd_item_node_cap) && 892 (!pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) && 893 (!pp_data->caps[caps_idx].IsRange) && // This node in list is no array 894 (!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array 895 (pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) && 896 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMin == pp_data->caps[caps_idx].NotButton.LogicalMin) && 897 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMax == pp_data->caps[caps_idx].NotButton.LogicalMax) && 898 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMin == pp_data->caps[caps_idx].NotButton.PhysicalMin) && 899 (pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMax == pp_data->caps[caps_idx].NotButton.PhysicalMax) && 900 (pp_data->caps[main_item_list->next->CapsIndex].UnitsExp == pp_data->caps[caps_idx].UnitsExp) && 901 (pp_data->caps[main_item_list->next->CapsIndex].Units == pp_data->caps[caps_idx].Units) && 902 (pp_data->caps[main_item_list->next->CapsIndex].ReportSize == pp_data->caps[caps_idx].ReportSize) && 903 (pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) && 904 (pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField) && 905 (pp_data->caps[main_item_list->next->CapsIndex].ReportCount == 1) && 906 (pp_data->caps[caps_idx].ReportCount == 1) 907 ) { 908 // Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields 909 report_count++; 910 } 911 else { 912 // Value 913 914 // Write logical range from "Logical Minimum" to "Logical Maximum" 915 rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].NotButton.LogicalMin, &rpt_desc); 916 rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].NotButton.LogicalMax, &rpt_desc); 917 918 if ((last_physical_min != pp_data->caps[caps_idx].NotButton.PhysicalMin) || 919 (last_physical_max != pp_data->caps[caps_idx].NotButton.PhysicalMax)) { 920 // Write range from "Physical Minimum" to " Physical Maximum", but only if one of them changed 921 rd_write_short_item(rd_global_physical_minimum, pp_data->caps[caps_idx].NotButton.PhysicalMin, &rpt_desc); 922 last_physical_min = pp_data->caps[caps_idx].NotButton.PhysicalMin; 923 rd_write_short_item(rd_global_physical_maximum, pp_data->caps[caps_idx].NotButton.PhysicalMax, &rpt_desc); 924 last_physical_max = pp_data->caps[caps_idx].NotButton.PhysicalMax; 925 } 926 927 928 if (last_unit_exponent != pp_data->caps[caps_idx].UnitsExp) { 929 // Write "Unit Exponent", but only if changed 930 rd_write_short_item(rd_global_unit_exponent, pp_data->caps[caps_idx].UnitsExp, &rpt_desc); 931 last_unit_exponent = pp_data->caps[caps_idx].UnitsExp; 932 } 933 934 if (last_unit != pp_data->caps[caps_idx].Units) { 935 // Write physical "Unit", but only if changed 936 rd_write_short_item(rd_global_unit, pp_data->caps[caps_idx].Units, &rpt_desc); 937 last_unit = pp_data->caps[caps_idx].Units; 938 } 939 940 // Write "Report Size" 941 rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc); 942 943 // Write "Report Count" 944 rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc); 945 946 if (rt_idx == HidP_Input) { 947 // Write "Input" main item 948 rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc); 949 } 950 else if (rt_idx == HidP_Output) { 951 // Write "Output" main item 952 rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc); 953 } 954 else if (rt_idx == HidP_Feature) { 955 // Write "Feature" main item 956 rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc); 957 } 958 report_count = 0; 959 } 960 } 961 962 // Go to next item in main_item_list and free the memory of the actual item 963 struct rd_main_item_node *main_item_list_prev = main_item_list; 964 main_item_list = main_item_list->next; 965 free(main_item_list_prev); 966 } 967 968 // Free multidimensionable array: coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE] 969 // Free multidimensionable array: coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX] 970 for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) { 971 for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) { 972 for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) { 973 free(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]); 974 } 975 free(coll_bit_range[collection_node_idx][reportid_idx]); 976 } 977 free(coll_bit_range[collection_node_idx]); 978 if (coll_number_of_direct_childs[collection_node_idx] != 0) free(coll_child_order[collection_node_idx]); 979 } 980 free(coll_bit_range); 981 free(coll_child_order); 982 983 // Free one dimensional arrays 984 free(coll_begin_lookup); 985 free(coll_end_lookup); 986 free(coll_levels); 987 free(coll_number_of_direct_childs); 988 989 return (int) rpt_desc.byte_idx; 990} 991[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.