112ccb71bSMatthias Ringwald /* 212ccb71bSMatthias Ringwald * Copyright (C) 2017 BlueKitchen GmbH 312ccb71bSMatthias Ringwald * 412ccb71bSMatthias Ringwald * Redistribution and use in source and binary forms, with or without 512ccb71bSMatthias Ringwald * modification, are permitted provided that the following conditions 612ccb71bSMatthias Ringwald * are met: 712ccb71bSMatthias Ringwald * 812ccb71bSMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 912ccb71bSMatthias Ringwald * notice, this list of conditions and the following disclaimer. 1012ccb71bSMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 1112ccb71bSMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 1212ccb71bSMatthias Ringwald * documentation and/or other materials provided with the distribution. 1312ccb71bSMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 1412ccb71bSMatthias Ringwald * contributors may be used to endorse or promote products derived 1512ccb71bSMatthias Ringwald * from this software without specific prior written permission. 1612ccb71bSMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 1712ccb71bSMatthias Ringwald * personal benefit and not for any commercial purpose or for 1812ccb71bSMatthias Ringwald * monetary gain. 1912ccb71bSMatthias Ringwald * 2012ccb71bSMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 2112ccb71bSMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2212ccb71bSMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2512ccb71bSMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2612ccb71bSMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2712ccb71bSMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2812ccb71bSMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2912ccb71bSMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 3012ccb71bSMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3112ccb71bSMatthias Ringwald * SUCH DAMAGE. 3212ccb71bSMatthias Ringwald * 3312ccb71bSMatthias Ringwald * Please inquire about commercial licensing options at 3412ccb71bSMatthias Ringwald * [email protected] 3512ccb71bSMatthias Ringwald * 3612ccb71bSMatthias Ringwald */ 3712ccb71bSMatthias Ringwald 38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_hid_parser.c" 3912ccb71bSMatthias Ringwald 40cb406331SDirk Helbig #include <inttypes.h> 4112ccb71bSMatthias Ringwald #include <string.h> 4212ccb71bSMatthias Ringwald 4312ccb71bSMatthias Ringwald #include "btstack_hid_parser.h" 4412ccb71bSMatthias Ringwald #include "btstack_util.h" 4512ccb71bSMatthias Ringwald #include "btstack_debug.h" 4612ccb71bSMatthias Ringwald 4712ccb71bSMatthias Ringwald // Not implemented: 4812ccb71bSMatthias Ringwald // - Support for Push/Pop 49*0ba748f2SMatthias Ringwald // - Optional Pretty Print of HID Descriptor 5012ccb71bSMatthias Ringwald 5112ccb71bSMatthias Ringwald // #define HID_PARSER_PRETTY_PRINT 5212ccb71bSMatthias Ringwald 5312ccb71bSMatthias Ringwald /* 5412ccb71bSMatthias Ringwald * btstack_hid_parser.c 5512ccb71bSMatthias Ringwald */ 5612ccb71bSMatthias Ringwald 5712ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 5812ccb71bSMatthias Ringwald 5912ccb71bSMatthias Ringwald static const char * type_names[] = { 6012ccb71bSMatthias Ringwald "Main", 6112ccb71bSMatthias Ringwald "Global", 6212ccb71bSMatthias Ringwald "Local", 6312ccb71bSMatthias Ringwald "Reserved" 6412ccb71bSMatthias Ringwald }; 6512ccb71bSMatthias Ringwald static const char * main_tags[] = { 6612ccb71bSMatthias Ringwald "", 6712ccb71bSMatthias Ringwald "", 6812ccb71bSMatthias Ringwald "", 6912ccb71bSMatthias Ringwald "", 7012ccb71bSMatthias Ringwald "", 7112ccb71bSMatthias Ringwald "", 7212ccb71bSMatthias Ringwald "", 7312ccb71bSMatthias Ringwald "", 7412ccb71bSMatthias Ringwald "Input ", 7512ccb71bSMatthias Ringwald "Output", 7612ccb71bSMatthias Ringwald "Collection", 7712ccb71bSMatthias Ringwald "Feature", 7812ccb71bSMatthias Ringwald "End Collection", 7912ccb71bSMatthias Ringwald "Reserved", 8012ccb71bSMatthias Ringwald "Reserved", 8112ccb71bSMatthias Ringwald "Reserved" 8212ccb71bSMatthias Ringwald }; 8312ccb71bSMatthias Ringwald static const char * global_tags[] = { 8412ccb71bSMatthias Ringwald "Usage Page", 8512ccb71bSMatthias Ringwald "Logical Minimum", 8612ccb71bSMatthias Ringwald "Logical Maximum", 8712ccb71bSMatthias Ringwald "Physical Minimum", 8812ccb71bSMatthias Ringwald "Physical Maximum", 8912ccb71bSMatthias Ringwald "Unit Exponent", 9012ccb71bSMatthias Ringwald "Unit", 9112ccb71bSMatthias Ringwald "Report Size", 9212ccb71bSMatthias Ringwald "Report ID", 9312ccb71bSMatthias Ringwald "Report Count", 9412ccb71bSMatthias Ringwald "Push", 9512ccb71bSMatthias Ringwald "Pop", 9612ccb71bSMatthias Ringwald "Reserved", 9712ccb71bSMatthias Ringwald "Reserved", 9812ccb71bSMatthias Ringwald "Reserved", 9912ccb71bSMatthias Ringwald "Reserved" 10012ccb71bSMatthias Ringwald }; 10112ccb71bSMatthias Ringwald static const char * local_tags[] = { 10212ccb71bSMatthias Ringwald "Usage", 10312ccb71bSMatthias Ringwald "Usage Minimum", 10412ccb71bSMatthias Ringwald "Usage Maximum", 10512ccb71bSMatthias Ringwald "Designator Index", 10612ccb71bSMatthias Ringwald "Designator Minimum", 10712ccb71bSMatthias Ringwald "Designator Maximum", 10812ccb71bSMatthias Ringwald "String Index", 10912ccb71bSMatthias Ringwald "String Minimum", 11012ccb71bSMatthias Ringwald "String Maximum", 11112ccb71bSMatthias Ringwald "Delimiter", 11212ccb71bSMatthias Ringwald "Reserved", 11312ccb71bSMatthias Ringwald "Reserved", 11412ccb71bSMatthias Ringwald "Reserved", 11512ccb71bSMatthias Ringwald "Reserved", 11612ccb71bSMatthias Ringwald "Reserved", 11712ccb71bSMatthias Ringwald "Reserved" 11812ccb71bSMatthias Ringwald }; 11912ccb71bSMatthias Ringwald #endif 12012ccb71bSMatthias Ringwald 12112ccb71bSMatthias Ringwald static void hid_pretty_print_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 12212ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 12312ccb71bSMatthias Ringwald const char ** item_tag_table; 1247bbeb3adSMilanka Ringwald switch ((TagType)item->item_type){ 12512ccb71bSMatthias Ringwald case Main: 12612ccb71bSMatthias Ringwald item_tag_table = main_tags; 12712ccb71bSMatthias Ringwald break; 12812ccb71bSMatthias Ringwald case Global: 12912ccb71bSMatthias Ringwald item_tag_table = global_tags; 13012ccb71bSMatthias Ringwald break; 13112ccb71bSMatthias Ringwald case Local: 13212ccb71bSMatthias Ringwald item_tag_table = local_tags; 13312ccb71bSMatthias Ringwald break; 13412ccb71bSMatthias Ringwald default: 13512ccb71bSMatthias Ringwald item_tag_table = NULL; 13612ccb71bSMatthias Ringwald break; 13712ccb71bSMatthias Ringwald } 13812ccb71bSMatthias Ringwald const char * item_tag_name = "Invalid"; 13912ccb71bSMatthias Ringwald if (item_tag_table){ 14012ccb71bSMatthias Ringwald item_tag_name = item_tag_table[item->item_tag]; 14112ccb71bSMatthias Ringwald } 142ea1e21c2SMatthias Ringwald log_info("%-15s (%-6s) // %02x 0x%0008x", item_tag_name, type_names[item->item_type], parser->descriptor[parser->descriptor_pos], item->item_value); 14312ccb71bSMatthias Ringwald #else 14412ccb71bSMatthias Ringwald UNUSED(parser); 14512ccb71bSMatthias Ringwald UNUSED(item); 14612ccb71bSMatthias Ringwald #endif 14712ccb71bSMatthias Ringwald } 14812ccb71bSMatthias Ringwald 14912ccb71bSMatthias Ringwald // parse descriptor item and read up to 32-bit bit value 15076fa2448SMatthias Ringwald bool btstack_hid_parse_descriptor_item(hid_descriptor_item_t * item, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 1518334d3d8SMatthias Ringwald 1528334d3d8SMatthias Ringwald const int hid_item_sizes[] = { 0, 1, 2, 4 }; 1538334d3d8SMatthias Ringwald 15412ccb71bSMatthias Ringwald // parse item header 15576fa2448SMatthias Ringwald if (hid_descriptor_len < 1u) return false; 15612ccb71bSMatthias Ringwald uint16_t pos = 0; 15712ccb71bSMatthias Ringwald uint8_t item_header = hid_descriptor[pos++]; 1584ea43905SMatthias Ringwald item->data_size = hid_item_sizes[item_header & 0x03u]; 1594ea43905SMatthias Ringwald item->item_type = (item_header & 0x0cu) >> 2u; 1604ea43905SMatthias Ringwald item->item_tag = (item_header & 0xf0u) >> 4u; 16112ccb71bSMatthias Ringwald // long item 1624ea43905SMatthias Ringwald if ((item->data_size == 2u) && (item->item_tag == 0x0fu) && (item->item_type == 3u)){ 16376fa2448SMatthias Ringwald if (hid_descriptor_len < 3u) return false; 16412ccb71bSMatthias Ringwald item->data_size = hid_descriptor[pos++]; 16512ccb71bSMatthias Ringwald item->item_tag = hid_descriptor[pos++]; 16612ccb71bSMatthias Ringwald } 16712ccb71bSMatthias Ringwald item->item_size = pos + item->data_size; 16812ccb71bSMatthias Ringwald item->item_value = 0; 16912ccb71bSMatthias Ringwald 17012ccb71bSMatthias Ringwald // read item value 17176fa2448SMatthias Ringwald if (hid_descriptor_len < item->item_size) return false; 17276fa2448SMatthias Ringwald if (item->data_size > 4u) return false; 17312ccb71bSMatthias Ringwald int i; 1744ea43905SMatthias Ringwald int sgnd = (item->item_type == Global) && (item->item_tag > 0u) && (item->item_tag < 5u); 17512ccb71bSMatthias Ringwald int32_t value = 0; 17612ccb71bSMatthias Ringwald uint8_t latest_byte = 0; 17712ccb71bSMatthias Ringwald for (i=0;i<item->data_size;i++){ 17812ccb71bSMatthias Ringwald latest_byte = hid_descriptor[pos++]; 17912ccb71bSMatthias Ringwald value = (latest_byte << (8*i)) | value; 18012ccb71bSMatthias Ringwald } 1814ea43905SMatthias Ringwald if (sgnd && (item->data_size > 0u)){ 1824ea43905SMatthias Ringwald if (latest_byte & 0x80u) { 1834ea43905SMatthias Ringwald value -= 1u << (item->data_size*8u); 18412ccb71bSMatthias Ringwald } 18512ccb71bSMatthias Ringwald } 18612ccb71bSMatthias Ringwald item->item_value = value; 18776fa2448SMatthias Ringwald return true; 18812ccb71bSMatthias Ringwald } 18912ccb71bSMatthias Ringwald 1900a4fc5fbSMatthias Ringwald static bool btstack_hid_main_item_tag_matches_report_type(MainItemTag tag, hid_report_type_t report_type){ 1910a4fc5fbSMatthias Ringwald switch (tag){ 1920a4fc5fbSMatthias Ringwald case Input: 1930a4fc5fbSMatthias Ringwald return report_type == HID_REPORT_TYPE_INPUT; 1940a4fc5fbSMatthias Ringwald case Output: 1950a4fc5fbSMatthias Ringwald return report_type == HID_REPORT_TYPE_OUTPUT; 1960a4fc5fbSMatthias Ringwald case Feature: 1970a4fc5fbSMatthias Ringwald return report_type == HID_REPORT_TYPE_FEATURE; 1980a4fc5fbSMatthias Ringwald default: 1990a4fc5fbSMatthias Ringwald return false; 2000a4fc5fbSMatthias Ringwald } 2010a4fc5fbSMatthias Ringwald } 2020a4fc5fbSMatthias Ringwald 20312ccb71bSMatthias Ringwald static void btstack_hid_handle_global_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 2047bbeb3adSMilanka Ringwald switch((GlobalItemTag)item->item_tag){ 20512ccb71bSMatthias Ringwald case UsagePage: 20612ccb71bSMatthias Ringwald parser->global_usage_page = item->item_value; 20712ccb71bSMatthias Ringwald break; 20812ccb71bSMatthias Ringwald case LogicalMinimum: 20912ccb71bSMatthias Ringwald parser->global_logical_minimum = item->item_value; 21012ccb71bSMatthias Ringwald break; 21112ccb71bSMatthias Ringwald case LogicalMaximum: 21212ccb71bSMatthias Ringwald parser->global_logical_maximum = item->item_value; 21312ccb71bSMatthias Ringwald break; 21412ccb71bSMatthias Ringwald case ReportSize: 21512ccb71bSMatthias Ringwald parser->global_report_size = item->item_value; 21612ccb71bSMatthias Ringwald break; 21712ccb71bSMatthias Ringwald case ReportID: 21812ccb71bSMatthias Ringwald parser->global_report_id = item->item_value; 21912ccb71bSMatthias Ringwald break; 22012ccb71bSMatthias Ringwald case ReportCount: 22112ccb71bSMatthias Ringwald parser->global_report_count = item->item_value; 22212ccb71bSMatthias Ringwald break; 2237bbeb3adSMilanka Ringwald 2247bbeb3adSMilanka Ringwald // TODO handle tags 2257bbeb3adSMilanka Ringwald case PhysicalMinimum: 2267bbeb3adSMilanka Ringwald case PhysicalMaximum: 2277bbeb3adSMilanka Ringwald case UnitExponent: 2287bbeb3adSMilanka Ringwald case Unit: 2297bbeb3adSMilanka Ringwald case Push: 2307bbeb3adSMilanka Ringwald case Pop: 2317bbeb3adSMilanka Ringwald break; 2327bbeb3adSMilanka Ringwald 23312ccb71bSMatthias Ringwald default: 2347bbeb3adSMilanka Ringwald btstack_assert(false); 23512ccb71bSMatthias Ringwald break; 23612ccb71bSMatthias Ringwald } 23712ccb71bSMatthias Ringwald } 23812ccb71bSMatthias Ringwald 23912ccb71bSMatthias Ringwald static void hid_find_next_usage(btstack_hid_parser_t * parser){ 2401a05cde1SMatthias Ringwald bool have_usage_min = false; 2411a05cde1SMatthias Ringwald bool have_usage_max = false; 2421a05cde1SMatthias Ringwald parser->usage_range = false; 24341afcabaSMatthias Ringwald btstack_hid_descriptor_iterator_t iterator; 24441afcabaSMatthias Ringwald btstack_hid_descriptor_iterator_init(&iterator, &parser->descriptor[parser->usage_pos], parser->descriptor_len - parser->usage_pos); 24541afcabaSMatthias Ringwald while ((parser->available_usages == 0u) && btstack_hid_descriptor_iterator_has_more(&iterator) ){ 24641afcabaSMatthias Ringwald hid_descriptor_item_t usage_item = *btstack_hid_descriptor_iterator_get_item(&iterator); 2470e588213SMatthias Ringwald if ((usage_item.item_type == Global) && (usage_item.item_tag == UsagePage)){ 24812ccb71bSMatthias Ringwald parser->usage_page = usage_item.item_value; 24912ccb71bSMatthias Ringwald } 25012ccb71bSMatthias Ringwald if (usage_item.item_type == Local){ 2514ea43905SMatthias Ringwald uint32_t usage_value = (usage_item.data_size > 2u) ? usage_item.item_value : ((parser->usage_page << 16u) | usage_item.item_value); 25212ccb71bSMatthias Ringwald switch (usage_item.item_tag){ 25312ccb71bSMatthias Ringwald case Usage: 25412ccb71bSMatthias Ringwald parser->available_usages = 1; 25512ccb71bSMatthias Ringwald parser->usage_minimum = usage_value; 25612ccb71bSMatthias Ringwald break; 25712ccb71bSMatthias Ringwald case UsageMinimum: 25812ccb71bSMatthias Ringwald parser->usage_minimum = usage_value; 2591a05cde1SMatthias Ringwald have_usage_min = true; 26012ccb71bSMatthias Ringwald break; 26112ccb71bSMatthias Ringwald case UsageMaximum: 26212ccb71bSMatthias Ringwald parser->usage_maximum = usage_value; 2631a05cde1SMatthias Ringwald have_usage_max = true; 26412ccb71bSMatthias Ringwald break; 26512ccb71bSMatthias Ringwald default: 26612ccb71bSMatthias Ringwald break; 26712ccb71bSMatthias Ringwald } 2681a05cde1SMatthias Ringwald if (have_usage_min && have_usage_max){ 2694ea43905SMatthias Ringwald parser->available_usages = parser->usage_maximum - parser->usage_minimum + 1u; 2701a05cde1SMatthias Ringwald parser->usage_range = true; 271dfb01e77SMatthias Ringwald if (parser->available_usages < parser->required_usages){ 272cb406331SDirk Helbig log_debug("Usage Min - Usage Max [%04"PRIx32"..%04"PRIx32"] < Report Count %u", parser->usage_minimum & 0xffff, parser->usage_maximum & 0xffff, parser->required_usages); 273dfb01e77SMatthias Ringwald } 27412ccb71bSMatthias Ringwald } 27512ccb71bSMatthias Ringwald } 27612ccb71bSMatthias Ringwald } 27741afcabaSMatthias Ringwald parser->usage_pos += iterator.descriptor_pos; 27812ccb71bSMatthias Ringwald } 27912ccb71bSMatthias Ringwald 28012ccb71bSMatthias Ringwald static void hid_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 28112ccb71bSMatthias Ringwald hid_pretty_print_item(parser, item); 28212ccb71bSMatthias Ringwald int valid_field = 0; 283eb78fadaSMatthias Ringwald uint16_t report_id_before; 2847bbeb3adSMilanka Ringwald switch ((TagType)item->item_type){ 28512ccb71bSMatthias Ringwald case Main: 2860a4fc5fbSMatthias Ringwald valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 2870a4fc5fbSMatthias Ringwald parser->report_type); 28812ccb71bSMatthias Ringwald break; 28912ccb71bSMatthias Ringwald case Global: 290eb78fadaSMatthias Ringwald report_id_before = parser->global_report_id; 29112ccb71bSMatthias Ringwald btstack_hid_handle_global_item(parser, item); 292eb78fadaSMatthias Ringwald // track record id for report handling 293eb78fadaSMatthias Ringwald if ((GlobalItemTag)item->item_tag == ReportID){ 294eb78fadaSMatthias Ringwald if (parser->active_record && (report_id_before != item->item_value)){ 295eb78fadaSMatthias Ringwald parser->active_record = 0; 296eb78fadaSMatthias Ringwald } 297eb78fadaSMatthias Ringwald } 29812ccb71bSMatthias Ringwald break; 29912ccb71bSMatthias Ringwald case Local: 3007bbeb3adSMilanka Ringwald case Reserved: 3017bbeb3adSMilanka Ringwald break; 3027bbeb3adSMilanka Ringwald default: 3037bbeb3adSMilanka Ringwald btstack_assert(false); 30412ccb71bSMatthias Ringwald break; 30512ccb71bSMatthias Ringwald } 30612ccb71bSMatthias Ringwald if (!valid_field) return; 30712ccb71bSMatthias Ringwald 30812ccb71bSMatthias Ringwald // verify record id 30912ccb71bSMatthias Ringwald if (parser->global_report_id && !parser->active_record){ 31012ccb71bSMatthias Ringwald if (parser->report[0] != parser->global_report_id){ 31112ccb71bSMatthias Ringwald return; 31212ccb71bSMatthias Ringwald } 3134ea43905SMatthias Ringwald parser->report_pos_in_bit += 8u; 31412ccb71bSMatthias Ringwald } 31512ccb71bSMatthias Ringwald parser->active_record = 1; 31612ccb71bSMatthias Ringwald // handle constant fields used for padding 31712ccb71bSMatthias Ringwald if (item->item_value & 1){ 31812ccb71bSMatthias Ringwald int item_bits = parser->global_report_size * parser->global_report_count; 31912ccb71bSMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 32012ccb71bSMatthias Ringwald log_info("- Skip %u constant bits", item_bits); 32112ccb71bSMatthias Ringwald #endif 32212ccb71bSMatthias Ringwald parser->report_pos_in_bit += item_bits; 32312ccb71bSMatthias Ringwald return; 32412ccb71bSMatthias Ringwald } 32512ccb71bSMatthias Ringwald // Empty Item 3264ea43905SMatthias Ringwald if (parser->global_report_count == 0u) return; 32712ccb71bSMatthias Ringwald // let's start 32812ccb71bSMatthias Ringwald parser->required_usages = parser->global_report_count; 32912ccb71bSMatthias Ringwald } 33012ccb71bSMatthias Ringwald 33112ccb71bSMatthias Ringwald // PUBLIC API 33212ccb71bSMatthias Ringwald 333*0ba748f2SMatthias Ringwald // HID Descriptor Iterator 334fada7179SMilanka Ringwald 3350c7e4a25SMatthias Ringwald void btstack_hid_descriptor_iterator_init(btstack_hid_descriptor_iterator_t * iterator, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len){ 3360c7e4a25SMatthias Ringwald iterator->descriptor = hid_descriptor; 3370c7e4a25SMatthias Ringwald iterator->descriptor_pos = 0; 3380c7e4a25SMatthias Ringwald iterator->descriptor_len = hid_descriptor_len; 3390c7e4a25SMatthias Ringwald iterator->item_ready = false; 3400c7e4a25SMatthias Ringwald iterator->valid = true; 3410c7e4a25SMatthias Ringwald } 3420c7e4a25SMatthias Ringwald 3430c7e4a25SMatthias Ringwald bool btstack_hid_descriptor_iterator_has_more(btstack_hid_descriptor_iterator_t * iterator){ 3443cc55c4aSMatthias Ringwald if ((iterator->item_ready == false) && (iterator->descriptor_len > iterator->descriptor_pos)){ 3450c7e4a25SMatthias Ringwald uint16_t item_len = iterator->descriptor_len - iterator->descriptor_pos; 3460c7e4a25SMatthias Ringwald const uint8_t *item_data = &iterator->descriptor[iterator->descriptor_pos]; 3470c7e4a25SMatthias Ringwald bool ok = btstack_hid_parse_descriptor_item(&iterator->descriptor_item, item_data, item_len); 3480c7e4a25SMatthias Ringwald if (ok){ 3490c7e4a25SMatthias Ringwald iterator->item_ready = true; 3500c7e4a25SMatthias Ringwald } else { 3510c7e4a25SMatthias Ringwald iterator->valid = false; 3520c7e4a25SMatthias Ringwald } 3530c7e4a25SMatthias Ringwald } 3540c7e4a25SMatthias Ringwald return iterator->item_ready; 3550c7e4a25SMatthias Ringwald } 3560c7e4a25SMatthias Ringwald 3570c7e4a25SMatthias Ringwald const hid_descriptor_item_t * const btstack_hid_descriptor_iterator_get_item(btstack_hid_descriptor_iterator_t * iterator){ 3583cc55c4aSMatthias Ringwald iterator->descriptor_pos += iterator->descriptor_item.item_size; 3590c7e4a25SMatthias Ringwald iterator->item_ready = false; 3600c7e4a25SMatthias Ringwald return &iterator->descriptor_item; 3610c7e4a25SMatthias Ringwald } 3620c7e4a25SMatthias Ringwald 3630c7e4a25SMatthias Ringwald bool btstack_hid_descriptor_iterator_valid(btstack_hid_descriptor_iterator_t * iterator){ 3640c7e4a25SMatthias Ringwald return iterator->valid; 3650c7e4a25SMatthias Ringwald } 3660c7e4a25SMatthias Ringwald 367*0ba748f2SMatthias Ringwald 368662cddc2SMilanka Ringwald 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) { 369fada7179SMilanka Ringwald int total_report_size = 0; 370fada7179SMilanka Ringwald int report_size = 0; 371fada7179SMilanka Ringwald int report_count = 0; 372fada7179SMilanka Ringwald int current_report_id = 0; 373fada7179SMilanka Ringwald 374960622b0SMatthias Ringwald btstack_hid_descriptor_iterator_t iterator; 375960622b0SMatthias Ringwald btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 376960622b0SMatthias Ringwald while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 377960622b0SMatthias Ringwald const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 378fada7179SMilanka Ringwald int valid_report_type = 0; 379960622b0SMatthias Ringwald switch (item->item_type) { 380fada7179SMilanka Ringwald case Global: 381960622b0SMatthias Ringwald switch ((GlobalItemTag) item->item_tag) { 382fada7179SMilanka Ringwald case ReportID: 383960622b0SMatthias Ringwald current_report_id = item->item_value; 384fada7179SMilanka Ringwald break; 385fada7179SMilanka Ringwald case ReportCount: 386960622b0SMatthias Ringwald report_count = item->item_value; 387fada7179SMilanka Ringwald break; 388fada7179SMilanka Ringwald case ReportSize: 389960622b0SMatthias Ringwald report_size = item->item_value; 390fada7179SMilanka Ringwald break; 391fada7179SMilanka Ringwald default: 392fada7179SMilanka Ringwald break; 393fada7179SMilanka Ringwald } 394fada7179SMilanka Ringwald break; 395fada7179SMilanka Ringwald case Main: 396fada7179SMilanka Ringwald if (current_report_id != report_id) break; 397960622b0SMatthias Ringwald switch ((MainItemTag) item->item_tag) { 398fada7179SMilanka Ringwald case Input: 399662cddc2SMilanka Ringwald if (report_type != HID_REPORT_TYPE_INPUT) break; 400fada7179SMilanka Ringwald valid_report_type = 1; 401fada7179SMilanka Ringwald break; 402fada7179SMilanka Ringwald case Output: 403662cddc2SMilanka Ringwald if (report_type != HID_REPORT_TYPE_OUTPUT) break; 404fada7179SMilanka Ringwald valid_report_type = 1; 405fada7179SMilanka Ringwald break; 406fada7179SMilanka Ringwald case Feature: 407662cddc2SMilanka Ringwald if (report_type != HID_REPORT_TYPE_FEATURE) break; 408fada7179SMilanka Ringwald valid_report_type = 1; 409fada7179SMilanka Ringwald break; 410fada7179SMilanka Ringwald default: 411fada7179SMilanka Ringwald break; 412fada7179SMilanka Ringwald } 413fada7179SMilanka Ringwald if (!valid_report_type) break; 414fada7179SMilanka Ringwald total_report_size += report_count * report_size; 415fada7179SMilanka Ringwald break; 416fada7179SMilanka Ringwald default: 417fada7179SMilanka Ringwald break; 418fada7179SMilanka Ringwald } 41915cf8612Sx0rloser if (total_report_size > 0 && current_report_id != report_id) break; 420fada7179SMilanka Ringwald } 421960622b0SMatthias Ringwald 422960622b0SMatthias Ringwald if (btstack_hid_descriptor_iterator_valid(&iterator)){ 423fada7179SMilanka Ringwald return (total_report_size + 7) / 8; 424960622b0SMatthias Ringwald } else { 425960622b0SMatthias Ringwald return 0; 426960622b0SMatthias Ringwald } 427fada7179SMilanka Ringwald } 428dbcaefc7SMilanka Ringwald 429dbcaefc7SMilanka Ringwald hid_report_id_status_t btstack_hid_id_valid(int report_id, uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 430960622b0SMatthias Ringwald int current_report_id = -1; 431960622b0SMatthias Ringwald btstack_hid_descriptor_iterator_t iterator; 432960622b0SMatthias Ringwald btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 433960622b0SMatthias Ringwald while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 434960622b0SMatthias Ringwald const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 435960622b0SMatthias Ringwald switch (item->item_type){ 436dbcaefc7SMilanka Ringwald case Global: 437960622b0SMatthias Ringwald switch ((GlobalItemTag)item->item_tag){ 438dbcaefc7SMilanka Ringwald case ReportID: 439960622b0SMatthias Ringwald current_report_id = item->item_value; 440dbcaefc7SMilanka Ringwald if (current_report_id != report_id) break; 441dbcaefc7SMilanka Ringwald return HID_REPORT_ID_VALID; 442dbcaefc7SMilanka Ringwald default: 443dbcaefc7SMilanka Ringwald break; 444dbcaefc7SMilanka Ringwald } 445dbcaefc7SMilanka Ringwald break; 446dbcaefc7SMilanka Ringwald default: 447dbcaefc7SMilanka Ringwald break; 448dbcaefc7SMilanka Ringwald } 449dbcaefc7SMilanka Ringwald } 450960622b0SMatthias Ringwald 451960622b0SMatthias Ringwald if (btstack_hid_descriptor_iterator_valid(&iterator)) { 452960622b0SMatthias Ringwald if (current_report_id != -1) { 453960622b0SMatthias Ringwald return HID_REPORT_ID_INVALID; 454960622b0SMatthias Ringwald } else { 455dbcaefc7SMilanka Ringwald return HID_REPORT_ID_UNDECLARED; 456dbcaefc7SMilanka Ringwald } 457960622b0SMatthias Ringwald } else { 458960622b0SMatthias Ringwald return HID_REPORT_ID_INVALID; 459960622b0SMatthias Ringwald } 460960622b0SMatthias Ringwald } 461dbcaefc7SMilanka Ringwald 462c17118d0SMatthias Ringwald bool btstack_hid_report_id_declared(uint16_t hid_descriptor_len, const uint8_t * hid_descriptor){ 463960622b0SMatthias Ringwald btstack_hid_descriptor_iterator_t iterator; 464960622b0SMatthias Ringwald btstack_hid_descriptor_iterator_init(&iterator, hid_descriptor, hid_descriptor_len); 465960622b0SMatthias Ringwald while (btstack_hid_descriptor_iterator_has_more(&iterator)) { 466960622b0SMatthias Ringwald const hid_descriptor_item_t *const item = btstack_hid_descriptor_iterator_get_item(&iterator); 467960622b0SMatthias Ringwald switch (item->item_type){ 468dbcaefc7SMilanka Ringwald case Global: 469960622b0SMatthias Ringwald switch ((GlobalItemTag)item->item_tag){ 470dbcaefc7SMilanka Ringwald case ReportID: 471c17118d0SMatthias Ringwald return true; 472dbcaefc7SMilanka Ringwald default: 473dbcaefc7SMilanka Ringwald break; 474dbcaefc7SMilanka Ringwald } 475dbcaefc7SMilanka Ringwald break; 476dbcaefc7SMilanka Ringwald default: 477dbcaefc7SMilanka Ringwald break; 478dbcaefc7SMilanka Ringwald } 479dbcaefc7SMilanka Ringwald } 480c17118d0SMatthias Ringwald return false; 481dbcaefc7SMilanka Ringwald } 482cdb96ae5SMatthias Ringwald 483*0ba748f2SMatthias Ringwald // HID Descriptor Usage Iterator 484*0ba748f2SMatthias Ringwald 4855285211dSMatthias Ringwald static void btstack_parser_usage_iterator_process_item(btstack_hid_parser_t * parser, hid_descriptor_item_t * item){ 486cdb96ae5SMatthias Ringwald hid_pretty_print_item(parser, item); 487cdb96ae5SMatthias Ringwald int valid_field = 0; 488cdb96ae5SMatthias Ringwald uint16_t report_id_before; 489cdb96ae5SMatthias Ringwald switch ((TagType)item->item_type){ 490cdb96ae5SMatthias Ringwald case Main: 491cdb96ae5SMatthias Ringwald valid_field = btstack_hid_main_item_tag_matches_report_type((MainItemTag) item->item_tag, 492cdb96ae5SMatthias Ringwald parser->report_type); 493cdb96ae5SMatthias Ringwald break; 494cdb96ae5SMatthias Ringwald case Global: 495cdb96ae5SMatthias Ringwald report_id_before = parser->global_report_id; 496cdb96ae5SMatthias Ringwald btstack_hid_handle_global_item(parser, item); 497cdb96ae5SMatthias Ringwald // track record id for report handling, reset report position 498cdb96ae5SMatthias Ringwald if (report_id_before != parser->global_report_id){ 499cdb96ae5SMatthias Ringwald parser->report_pos_in_bit = 8u; 500cdb96ae5SMatthias Ringwald } 501cdb96ae5SMatthias Ringwald break; 502cdb96ae5SMatthias Ringwald case Local: 503cdb96ae5SMatthias Ringwald case Reserved: 504cdb96ae5SMatthias Ringwald break; 505cdb96ae5SMatthias Ringwald default: 506cdb96ae5SMatthias Ringwald btstack_assert(false); 507cdb96ae5SMatthias Ringwald break; 508cdb96ae5SMatthias Ringwald } 509cdb96ae5SMatthias Ringwald if (!valid_field) return; 510cdb96ae5SMatthias Ringwald 511cdb96ae5SMatthias Ringwald // handle constant fields used for padding 512cdb96ae5SMatthias Ringwald if (item->item_value & 1){ 513cdb96ae5SMatthias Ringwald int item_bits = parser->global_report_size * parser->global_report_count; 514cdb96ae5SMatthias Ringwald #ifdef HID_PARSER_PRETTY_PRINT 515cdb96ae5SMatthias Ringwald log_info("- Skip %u constant bits", item_bits); 516cdb96ae5SMatthias Ringwald #endif 517cdb96ae5SMatthias Ringwald parser->report_pos_in_bit += item_bits; 518cdb96ae5SMatthias Ringwald return; 519cdb96ae5SMatthias Ringwald } 520cdb96ae5SMatthias Ringwald // Empty Item 521cdb96ae5SMatthias Ringwald if (parser->global_report_count == 0u) return; 522cdb96ae5SMatthias Ringwald // let's start 523cdb96ae5SMatthias Ringwald parser->required_usages = parser->global_report_count; 524cdb96ae5SMatthias Ringwald } 525cdb96ae5SMatthias Ringwald 526cdb96ae5SMatthias Ringwald static void btstack_hid_usage_iterator_find_next_usage(btstack_hid_parser_t * parser) { 527cdb96ae5SMatthias Ringwald while (btstack_hid_descriptor_iterator_has_more(&parser->descriptor_iterator)){ 528cdb96ae5SMatthias Ringwald parser->descriptor_item = * btstack_hid_descriptor_iterator_get_item(&parser->descriptor_iterator); 529cdb96ae5SMatthias Ringwald 5305285211dSMatthias Ringwald btstack_parser_usage_iterator_process_item(parser, &parser->descriptor_item); 531cdb96ae5SMatthias Ringwald 532cdb96ae5SMatthias Ringwald if (parser->required_usages){ 533cdb96ae5SMatthias Ringwald hid_find_next_usage(parser); 534cdb96ae5SMatthias Ringwald if (parser->available_usages) { 535cdb96ae5SMatthias Ringwald parser->state = BTSTACK_HID_PARSER_USAGES_AVAILABLE; 536cdb96ae5SMatthias Ringwald return; 537cdb96ae5SMatthias Ringwald } else { 538cdb96ae5SMatthias Ringwald log_debug("no usages found"); 539cdb96ae5SMatthias Ringwald parser->state = BTSTACK_HID_PARSER_COMPLETE; 540cdb96ae5SMatthias Ringwald return; 541cdb96ae5SMatthias Ringwald } 542cdb96ae5SMatthias Ringwald } else { 543cdb96ae5SMatthias Ringwald if ((TagType) (&parser->descriptor_item)->item_type == Main) { 544cdb96ae5SMatthias Ringwald // reset usage 545cdb96ae5SMatthias Ringwald parser->usage_pos = parser->descriptor_iterator.descriptor_pos; 546cdb96ae5SMatthias Ringwald parser->usage_page = parser->global_usage_page; 547cdb96ae5SMatthias Ringwald } 548cdb96ae5SMatthias Ringwald } 549cdb96ae5SMatthias Ringwald } 550cdb96ae5SMatthias Ringwald // end of descriptor 551cdb96ae5SMatthias Ringwald parser->state = BTSTACK_HID_PARSER_COMPLETE; 552cdb96ae5SMatthias Ringwald } 553cdb96ae5SMatthias Ringwald 554cdb96ae5SMatthias Ringwald void btstack_hid_usage_iterator_init(btstack_hid_parser_t * parser, const uint8_t * hid_descriptor, uint16_t hid_descriptor_len, hid_report_type_t hid_report_type){ 555cdb96ae5SMatthias Ringwald memset(parser, 0, sizeof(btstack_hid_parser_t)); 556cdb96ae5SMatthias Ringwald 557cdb96ae5SMatthias Ringwald parser->descriptor = hid_descriptor; 558cdb96ae5SMatthias Ringwald parser->descriptor_len = hid_descriptor_len; 559cdb96ae5SMatthias Ringwald parser->report_type = hid_report_type; 560cdb96ae5SMatthias Ringwald parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 5615285211dSMatthias Ringwald parser->global_report_id = 0xffff; 562cdb96ae5SMatthias Ringwald btstack_hid_descriptor_iterator_init(&parser->descriptor_iterator, hid_descriptor, hid_descriptor_len); 563cdb96ae5SMatthias Ringwald 564cdb96ae5SMatthias Ringwald btstack_hid_usage_iterator_find_next_usage(parser); 565cdb96ae5SMatthias Ringwald } 566cdb96ae5SMatthias Ringwald 567cdb96ae5SMatthias Ringwald bool btstack_hid_usage_iterator_has_more(btstack_hid_parser_t * parser){ 568cdb96ae5SMatthias Ringwald return parser->state == BTSTACK_HID_PARSER_USAGES_AVAILABLE; 569cdb96ae5SMatthias Ringwald } 570cdb96ae5SMatthias Ringwald 571cdb96ae5SMatthias Ringwald void btstack_hid_usage_iterator_get_item(btstack_hid_parser_t * parser, btstack_hid_usage_item_t * item){ 572cdb96ae5SMatthias Ringwald // cache current values 573cdb96ae5SMatthias Ringwald memset(item, 0, sizeof(btstack_hid_usage_item_t)); 574cdb96ae5SMatthias Ringwald item->size = parser->global_report_size; 575cdb96ae5SMatthias Ringwald item->report_id = parser->global_report_id; 576cdb96ae5SMatthias Ringwald item->usage_page = parser->usage_minimum >> 16; 577cdb96ae5SMatthias Ringwald item->bit_pos = parser->report_pos_in_bit; 578cdb96ae5SMatthias Ringwald 579cdb96ae5SMatthias Ringwald bool is_variable = (parser->descriptor_item.item_value & 2) != 0; 580cdb96ae5SMatthias Ringwald if (is_variable){ 581cdb96ae5SMatthias Ringwald item->usage = parser->usage_minimum & 0xffffu; 582cdb96ae5SMatthias Ringwald } 583cdb96ae5SMatthias Ringwald parser->required_usages--; 584cdb96ae5SMatthias Ringwald parser->report_pos_in_bit += parser->global_report_size; 585cdb96ae5SMatthias Ringwald 586*0ba748f2SMatthias Ringwald // cache descriptor item and 587*0ba748f2SMatthias Ringwald item->descriptor_item = parser->descriptor_item; 588*0ba748f2SMatthias Ringwald item->global_logical_minimum = parser->global_logical_minimum; 589*0ba748f2SMatthias Ringwald 590cdb96ae5SMatthias Ringwald // next usage 591cdb96ae5SMatthias Ringwald if (is_variable){ 592cdb96ae5SMatthias Ringwald parser->usage_minimum++; 593cdb96ae5SMatthias Ringwald parser->available_usages--; 594cdb96ae5SMatthias Ringwald if (parser->usage_range && (parser->usage_minimum > parser->usage_maximum)){ 595cdb96ae5SMatthias Ringwald // usage min - max range smaller than report count, ignore remaining bit in report 596cdb96ae5SMatthias Ringwald log_debug("Ignoring %u items without Usage", parser->required_usages); 597cdb96ae5SMatthias Ringwald parser->report_pos_in_bit += parser->global_report_size * parser->required_usages; 598cdb96ae5SMatthias Ringwald parser->required_usages = 0; 599cdb96ae5SMatthias Ringwald } 600cdb96ae5SMatthias Ringwald } else { 601cdb96ae5SMatthias Ringwald if (parser->required_usages == 0u){ 602cdb96ae5SMatthias Ringwald parser->available_usages = 0; 603cdb96ae5SMatthias Ringwald } 604cdb96ae5SMatthias Ringwald } 605cdb96ae5SMatthias Ringwald if (parser->available_usages) { 606cdb96ae5SMatthias Ringwald return; 607cdb96ae5SMatthias Ringwald } 608cdb96ae5SMatthias Ringwald if (parser->required_usages == 0u){ 609cdb96ae5SMatthias Ringwald parser->state = BTSTACK_HID_PARSER_SCAN_FOR_REPORT_ITEM; 610cdb96ae5SMatthias Ringwald btstack_hid_usage_iterator_find_next_usage(parser); 611cdb96ae5SMatthias Ringwald } else { 612cdb96ae5SMatthias Ringwald hid_find_next_usage(parser); 613cdb96ae5SMatthias Ringwald if (parser->available_usages == 0u) { 614cdb96ae5SMatthias Ringwald parser->state = BTSTACK_HID_PARSER_COMPLETE; 615cdb96ae5SMatthias Ringwald } 616cdb96ae5SMatthias Ringwald } 617cdb96ae5SMatthias Ringwald } 618cdb96ae5SMatthias Ringwald 619*0ba748f2SMatthias Ringwald 620*0ba748f2SMatthias Ringwald // HID Report Parser 621*0ba748f2SMatthias Ringwald 622*0ba748f2SMatthias Ringwald 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){ 623*0ba748f2SMatthias Ringwald btstack_hid_usage_iterator_init(parser, hid_descriptor, hid_descriptor_len, hid_report_type); 624*0ba748f2SMatthias Ringwald parser->report = hid_report; 625*0ba748f2SMatthias Ringwald parser->report_len = hid_report_len; 626*0ba748f2SMatthias Ringwald parser->have_report_usage_ready = false; 627*0ba748f2SMatthias Ringwald } 628*0ba748f2SMatthias Ringwald 629*0ba748f2SMatthias Ringwald /** 630*0ba748f2SMatthias Ringwald * @brief Checks if more fields are available 631*0ba748f2SMatthias Ringwald * @param parser 632*0ba748f2SMatthias Ringwald */ 633*0ba748f2SMatthias Ringwald bool btstack_hid_parser_has_more(btstack_hid_parser_t * parser){ 634*0ba748f2SMatthias Ringwald while ((parser->have_report_usage_ready == false) && btstack_hid_usage_iterator_has_more(parser)){ 635*0ba748f2SMatthias Ringwald btstack_hid_usage_iterator_get_item(parser, &parser->descriptor__usage_item); 636*0ba748f2SMatthias Ringwald // ignore usages for other report ids 637*0ba748f2SMatthias Ringwald if (parser->descriptor__usage_item.report_id != 0xffff){ 638*0ba748f2SMatthias Ringwald if (parser->descriptor__usage_item.report_id != parser->report[0]){ 639*0ba748f2SMatthias Ringwald continue; 640*0ba748f2SMatthias Ringwald } 641*0ba748f2SMatthias Ringwald } 642*0ba748f2SMatthias Ringwald parser->have_report_usage_ready = true; 643*0ba748f2SMatthias Ringwald } 644*0ba748f2SMatthias Ringwald return parser->have_report_usage_ready; 645*0ba748f2SMatthias Ringwald } 646*0ba748f2SMatthias Ringwald 647*0ba748f2SMatthias Ringwald /** 648*0ba748f2SMatthias Ringwald * @brief Get next field 649*0ba748f2SMatthias Ringwald * @param parser 650*0ba748f2SMatthias Ringwald * @param usage_page 651*0ba748f2SMatthias Ringwald * @param usage 652*0ba748f2SMatthias Ringwald * @param value provided in HID report 653*0ba748f2SMatthias Ringwald */ 654*0ba748f2SMatthias Ringwald 655*0ba748f2SMatthias Ringwald void btstack_hid_parser_get_field(btstack_hid_parser_t * parser, uint16_t * usage_page, uint16_t * usage, int32_t * value){ 656*0ba748f2SMatthias Ringwald 657*0ba748f2SMatthias Ringwald // fetch data from descriptor usage item 658*0ba748f2SMatthias Ringwald uint16_t bit_pos = parser->descriptor__usage_item.bit_pos; 659*0ba748f2SMatthias Ringwald uint16_t size = parser->descriptor__usage_item.size; 660*0ba748f2SMatthias Ringwald *usage_page = parser->descriptor__usage_item.usage_page; 661*0ba748f2SMatthias Ringwald *usage = parser->descriptor__usage_item.usage; 662*0ba748f2SMatthias Ringwald 663*0ba748f2SMatthias Ringwald 664*0ba748f2SMatthias Ringwald // read field (up to 32 bit unsigned, up to 31 bit signed - 32 bit signed behaviour is undefined) - check report len 665*0ba748f2SMatthias Ringwald bool is_variable = (parser->descriptor__usage_item.descriptor_item.item_value & 2) != 0; 666*0ba748f2SMatthias Ringwald bool is_signed = parser->descriptor__usage_item.global_logical_minimum < 0; 667*0ba748f2SMatthias Ringwald int pos_start = btstack_min( bit_pos >> 3, parser->report_len); 668*0ba748f2SMatthias Ringwald int pos_end = btstack_min( (bit_pos + size - 1u) >> 3u, parser->report_len); 669*0ba748f2SMatthias Ringwald int bytes_to_read = pos_end - pos_start + 1; 670*0ba748f2SMatthias Ringwald 671*0ba748f2SMatthias Ringwald int i; 672*0ba748f2SMatthias Ringwald uint32_t multi_byte_value = 0; 673*0ba748f2SMatthias Ringwald for (i=0;i < bytes_to_read;i++){ 674*0ba748f2SMatthias Ringwald multi_byte_value |= parser->report[pos_start+i] << (i*8); 675*0ba748f2SMatthias Ringwald } 676*0ba748f2SMatthias Ringwald uint32_t unsigned_value = (multi_byte_value >> (bit_pos & 0x07u)) & ((1u<<size)-1u); 677*0ba748f2SMatthias Ringwald // 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); 678*0ba748f2SMatthias Ringwald if (is_variable){ 679*0ba748f2SMatthias Ringwald if (is_signed && (unsigned_value & (1u<<(size-1u)))){ 680*0ba748f2SMatthias Ringwald *value = unsigned_value - (1u<<size); 681*0ba748f2SMatthias Ringwald } else { 682*0ba748f2SMatthias Ringwald *value = unsigned_value; 683*0ba748f2SMatthias Ringwald } 684*0ba748f2SMatthias Ringwald } else { 685*0ba748f2SMatthias Ringwald *usage = unsigned_value; 686*0ba748f2SMatthias Ringwald *value = 1; 687*0ba748f2SMatthias Ringwald } 688*0ba748f2SMatthias Ringwald 689*0ba748f2SMatthias Ringwald parser->have_report_usage_ready = false; 690*0ba748f2SMatthias Ringwald } 691