Ignore:
File:
1 edited

Legend:

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

    r2571089 r28d7185  
    11/*
    2  * Copyright (c) 2011 Matej Klonfar
     2 * Copyright (c) 2010 Vojtech Horky
    33 * All rights reserved.
    44 *
     
    4141#include <assert.h>
    4242
    43 
     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 */
     46#define USB_HID_NEW_REPORT_ITEM 1
     47
     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*/
     56#define USB_HID_UNKNOWN_TAG             -99
     57
     58/*
     59 * Private descriptor parser functions
     60 */
     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);
     64int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
     65                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
     66int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
     67                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
     68int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
     69                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
     70int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
     71                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path);
     72
     73void usb_hid_print_usage_path(usb_hid_report_path_t *path);
     74void usb_hid_descriptor_print_list(link_t *head);
     75void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item);
     76void usb_hid_free_report_list(link_t *head);
     77usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item);
    4478/*
    4579 * Data translation private functions
     
    5185int usb_pow(int a, int b);
    5286
    53 
     87#define USB_HID_UINT32_TO_INT32(x, size)        ((((x) & (1 << ((size) - 1))) != 0) ? -(~(x - 1) & ((1 << size) - 1)) : (x)) //(-(~((x) - 1)))
     88#define USB_HID_INT32_TO_UINT32(x, size)        (((x) < 0 ) ? ((1 << (size)) + (x)) : (x))
    5489// TODO: tohle ma bejt asi jinde
    5590int usb_pow(int a, int b)
     
    68103}
    69104
    70 
    71 
     105/**
     106 * Initialize the report descriptor parser structure
     107 *
     108 * @param parser Report descriptor parser structure
     109 * @return Error code
     110 */
     111int usb_hid_report_init(usb_hid_report_t *report)
     112{
     113        if(report == NULL) {
     114                return EINVAL;
     115        }
     116
     117        memset(report, 0, sizeof(usb_hid_report_t));
     118        list_initialize(&report->reports);
     119        list_initialize(&report->collection_paths);
     120
     121        report->use_report_ids = 0;
     122    return EOK;   
     123}
     124
     125int usb_hid_report_append_fields(usb_hid_report_t *report, usb_hid_report_item_t *report_item)
     126{
     127        usb_hid_report_field_t *field;
     128        int i;
     129
     130
     131        /* find or append current collection path to the list */
     132        link_t *path_it = report->collection_paths.next;
     133        usb_hid_report_path_t *path = NULL;
     134        while(path_it != &report->collection_paths) {
     135                path = list_get_instance(path_it, usb_hid_report_path_t, link);
     136               
     137                if(usb_hid_report_compare_usage_path(path, report_item->usage_path, USB_HID_PATH_COMPARE_STRICT) == EOK){
     138                        break;
     139                }                       
     140                path_it = path_it->next;
     141        }
     142        if(path_it == &report->collection_paths) {
     143                path = usb_hid_report_path_clone(report_item->usage_path);                     
     144                list_append(&path->link, &report->collection_paths);                                   
     145                report->collection_paths_count++;
     146        }
     147
     148        for(i=0; i<report_item->usages_count; i++){
     149                usb_log_debug("usages (%d) - %x\n", i, report_item->usages[i]);
     150        }
     151
     152       
     153        for(i=0; i<report_item->count; i++){
     154
     155                field = malloc(sizeof(usb_hid_report_field_t));
     156                memset(field, 0, sizeof(usb_hid_report_field_t));
     157                list_initialize(&field->link);
     158
     159                /* fill the attributes */               
     160                field->collection_path = path;
     161                field->logical_minimum = report_item->logical_minimum;
     162                field->logical_maximum = report_item->logical_maximum;
     163                field->physical_minimum = report_item->physical_minimum;
     164                field->physical_maximum = report_item->physical_maximum;
     165
     166                field->usage_minimum = report_item->usage_minimum;
     167                field->usage_maximum = report_item->usage_maximum;
     168                if(report_item->extended_usage_page != 0){
     169                        field->usage_page = report_item->extended_usage_page;
     170                }
     171                else {
     172                        field->usage_page = report_item->usage_page;
     173                }
     174
     175                if(report_item->usages_count > 0 && ((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0))) {
     176                        uint32_t usage;
     177                        if(report_item->type != USB_HID_REPORT_TYPE_INPUT) {
     178                                if(i < report_item->usages_count){
     179                                        usage = report_item->usages[i];
     180                                }
     181                                else {
     182                                        usage = report_item->usages[report_item->usages_count - 1];
     183                                }
     184                        }
     185                        else {
     186                                if((report_item->count - i - 1) < report_item->usages_count){
     187                                        usage = report_item->usages[(report_item->count - i - 1)];
     188                                }
     189                                else {
     190                                        usage = report_item->usages[report_item->usages_count - 1];
     191                                }
     192                        }
     193
     194                                               
     195                        if((usage & 0xFFFF0000) != 0){
     196                                field->usage_page = (usage >> 16);                                     
     197                                field->usage = (usage & 0xFFFF);
     198                        }
     199                        else {
     200                                field->usage = usage;
     201                        }
     202
     203                       
     204                }       
     205
     206                if((USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) != 0) && (!((report_item->usage_minimum == 0) && (report_item->usage_maximum == 0)))) {
     207                        if(report_item->type == USB_HID_REPORT_TYPE_INPUT) {
     208                                field->usage = report_item->usage_maximum - i;
     209                        }
     210                        else {
     211                                field->usage = report_item->usage_minimum + i;                                 
     212                        }
     213
     214                }
     215               
     216                field->size = report_item->size;
     217                field->offset = report_item->offset + (i * report_item->size);
     218                if(report_item->id != 0) {
     219                        field->offset += 8;
     220                        report->use_report_ids = 1;
     221                }
     222                field->item_flags = report_item->item_flags;
     223
     224                /* find the right report list*/
     225                usb_hid_report_description_t *report_des;
     226                report_des = usb_hid_report_find_description(report, report_item->id, report_item->type);
     227                if(report_des == NULL){
     228                        report_des = malloc(sizeof(usb_hid_report_description_t));
     229                        memset(report_des, 0, sizeof(usb_hid_report_description_t));
     230
     231                        report_des->type = report_item->type;
     232                        report_des->report_id = report_item->id;
     233                        list_initialize (&report_des->link);
     234                        list_initialize (&report_des->report_items);
     235
     236                        list_append(&report_des->link, &report->reports);
     237                        report->report_count++;
     238                }
     239
     240                /* append this field to the end of founded report list */
     241                list_append (&field->link, &report_des->report_items);
     242               
     243                /* update the sizes */
     244                report_des->bit_length += field->size;
     245                report_des->item_length++;
     246
     247        }
     248
     249
     250        return EOK;
     251}
     252
     253usb_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)
     254{
     255        link_t *report_it = report->reports.next;
     256        usb_hid_report_description_t *report_des = NULL;
     257       
     258        while(report_it != &report->reports) {
     259                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     260
     261                if((report_des->report_id == report_id) && (report_des->type == type)){
     262                        return report_des;
     263                }
     264               
     265                report_it = report_it->next;
     266        }
     267
     268        return NULL;
     269}
     270
     271/** Parse HID report descriptor.
     272 *
     273 * @param parser Opaque HID report parser structure.
     274 * @param data Data describing the report.
     275 * @return Error code.
     276 */
     277int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
     278    const uint8_t *data, size_t size)
     279{
     280        size_t i=0;
     281        uint8_t tag=0;
     282        uint8_t item_size=0;
     283        int class=0;
     284        int ret;
     285        usb_hid_report_item_t *report_item=0;
     286        usb_hid_report_item_t *new_report_item;
     287        usb_hid_report_path_t *usage_path;
     288
     289        size_t offset_input=0;
     290        size_t offset_output=0;
     291        size_t offset_feature=0;
     292
     293        link_t stack;
     294        list_initialize(&stack);       
     295
     296        /* parser structure initialization*/
     297        if(usb_hid_report_init(report) != EOK) {
     298                return EINVAL;
     299        }
     300       
     301        /*report item initialization*/
     302        if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
     303                return ENOMEM;
     304        }
     305        memset(report_item, 0, sizeof(usb_hid_report_item_t));
     306        list_initialize(&(report_item->link)); 
     307
     308        /* usage path context initialization */
     309        if(!(usage_path=usb_hid_report_path())){
     310                return ENOMEM;
     311        }
     312       
     313        while(i<size){ 
     314                if(!USB_HID_ITEM_IS_LONG(data[i])){
     315
     316                        if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
     317                                return EINVAL;
     318                        }
     319                       
     320                        tag = USB_HID_ITEM_TAG(data[i]);
     321                        item_size = USB_HID_ITEM_SIZE(data[i]);
     322                        class = USB_HID_ITEM_TAG_CLASS(data[i]);
     323                       
     324                        ret = usb_hid_report_parse_tag(tag,class,data+i+1,
     325                                                       item_size,report_item, usage_path);
     326                        switch(ret){
     327                                case USB_HID_NEW_REPORT_ITEM:
     328                                        // store report item to report and create the new one
     329                                        // store current collection path
     330                                        report_item->usage_path = usage_path;
     331                                       
     332                                        usb_hid_report_path_set_report_id(report_item->usage_path, report_item->id);   
     333                                        if(report_item->id != 0){
     334                                                report->use_report_ids = 1;
     335                                        }
     336                                       
     337                                        switch(tag) {
     338                                                case USB_HID_REPORT_TAG_INPUT:
     339                                                        report_item->type = USB_HID_REPORT_TYPE_INPUT;
     340                                                        report_item->offset = offset_input;
     341                                                        offset_input += report_item->count * report_item->size;
     342                                                        break;
     343                                                case USB_HID_REPORT_TAG_OUTPUT:
     344                                                        report_item->type = USB_HID_REPORT_TYPE_OUTPUT;
     345                                                        report_item->offset = offset_output;
     346                                                        offset_output += report_item->count * report_item->size;
     347
     348                                                        break;
     349                                                case USB_HID_REPORT_TAG_FEATURE:
     350                                                        report_item->type = USB_HID_REPORT_TYPE_FEATURE;
     351                                                        report_item->offset = offset_feature;
     352                                                        offset_feature += report_item->count * report_item->size;
     353                                                        break;
     354                                                default:
     355                                                    usb_log_debug("\tjump over - tag %X\n", tag);
     356                                                    break;
     357                                        }
     358                                       
     359                                        /*
     360                                         * append new fields to the report
     361                                         * structure                                     
     362                                         */
     363                                        usb_hid_report_append_fields(report, report_item);
     364
     365                                        /* reset local items */
     366                                        usb_hid_report_reset_local_items (report_item);
     367
     368                                        break;
     369
     370                                case USB_HID_RESET_OFFSET:
     371                                        offset_input = 0;
     372                                        offset_output = 0;
     373                                        offset_feature = 0;
     374                                        usb_hid_report_path_set_report_id (usage_path, report_item->id);
     375                                        break;
     376
     377                                case USB_HID_REPORT_TAG_PUSH:
     378                                        // push current state to stack
     379                                        new_report_item = usb_hid_report_item_clone(report_item);
     380                                        usb_hid_report_path_t *tmp_path = usb_hid_report_path_clone(usage_path);
     381                                        new_report_item->usage_path = tmp_path;
     382
     383                                        list_prepend (&new_report_item->link, &stack);
     384                                        break;
     385                                case USB_HID_REPORT_TAG_POP:
     386                                        // restore current state from stack
     387                                        if(list_empty (&stack)) {
     388                                                return EINVAL;
     389                                        }
     390                                        free(report_item);
     391                                               
     392                                        report_item = list_get_instance(stack.next, usb_hid_report_item_t, link);
     393                                       
     394                                        usb_hid_report_usage_path_t *tmp_usage_path;
     395                                        tmp_usage_path = list_get_instance(report_item->usage_path->link.prev, usb_hid_report_usage_path_t, link);
     396                                       
     397                                        usb_hid_report_set_last_item(usage_path, tmp_usage_path->usage_page, tmp_usage_path->usage);
     398
     399                                        usb_hid_report_path_free(report_item->usage_path);
     400                                        list_initialize(&report_item->usage_path->link);
     401                                        list_remove (stack.next);
     402                                       
     403                                        break;
     404                                       
     405                                default:
     406                                        // nothing special to do                                       
     407                                        break;
     408                        }
     409
     410                        /* jump over the processed block */
     411                        i += 1 + USB_HID_ITEM_SIZE(data[i]);
     412                }
     413                else{
     414                        // TBD
     415                        i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
     416                }
     417               
     418
     419        }
     420       
     421        return EOK;
     422}
     423
     424
     425/**
     426 * Parse one tag of the report descriptor
     427 *
     428 * @param Tag to parse
     429 * @param Report descriptor buffer
     430 * @param Size of data belongs to this tag
     431 * @param Current report item structe
     432 * @return Code of action to be done next
     433 */
     434int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
     435                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
     436{       
     437        int ret;
     438       
     439        switch(class){
     440                case USB_HID_TAG_CLASS_MAIN:
     441
     442                        if((ret=usb_hid_report_parse_main_tag(tag,data,item_size,report_item, usage_path)) == EOK) {
     443                                return USB_HID_NEW_REPORT_ITEM;
     444                        }
     445                        else {
     446                                /*TODO process the error */
     447                                return ret;
     448                           }
     449                        break;
     450
     451                case USB_HID_TAG_CLASS_GLOBAL: 
     452                        return usb_hid_report_parse_global_tag(tag,data,item_size,report_item, usage_path);
     453                        break;
     454
     455                case USB_HID_TAG_CLASS_LOCAL:                   
     456                        return usb_hid_report_parse_local_tag(tag,data,item_size,report_item, usage_path);
     457                        break;
     458                default:
     459                        return USB_HID_NO_ACTION;
     460        }
     461}
     462
     463/**
     464 * Parse main tags of report descriptor
     465 *
     466 * @param Tag identifier
     467 * @param Data buffer
     468 * @param Length of data buffer
     469 * @param Current state table
     470 * @return Error code
     471 */
     472
     473int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
     474                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
     475{               
     476        switch(tag)
     477        {
     478                case USB_HID_REPORT_TAG_INPUT:
     479                case USB_HID_REPORT_TAG_OUTPUT:
     480                case USB_HID_REPORT_TAG_FEATURE:
     481                        report_item->item_flags = *data;                       
     482                        return EOK;                     
     483                        break;
     484                       
     485                case USB_HID_REPORT_TAG_COLLECTION:
     486                        // TODO usage_path->flags = *data;
     487                        usb_hid_report_path_append_item(usage_path, report_item->usage_page, report_item->usages[report_item->usages_count-1]);                                         
     488                        usb_hid_report_reset_local_items (report_item);
     489                        return USB_HID_NO_ACTION;
     490                        break;
     491                       
     492                case USB_HID_REPORT_TAG_END_COLLECTION:
     493                        usb_hid_report_remove_last_item(usage_path);
     494                        return USB_HID_NO_ACTION;
     495                        break;
     496                default:
     497                        return USB_HID_NO_ACTION;
     498        }
     499
     500        return EOK;
     501}
     502
     503/**
     504 * Parse global tags of report descriptor
     505 *
     506 * @param Tag identifier
     507 * @param Data buffer
     508 * @param Length of data buffer
     509 * @param Current state table
     510 * @return Error code
     511 */
     512int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
     513                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
     514{
     515        // TODO take care about the bit length of data
     516        switch(tag)
     517        {
     518                case USB_HID_REPORT_TAG_USAGE_PAGE:
     519                        report_item->usage_page = usb_hid_report_tag_data_uint32(data, item_size);
     520                        break;
     521                case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
     522                        report_item->logical_minimum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
     523                        break;
     524                case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
     525                        report_item->logical_maximum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
     526                        break;
     527                case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
     528                        report_item->physical_minimum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
     529                        break;                 
     530                case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
     531                        report_item->physical_maximum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
     532
     533                        break;
     534                case USB_HID_REPORT_TAG_UNIT_EXPONENT:
     535                        report_item->unit_exponent = usb_hid_report_tag_data_uint32(data,item_size);
     536                        break;
     537                case USB_HID_REPORT_TAG_UNIT:
     538                        report_item->unit = usb_hid_report_tag_data_uint32(data,item_size);
     539                        break;
     540                case USB_HID_REPORT_TAG_REPORT_SIZE:
     541                        report_item->size = usb_hid_report_tag_data_uint32(data,item_size);
     542                        break;
     543                case USB_HID_REPORT_TAG_REPORT_COUNT:
     544                        report_item->count = usb_hid_report_tag_data_uint32(data,item_size);
     545                        break;
     546                case USB_HID_REPORT_TAG_REPORT_ID:
     547                        report_item->id = usb_hid_report_tag_data_uint32(data,item_size);
     548                        return USB_HID_RESET_OFFSET;
     549                        break;
     550                case USB_HID_REPORT_TAG_PUSH:
     551                case USB_HID_REPORT_TAG_POP:
     552                        /*
     553                         * stack operations are done in top level parsing
     554                         * function
     555                         */
     556                        return tag;
     557                        break;
     558                       
     559                default:
     560                        return USB_HID_NO_ACTION;
     561        }
     562
     563        return EOK;
     564}
     565
     566/**
     567 * Parse local tags of report descriptor
     568 *
     569 * @param Tag identifier
     570 * @param Data buffer
     571 * @param Length of data buffer
     572 * @param Current state table
     573 * @return Error code
     574 */
     575int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
     576                             usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
     577{
     578        switch(tag)
     579        {
     580                case USB_HID_REPORT_TAG_USAGE:
     581                        report_item->usages[report_item->usages_count] = usb_hid_report_tag_data_uint32(data,item_size);
     582                        report_item->usages_count++;
     583                        break;
     584                case USB_HID_REPORT_TAG_USAGE_MINIMUM:
     585                        if (item_size == 3) {
     586                                // usage extended usages
     587                                report_item->extended_usage_page = (usb_hid_report_tag_data_uint32(data,item_size) & 0xFF00) >> 16;
     588                                report_item->usage_minimum = usb_hid_report_tag_data_uint32(data,item_size) & 0xFF;
     589                        }
     590                        else {
     591                                report_item->usage_minimum = usb_hid_report_tag_data_uint32(data,item_size);
     592                        }
     593                        break;
     594                case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
     595                        if (item_size == 3) {
     596                                // usage extended usages
     597                                report_item->extended_usage_page = (usb_hid_report_tag_data_uint32(data,item_size) & 0xFF00) >> 16;
     598                                report_item->usage_maximum = usb_hid_report_tag_data_uint32(data,item_size) & 0xFF;
     599                        }
     600                        else {
     601                                report_item->usage_maximum = usb_hid_report_tag_data_uint32(data,item_size);
     602                        }
     603                        break;
     604                case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
     605                        report_item->designator_index = usb_hid_report_tag_data_uint32(data,item_size);
     606                        break;
     607                case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
     608                        report_item->designator_minimum = usb_hid_report_tag_data_uint32(data,item_size);
     609                        break;
     610                case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
     611                        report_item->designator_maximum = usb_hid_report_tag_data_uint32(data,item_size);
     612                        break;
     613                case USB_HID_REPORT_TAG_STRING_INDEX:
     614                        report_item->string_index = usb_hid_report_tag_data_uint32(data,item_size);
     615                        break;
     616                case USB_HID_REPORT_TAG_STRING_MINIMUM:
     617                        report_item->string_minimum = usb_hid_report_tag_data_uint32(data,item_size);
     618                        break;
     619                case USB_HID_REPORT_TAG_STRING_MAXIMUM:
     620                        report_item->string_maximum = usb_hid_report_tag_data_uint32(data,item_size);
     621                        break;                 
     622                case USB_HID_REPORT_TAG_DELIMITER:
     623                        //report_item->delimiter = usb_hid_report_tag_data_uint32(data,item_size);
     624                        //TODO:
     625                        //      DELIMITER STUFF
     626                        break;
     627               
     628                default:
     629                        return USB_HID_NO_ACTION;
     630        }
     631       
     632        return EOK;
     633}
     634
     635/**
     636 * Converts raw data to uint32 (thats the maximum length of short item data)
     637 *
     638 * @param Data buffer
     639 * @param Size of buffer
     640 * @return Converted int32 number
     641 */
     642uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
     643{
     644        unsigned int i;
     645        uint32_t result;
     646
     647        result = 0;
     648        for(i=0; i<size; i++) {
     649                result = (result | (data[i]) << (i*8));
     650        }
     651
     652        return result;
     653}
     654
     655/**
     656 * Prints content of given list of report items.
     657 *
     658 * @param List of report items (usb_hid_report_item_t)
     659 * @return void
     660 */
     661void usb_hid_descriptor_print_list(link_t *head)
     662{
     663        usb_hid_report_field_t *report_item;
     664        link_t *item;
     665
     666
     667        if(head == NULL || list_empty(head)) {
     668            usb_log_debug("\tempty\n");
     669            return;
     670        }
     671       
     672        for(item = head->next; item != head; item = item->next) {
     673               
     674                report_item = list_get_instance(item, usb_hid_report_field_t, link);
     675
     676                usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
     677                usb_log_debug("\t\tSIZE: %X\n", report_item->size);                             
     678                usb_log_debug("\t\tLOGMIN: %d\n", report_item->logical_minimum);
     679                usb_log_debug("\t\tLOGMAX: %d\n", report_item->logical_maximum);               
     680                usb_log_debug("\t\tPHYMIN: %d\n", report_item->physical_minimum);               
     681                usb_log_debug("\t\tPHYMAX: %d\n", report_item->physical_maximum);                               
     682                usb_log_debug("\t\ttUSAGEMIN: %X\n", report_item->usage_minimum);
     683                usb_log_debug("\t\tUSAGEMAX: %X\n", report_item->usage_maximum);
     684
     685                usb_log_debug("\t\tVALUE: %X\n", report_item->value);
     686                usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
     687                usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
     688                                               
     689//              usb_log_debug("\n");           
     690
     691        }
     692
     693
     694}
     695/**
     696 * Prints content of given report descriptor in human readable format.
     697 *
     698 * @param parser Parsed descriptor to print
     699 * @return void
     700 */
     701void usb_hid_descriptor_print(usb_hid_report_t *report)
     702{
     703        if(report == NULL) {
     704                return;
     705        }
     706
     707        link_t *report_it = report->reports.next;
     708        usb_hid_report_description_t *report_des;
     709
     710        while(report_it != &report->reports) {
     711                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     712                usb_log_debug("Report ID: %d\n", report_des->report_id);
     713                usb_log_debug("\tType: %d\n", report_des->type);
     714                usb_log_debug("\tLength: %d\n", report_des->bit_length);               
     715                usb_log_debug("\tItems: %d\n", report_des->item_length);               
     716
     717                usb_hid_descriptor_print_list(&report_des->report_items);
     718
     719
     720                link_t *path_it = report->collection_paths.next;
     721                while(path_it != &report->collection_paths) {
     722                        usb_hid_print_usage_path (list_get_instance(path_it, usb_hid_report_path_t, link));
     723                        path_it = path_it->next;
     724                }
     725               
     726                report_it = report_it->next;
     727        }
     728}
     729
     730/**
     731 * Releases whole linked list of report items
     732 *
     733 * @param head Head of list of report descriptor items (usb_hid_report_item_t)
     734 * @return void
     735 */
     736void usb_hid_free_report_list(link_t *head)
     737{
     738        return;
     739       
     740        usb_hid_report_item_t *report_item;
     741        link_t *next;
     742       
     743        if(head == NULL || list_empty(head)) {         
     744            return;
     745        }
     746       
     747        next = head->next;
     748        while(next != head) {
     749       
     750            report_item = list_get_instance(next, usb_hid_report_item_t, link);
     751
     752                while(!list_empty(&report_item->usage_path->link)) {
     753                        usb_hid_report_remove_last_item(report_item->usage_path);
     754                }
     755
     756               
     757            next = next->next;
     758           
     759            free(report_item);
     760        }
     761       
     762        return;
     763       
     764}
     765
     766/** Frees the HID report descriptor parser structure
     767 *
     768 * @param parser Opaque HID report parser structure
     769 * @return void
     770 */
     771void usb_hid_free_report(usb_hid_report_t *report)
     772{
     773        if(report == NULL){
     774                return;
     775        }
     776
     777        // free collection paths
     778        usb_hid_report_path_t *path;
     779        while(!list_empty(&report->collection_paths)) {
     780                path = list_get_instance(report->collection_paths.next, usb_hid_report_path_t, link);
     781                usb_hid_report_path_free(path);         
     782        }
     783       
     784        // free report items
     785        usb_hid_report_description_t *report_des;
     786        usb_hid_report_field_t *field;
     787        while(!list_empty(&report->reports)) {
     788                report_des = list_get_instance(report->reports.next, usb_hid_report_description_t, link);
     789                list_remove(&report_des->link);
     790               
     791                while(!list_empty(&report_des->report_items)) {
     792                        field = list_get_instance(report_des->report_items.next, usb_hid_report_field_t, link);
     793                        list_remove(&field->link);
     794
     795                        free(field);
     796                }
     797               
     798                free(report_des);
     799        }
     800       
     801        return;
     802}
    72803
    73804/** Parse and act upon a HID report.
     
    249980        return ret;
    250981        }
     982
     983
     984/**
     985 * Appends one item (couple of usage_path and usage) into the usage path
     986 * structure
     987 *
     988 * @param usage_path Usage path structure
     989 * @param usage_page Usage page constant
     990 * @param usage Usage constant
     991 * @return Error code
     992 */
     993int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path,
     994                                    int32_t usage_page, int32_t usage)
     995{       
     996        usb_hid_report_usage_path_t *item;
     997
     998        if(!(item=malloc(sizeof(usb_hid_report_usage_path_t)))) {
     999                return ENOMEM;
     1000        }
     1001        list_initialize(&item->link);
     1002
     1003        item->usage = usage;
     1004        item->usage_page = usage_page;
     1005        item->flags = 0;
     1006       
     1007        list_append (&item->link, &usage_path->head);
     1008        usage_path->depth++;
     1009        return EOK;
     1010}
     1011
     1012/**
     1013 * Removes last item from the usage path structure
     1014 * @param usage_path
     1015 * @return void
     1016 */
     1017void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
     1018{
     1019        usb_hid_report_usage_path_t *item;
     1020       
     1021        if(!list_empty(&usage_path->head)){
     1022                item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);             
     1023                list_remove(usage_path->head.prev);
     1024                usage_path->depth--;
     1025                free(item);
     1026        }
     1027}
     1028
     1029/**
     1030 * Nulls last item of the usage path structure.
     1031 *
     1032 * @param usage_path
     1033 * @return void
     1034 */
     1035void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
     1036{
     1037        usb_hid_report_usage_path_t *item;
     1038       
     1039        if(!list_empty(&usage_path->head)){     
     1040                item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
     1041                memset(item, 0, sizeof(usb_hid_report_usage_path_t));
     1042        }
     1043}
     1044
     1045/**
     1046 * Modifies last item of usage path structure by given usage page or usage
     1047 *
     1048 * @param usage_path Opaque usage path structure
     1049 * @param tag Class of currently processed tag (Usage page tag falls into Global
     1050 * class but Usage tag into the Local)
     1051 * @param data Value of the processed tag
     1052 * @return void
     1053 */
     1054void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, int32_t tag, int32_t data)
     1055{
     1056        usb_hid_report_usage_path_t *item;
     1057       
     1058        if(!list_empty(&usage_path->head)){     
     1059                item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
     1060
     1061                switch(tag) {
     1062                        case USB_HID_TAG_CLASS_GLOBAL:
     1063                                item->usage_page = data;
     1064                                break;
     1065                        case USB_HID_TAG_CLASS_LOCAL:
     1066                                item->usage = data;
     1067                                break;
     1068                }
     1069        }
     1070       
     1071}
     1072
     1073
     1074void usb_hid_print_usage_path(usb_hid_report_path_t *path)
     1075{
     1076        usb_log_debug("USAGE_PATH FOR RId(%d):\n", path->report_id);
     1077        usb_log_debug("\tLENGTH: %d\n", path->depth);
     1078
     1079        link_t *item = path->head.next;
     1080        usb_hid_report_usage_path_t *path_item;
     1081        while(item != &path->head) {
     1082
     1083                path_item = list_get_instance(item, usb_hid_report_usage_path_t, link);
     1084                usb_log_debug("\tUSAGE_PAGE: %X\n", path_item->usage_page);
     1085                usb_log_debug("\tUSAGE: %X\n", path_item->usage);
     1086                usb_log_debug("\tFLAGS: %d\n", path_item->flags);               
     1087               
     1088                item = item->next;
     1089        }
     1090}
     1091
     1092/**
     1093 * Compares two usage paths structures
     1094 *
     1095 * If USB_HID_PATH_COMPARE_COLLECTION_ONLY flag is given, the last item in report_path structure is forgotten
     1096 *
     1097 * @param report_path usage path structure to compare
     1098 * @param path usage patrh structure to compare
     1099 * @param flags Flags determining the mode of comparison
     1100 * @return EOK if both paths are identical, non zero number otherwise
     1101 */
     1102int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path,
     1103                                      usb_hid_report_path_t *path,
     1104                                      int flags)
     1105{
     1106        usb_hid_report_usage_path_t *report_item;
     1107        usb_hid_report_usage_path_t *path_item;
     1108
     1109        link_t *report_link;
     1110        link_t *path_link;
     1111
     1112        int only_page;
     1113
     1114        if(report_path->report_id != path->report_id) {
     1115                return 1;
     1116        }
     1117
     1118        if(path->depth == 0){
     1119                return EOK;
     1120        }
     1121
     1122
     1123        if((only_page = flags & USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY) != 0){
     1124                flags -= USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY;
     1125        }
     1126       
     1127        switch(flags){
     1128                /* path must be completly identical */
     1129                case USB_HID_PATH_COMPARE_STRICT:
     1130                                if(report_path->depth != path->depth){
     1131                                        return 1;
     1132                                }
     1133
     1134                                report_link = report_path->head.next;
     1135                                path_link = path->head.next;
     1136                       
     1137                                while((report_link != &report_path->head) && (path_link != &path->head)) {
     1138                                        report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
     1139                                        path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);           
     1140
     1141                                        if((report_item->usage_page != path_item->usage_page) ||
     1142                                           ((only_page == 0) && (report_item->usage != path_item->usage))) {
     1143                                                   return 1;
     1144                                        } else {
     1145                                                report_link = report_link->next;
     1146                                                path_link = path_link->next;                   
     1147                                        }
     1148                       
     1149                                }
     1150
     1151                                if(((report_link == &report_path->head) && (path_link == &path->head)) ||
     1152                                   (((flags & USB_HID_PATH_COMPARE_COLLECTION_ONLY) != 0) && (path_link = &path->head) && (report_link == report_path->head.prev))) {
     1153                                        return EOK;
     1154                                }
     1155                                else {
     1156                                        return 1;
     1157                                }                                               
     1158                        break;
     1159
     1160                /* compare with only the end of path*/
     1161                case USB_HID_PATH_COMPARE_END:
     1162
     1163                                if((flags & USB_HID_PATH_COMPARE_COLLECTION_ONLY) != 0) {
     1164                                        report_link = report_path->head.prev->prev;
     1165                                }
     1166                                else {
     1167                                        report_link = report_path->head.prev;
     1168                                }
     1169                                path_link = path->head.prev;
     1170
     1171                                if(list_empty(&path->head)){
     1172                                        return EOK;
     1173                                }
     1174                       
     1175                                while((report_link != &report_path->head) && (path_link != &path->head)) {
     1176                                        report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
     1177                                        path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);           
     1178
     1179                                        if((report_item->usage_page != path_item->usage_page) ||
     1180                                           ((only_page == 0) && (report_item->usage != path_item->usage))) {
     1181                                                   return 1;
     1182                                        } else {
     1183                                                report_link = report_link->prev;
     1184                                                path_link = path_link->prev;                   
     1185                                        }
     1186                       
     1187                                }
     1188
     1189                                if(path_link == &path->head) {
     1190                                        return EOK;
     1191                                }
     1192                                else {
     1193                                        return 1;
     1194                                }                                               
     1195                       
     1196                        break;
     1197
     1198                default:
     1199                        return EINVAL;
     1200        }
     1201       
     1202       
     1203       
     1204       
     1205}
     1206
     1207/**
     1208 * Allocates and initializes new usage path structure.
     1209 *
     1210 * @return Initialized usage path structure
     1211 */
     1212usb_hid_report_path_t *usb_hid_report_path(void)
     1213{
     1214        usb_hid_report_path_t *path;
     1215        path = malloc(sizeof(usb_hid_report_path_t));
     1216        if(path == NULL){
     1217                return NULL;
     1218        }
     1219        else {
     1220                path->depth = 0;
     1221                path->report_id = 0;
     1222                list_initialize(&path->link);
     1223                list_initialize(&path->head);
     1224                return path;
     1225        }
     1226}
     1227
     1228/**
     1229 * Releases given usage path structure.
     1230 *
     1231 * @param path usage path structure to release
     1232 * @return void
     1233 */
     1234void usb_hid_report_path_free(usb_hid_report_path_t *path)
     1235{
     1236        while(!list_empty(&path->head)){
     1237                usb_hid_report_remove_last_item(path);
     1238        }
     1239
     1240        list_remove(&path->link);
     1241        free(path);
     1242}
     1243
     1244
     1245/**
     1246 * Clone content of given usage path to the new one
     1247 *
     1248 * @param usage_path Usage path structure to clone
     1249 * @return New copy of given usage path structure
     1250 */
     1251usb_hid_report_path_t *usb_hid_report_path_clone(usb_hid_report_path_t *usage_path)
     1252{
     1253        link_t *path_link;
     1254        usb_hid_report_usage_path_t *path_item;
     1255        usb_hid_report_usage_path_t *new_path_item;
     1256        usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
     1257
     1258        if(new_usage_path == NULL){
     1259                return NULL;
     1260        }
     1261
     1262        new_usage_path->report_id = usage_path->report_id;
     1263       
     1264        if(list_empty(&usage_path->head)){
     1265                return new_usage_path;
     1266        }
     1267
     1268        path_link = usage_path->head.next;
     1269        while(path_link != &usage_path->head) {
     1270                path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
     1271                new_path_item = malloc(sizeof(usb_hid_report_usage_path_t));
     1272                if(new_path_item == NULL) {
     1273                        return NULL;
     1274                }
     1275               
     1276                list_initialize (&new_path_item->link);         
     1277                new_path_item->usage_page = path_item->usage_page;
     1278                new_path_item->usage = path_item->usage;               
     1279                new_path_item->flags = path_item->flags;               
     1280               
     1281                list_append(&new_path_item->link, &new_usage_path->head);
     1282                new_usage_path->depth++;
     1283
     1284                path_link = path_link->next;
     1285        }
     1286
     1287        return new_usage_path;
     1288}
     1289
    2511290
    2521291/*** OUTPUT API **/
     
    5041543}
    5051544
     1545/**
     1546 * Sets report id in usage path structure
     1547 *
     1548 * @param path Usage path structure
     1549 * @param report_id Report id to set
     1550 * @return Error code
     1551 */
     1552int usb_hid_report_path_set_report_id(usb_hid_report_path_t *path, uint8_t report_id)
     1553{
     1554        if(path == NULL){
     1555                return EINVAL;
     1556        }
     1557
     1558        path->report_id = report_id;
     1559        return EOK;
     1560}
     1561
     1562/**
     1563 *
     1564 *
     1565 *
     1566 *
     1567 *
     1568 */
     1569int usb_hid_report_output_set_data(usb_hid_report_t *report,
     1570                                   usb_hid_report_path_t *path, int flags,
     1571                                  int *data, size_t data_size)
     1572{
     1573        size_t data_idx = 0;
     1574        if(report == NULL){
     1575                return EINVAL;
     1576        }
     1577
     1578        usb_hid_report_description_t *report_des;
     1579        report_des = usb_hid_report_find_description (report, path->report_id,
     1580                                                      USB_HID_REPORT_TYPE_OUTPUT);
     1581        if(report_des == NULL){
     1582                return EINVAL;
     1583        }
     1584
     1585        usb_hid_report_field_t *field;
     1586        link_t *field_it = report_des->report_items.next;       
     1587        while(field_it != &report_des->report_items){
     1588
     1589                field = list_get_instance(field_it, usb_hid_report_field_t, link);             
     1590                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
     1591                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     1592                        if(usb_hid_report_compare_usage_path (field->collection_path, path,
     1593                                                      flags) == EOK) {
     1594                                if(data_idx < data_size) {
     1595                                        if((data[data_idx] >= field->physical_minimum) && (data[data_idx] >= field->physical_minimum)) {
     1596                                                field->value = data[data_idx];
     1597                                        }
     1598                                        else {
     1599                                                return ERANGE;
     1600                                        }
     1601
     1602                                        data_idx++;
     1603                                }
     1604                                else {
     1605                                        field->value = 0;
     1606                                }
     1607                        }
     1608                        usb_hid_report_remove_last_item (field->collection_path);
     1609                }
     1610               
     1611                field_it = field_it->next;
     1612        }
     1613
     1614        return EOK;
     1615}
     1616
     1617
    5061618usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item)
    5071619{
Note: See TracChangeset for help on using the changeset viewer.