1 /* 2 * Copyright (C) 2017 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "btstack_hid_parser.c" 39 40 #include <inttypes.h> 41 #include <string.h> 42 43 #include "btstack_hid_parser.h" 44 #include "btstack_util.h" 45 #include "btstack_debug.h" 46 47 // Not implemented: 48 // - Support for Push/Pop 49 // - Optional Pretty Print of HID Descriptor 50 51 // #define HID_PARSER_PRETTY_PRINT 52 53 /* 54 * btstack_hid_parser.c 55 */ 56 57 #ifdef HID_PARSER_PRETTY_PRINT 58 59 static const char * type_names[] = { 60 "Main", 61 "Global", 62 "Local", 63 "Reserved" 64 }; 65 static const char * main_tags[] = { 66 "", 67 "", 68 "", 69 "", 70 "", 71 "", 72 "", 73 "", 74 "Input ", 75 "Output", 76 "Collection", 77 "Feature", 78 "End Collection", 79 "Reserved", 80 "Reserved", 81 "Reserved" 82 }; 83 static const char * global_tags[] = { 84 "Usage Page", 85 "Logical Minimum", 86 "Logical Maximum", 87 "Physical Minimum", 88 "Physical Maximum", 89 "Unit Exponent", 90 "Unit", 91 "Report Size", 92 "Report ID", 93 "Report Count", 94 "Push", 95 "Pop", 96 "Reserved", 97 "Reserved", 98 "Reserved", 99 "Reserved" 100 }; 101 static const char * local_tags[] = { 102 "Usage", 103 "Usage Minimum", 104 "Usage Maximum", 105 "Designator Index", 106 "Designator Minimum", 107 "Designator Maximum", 108 "String Index", 109 "String Minimum", 110 "String Maximum", 111 "Delimiter", 112 "Reserved", 113 "Reserved", 114 "Reserved", 115 "Reserved", 116 "Reserved", 117 "Reserved" 118 }; 119 #endif 120 121 static void hid_pretty_print_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){ 122 #ifdef HID_PARSER_PRETTY_PRINT 123 const char ** item_tag_table; 124 switch ((TagType)item->item_type){ 125 case Main: 126 item_tag_table = main_tags; 127 break; 128 case Global: 129 item_tag_table = global_tags; 130 break; 131 case Local: 132 item_tag_table = local_tags; 133 break; 134 default: 135 item_tag_table = NULL; 136 break; 137 } 138 const char * item_tag_name = "Invalid"; 139 if (item_tag_table){ 140 item_tag_name = item_tag_table[item->item_tag]; 141 } 142 log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], iterator->descriptor[iterator->descriptor_pos], item->item_value); 143 #else 144 UNUSED(iterator); 145 UNUSED(item); 146 #endif 147 } 148 149 // parse descriptor item and read up to 32-bit bit value 150 bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 151 152 const int hid_item_sizes[] = { 0, 1, 2, 4 }; 153 154 // parse item header 155 if (hid_descriptor_len < 1u) return false; 156 uint16_t pos = 0; 157 uint8_t item_header = hid_descriptor[pos++]; 158 item->data_size = hid_item_sizes[item_header & 0x03u]; 159 item->item_type = (item_header & 0x0cu) >> 2u; 160 item->item_tag = (item_header & 0xf0u) >> 4u; 161 // long item 162 if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){ 163 if (hid_descriptor_len < 3u) return false; 164 item->data_size = hid_descriptor[pos++]; 165 item->item_tag = hid_descriptor[pos++]; 166 } 167 item->item_size = pos + item->data_size; 168 item->item_value = 0; 169 170 // read item value 171 if (hid_descriptor_len < item->item_size) return false; 172 if (item->data_size > 4u) return false; 173 int i; 174 int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u); 175 int32_t value = 0; 176 uint8_t latest_byte = 0; 177 for (i=0;i<item->data_size;i++){ 178 latest_byte = hid_descriptor[pos++]; 179 value = (latest_byte << (8*i)) | value; 180 } 181 if (sgnd && (item->data_size > 0u)){ 182 if (latest_byte & 0x80u) { 183 value -= 1u << (item->data_size*8u); 184 } 185 } 186 item->item_value = value; 187 return true; 188 } 189 190 static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){ 191 switch (tag){ 192 case Input: 193 return report_type == HID_REPORT_TYPE_INPUT; 194 case Output: 195 return report_type == HID_REPORT_TYPE_OUTPUT; 196 case Feature: 197 return report_type == HID_REPORT_TYPE_FEATURE; 198 default: 199 return false; 200 } 201 } 202 203 static void btstack_hid_handle_global_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){ 204 switch((GlobalItemTag)item->item_tag){ 205 case UsagePage: 206 iterator->global_usage_page = item->item_value; 207 break; 208 case LogicalMinimum: 209 iterator->global_logical_minimum = item->item_value; 210 break; 211 case LogicalMaximum: 212 iterator->global_logical_maximum = item->item_value; 213 break; 214 case ReportSize: 215 iterator->global_report_size = item->item_value; 216 break; 217 case ReportID: 218 iterator->global_report_id = item->item_value; 219 break; 220 case ReportCount: 221 iterator->global_report_count = item->item_value; 222 break; 223 224 // TODO handle tags 225 case PhysicalMinimum: 226 case PhysicalMaximum: 227 case UnitExponent: 228 case Unit: 229 case Push: 230 case Pop: 231 break; 232 233 default: 234 btstack_assert(false); 235 break; 236 } 237 } 238 239 static void hid_find_next_usage(btstack_hid_usage_iterator_t * main_iterator){ 240 bool have_usage_min = false; 241 bool have_usage_max = false; 242 main_iterator->usage_range = false; 243 btstack_hid_descriptor_iterator_t iterator; 244 btstack_hid_descriptor_iterator_init(&iterator, &main_iterator->descriptor[main_iterator->usage_pos], main_iterator->descriptor_len - main_iterator->usage_pos); 245 while ((main_iterator->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ 246 hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator); 247 if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 248 main_iterator->usage_page = usage_item.item_value; 249 } 250 if (usage_item.item_type == Local){ 251 uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((main_iterator->usage_page << 16u) | usage_item.item_value); 252 switch (usage_item.item_tag){ 253 case Usage: 254 main_iterator->available_usages = 1; 255 main_iterator->usage_minimum = usage_value; 256 break; 257 case UsageMinimum: 258 main_iterator->usage_minimum = usage_value; 259 have_usage_min = true; 260 break; 261 case UsageMaximum: 262 main_iterator->usage_maximum = usage_value; 263 have_usage_max = true; 264 break; 265 default: 266 break; 267 } 268 if (have_usage_min && have_usage_max){ 269 main_iterator->available_usages = main_iterator->usage_maximum - main_iterator->usage_minimum + 1u; 270 main_iterator->usage_range = true; 271 if (main_iterator->available_usages < main_iterator->required_usages){ 272 log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", main_iterator->usage_minimum & 0xffff, main_iterator->usage_maximum & 0xffff, main_iterator->required_usages); 273 } 274 } 275 } 276 } 277 main_iterator->usage_pos += iterator.descriptor_pos; 278 } 279 280 281 // PUBLIC API 282 283 // HID Descriptor Iterator 284 285 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 286 iterator->descriptor = hid_descriptor; 287 iterator->descriptor_pos = 0; 288 iterator->descriptor_len = hid_descriptor_len; 289 iterator->item_ready = false; 290 iterator->valid = true; 291 } 292 293 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 294 if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){ 295 uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 296 const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 297 bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 298 if (ok){ 299 iterator->item_ready = true; 300 } else { 301 iterator->valid = false; 302 } 303 } 304 return iterator->item_ready; 305 } 306 307 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 308 iterator->descriptor_pos += iterator->descriptor_item.item_size; 309 iterator->item_ready = false; 310 return &iterator->descriptor_item; 311 } 312 313 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 314 return iterator->valid; 315 } 316 317 318 int btstack_hid_get_report_size_for_id(uint16_t report_id, hid_report_type_t report_type, const uint8_t *hid_descriptor, 319 uint16_t hid_descriptor_len) { 320 int total_report_size = 0; 321 int report_size = 0; 322 int report_count = 0; 323 int current_report_id = HID_REPORT_ID_UNDEFINED; 324 325 btstack_hid_descriptor_iterator_t iterator; 326 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 327 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 328 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 329 int valid_report_type = 0; 330 switch (item->item_type) { 331 case Global: 332 switch ((GlobalItemTag) item->item_tag) { 333 case ReportID: 334 current_report_id = item->item_value; 335 break; 336 case ReportCount: 337 report_count = item->item_value; 338 break; 339 case ReportSize: 340 report_size = item->item_value; 341 break; 342 default: 343 break; 344 } 345 break; 346 case Main: 347 if (current_report_id != report_id) break; 348 switch ((MainItemTag) item->item_tag) { 349 case Input: 350 if (report_type != HID_REPORT_TYPE_INPUT) break; 351 valid_report_type = 1; 352 break; 353 case Output: 354 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 355 valid_report_type = 1; 356 break; 357 case Feature: 358 if (report_type != HID_REPORT_TYPE_FEATURE) break; 359 valid_report_type = 1; 360 break; 361 default: 362 break; 363 } 364 if (!valid_report_type) break; 365 total_report_size += report_count * report_size; 366 break; 367 default: 368 break; 369 } 370 if (total_report_size > 0 && current_report_id != report_id) break; 371 } 372 373 if (btstack_hid_descriptor_iterator_valid(&iterator)){ 374 return (total_report_size + 7) / 8; 375 } else { 376 return 0; 377 } 378 } 379 380 hid_report_id_status_t btstack_hid_report_id_valid(uint16_t report_id, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 381 uint16_t current_report_id = HID_REPORT_ID_UNDEFINED; 382 btstack_hid_descriptor_iterator_t iterator; 383 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 384 bool report_id_found = false; 385 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 386 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 387 switch (item->item_type){ 388 case Global: 389 switch ((GlobalItemTag)item->item_tag){ 390 case ReportID: 391 current_report_id = item->item_value; 392 if (current_report_id == report_id) { 393 report_id_found = true; 394 } 395 default: 396 break; 397 } 398 break; 399 default: 400 break; 401 } 402 } 403 404 if (btstack_hid_descriptor_iterator_valid(&iterator)) { 405 if (report_id_found){ 406 return HID_REPORT_ID_VALID; 407 } 408 if ((report_id == HID_REPORT_ID_UNDEFINED) && (current_report_id == HID_REPORT_ID_UNDEFINED)) { 409 return HID_REPORT_ID_VALID; 410 } 411 return HID_REPORT_ID_UNDECLARED; 412 } else { 413 return HID_REPORT_ID_INVALID; 414 } 415 } 416 417 bool btstack_hid_report_id_declared(const uint8_t *hid_descriptor, uint16_t hid_descriptor_len) { 418 btstack_hid_descriptor_iterator_t iterator; 419 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 420 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 421 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 422 switch (item->item_type){ 423 case Global: 424 switch ((GlobalItemTag)item->item_tag){ 425 case ReportID: 426 return true; 427 default: 428 break; 429 } 430 break; 431 default: 432 break; 433 } 434 } 435 return false; 436 } 437 438 // HID Descriptor Usage Iterator 439 440 static void btstack_parser_usage_iterator_process_item(btstack_hid_usage_iterator_t * iterator, hid_descriptor_item_t * item){ 441 hid_pretty_print_item(iterator, item); 442 int valid_field = 0; 443 uint16_t report_id_before; 444 switch ((TagType)item->item_type){ 445 case Main: 446 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 447 iterator->report_type); 448 break; 449 case Global: 450 report_id_before = iterator->global_report_id; 451 btstack_hid_handle_global_item(iterator, item); 452 // track record id for report handling, reset report position 453 if (report_id_before != iterator->global_report_id){ 454 iterator->report_pos_in_bit = 8u; 455 } 456 break; 457 case Local: 458 case Reserved: 459 break; 460 default: 461 btstack_assert(false); 462 break; 463 } 464 if (!valid_field) return; 465 466 // handle constant fields used for padding 467 if (item->item_value & 1){ 468 int item_bits = iterator->global_report_size * iterator->global_report_count; 469 #ifdef HID_PARSER_PRETTY_PRINT 470 log_info("- Skip %u constant bits", item_bits); 471 #endif 472 iterator->report_pos_in_bit += item_bits; 473 return; 474 } 475 // Empty Item 476 if (iterator->global_report_count == 0u) return; 477 // let's start 478 iterator->required_usages = iterator->global_report_count; 479 } 480 481 static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_usage_iterator_t * iterator) { 482 while (btstack_hid_descriptor_iterator_has_more(&iterator->descriptor_iterator)){ 483 iterator->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&iterator->descriptor_iterator); 484 485 btstack_parser_usage_iterator_process_item(iterator, &iterator->descriptor_item); 486 487 if (iterator->required_usages){ 488 hid_find_next_usage(iterator); 489 if (iterator->available_usages) { 490 iterator->state = BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; 491 return; 492 } else { 493 log_debug("no usages found"); 494 iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; 495 return; 496 } 497 } else { 498 if ((TagType) (&iterator->descriptor_item)->item_type == Main) { 499 // reset usage 500 iterator->usage_pos = iterator->descriptor_iterator.descriptor_pos; 501 iterator->usage_page = iterator->global_usage_page; 502 } 503 } 504 } 505 // end of descriptor 506 iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; 507 } 508 509 void btstack_hid_usage_iterator_init(btstack_hid_usage_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type){ 510 memset(iterator, 0, sizeof(btstack_hid_usage_iterator_t)); 511 512 iterator->descriptor = hid_descriptor; 513 iterator->descriptor_len = hid_descriptor_len; 514 iterator->report_type = hid_report_type; 515 iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; 516 iterator->global_report_id = HID_REPORT_ID_UNDEFINED; 517 btstack_hid_descriptor_iterator_init(&iterator->descriptor_iterator, hid_descriptor, hid_descriptor_len); 518 } 519 520 bool btstack_hid_usage_iterator_has_more(btstack_hid_usage_iterator_t * iterator){ 521 while (iterator->state == BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM){ 522 btstack_hid_usage_iterator_find_next_usage(iterator); 523 } 524 return iterator->state == BTSTACK_HID_USAGE_ITERATOR_USAGES_AVAILABLE; 525 } 526 527 void btstack_hid_usage_iterator_get_item(btstack_hid_usage_iterator_t * iterator, btstack_hid_usage_item_t * item){ 528 // cache current values 529 memset(item, 0, sizeof(btstack_hid_usage_item_t)); 530 item->size = iterator->global_report_size; 531 item->report_id = iterator->global_report_id; 532 item->usage_page = iterator->usage_minimum >> 16; 533 item->bit_pos = iterator->report_pos_in_bit; 534 535 bool is_variable = (iterator->descriptor_item.item_value & 2) != 0; 536 if (is_variable){ 537 item->usage = iterator->usage_minimum & 0xffffu; 538 } 539 iterator->required_usages--; 540 iterator->report_pos_in_bit += iterator->global_report_size; 541 542 // cache descriptor item and 543 item->descriptor_item = iterator->descriptor_item; 544 item->global_logical_minimum = iterator->global_logical_minimum; 545 546 // next usage 547 if (is_variable){ 548 iterator->usage_minimum++; 549 iterator->available_usages--; 550 if (iterator->usage_range && (iterator->usage_minimum > iterator->usage_maximum)){ 551 // usage min - max range smaller than report count, ignore remaining bit in report 552 log_debug("Ignoring %u items without Usage", parser->required_usages); 553 iterator->report_pos_in_bit += iterator->global_report_size * iterator->required_usages; 554 iterator->required_usages = 0; 555 } 556 } else { 557 if (iterator->required_usages == 0u){ 558 iterator->available_usages = 0; 559 } 560 } 561 562 if (iterator->available_usages) { 563 return; 564 } 565 if (iterator->required_usages == 0u){ 566 iterator->state = BTSTACK_HID_USAGE_ITERATOR_STATE_SCAN_FOR_REPORT_ITEM; 567 } else { 568 hid_find_next_usage(iterator); 569 if (iterator->available_usages == 0u) { 570 iterator->state = BTSTACK_HID_USAGE_ITERATOR_PARSER_COMPLETE; 571 } 572 } 573 } 574 575 576 // HID Report Parser 577 578 void btstack_hid_parser_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type, const uint8_t * hid_report, uint16_t hid_report_len){ 579 btstack_hid_usage_iterator_init(&parser->usage_iterator, hid_descriptor, hid_descriptor_len, hid_report_type); 580 parser->report = hid_report; 581 parser->report_len = hid_report_len; 582 parser->have_report_usage_ready = false; 583 } 584 585 /** 586 * @brief Checks if more fields are available 587 * @param parser 588 */ 589 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 590 while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(&parser->usage_iterator)){ 591 btstack_hid_usage_iterator_get_item(&parser->usage_iterator, &parser->descriptor__usage_item); 592 // ignore usages for other report ids 593 if (parser->descriptor__usage_item.report_id != HID_REPORT_ID_UNDEFINED){ 594 if (parser->descriptor__usage_item.report_id != parser->report[0]){ 595 continue; 596 } 597 } 598 parser->have_report_usage_ready = true; 599 } 600 return parser->have_report_usage_ready; 601 } 602 603 /** 604 * @brief Get next field 605 * @param parser 606 * @param usage_page 607 * @param usage 608 * @param value provided in HID report 609 */ 610 611 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 612 613 // fetch data from descriptor usage item 614 uint16_t bit_pos = parser->descriptor__usage_item.bit_pos; 615 uint16_t size = parser->descriptor__usage_item.size; 616 *usage_page = parser->descriptor__usage_item.usage_page; 617 *usage = parser->descriptor__usage_item.usage; 618 619 620 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 621 bool is_variable = (parser->descriptor__usage_item.descriptor_item.item_value & 2) != 0; 622 bool is_signed = parser->descriptor__usage_item.global_logical_minimum < 0; 623 int pos_start = btstack_min( bit_pos >> 3, parser->report_len); 624 int pos_end = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len); 625 int bytes_to_read = pos_end - pos_start + 1; 626 627 int i; 628 uint32_t multi_byte_value = 0; 629 for (i=0;i < bytes_to_read;i++){ 630 multi_byte_value |= parser->report[pos_start+i] << (i*8); 631 } 632 uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u); 633 // log_debug("bit pos %2u, report size %u, start %u, end %u, len %u;; unsigned value %08x", parser->report_pos_in_bit, parser->global_report_size, pos_start, pos_end, parser->report_len, unsigned_value); 634 if (is_variable){ 635 if (is_signed && (unsigned_value & (1u<<(size-1u)))){ 636 *value = unsigned_value - (1u<<size); 637 } else { 638 *value = unsigned_value; 639 } 640 } else { 641 *usage = unsigned_value; 642 *value = 1; 643 } 644 645 parser->have_report_usage_ready = false; 646 } 647