Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/usb/src/hidparser.c

    r4125b7d rc7c0984a  
    3939#include <mem.h>
    4040#include <usb/debug.h>
    41 
    42 /** */
     41#include <assert.h>
     42
     43/** The new report item flag. Used to determine when the item is completly
     44 * configured and should be added to the report structure
     45 */
    4346#define USB_HID_NEW_REPORT_ITEM 1
    4447
    45 /** */
    46 #define USB_HID_NO_ACTION               2
    47 
    48 /** */
     48/** No special action after the report descriptor tag is processed should be
     49 * done
     50 */
     51#define USB_HID_NO_ACTION       2
     52
     53#define USB_HID_RESET_OFFSET    3
     54
     55/** Unknown tag was founded in report descriptor data*/
    4956#define USB_HID_UNKNOWN_TAG             -99
    5057
     
    5259 * Private descriptor parser functions
    5360 */
     61int usb_hid_report_init(usb_hid_report_t *report);
     62int usb_hid_report_append_fields(usb_hid_report_t *report, usb_hid_report_item_t *report_item);
     63usb_hid_report_description_t * usb_hid_report_find_description(const usb_hid_report_t *report, uint8_t report_id, usb_hid_report_type_t type);
    5464int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
    5565                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
     
    6171                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
    6272
     73void usb_hid_print_usage_path(usb_hid_report_path_t *path);
    6374void usb_hid_descriptor_print_list(link_t *head);
    6475int usb_hid_report_reset_local_items();
     
    7081int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size);
    7182inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
    72 int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j);
    73 int32_t usb_hid_translate_data_reverse(usb_hid_report_item_t *item, int32_t value);
     83int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data);
     84uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, int32_t value);
    7485int usb_pow(int a, int b);
    7586
     
    96107 * @return Error code
    97108 */
    98 int usb_hid_parser_init(usb_hid_report_parser_t *parser)
    99 {
    100         if(parser == NULL) {
     109int usb_hid_report_init(usb_hid_report_t *report)
     110{
     111        if(report == NULL) {
    101112                return EINVAL;
    102113        }
    103114
    104         list_initialize(&(parser->input));
    105     list_initialize(&(parser->output));
    106     list_initialize(&(parser->feature));
    107 
    108         list_initialize(&(parser->stack));
    109 
    110         parser->use_report_id = 0;
     115        memset(report, 0, sizeof(usb_hid_report_t));
     116        list_initialize(&report->reports);
     117        list_initialize(&report->collection_paths);
     118
     119        report->use_report_ids = 0;
    111120    return EOK;   
    112121}
    113122
     123int usb_hid_report_append_fields(usb_hid_report_t *report, usb_hid_report_item_t *report_item)
     124{
     125        usb_hid_report_field_t *field;
     126        int i;
     127
     128
     129        /* find or append current collection path to the list */
     130        link_t *path_it = report->collection_paths.next;
     131        usb_hid_report_path_t *path = NULL;
     132        while(path_it != &report->collection_paths) {
     133                path = list_get_instance(path_it, usb_hid_report_path_t, link);
     134               
     135                if(usb_hid_report_compare_usage_path(path, report_item->usage_path, USB_HID_PATH_COMPARE_STRICT) == EOK){
     136                        break;
     137                }                       
     138                path_it = path_it->next;
     139        }
     140        if(path_it == &report->collection_paths) {
     141                path = usb_hid_report_path_clone(report_item->usage_path);                     
     142                list_append(&path->link, &report->collection_paths);                                   
     143                report->collection_paths_count++;
     144        }
     145
     146       
     147        for(i=0; i<report_item->count; i++){
     148
     149                field = malloc(sizeof(usb_hid_report_field_t));
     150                memset(field, 0, sizeof(usb_hid_report_field_t));
     151                list_initialize(&field->link);
     152
     153                /* fill the attributes */               
     154                field->collection_path = path;
     155                field->logical_minimum = report_item->logical_minimum;
     156                field->logical_maximum = report_item->logical_maximum;
     157                field->physical_minimum = report_item->physical_minimum;
     158                field->physical_maximum = report_item->physical_maximum;
     159
     160                field->usage_minimum = report_item->usage_minimum;
     161                field->usage_maximum = report_item->usage_maximum;
     162                if(report_item->extended_usage_page != 0){
     163                        field->usage_page = report_item->extended_usage_page;
     164                }
     165                else {
     166                        field->usage_page = report_item->usage_page;
     167                }
     168
     169                if(report_item->usages_count > 0 && ((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0))) {
     170                        if(i < report_item->usages_count){
     171                                if((report_item->usages[i] & 0xFF00) != 0){
     172                                        field->usage_page = (report_item->usages[i] >> 16);                                     
     173                                        field->usage = (report_item->usages[i] & 0xFF);
     174                                }
     175                                else {
     176                                        field->usage = report_item->usages[i];
     177                                }
     178                        }
     179                        else {
     180                                field->usage = report_item->usages[report_item->usages_count - 1];
     181                        }
     182                }       
     183
     184                if((USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) != 0) && (!((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0)))) {
     185                        if(report_item->type == USB_HID_REPORT_TYPE_INPUT) {
     186                                field->usage = report_item->usage_maximum - i;
     187                        }
     188                        else {
     189                                field->usage = report_item->usage_minimum + i;                                 
     190                        }
     191
     192                }
     193               
     194                field->size = report_item->size;
     195                field->offset = report_item->offset + (i * report_item->size);
     196                if(report_item->id != 0) {
     197                        field->offset += 8;
     198                        report->use_report_ids = 1;
     199                }
     200                field->item_flags = report_item->item_flags;
     201
     202                /* find the right report list*/
     203                usb_hid_report_description_t *report_des;
     204                report_des = usb_hid_report_find_description(report, report_item->id, report_item->type);
     205                if(report_des == NULL){
     206                        report_des = malloc(sizeof(usb_hid_report_description_t));
     207                        memset(report_des, 0, sizeof(usb_hid_report_description_t));
     208
     209                        report_des->type = report_item->type;
     210                        report_des->report_id = report_item->id;
     211                        list_initialize (&report_des->link);
     212                        list_initialize (&report_des->report_items);
     213
     214                        list_append(&report_des->link, &report->reports);
     215                        report->report_count++;
     216                }
     217
     218                /* append this field to the end of founded report list */
     219                list_append (&field->link, &report_des->report_items);
     220               
     221                /* update the sizes */
     222                report_des->bit_length += field->size;
     223                report_des->item_length++;
     224
     225        }
     226
     227
     228        return EOK;
     229}
     230
     231usb_hid_report_description_t * usb_hid_report_find_description(const usb_hid_report_t *report, uint8_t report_id, usb_hid_report_type_t type)
     232{
     233        link_t *report_it = report->reports.next;
     234        usb_hid_report_description_t *report_des = NULL;
     235       
     236        while(report_it != &report->reports) {
     237                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     238
     239                if((report_des->report_id == report_id) && (report_des->type == type)){
     240                        return report_des;
     241                }
     242               
     243                report_it = report_it->next;
     244        }
     245
     246        return NULL;
     247}
    114248
    115249/** Parse HID report descriptor.
     
    119253 * @return Error code.
    120254 */
    121 int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser,
     255int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
    122256    const uint8_t *data, size_t size)
    123257{
     
    130264        usb_hid_report_item_t *new_report_item;
    131265        usb_hid_report_path_t *usage_path;
    132         usb_hid_report_path_t *tmp_usage_path;
    133266
    134267        size_t offset_input=0;
    135268        size_t offset_output=0;
    136269        size_t offset_feature=0;
    137        
     270
     271        link_t stack;
     272        list_initialize(&stack);       
    138273
    139274        /* parser structure initialization*/
    140         if(usb_hid_parser_init(parser) != EOK) {
     275        if(usb_hid_report_init(report) != EOK) {
    141276                return EINVAL;
    142277        }
    143278       
    144 
    145279        /*report item initialization*/
    146280        if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
     
    159293
    160294                        if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
    161                                 return EINVAL; // TODO ERROR CODE
     295                                return EINVAL;
    162296                        }
    163297                       
     
    165299                        item_size = USB_HID_ITEM_SIZE(data[i]);
    166300                        class = USB_HID_ITEM_TAG_CLASS(data[i]);
    167 
    168                         usb_log_debug2(
    169                                 "i(%zu) data(%X) value(%X): TAG %d, class %u, size %u - ", i,
    170                             data[i], usb_hid_report_tag_data_int32(data+i+1,item_size),
    171                             tag, class, item_size);
    172301                       
    173302                        ret = usb_hid_report_parse_tag(tag,class,data+i+1,
    174303                                                       item_size,report_item, usage_path);
    175                         usb_log_debug2("ret: %u\n", ret);
    176304                        switch(ret){
    177305                                case USB_HID_NEW_REPORT_ITEM:
    178306                                        // store report item to report and create the new one
    179                                         usb_log_debug("\nNEW REPORT ITEM: %X",ret);
    180 
    181                                         // store current usage path
     307                                        // store current collection path
    182308                                        report_item->usage_path = usage_path;
    183309                                       
    184                                         // clone path to the new one
    185                                         tmp_usage_path = usb_hid_report_path_clone(usage_path);
    186 
    187                                         // swap
    188                                         usage_path = tmp_usage_path;
    189                                         tmp_usage_path = NULL;
    190 
    191310                                        usb_hid_report_path_set_report_id(report_item->usage_path, report_item->id);   
    192311                                        if(report_item->id != 0){
    193                                                 parser->use_report_id = 1;
     312                                                report->use_report_ids = 1;
    194313                                        }
    195314                                       
    196315                                        switch(tag) {
    197316                                                case USB_HID_REPORT_TAG_INPUT:
     317                                                        report_item->type = USB_HID_REPORT_TYPE_INPUT;
    198318                                                        report_item->offset = offset_input;
    199319                                                        offset_input += report_item->count * report_item->size;
    200                                                         usb_log_debug(" - INPUT\n");
    201                                                         list_append(&(report_item->link), &(parser->input));
    202320                                                        break;
    203321                                                case USB_HID_REPORT_TAG_OUTPUT:
     322                                                        report_item->type = USB_HID_REPORT_TYPE_OUTPUT;
    204323                                                        report_item->offset = offset_output;
    205324                                                        offset_output += report_item->count * report_item->size;
    206                                                         usb_log_debug(" - OUTPUT\n");
    207                                                                 list_append(&(report_item->link), &(parser->output));
    208325
    209326                                                        break;
    210327                                                case USB_HID_REPORT_TAG_FEATURE:
     328                                                        report_item->type = USB_HID_REPORT_TYPE_FEATURE;
    211329                                                        report_item->offset = offset_feature;
    212330                                                        offset_feature += report_item->count * report_item->size;
    213                                                         usb_log_debug(" - FEATURE\n");
    214                                                                 list_append(&(report_item->link), &(parser->feature));
    215331                                                        break;
    216332                                                default:
     
    218334                                                    break;
    219335                                        }
    220 
    221                                         /* clone current state table to the new item */
    222                                         if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
    223                                                 return ENOMEM;
    224                                         }                                       
    225                                         memcpy(new_report_item,report_item, sizeof(usb_hid_report_item_t));
    226                                         link_initialize(&(new_report_item->link));
    227336                                       
     337                                        /*
     338                                         * append new fields to the report
     339                                         * structure                                     
     340                                         */
     341                                        usb_hid_report_append_fields(report, report_item);
     342
    228343                                        /* reset local items */
    229                                         new_report_item->usage_minimum = 0;
    230                                         new_report_item->usage_maximum = 0;
    231                                         new_report_item->designator_index = 0;
    232                                         new_report_item->designator_minimum = 0;
    233                                         new_report_item->designator_maximum = 0;
    234                                         new_report_item->string_index = 0;
    235                                         new_report_item->string_minimum = 0;
    236                                         new_report_item->string_maximum = 0;
    237 
    238                                         /* reset usage from current usage path */
    239                                         usb_hid_report_usage_path_t *path = list_get_instance(&usage_path->link, usb_hid_report_usage_path_t, link);
    240                                         path->usage = 0;
    241                                        
    242                                         report_item = new_report_item;
    243                                                                                
     344                                        while(report_item->usages_count > 0){
     345                                                report_item->usages[--(report_item->usages_count)] = 0;
     346                                        }
     347
     348                                        report_item->extended_usage_page = 0;
     349                                        report_item->usage_minimum = 0;
     350                                        report_item->usage_maximum = 0;
     351                                        report_item->designator_index = 0;
     352                                        report_item->designator_minimum = 0;
     353                                        report_item->designator_maximum = 0;
     354                                        report_item->string_index = 0;
     355                                        report_item->string_minimum = 0;
     356                                        report_item->string_maximum = 0;
     357
    244358                                        break;
     359
     360                                case USB_HID_RESET_OFFSET:
     361                                        offset_input = 0;
     362                                        offset_output = 0;
     363                                        offset_feature = 0;
     364                                        usb_hid_report_path_set_report_id (usage_path, report_item->id);
     365                                        break;
     366
    245367                                case USB_HID_REPORT_TAG_PUSH:
    246368                                        // push current state to stack
    247369                                        new_report_item = usb_hid_report_item_clone(report_item);
    248                                         list_prepend (&parser->stack, &new_report_item->link);
    249                                        
     370                                        usb_hid_report_path_t *tmp_path = usb_hid_report_path_clone(usage_path);
     371                                        new_report_item->usage_path = tmp_path;
     372
     373                                        list_prepend (&new_report_item->link, &stack);
    250374                                        break;
    251375                                case USB_HID_REPORT_TAG_POP:
    252376                                        // restore current state from stack
    253                                         if(list_empty (&parser->stack)) {
     377                                        if(list_empty (&stack)) {
    254378                                                return EINVAL;
    255379                                        }
     380                                        free(report_item);
     381                                               
     382                                        report_item = list_get_instance(stack.next, usb_hid_report_item_t, link);
    256383                                       
    257                                         report_item = list_get_instance(&parser->stack, usb_hid_report_item_t, link);
    258                                         list_remove (parser->stack.next);
     384                                        usb_hid_report_usage_path_t *tmp_usage_path;
     385                                        tmp_usage_path = list_get_instance(report_item->usage_path->link.prev, usb_hid_report_usage_path_t, link);
     386                                       
     387                                        usb_hid_report_set_last_item(usage_path, tmp_usage_path->usage_page, tmp_usage_path->usage);
     388
     389                                        usb_hid_report_path_free(report_item->usage_path);
     390                                        list_initialize(&report_item->usage_path->link);
     391                                        list_remove (stack.next);
    259392                                       
    260393                                        break;
     
    279412}
    280413
    281 
    282 /**
    283  * Parse input report.
    284  *
    285  * @param data Data for report
    286  * @param size Size of report
    287  * @param callbacks Callbacks for report actions
    288  * @param arg Custom arguments
    289  *
    290  * @return Error code
    291  */
    292 int usb_hid_boot_keyboard_input_report(const uint8_t *data, size_t size,
    293         const usb_hid_report_in_callbacks_t *callbacks, void *arg)
    294 {
    295         int i;
    296         usb_hid_report_item_t item;
    297 
    298         /* fill item due to the boot protocol report descriptor */
    299         // modifier keys are in the first byte
    300         uint8_t modifiers = data[0];
    301 
    302         item.offset = 2; /* second byte is reserved */
    303         item.size = 8;
    304         item.count = 6;
    305         item.usage_minimum = 0;
    306         item.usage_maximum = 255;
    307         item.logical_minimum = 0;
    308         item.logical_maximum = 255;
    309 
    310         if (size != 8) {
    311                 return -1; //ERANGE;
    312         }
    313 
    314         uint8_t keys[6];
    315         for (i = 0; i < item.count; i++) {
    316                 keys[i] = data[i + item.offset];
    317         }
    318 
    319         callbacks->keyboard(keys, 6, modifiers, arg);
    320         return EOK;
    321 }
    322 
    323 /**
    324  * Makes output report for keyboard boot protocol
    325  *
    326  * @param leds
    327  * @param output Output report data buffer
    328  * @param size Size of the output buffer
    329  * @return Error code
    330  */
    331 int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size)
    332 {
    333         if(size != 1){
    334                 return -1;
    335         }
    336 
    337         /* used only first five bits, others are only padding*/
    338         *data = leds;
    339         return EOK;
    340 }
    341414
    342415/**
     
    401474                       
    402475                case USB_HID_REPORT_TAG_COLLECTION:
    403                         usb_hid_report_path_append_item(usage_path, 0, 0);
    404                                                
     476                        // TODO usage_path->flags = *data;
     477                        usb_hid_report_path_append_item(usage_path, report_item->usage_page, report_item->usages[report_item->usages_count-1]);                                        
    405478                        return USB_HID_NO_ACTION;
    406479                        break;
    407480                       
    408481                case USB_HID_REPORT_TAG_END_COLLECTION:
    409                         // TODO
    410                         // znici posledni uroven ve vsech usage paths
    411                         // otazka jestli nema nicit dve, respektive novou posledni vynulovat?
    412482                        usb_hid_report_remove_last_item(usage_path);
    413483                        return USB_HID_NO_ACTION;
     
    436506        {
    437507                case USB_HID_REPORT_TAG_USAGE_PAGE:
    438                         // zmeni to jenom v poslednim poli aktualni usage path
    439                         usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_GLOBAL,
    440                                 usb_hid_report_tag_data_int32(data,item_size));
     508                        report_item->usage_page = usb_hid_report_tag_data_int32(data, item_size);
    441509                        break;
    442510                case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
     
    466534                case USB_HID_REPORT_TAG_REPORT_ID:
    467535                        report_item->id = usb_hid_report_tag_data_int32(data,item_size);
     536                        return USB_HID_RESET_OFFSET;
    468537                        break;
    469538                case USB_HID_REPORT_TAG_PUSH:
    470539                case USB_HID_REPORT_TAG_POP:
     540                        /*
     541                         * stack operations are done in top level parsing
     542                         * function
     543                         */
    471544                        return tag;
    472545                        break;
     
    494567        {
    495568                case USB_HID_REPORT_TAG_USAGE:
    496                         usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_LOCAL,
    497                                 usb_hid_report_tag_data_int32(data,item_size));
     569                        report_item->usages[report_item->usages_count++] = usb_hid_report_tag_data_int32(data,item_size);
    498570                        break;
    499571                case USB_HID_REPORT_TAG_USAGE_MINIMUM:
    500                         report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size);
     572                        if (item_size == 3) {
     573                                // usage extended usages
     574                                report_item->extended_usage_page = (usb_hid_report_tag_data_int32(data,item_size) & 0xFF00) >> 16;
     575                                report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size) & 0xFF;
     576                        }
     577                        else {
     578                                report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size);
     579                        }
    501580                        break;
    502581                case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
    503                         report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size);
     582                        if (item_size == 3) {
     583                                // usage extended usages
     584                                report_item->extended_usage_page = (usb_hid_report_tag_data_int32(data,item_size) & 0xFF00) >> 16;
     585                                report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size) & 0xFF;
     586                        }
     587                        else {
     588                                report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size);
     589                        }
    504590                        break;
    505591                case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
     
    522608                        break;                 
    523609                case USB_HID_REPORT_TAG_DELIMITER:
    524                         report_item->delimiter = usb_hid_report_tag_data_int32(data,item_size);
     610                        //report_item->delimiter = usb_hid_report_tag_data_int32(data,item_size);
     611                        //TODO:
     612                        //      DELIMITER STUFF
    525613                        break;
    526614               
     
    562650void usb_hid_descriptor_print_list(link_t *head)
    563651{
    564         usb_hid_report_item_t *report_item;
    565         usb_hid_report_usage_path_t *path_item;
    566         link_t *path;
     652        usb_hid_report_field_t *report_item;
    567653        link_t *item;
    568        
     654
     655
    569656        if(head == NULL || list_empty(head)) {
    570657            usb_log_debug("\tempty\n");
     
    574661        for(item = head->next; item != head; item = item->next) {
    575662               
    576                 report_item = list_get_instance(item, usb_hid_report_item_t, link);
    577 
    578                 usb_log_debug("\tOFFSET: %zX\n", report_item->offset);
    579                 usb_log_debug("\tCOUNT: %X\n", report_item->count);
    580                 usb_log_debug("\tSIZE: %X\n", report_item->size);
    581                 usb_log_debug("\tCONSTANT/VAR: %X\n", USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags));
    582                 usb_log_debug("\tVARIABLE/ARRAY: %X\n", USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags));
    583                 usb_log_debug("\tUSAGE PATH:\n");
    584 
    585                 path = report_item->usage_path->link.next;
    586                 while(path != &report_item->usage_path->link)   {
    587                         path_item = list_get_instance(path, usb_hid_report_usage_path_t, link);
    588                         usb_log_debug("\t\tUSAGE PAGE: %X, USAGE: %X\n", path_item->usage_page, path_item->usage);
    589                         path = path->next;
    590                 }
    591                                
    592                 usb_log_debug("\tLOGMIN: %X\n", report_item->logical_minimum);
    593                 usb_log_debug("\tLOGMAX: %X\n", report_item->logical_maximum);         
    594                 usb_log_debug("\tPHYMIN: %X\n", report_item->physical_minimum);         
    595                 usb_log_debug("\tPHYMAX: %X\n", report_item->physical_maximum);                         
    596                 usb_log_debug("\tUSAGEMIN: %X\n", report_item->usage_minimum);
    597                 usb_log_debug("\tUSAGEMAX: %X\n", report_item->usage_maximum);
    598                
    599                 usb_log_debug("\n");           
     663                report_item = list_get_instance(item, usb_hid_report_field_t, link);
     664
     665                usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
     666                usb_log_debug("\t\tSIZE: %X\n", report_item->size);                             
     667                usb_log_debug("\t\tLOGMIN: %X\n", report_item->logical_minimum);
     668                usb_log_debug("\t\tLOGMAX: %X\n", report_item->logical_maximum);               
     669                usb_log_debug("\t\tPHYMIN: %X\n", report_item->physical_minimum);               
     670                usb_log_debug("\t\tPHYMAX: %X\n", report_item->physical_maximum);                               
     671                usb_log_debug("\t\ttUSAGEMIN: %X\n", report_item->usage_minimum);
     672                usb_log_debug("\t\tUSAGEMAX: %X\n", report_item->usage_maximum);
     673
     674                usb_log_debug("\t\tVALUE: %X\n", report_item->value);
     675                usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
     676                usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
     677                                               
     678//              usb_log_debug("\n");           
    600679
    601680        }
     
    609688 * @return void
    610689 */
    611 void usb_hid_descriptor_print(usb_hid_report_parser_t *parser)
    612 {
    613         if(parser == NULL) {
     690void usb_hid_descriptor_print(usb_hid_report_t *report)
     691{
     692        if(report == NULL) {
    614693                return;
    615694        }
    616        
    617         usb_log_debug("INPUT:\n");
    618         usb_hid_descriptor_print_list(&parser->input);
    619        
    620         usb_log_debug("OUTPUT: \n");
    621         usb_hid_descriptor_print_list(&parser->output);
    622        
    623         usb_log_debug("FEATURE:\n");   
    624         usb_hid_descriptor_print_list(&parser->feature);
    625 
     695
     696        link_t *report_it = report->reports.next;
     697        usb_hid_report_description_t *report_des;
     698
     699        while(report_it != &report->reports) {
     700                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     701                usb_log_debug("Report ID: %d\n", report_des->report_id);
     702                usb_log_debug("\tType: %d\n", report_des->type);
     703                usb_log_debug("\tLength: %d\n", report_des->bit_length);               
     704                usb_log_debug("\tItems: %d\n", report_des->item_length);               
     705
     706                usb_hid_descriptor_print_list(&report_des->report_items);
     707
     708
     709                link_t *path_it = report->collection_paths.next;
     710                while(path_it != &report->collection_paths) {
     711                        usb_hid_print_usage_path (list_get_instance(path_it, usb_hid_report_path_t, link));
     712                        path_it = path_it->next;
     713                }
     714               
     715                report_it = report_it->next;
     716        }
    626717}
    627718
     
    667758 * @return void
    668759 */
    669 void usb_hid_free_report_parser(usb_hid_report_parser_t *parser)
    670 {
    671         if(parser == NULL){
     760void usb_hid_free_report(usb_hid_report_t *report)
     761{
     762        if(report == NULL){
    672763                return;
    673764        }
    674765
    675         parser->use_report_id = 0;
    676 
    677         usb_hid_free_report_list(&parser->input);
    678         usb_hid_free_report_list(&parser->output);
    679         usb_hid_free_report_list(&parser->feature);
    680 
     766        // free collection paths
     767        usb_hid_report_path_t *path;
     768        while(!list_empty(&report->collection_paths)) {
     769                path = list_get_instance(report->collection_paths.next, usb_hid_report_path_t, link);
     770                usb_hid_report_path_free(path);         
     771        }
     772       
     773        // free report items
     774        usb_hid_report_description_t *report_des;
     775        usb_hid_report_field_t *field;
     776        while(!list_empty(&report->reports)) {
     777                report_des = list_get_instance(report->reports.next, usb_hid_report_description_t, link);
     778                list_remove(&report_des->link);
     779               
     780                while(!list_empty(&report_des->report_items)) {
     781                        field = list_get_instance(report_des->report_items.next, usb_hid_report_field_t, link);
     782                        list_remove(&field->link);
     783
     784                        free(field);
     785                }
     786               
     787                free(report_des);
     788        }
     789       
    681790        return;
    682791}
     
    688797 * @param parser Opaque HID report parser structure.
    689798 * @param data Data for the report.
    690  * @param callbacks Callbacks for report actions.
    691  * @param arg Custom argument (passed through to the callbacks).
    692799 * @return Error code.
    693800 */
    694 int usb_hid_parse_report(const usb_hid_report_parser_t *parser, 
    695     const uint8_t *data, size_t size,
    696     usb_hid_report_path_t *path, int flags,
    697     const usb_hid_report_in_callbacks_t *callbacks, void *arg)
     801int usb_hid_parse_report(const usb_hid_report_t *report, 
     802    const uint8_t *data, size_t size, uint8_t *report_id)
    698803{
    699804        link_t *list_item;
    700         usb_hid_report_item_t *item;
    701         uint8_t *keys;
    702         uint8_t item_value;
    703         size_t key_count=0;
    704         size_t i=0;
    705         size_t j=0;
    706         uint8_t report_id = 0;
    707 
    708         if(parser == NULL) {
     805        usb_hid_report_field_t *item;
     806
     807        usb_hid_report_description_t *report_des;
     808        usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
     809
     810        if(report == NULL) {
    709811                return EINVAL;
    710812        }
    711        
    712         /* get the size of result array */
    713         key_count = usb_hid_report_input_length(parser, path, flags);
    714 
    715         if(!(keys = malloc(sizeof(uint8_t) * key_count))){
    716                 return ENOMEM;
    717         }
    718 
    719         if(parser->use_report_id != 0) {
    720                 report_id = data[0];
    721                 usb_hid_report_path_set_report_id(path, report_id);
    722         }
     813
     814        if(report->use_report_ids != 0) {
     815                *report_id = data[0];
     816        }       
     817        else {
     818                *report_id = 0;
     819        }
     820
     821
     822        report_des = usb_hid_report_find_description(report, *report_id, type);
    723823
    724824        /* read data */
    725         list_item = parser->input.next;   
    726         while(list_item != &(parser->input)) {
    727 
    728                 item = list_get_instance(list_item, usb_hid_report_item_t, link);
    729 
    730                 if(!USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) &&
    731                    (usb_hid_report_compare_usage_path(item->usage_path, path, flags) == EOK)) {
    732                         for(j=0; j<(size_t)(item->count); j++) {
    733                                 if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) ||
    734                                    ((item->usage_minimum == 0) && (item->usage_maximum == 0))) {
    735                                         // variable item
    736                                         keys[i++] = usb_hid_translate_data(item, data,j);
    737                                 }
    738                                 else {
    739                                         // bitmapa
    740                                         if((item_value = usb_hid_translate_data(item, data, j)) != 0) {
    741                                                 keys[i++] = (item->count - 1 - j) + item->usage_minimum;
    742                                         }
    743                                         else {
    744                                                 keys[i++] = 0;
    745                                         }
    746                                 }
    747                         }
     825        list_item = report_des->report_items.next;         
     826        while(list_item != &(report_des->report_items)) {
     827
     828                item = list_get_instance(list_item, usb_hid_report_field_t, link);
     829
     830                if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
     831                       
     832                        if(USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) {
     833
     834                                // array
     835                                item->value = usb_hid_translate_data(item, data);
     836                            item->usage = (item->value - item->physical_minimum) + item->usage_minimum;
     837                        }
     838                        else {
     839                                // variable item
     840                                item->value = usb_hid_translate_data(item, data);                               
     841                        }                               
    748842                }
    749843                list_item = list_item->next;
    750844        }
    751 
    752         callbacks->keyboard(keys, key_count, report_id, arg);
    753845           
    754         free(keys);     
    755846        return EOK;
    756847       
     
    758849
    759850/**
    760  * Translate data from the report as specified in report descriptor
     851 * Translate data from the report as specified in report descriptor item
    761852 *
    762853 * @param item Report descriptor item with definition of translation
     
    765856 * @return Translated data
    766857 */
    767 int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j)
     858int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data)
    768859{
    769860        int resolution;
     
    771862        int part_size;
    772863       
    773         int32_t value;
     864        int32_t value=0;
    774865        int32_t mask;
    775866        const uint8_t *foo;
    776867
    777         // now only common numbers llowed
     868        // now only shot tags are allowed
    778869        if(item->size > 32) {
    779870                return 0;
    780871        }
    781872
    782         if((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
     873        if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
    783874                item->physical_minimum = item->logical_minimum;
    784                 item->physical_maximum = item->logical_maximum;         
    785         }
     875                item->physical_maximum = item->logical_maximum;                 
     876        }
     877       
    786878
    787879        if(item->physical_maximum == item->physical_minimum){
     
    794886        }
    795887
    796         offset = item->offset + (j * item->size);
    797         if(item->id != 0) {
    798                 offset += 8;
    799                 usb_log_debug("MOVED OFFSET BY 1Byte, REPORT_ID(%d)\n", item->id);
    800         }
    801        
     888        offset = item->offset;
    802889        // FIXME
    803         if((offset/8) != ((offset+item->size)/8)) {
    804                 usb_log_debug2("offset %d\n", offset);
     890        if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
    805891               
    806892                part_size = ((offset+item->size)%8);
    807                 usb_log_debug2("part size %d\n",part_size);
    808 
    809                 // the higher one
    810                 foo = data+(offset/8);
    811                 mask =  ((1 << (item->size-part_size))-1);
    812                 value = (*foo & mask) << part_size;
    813 
    814                 usb_log_debug2("hfoo %x\n", *foo);
    815                 usb_log_debug2("hmaska %x\n",  mask);
    816                 usb_log_debug2("hval %d\n", value);             
    817 
    818                 // the lower one
    819                 foo = data+((offset+item->size)/8);
    820                 mask =  ((1 << part_size)-1) << (8-part_size);
    821                 value += ((*foo & mask) >> (8-part_size));
    822 
    823                 usb_log_debug2("lfoo %x\n", *foo);
    824                 usb_log_debug2("lmaska %x\n",  mask);
    825                 usb_log_debug2("lval %d\n", ((*foo & mask) >> (8-(item->size-part_size))));             
    826                 usb_log_debug2("val %d\n", value);
    827                
    828                
     893
     894                size_t i=0;
     895                for(i=(size_t)(offset/8); i<=(size_t)(offset+item->size-1)/8; i++){
     896                        if(i == (size_t)(offset/8)) {
     897                                // the higher one
     898                                foo = data + i;
     899                                mask =  ((1 << (item->size-part_size))-1);
     900                                value = (*foo & mask) << part_size;
     901                        }
     902                        else if(i == ((offset+item->size-1)/8)){
     903                                // the lower one
     904                                foo = data + i;
     905                                mask =  ((1 << part_size)-1) << (8-part_size);
     906                                value += ((*foo & mask) >> (8-part_size));
     907                        }
     908                        else {
     909                                value = value << 8;
     910                                value += *(data + 1);
     911                        }
     912                }
    829913        }
    830914        else {         
     
    832916                mask =  ((1 << item->size)-1) << (8-((offset%8)+item->size));
    833917                value = (*foo & mask) >> (8-((offset%8)+item->size));
    834 
    835                 usb_log_debug2("offset %d\n", offset);
    836        
    837                 usb_log_debug2("foo %x\n", *foo);
    838                 usb_log_debug2("maska %x\n",  mask);
    839                 usb_log_debug2("val %d\n", value);                             
    840         }
    841 
    842         usb_log_debug2("---\n\n");
     918        }
     919
     920        if(!(item->logical_minimum >= 0 && item->logical_maximum >= 0)){
     921                value = (int32_t)value;
     922        }
     923        else {
     924                value = (uint32_t)value;
     925        }
    843926
    844927        return (int)(((value - item->logical_minimum) / resolution) + item->physical_minimum);
     
    847930
    848931/**
    849  *
    850  *
    851  * @param parser
    852  * @param path
    853  * @param flags
    854  * @return
    855  */
    856 size_t usb_hid_report_input_length(const usb_hid_report_parser_t *parser,
     932 * Returns number of items in input report which are accessible by given usage path
     933 *
     934 * @param parser Opaque report descriptor structure
     935 * @param path Usage path specification
     936 * @param flags Usage path comparison flags
     937 * @return Number of items in input report
     938 */
     939size_t usb_hid_report_input_length(const usb_hid_report_t *report,
    857940        usb_hid_report_path_t *path, int flags)
    858941{       
     942       
    859943        size_t ret = 0;
    860         link_t *item;
    861         usb_hid_report_item_t *report_item;
    862 
    863         if(parser == NULL) {
     944
     945        if(report == NULL) {
    864946                return 0;
    865947        }
    866        
    867         item = parser->input.next;
    868         while(&parser->input != item) {
    869                 report_item = list_get_instance(item, usb_hid_report_item_t, link);
    870                 if(!USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags) &&
    871                    (usb_hid_report_compare_usage_path(report_item->usage_path, path, flags) == EOK)) {
    872                         ret += report_item->count;
    873                 }
    874 
    875                 item = item->next;
    876         }
     948
     949        usb_hid_report_description_t *report_des;
     950        report_des = usb_hid_report_find_description (report, path->report_id, USB_HID_REPORT_TYPE_INPUT);
     951        if(report_des == NULL) {
     952                return 0;
     953        }
     954
     955        link_t *field_it = report_des->report_items.next;
     956        usb_hid_report_field_t *field;
     957        while(field_it != &report_des->report_items) {
     958
     959                field = list_get_instance(field_it, usb_hid_report_field_t, link);
     960                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
     961                       
     962                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     963                        if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK) {
     964                                ret++;
     965                        }
     966                        usb_hid_report_remove_last_item (field->collection_path);
     967                }
     968               
     969                field_it = field_it->next;
     970        }
    877971
    878972        return ret;
    879 }
    880 
    881 
    882 /**
    883  *
    884  * @param usage_path
    885  * @param usage_page
    886  * @param usage
    887  * @return
     973        }
     974
     975
     976/**
     977 * Appends one item (couple of usage_path and usage) into the usage path
     978 * structure
     979 *
     980 * @param usage_path Usage path structure
     981 * @param usage_page Usage page constant
     982 * @param usage Usage constant
     983 * @return Error code
    888984 */
    889985int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path,
     
    899995        item->usage = usage;
    900996        item->usage_page = usage_page;
    901        
    902         usb_log_debug("Appending usage %d, usage page %d\n", usage, usage_page);
    903        
    904         list_append (&usage_path->link, &item->link);
     997        item->flags = 0;
     998       
     999        list_append (&item->link, &usage_path->head);
    9051000        usage_path->depth++;
    9061001        return EOK;
     
    9081003
    9091004/**
    910  *
    911  * @param usage_path
    912  * @return
     1005 * Removes last item from the usage path structure
     1006 * @param usage_path 
     1007 * @return void
    9131008 */
    9141009void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
     
    9161011        usb_hid_report_usage_path_t *item;
    9171012       
    918         if(!list_empty(&usage_path->link)){
    919                 item = list_get_instance(usage_path->link.prev, usb_hid_report_usage_path_t, link);             
    920                 list_remove(usage_path->link.prev);
     1013        if(!list_empty(&usage_path->head)){
     1014                item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);             
     1015                list_remove(usage_path->head.prev);
    9211016                usage_path->depth--;
    9221017                free(item);
     
    9251020
    9261021/**
     1022 * Nulls last item of the usage path structure.
    9271023 *
    9281024 * @param usage_path
    929  * @return
     1025 * @return void
    9301026 */
    9311027void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
     
    9331029        usb_hid_report_usage_path_t *item;
    9341030       
    935         if(!list_empty(&usage_path->link)){     
    936                 item = list_get_instance(usage_path->link.prev, usb_hid_report_usage_path_t, link);
     1031        if(!list_empty(&usage_path->head)){     
     1032                item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
    9371033                memset(item, 0, sizeof(usb_hid_report_usage_path_t));
    9381034        }
     
    9401036
    9411037/**
    942  *
    943  * @param usage_path
    944  * @param tag
    945  * @param data
    946  * @return
     1038 * Modifies last item of usage path structure by given usage page or usage
     1039 *
     1040 * @param usage_path Opaque usage path structure
     1041 * @param tag Class of currently processed tag (Usage page tag falls into Global
     1042 * class but Usage tag into the Local)
     1043 * @param data Value of the processed tag
     1044 * @return void
    9471045 */
    9481046void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, int32_t tag, int32_t data)
     
    9501048        usb_hid_report_usage_path_t *item;
    9511049       
    952         if(!list_empty(&usage_path->link)){     
    953                 item = list_get_instance(usage_path->link.prev, usb_hid_report_usage_path_t, link);
     1050        if(!list_empty(&usage_path->head)){     
     1051                item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
    9541052
    9551053                switch(tag) {
     
    9651063}
    9661064
    967 /**
    968  *
    969  *
    970  * @param report_path
    971  * @param path
    972  * @param flags
    973  * @return
     1065
     1066void usb_hid_print_usage_path(usb_hid_report_path_t *path)
     1067{
     1068        usb_log_debug("USAGE_PATH FOR RId(%d):\n", path->report_id);
     1069        usb_log_debug("\tLENGTH: %d\n", path->depth);
     1070
     1071        link_t *item = path->head.next;
     1072        usb_hid_report_usage_path_t *path_item;
     1073        while(item != &path->head) {
     1074
     1075                path_item = list_get_instance(item, usb_hid_report_usage_path_t, link);
     1076                usb_log_debug("\tUSAGE_PAGE: %X\n", path_item->usage_page);
     1077                usb_log_debug("\tUSAGE: %X\n", path_item->usage);
     1078                usb_log_debug("\tFLAGS: %d\n", path_item->flags);               
     1079               
     1080                item = item->next;
     1081        }
     1082}
     1083
     1084/**
     1085 * Compares two usage paths structures
     1086 *
     1087 * If USB_HID_PATH_COMPARE_COLLECTION_ONLY flag is given, the last item in report_path structure is forgotten
     1088 *
     1089 * @param report_path usage path structure to compare
     1090 * @param path usage patrh structure to compare
     1091 * @param flags Flags determining the mode of comparison
     1092 * @return EOK if both paths are identical, non zero number otherwise
    9741093 */
    9751094int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path,
     
    10051124                                }
    10061125
    1007                                 report_link = report_path->link.next;
    1008                                 path_link = path->link.next;
     1126                                report_link = report_path->head.next;
     1127                                path_link = path->head.next;
    10091128                       
    1010                                 while((report_link != &report_path->link) && (path_link != &path->link)) {
     1129                                while((report_link != &report_path->head) && (path_link != &path->head)) {
    10111130                                        report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
    10121131                                        path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);           
     
    10221141                                }
    10231142
    1024                                 if((report_link == &report_path->link) && (path_link == &path->link)) {
     1143                                if(((report_link == &report_path->head) && (path_link == &path->head)) ||
     1144                                   (((flags & USB_HID_PATH_COMPARE_COLLECTION_ONLY) != 0) && (path_link = &path->head) && (report_link == report_path->head.prev))) {
    10251145                                        return EOK;
    10261146                                }
     
    10321152                /* compare with only the end of path*/
    10331153                case USB_HID_PATH_COMPARE_END:
    1034                                 report_link = report_path->link.prev;
    1035                                 path_link = path->link.prev;
    1036 
    1037                                 if(list_empty(&path->link)){
     1154
     1155                                if((flags & USB_HID_PATH_COMPARE_COLLECTION_ONLY) != 0) {
     1156                                        report_link = report_path->head.prev->prev;
     1157                                }
     1158                                else {
     1159                                        report_link = report_path->head.prev;
     1160                                }
     1161                                path_link = path->head.prev;
     1162
     1163                                if(list_empty(&path->head)){
    10381164                                        return EOK;
    10391165                                }
    10401166                       
    1041                                 while((report_link != &report_path->link) && (path_link != &path->link)) {
     1167                                while((report_link != &report_path->head) && (path_link != &path->head)) {
    10421168                                        report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
    10431169                                        path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);           
     
    10531179                                }
    10541180
    1055                                 if(path_link == &path->link) {
     1181                                if(path_link == &path->head) {
    10561182                                        return EOK;
    10571183                                }
     
    10721198
    10731199/**
    1074  *
    1075  * @return
     1200 * Allocates and initializes new usage path structure.
     1201 *
     1202 * @return Initialized usage path structure
    10761203 */
    10771204usb_hid_report_path_t *usb_hid_report_path(void)
     
    10791206        usb_hid_report_path_t *path;
    10801207        path = malloc(sizeof(usb_hid_report_path_t));
    1081         if(!path){
     1208        if(path == NULL){
    10821209                return NULL;
    10831210        }
     
    10861213                path->report_id = 0;
    10871214                list_initialize(&path->link);
     1215                list_initialize(&path->head);
    10881216                return path;
    10891217        }
     
    10911219
    10921220/**
    1093  *
    1094  * @param path
     1221 * Releases given usage path structure.
     1222 *
     1223 * @param path usage path structure to release
    10951224 * @return void
    10961225 */
    10971226void usb_hid_report_path_free(usb_hid_report_path_t *path)
    10981227{
    1099         while(!list_empty(&path->link)){
     1228        while(!list_empty(&path->head)){
    11001229                usb_hid_report_remove_last_item(path);
    11011230        }
     1231
     1232        list_remove(&path->link);
     1233        free(path);
    11021234}
    11031235
     
    11061238 * Clone content of given usage path to the new one
    11071239 *
    1108  * @param usage_path
    1109  * @return
     1240 * @param usage_path Usage path structure to clone
     1241 * @return New copy of given usage path structure
    11101242 */
    11111243usb_hid_report_path_t *usb_hid_report_path_clone(usb_hid_report_path_t *usage_path)
    11121244{
     1245        link_t *path_link;
    11131246        usb_hid_report_usage_path_t *path_item;
    1114         link_t *path_link;
     1247        usb_hid_report_usage_path_t *new_path_item;
    11151248        usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
    11161249
     
    11181251                return NULL;
    11191252        }
    1120        
    1121         if(list_empty(&usage_path->link)){
     1253
     1254        new_usage_path->report_id = usage_path->report_id;
     1255       
     1256        if(list_empty(&usage_path->head)){
    11221257                return new_usage_path;
    11231258        }
    11241259
    1125         path_link = usage_path->link.next;
    1126         while(path_link != &usage_path->link) {
     1260        path_link = usage_path->head.next;
     1261        while(path_link != &usage_path->head) {
    11271262                path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
    1128                 usb_hid_report_path_append_item (new_usage_path, path_item->usage_page, path_item->usage);
     1263                new_path_item = malloc(sizeof(usb_hid_report_usage_path_t));
     1264                if(new_path_item == NULL) {
     1265                        return NULL;
     1266                }
     1267               
     1268                list_initialize (&new_path_item->link);         
     1269                new_path_item->usage_page = path_item->usage_page;
     1270                new_path_item->usage = path_item->usage;               
     1271                new_path_item->flags = path_item->flags;               
     1272               
     1273                list_append(&new_path_item->link, &new_usage_path->head);
     1274                new_usage_path->depth++;
    11291275
    11301276                path_link = path_link->next;
     
    11371283/*** OUTPUT API **/
    11381284
    1139 /** Allocates output report buffer
    1140  *
    1141  * @param parser
    1142  * @param size
    1143  * @return
    1144  */
    1145 uint8_t *usb_hid_report_output(usb_hid_report_parser_t *parser, size_t *size)
    1146 {
    1147         if(parser == NULL) {
     1285/**
     1286 * Allocates output report buffer for output report
     1287 *
     1288 * @param parser Report parsed structure
     1289 * @param size Size of returned buffer
     1290 * @param report_id Report id of created output report
     1291 * @return Returns allocated output buffer for specified output
     1292 */
     1293uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, uint8_t report_id)
     1294{
     1295        if(report == NULL) {
    11481296                *size = 0;
    11491297                return NULL;
    11501298        }
    1151        
    1152         // read the last output report item
    1153         usb_hid_report_item_t *last;
    1154         link_t *link;
    1155 
    1156         link = parser->output.prev;
    1157         if(link != &parser->output) {
    1158                 last = list_get_instance(link, usb_hid_report_item_t, link);
    1159                 *size = (last->offset + (last->size * last->count)) / 8;
    1160 
    1161                 uint8_t *buffer = malloc(sizeof(uint8_t) * (*size));
    1162                 memset(buffer, 0, sizeof(uint8_t) * (*size));
    1163                 usb_log_debug("output buffer: %s\n", usb_debug_str_buffer(buffer, *size, 0));
    1164 
    1165                 return buffer;
     1299
     1300        link_t *report_it = report->reports.next;
     1301        usb_hid_report_description_t *report_des = NULL;
     1302        while(report_it != &report->reports) {
     1303                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     1304                if((report_des->report_id == report_id) && (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
     1305                        break;
     1306                }
     1307
     1308                report_it = report_it->next;
     1309        }
     1310
     1311        if(report_des == NULL){
     1312                *size = 0;
     1313                return NULL;
    11661314        }
    11671315        else {
    1168                 *size = 0;             
    1169                 return NULL;
     1316                *size = (report_des->bit_length + (8 - 1))/8;
     1317                uint8_t *ret = malloc((*size) * sizeof(uint8_t));
     1318                memset(ret, 0, (*size) * sizeof(uint8_t));
     1319                return ret;
    11701320        }
    11711321}
     
    11751325 *
    11761326 * @param output Output report buffer
    1177  * @return
     1327 * @return void
    11781328 */
    11791329void usb_hid_report_output_free(uint8_t *output)
     
    11871337/** Returns size of output for given usage path
    11881338 *
    1189  * @param parser
    1190  * @param path
    1191  * @param flags
    1192  * @return
    1193  */
    1194 size_t usb_hid_report_output_size(usb_hid_report_parser_t *parser,
     1339 * @param parser Opaque report parser structure
     1340 * @param path Usage path specified which items will be thought for the output
     1341 * @param flags Flags of usage path structure comparison
     1342 * @return Number of items matching the given usage path
     1343 */
     1344size_t usb_hid_report_output_size(usb_hid_report_t *report,
    11951345                                  usb_hid_report_path_t *path, int flags)
    11961346{
    1197         size_t ret = 0;
    1198         link_t *item;
    1199         usb_hid_report_item_t *report_item;
    1200 
    1201         if(parser == NULL) {
     1347        size_t ret = 0;
     1348        usb_hid_report_description_t *report_des;
     1349
     1350        if(report == NULL) {
    12021351                return 0;
    12031352        }
    12041353
    1205         item = parser->output.next;
    1206         while(&parser->output != item) {
    1207                 report_item = list_get_instance(item, usb_hid_report_item_t, link);
    1208                 if(!USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags) &&
    1209                    (usb_hid_report_compare_usage_path(report_item->usage_path, path, flags) == EOK)) {
    1210                         ret += report_item->count;
    1211                 }
    1212 
    1213                 item = item->next;
    1214         }
     1354        report_des = usb_hid_report_find_description (report, path->report_id, USB_HID_REPORT_TYPE_OUTPUT);
     1355        if(report_des == NULL){
     1356                return 0;
     1357        }
     1358       
     1359        link_t *field_it = report_des->report_items.next;
     1360        usb_hid_report_field_t *field;
     1361        while(field_it != &report_des->report_items) {
     1362
     1363                field = list_get_instance(field_it, usb_hid_report_field_t, link);
     1364                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0){
     1365                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     1366                        if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK) {
     1367                                ret++;
     1368                        }
     1369                        usb_hid_report_remove_last_item (field->collection_path);
     1370                }
     1371               
     1372                field_it = field_it->next;
     1373        }
    12151374
    12161375        return ret;
     
    12181377}
    12191378
    1220 /** Updates the output report buffer by translated given data
    1221  *
    1222  * @param parser
    1223  * @param path
    1224  * @param flags
    1225  * @param buffer
    1226  * @param size
    1227  * @param data
    1228  * @param data_size
    1229  * @return
    1230  */
    1231 int usb_hid_report_output_translate(usb_hid_report_parser_t *parser,
    1232                                     usb_hid_report_path_t *path, int flags,
    1233                                     uint8_t *buffer, size_t size,
    1234                                     int32_t *data, size_t data_size)
    1235 {
    1236         usb_hid_report_item_t *report_item;
     1379/** Makes the output report buffer for data given in the report structure
     1380 *
     1381 * @param parser Opaque report parser structure
     1382 * @param path Usage path specifing which parts of output will be set
     1383 * @param flags Usage path structure comparison flags
     1384 * @param buffer Output buffer
     1385 * @param size Size of output buffer
     1386 * @return Error code
     1387 */
     1388int usb_hid_report_output_translate(usb_hid_report_t *report, uint8_t report_id,
     1389                                    uint8_t *buffer, size_t size)
     1390{
    12371391        link_t *item;   
    1238         size_t idx=0;
    1239         int i=0;
    12401392        int32_t value=0;
    12411393        int offset;
    12421394        int length;
    12431395        int32_t tmp_value;
    1244         size_t offset_prefix = 0;
    1245        
    1246         if(parser == NULL) {
     1396       
     1397        if(report == NULL) {
    12471398                return EINVAL;
    12481399        }
    12491400
    1250         if(parser->use_report_id != 0) {
    1251                 buffer[0] = path->report_id;
    1252                 offset_prefix = 8;
     1401        if(report->use_report_ids != 0) {
     1402                buffer[0] = report_id;         
    12531403        }
    12541404
    12551405        usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
    1256         usb_log_debug("OUTPUT DATA[0]: %d, DATA[1]: %d, DATA[2]: %d\n", data[0], data[1], data[2]);
    1257 
    1258         item = parser->output.next;     
    1259         while(item != &parser->output) {
    1260                 report_item = list_get_instance(item, usb_hid_report_item_t, link);
    1261 
    1262                 for(i=0; i<report_item->count; i++) {
    1263 
    1264                         if(idx >= data_size) {
    1265                                 break;
    1266                         }
    1267 
    1268                         if((USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0) ||
    1269                                 ((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0))) {
     1406       
     1407        usb_hid_report_description_t *report_des;
     1408        report_des = usb_hid_report_find_description (report, report_id, USB_HID_REPORT_TYPE_OUTPUT);
     1409        if(report_des == NULL){
     1410                return EINVAL;
     1411        }
     1412
     1413        usb_hid_report_field_t *report_item;   
     1414        item = report_des->report_items.next;   
     1415        while(item != &report_des->report_items) {
     1416                report_item = list_get_instance(item, usb_hid_report_field_t, link);
     1417
     1418                        if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0) {
    12701419                                       
    1271 //                              // variable item
    1272                                 value = usb_hid_translate_data_reverse(report_item, data[idx++]);
    1273                                 offset = report_item->offset + (i * report_item->size) + offset_prefix;
     1420                                // array
     1421                                value = usb_hid_translate_data_reverse(report_item, report_item->value);
     1422                                offset = report_item->offset;
    12741423                                length = report_item->size;
    12751424                        }
    12761425                        else {
    1277                                 //bitmap
    1278                                 value += usb_hid_translate_data_reverse(report_item, data[idx++]);
    1279                                 offset = report_item->offset + offset_prefix;
    1280                                 length = report_item->size * report_item->count;
     1426                                // variable item
     1427                                value  = usb_hid_translate_data_reverse(report_item, report_item->value);
     1428                                offset = report_item->offset;
     1429                                length = report_item->size;
    12811430                        }
    12821431
     
    12971446                        }
    12981447                        else {
    1299                                 // je to ve dvou!! FIXME: melo by to umet delsi jak 2
    1300 
    1301                                 // konec prvniho -- dolni x bitu
    1302                                 tmp_value = value;
    1303                                 tmp_value = tmp_value & ((1 << (8-(offset%8)))-1);                             
    1304                                 tmp_value = tmp_value << (offset%8);
    1305 
     1448                                int i = 0;
    13061449                                uint8_t mask = 0;
    1307                                 mask = ~(((1 << (8-(offset%8)))-1) << (offset%8));
    1308                                 buffer[offset/8] = (buffer[offset/8] & mask) | tmp_value;
    1309 
    1310                                 // a ted druhej -- hornich length-x bitu
    1311                                 value = value >> (8 - (offset % 8));
    1312                                 value = value & ((1 << (length - (8 - (offset % 8)))) - 1);
     1450                                for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
     1451                                        if(i == (offset/8)) {
     1452                                                tmp_value = value;
     1453                                                tmp_value = tmp_value & ((1 << (8-(offset%8)))-1);                             
     1454                                                tmp_value = tmp_value << (offset%8);
     1455       
     1456                                                mask = ~(((1 << (8-(offset%8)))-1) << (offset%8));
     1457                                                buffer[i] = (buffer[i] & mask) | tmp_value;                     
     1458                                        }
     1459                                        else if (i == ((offset + length -1)/8)) {
     1460                                               
     1461                                                value = value >> (length - ((offset + length) % 8));
     1462                                                value = value & ((1 << (length - ((offset + length) % 8))) - 1);
    13131463                               
    1314                                 mask = ((1 << (length - (8 - (offset % 8)))) - 1);
    1315                                 buffer[(offset+length-1)/8] = (buffer[(offset+length-1)/8] & mask) | value;
    1316                         }
    1317 
    1318                 }
    1319 
     1464                                                mask = (1 << (length - ((offset + length) % 8))) - 1;
     1465                                                buffer[i] = (buffer[i] & mask) | value;
     1466                                        }
     1467                                        else {
     1468                                                buffer[i] = value & (0xFF << i);
     1469                                        }
     1470                                }
     1471                        }
     1472
     1473
     1474                // reset value
     1475                report_item->value = 0;
     1476               
    13201477                item = item->next;
    13211478        }
    1322 
     1479       
    13231480        usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
    13241481
     
    13271484
    13281485/**
    1329  *
    1330  * @param item
    1331  * @param value
    1332  * @return
    1333  */
    1334 int32_t usb_hid_translate_data_reverse(usb_hid_report_item_t *item, int value)
     1486 * Translate given data for putting them into the outoput report
     1487 * @param item Report item structure
     1488 * @param value Value to translate
     1489 * @return ranslated value
     1490 */
     1491uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, int value)
    13351492{
    13361493        int ret=0;
     
    13411498        }
    13421499
     1500        if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
     1501                item->physical_minimum = item->logical_minimum;
     1502                item->physical_maximum = item->logical_maximum;                 
     1503        }
     1504       
     1505
    13431506        if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0)) {
    13441507
    13451508                // variable item
    1346                 if((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
    1347                         item->physical_minimum = item->logical_minimum;
    1348                         item->physical_maximum = item->logical_maximum;
    1349                 }
    1350 
    13511509                if(item->physical_maximum == item->physical_minimum){
    13521510                    resolution = 1;
     
    13721530
    13731531
    1374         return ret;
    1375 }
    1376 
    1377 
     1532        return (uint32_t)ret;
     1533}
     1534
     1535/**
     1536 * Sets report id in usage path structure
     1537 *
     1538 * @param path Usage path structure
     1539 * @param report_id Report id to set
     1540 * @return Error code
     1541 */
    13781542int usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, uint8_t report_id)
    13791543{
     
    13831547
    13841548        path->report_id = report_id;
     1549        return EOK;
     1550}
     1551
     1552/**
     1553 *
     1554 *
     1555 *
     1556 *
     1557 *
     1558 */
     1559int usb_hid_report_output_set_data(usb_hid_report_t *report,
     1560                                   usb_hid_report_path_t *path, int flags,
     1561                                  int *data, size_t data_size)
     1562{
     1563        size_t data_idx = 0;
     1564        if(report == NULL){
     1565                return EINVAL;
     1566        }
     1567
     1568        usb_hid_report_description_t *report_des;
     1569        report_des = usb_hid_report_find_description (report, path->report_id,
     1570                                                      USB_HID_REPORT_TYPE_OUTPUT);
     1571        if(report_des == NULL){
     1572                return EINVAL;
     1573        }
     1574
     1575        usb_hid_report_field_t *field;
     1576        link_t *field_it = report_des->report_items.next;       
     1577        while(field_it != &report_des->report_items){
     1578
     1579                field = list_get_instance(field_it, usb_hid_report_field_t, link);             
     1580                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
     1581                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     1582                        if(usb_hid_report_compare_usage_path (field->collection_path, path,
     1583                                                      flags) == EOK) {
     1584                                if(data_idx < data_size) {
     1585                                        if((data[data_idx] >= field->physical_minimum) && (data[data_idx] >= field->physical_minimum)) {
     1586                                                field->value = data[data_idx];
     1587                                        }
     1588                                        else {
     1589                                                return ERANGE;
     1590                                        }
     1591
     1592                                        data_idx++;
     1593                                }
     1594                                else {
     1595                                        field->value = 0;
     1596                                }
     1597                        }
     1598                        usb_hid_report_remove_last_item (field->collection_path);
     1599                }
     1600               
     1601                field_it = field_it->next;
     1602        }
     1603
    13851604        return EOK;
    13861605}
     
    14001619}
    14011620
     1621
     1622usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report,
     1623                                                        usb_hid_report_field_t *field,
     1624                            usb_hid_report_path_t *path, int flags,
     1625                            usb_hid_report_type_t type)
     1626{
     1627        usb_hid_report_description_t *report_des = usb_hid_report_find_description (report, path->report_id, type);
     1628        link_t *field_it;
     1629       
     1630        if(report_des == NULL){
     1631                return NULL;
     1632        }
     1633
     1634        if(field == NULL){
     1635                // vezmu prvni co mathuje podle path!!
     1636                field_it = report_des->report_items.next;
     1637        }
     1638        else {
     1639                field_it = field->link.next;
     1640        }
     1641
     1642        while(field_it != &report_des->report_items) {
     1643                field = list_get_instance(field_it, usb_hid_report_field_t, link);
     1644
     1645                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
     1646                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     1647                        if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK){
     1648                                usb_hid_report_remove_last_item (field->collection_path);
     1649                                return field;
     1650                        }
     1651                        usb_hid_report_remove_last_item (field->collection_path);
     1652                }
     1653                field_it = field_it->next;
     1654        }
     1655
     1656        return NULL;
     1657}
     1658
     1659uint8_t usb_hid_report_get_report_id(usb_hid_report_t *report, uint8_t report_id, usb_hid_report_type_t type)
     1660{
     1661        if(report == NULL){
     1662                return 0;
     1663        }
     1664
     1665        usb_hid_report_description_t *report_des;
     1666        link_t *report_it;
     1667       
     1668        if(report_id == 0) {
     1669                report_it = usb_hid_report_find_description (report, report_id, type)->link.next;               
     1670        }
     1671        else {
     1672                report_it = report->reports.next;
     1673        }
     1674
     1675        while(report_it != &report->reports) {
     1676                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     1677                if(report_des->type == type){
     1678                        return report_des->report_id;
     1679                }
     1680        }
     1681
     1682        return 0;
     1683}
     1684
     1685
    14021686/**
    14031687 * @}
Note: See TracChangeset for help on using the changeset viewer.