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 Descripor 50 // - Support to query descriptort for contained usages, e.g. to detect keyboard or mouse 51 52 // #define HID_PARSER_PRETTY_PRINT 53 54 /* 55 * btstack_hid_parser.c 56 */ 57 58 #ifdef HID_PARSER_PRETTY_PRINT 59 60 static const char * type_names[] = { 61 "Main", 62 "Global", 63 "Local", 64 "Reserved" 65 }; 66 static const char * main_tags[] = { 67 "", 68 "", 69 "", 70 "", 71 "", 72 "", 73 "", 74 "", 75 "Input ", 76 "Output", 77 "Collection", 78 "Feature", 79 "End Collection", 80 "Reserved", 81 "Reserved", 82 "Reserved" 83 }; 84 static const char * global_tags[] = { 85 "Usage Page", 86 "Logical Minimum", 87 "Logical Maximum", 88 "Physical Minimum", 89 "Physical Maximum", 90 "Unit Exponent", 91 "Unit", 92 "Report Size", 93 "Report ID", 94 "Report Count", 95 "Push", 96 "Pop", 97 "Reserved", 98 "Reserved", 99 "Reserved", 100 "Reserved" 101 }; 102 static const char * local_tags[] = { 103 "Usage", 104 "Usage Minimum", 105 "Usage Maximum", 106 "Designator Index", 107 "Designator Minimum", 108 "Designator Maximum", 109 "String Index", 110 "String Minimum", 111 "String Maximum", 112 "Delimiter", 113 "Reserved", 114 "Reserved", 115 "Reserved", 116 "Reserved", 117 "Reserved", 118 "Reserved" 119 }; 120 #endif 121 122 static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 123 #ifdef HID_PARSER_PRETTY_PRINT 124 const char ** item_tag_table; 125 switch ((TagType)item->item_type){ 126 case Main: 127 item_tag_table = main_tags; 128 break; 129 case Global: 130 item_tag_table = global_tags; 131 break; 132 case Local: 133 item_tag_table = local_tags; 134 break; 135 default: 136 item_tag_table = NULL; 137 break; 138 } 139 const char * item_tag_name = "Invalid"; 140 if (item_tag_table){ 141 item_tag_name = item_tag_table[item->item_tag]; 142 } 143 log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); 144 #else 145 UNUSED(parser); 146 UNUSED(item); 147 #endif 148 } 149 150 // parse descriptor item and read up to 32-bit bit value 151 bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 152 153 const int hid_item_sizes[] = { 0, 1, 2, 4 }; 154 155 // parse item header 156 if (hid_descriptor_len < 1u) return false; 157 uint16_t pos = 0; 158 uint8_t item_header = hid_descriptor[pos++]; 159 item->data_size = hid_item_sizes[item_header & 0x03u]; 160 item->item_type = (item_header & 0x0cu) >> 2u; 161 item->item_tag = (item_header & 0xf0u) >> 4u; 162 // long item 163 if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){ 164 if (hid_descriptor_len < 3u) return false; 165 item->data_size = hid_descriptor[pos++]; 166 item->item_tag = hid_descriptor[pos++]; 167 } 168 item->item_size = pos + item->data_size; 169 item->item_value = 0; 170 171 // read item value 172 if (hid_descriptor_len < item->item_size) return false; 173 if (item->data_size > 4u) return false; 174 int i; 175 int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u); 176 int32_t value = 0; 177 uint8_t latest_byte = 0; 178 for (i=0;i<item->data_size;i++){ 179 latest_byte = hid_descriptor[pos++]; 180 value = (latest_byte << (8*i)) | value; 181 } 182 if (sgnd && (item->data_size > 0u)){ 183 if (latest_byte & 0x80u) { 184 value -= 1u << (item->data_size*8u); 185 } 186 } 187 item->item_value = value; 188 return true; 189 } 190 191 static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){ 192 switch (tag){ 193 case Input: 194 return report_type == HID_REPORT_TYPE_INPUT; 195 case Output: 196 return report_type == HID_REPORT_TYPE_OUTPUT; 197 case Feature: 198 return report_type == HID_REPORT_TYPE_FEATURE; 199 default: 200 return false; 201 } 202 } 203 204 static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 205 switch((GlobalItemTag)item->item_tag){ 206 case UsagePage: 207 parser->global_usage_page = item->item_value; 208 break; 209 case LogicalMinimum: 210 parser->global_logical_minimum = item->item_value; 211 break; 212 case LogicalMaximum: 213 parser->global_logical_maximum = item->item_value; 214 break; 215 case ReportSize: 216 parser->global_report_size = item->item_value; 217 break; 218 case ReportID: 219 parser->global_report_id = item->item_value; 220 break; 221 case ReportCount: 222 parser->global_report_count = item->item_value; 223 break; 224 225 // TODO handle tags 226 case PhysicalMinimum: 227 case PhysicalMaximum: 228 case UnitExponent: 229 case Unit: 230 case Push: 231 case Pop: 232 break; 233 234 default: 235 btstack_assert(false); 236 break; 237 } 238 } 239 240 static void hid_find_next_usage(btstack_hid_parser_t * parser){ 241 bool have_usage_min = false; 242 bool have_usage_max = false; 243 parser->usage_range = false; 244 btstack_hid_descriptor_iterator_t iterator; 245 btstack_hid_descriptor_iterator_init(&iterator, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 246 while ((parser->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ 247 hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator); 248 if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 249 parser->usage_page = usage_item.item_value; 250 } 251 if (usage_item.item_type == Local){ 252 uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); 253 switch (usage_item.item_tag){ 254 case Usage: 255 parser->available_usages = 1; 256 parser->usage_minimum = usage_value; 257 break; 258 case UsageMinimum: 259 parser->usage_minimum = usage_value; 260 have_usage_min = true; 261 break; 262 case UsageMaximum: 263 parser->usage_maximum = usage_value; 264 have_usage_max = true; 265 break; 266 default: 267 break; 268 } 269 if (have_usage_min && have_usage_max){ 270 parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; 271 parser->usage_range = true; 272 if (parser->available_usages < parser->required_usages){ 273 log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); 274 } 275 } 276 } 277 } 278 parser->usage_pos += iterator.descriptor_pos; 279 } 280 281 static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 282 hid_pretty_print_item(parser, item); 283 int valid_field = 0; 284 uint16_t report_id_before; 285 switch ((TagType)item->item_type){ 286 case Main: 287 valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 288 parser->report_type); 289 break; 290 case Global: 291 report_id_before = parser->global_report_id; 292 btstack_hid_handle_global_item(parser, item); 293 // track record id for report handling 294 if ((GlobalItemTag)item->item_tag == ReportID){ 295 if (parser->active_record && (report_id_before != item->item_value)){ 296 parser->active_record = 0; 297 } 298 } 299 break; 300 case Local: 301 case Reserved: 302 break; 303 default: 304 btstack_assert(false); 305 break; 306 } 307 if (!valid_field) return; 308 309 // verify record id 310 if (parser->global_report_id && !parser->active_record){ 311 if (parser->report[0] != parser->global_report_id){ 312 return; 313 } 314 parser->report_pos_in_bit += 8u; 315 } 316 parser->active_record = 1; 317 // handle constant fields used for padding 318 if (item->item_value & 1){ 319 int item_bits = parser->global_report_size * parser->global_report_count; 320 #ifdef HID_PARSER_PRETTY_PRINT 321 log_info("- Skip %u constant bits", item_bits); 322 #endif 323 parser->report_pos_in_bit += item_bits; 324 return; 325 } 326 // Empty Item 327 if (parser->global_report_count == 0u) return; 328 // let's start 329 parser->required_usages = parser->global_report_count; 330 } 331 332 static void btstack_hid_parser_find_next_usage(btstack_hid_parser_t * parser){ 333 while (parser->state == BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM){ 334 if (parser->descriptor_pos >= parser->descriptor_len){ 335 // end of descriptor 336 parser->state = BTSTACK_HID_PARSER_COMPLETE; 337 break; 338 } 339 bool ok = btstack_hid_parse_descriptor_item(&parser->descriptor_item, &parser->descriptor[parser->descriptor_pos], parser->descriptor_len - parser->descriptor_pos); 340 if (ok == false){ 341 // abort parsing 342 parser->state = BTSTACK_HID_PARSER_COMPLETE; 343 break; 344 } 345 hid_process_item(parser, &parser->descriptor_item); 346 if (parser->required_usages){ 347 hid_find_next_usage(parser); 348 if (parser->available_usages) { 349 parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 350 } else { 351 log_debug("no usages found"); 352 parser->state = BTSTACK_HID_PARSER_COMPLETE; 353 } 354 } else { 355 if ((TagType) (&parser->descriptor_item)->item_type == Main) { 356 // reset usage 357 parser->usage_pos = parser->descriptor_pos; 358 parser->usage_page = parser->global_usage_page; 359 } 360 parser->descriptor_pos += parser->descriptor_item.item_size; 361 } 362 } 363 } 364 365 // PUBLIC API 366 367 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){ 368 369 memset(parser, 0, sizeof(btstack_hid_parser_t)); 370 371 parser->descriptor = hid_descriptor; 372 parser->descriptor_len = hid_descriptor_len; 373 parser->report_type = hid_report_type; 374 parser->report = hid_report; 375 parser->report_len = hid_report_len; 376 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 377 378 btstack_hid_parser_find_next_usage(parser); 379 } 380 381 bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 382 return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 383 } 384 385 void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 386 387 *usage_page = parser->usage_minimum >> 16; 388 389 // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 390 bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 391 bool is_signed = parser->global_logical_minimum < 0; 392 int pos_start = btstack_min( parser->report_pos_in_bit >> 3, parser->report_len); 393 int pos_end = btstack_min( (parser->report_pos_in_bit + parser->global_report_size - 1u) >> 3u, parser->report_len); 394 int bytes_to_read = pos_end - pos_start + 1; 395 int i; 396 uint32_t multi_byte_value = 0; 397 for (i=0;i < bytes_to_read;i++){ 398 multi_byte_value |= parser->report[pos_start+i] << (i*8); 399 } 400 uint32_t unsigned_value = (multi_byte_value >> (parser->report_pos_in_bit & 0x07u)) & ((1u<<parser->global_report_size)-1u); 401 // 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); 402 if (is_variable){ 403 *usage = parser->usage_minimum & 0xffffu; 404 if (is_signed && (unsigned_value & (1u<<(parser->global_report_size-1u)))){ 405 *value = unsigned_value - (1u<<parser->global_report_size); 406 } else { 407 *value = unsigned_value; 408 } 409 } else { 410 *usage = unsigned_value; 411 *value = 1; 412 } 413 parser->required_usages--; 414 parser->report_pos_in_bit += parser->global_report_size; 415 416 // next usage 417 if (is_variable){ 418 parser->usage_minimum++; 419 parser->available_usages--; 420 if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 421 // usage min - max range smaller than report count, ignore remaining bit in report 422 log_debug("Ignoring %u items without Usage", parser->required_usages); 423 parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 424 parser->required_usages = 0; 425 } 426 } else { 427 if (parser->required_usages == 0u){ 428 parser->available_usages = 0; 429 } 430 } 431 if (parser->available_usages) { 432 return; 433 } 434 if (parser->required_usages == 0u){ 435 parser->descriptor_pos += parser->descriptor_item.item_size; 436 parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 437 btstack_hid_parser_find_next_usage(parser); 438 } else { 439 hid_find_next_usage(parser); 440 if (parser->available_usages == 0u) { 441 parser->state = BTSTACK_HID_PARSER_COMPLETE; 442 } 443 } 444 } 445 446 void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 447 iterator->descriptor = hid_descriptor; 448 iterator->descriptor_pos = 0; 449 iterator->descriptor_len = hid_descriptor_len; 450 iterator->item_ready = false; 451 iterator->valid = true; 452 } 453 454 bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 455 if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){ 456 uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 457 const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 458 bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 459 if (ok){ 460 iterator->item_ready = true; 461 } else { 462 iterator->valid = false; 463 } 464 } 465 return iterator->item_ready; 466 } 467 468 const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 469 iterator->descriptor_pos += iterator->descriptor_item.item_size; 470 iterator->item_ready = false; 471 return &iterator->descriptor_item; 472 } 473 474 bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 475 return iterator->valid; 476 } 477 478 int btstack_hid_get_report_size_for_id(int report_id, hid_report_type_t report_type, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor) { 479 int total_report_size = 0; 480 int report_size = 0; 481 int report_count = 0; 482 int current_report_id = 0; 483 484 btstack_hid_descriptor_iterator_t iterator; 485 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 486 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 487 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 488 int valid_report_type = 0; 489 switch (item->item_type) { 490 case Global: 491 switch ((GlobalItemTag) item->item_tag) { 492 case ReportID: 493 current_report_id = item->item_value; 494 break; 495 case ReportCount: 496 report_count = item->item_value; 497 break; 498 case ReportSize: 499 report_size = item->item_value; 500 break; 501 default: 502 break; 503 } 504 break; 505 case Main: 506 if (current_report_id != report_id) break; 507 switch ((MainItemTag) item->item_tag) { 508 case Input: 509 if (report_type != HID_REPORT_TYPE_INPUT) break; 510 valid_report_type = 1; 511 break; 512 case Output: 513 if (report_type != HID_REPORT_TYPE_OUTPUT) break; 514 valid_report_type = 1; 515 break; 516 case Feature: 517 if (report_type != HID_REPORT_TYPE_FEATURE) break; 518 valid_report_type = 1; 519 break; 520 default: 521 break; 522 } 523 if (!valid_report_type) break; 524 total_report_size += report_count * report_size; 525 break; 526 default: 527 break; 528 } 529 if (total_report_size > 0 && current_report_id != report_id) break; 530 } 531 532 if (btstack_hid_descriptor_iterator_valid(&iterator)){ 533 return (total_report_size + 7) / 8; 534 } else { 535 return 0; 536 } 537 } 538 539 hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 540 int current_report_id = -1; 541 btstack_hid_descriptor_iterator_t iterator; 542 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 543 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 544 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 545 switch (item->item_type){ 546 case Global: 547 switch ((GlobalItemTag)item->item_tag){ 548 case ReportID: 549 current_report_id = item->item_value; 550 if (current_report_id != report_id) break; 551 return HID_REPORT_ID_VALID; 552 default: 553 break; 554 } 555 break; 556 default: 557 break; 558 } 559 } 560 561 if (btstack_hid_descriptor_iterator_valid(&iterator)) { 562 if (current_report_id != -1) { 563 return HID_REPORT_ID_INVALID; 564 } else { 565 return HID_REPORT_ID_UNDECLARED; 566 } 567 } else { 568 return HID_REPORT_ID_INVALID; 569 } 570 } 571 572 bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 573 btstack_hid_descriptor_iterator_t iterator; 574 btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 575 while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 576 const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 577 switch (item->item_type){ 578 case Global: 579 switch ((GlobalItemTag)item->item_tag){ 580 case ReportID: 581 return true; 582 default: 583 break; 584 } 585 break; 586 default: 587 break; 588 } 589 } 590 return false; 591 } 592