Ignore:
File:
1 edited

Legend:

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

    rd861c22 r160b75e  
    3131 */
    3232/** @file
    33  * USB HID report data parser implementation.
     33 * HID report descriptor and report data parser implementation.
    3434 */
    3535#include <usb/hid/hidparser.h>
     
    4141#include <assert.h>
    4242
    43 /*---------------------------------------------------------------------------*/
     43
    4444/*
    4545 * Data translation private functions
    4646 */
    4747uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
    48 
     48//inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
    4949int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data);
    50 
    51 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item,
    52         int32_t value);
    53 
     50uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, int32_t value);
    5451int usb_pow(int a, int b);
    5552
    56 /*---------------------------------------------------------------------------*/
    5753
    5854// TODO: tohle ma bejt asi jinde
     
    6056{
    6157        switch(b) {
    62         case 0:
    63                 return 1;
    64                 break;
    65         case 1:
    66                 return a;
    67                 break;
    68         default:
    69                 return a * usb_pow(a, b-1);
    70                 break;
    71         }
    72 }
    73 /*---------------------------------------------------------------------------*/
    74 
    75 /** Returns size of report of specified report id and type in items
    76  *
    77  * @param parser Opaque report parser structure
    78  * @param report_id
    79  * @param type
    80  * @return Number of items in specified report
    81  */
    82 size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id,
    83                            usb_hid_report_type_t type)
    84 {
    85         usb_hid_report_description_t *report_des;
    86 
    87         if(report == NULL) {
    88                 return 0;
    89         }
    90 
    91         report_des = usb_hid_report_find_description (report, report_id, type);
    92         if(report_des == NULL){
    93                 return 0;
    94         }
    95         else {
    96                 return report_des->item_length;
    97         }
    98 }
    99 
    100 /** Returns size of report of specified report id and type in bytes
    101  *
    102  * @param parser Opaque report parser structure
    103  * @param report_id
    104  * @param type
    105  * @return Number of items in specified report
    106  */
    107 size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id,
    108                            usb_hid_report_type_t type)
    109 {
    110         usb_hid_report_description_t *report_des;
    111 
    112         if(report == NULL) {
    113                 return 0;
    114         }
    115 
    116         report_des = usb_hid_report_find_description (report, report_id, type);
    117         if(report_des == NULL){
    118                 return 0;
    119         }
    120         else {
    121                 return ((report_des->bit_length + 7) / 8) ;
    122         }
    123 }
    124 /*---------------------------------------------------------------------------*/
     58                case 0:
     59                        return 1;
     60                        break;
     61                case 1:
     62                        return a;
     63                        break;
     64                default:
     65                        return a * usb_pow(a, b-1);
     66                        break;
     67        }
     68}
     69
     70
     71
    12572
    12673/** Parse and act upon a HID report.
     
    13279 * @return Error code.
    13380 */
    134 int usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data,
    135         size_t size, uint8_t *report_id)
     81int usb_hid_parse_report(const usb_hid_report_t *report,
     82    const uint8_t *data, size_t size, uint8_t *report_id)
    13683{
    13784        link_t *list_item;
     
    14087        usb_hid_report_description_t *report_des;
    14188        usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
    142        
     89
    14390        if(report == NULL) {
    14491                return EINVAL;
     
    154101
    155102        report_des = usb_hid_report_find_description(report, *report_id, type);
    156         if(report_des == NULL) {
    157                 return EINVAL;
    158         }
    159103
    160104        /* read data */
     
    162106        while(list_item != &(report_des->report_items)) {
    163107
    164                 item = list_get_instance(list_item, usb_hid_report_field_t,
    165                                 link);
     108                item = list_get_instance(list_item, usb_hid_report_field_t, link);
    166109
    167110                if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
     
    170113
    171114                                // array
    172                                 item->value =
    173                                         usb_hid_translate_data(item, data);
    174                
    175                                 item->usage = USB_HID_EXTENDED_USAGE(
    176                                     item->usages[item->value - item->physical_minimum]);
    177 
    178                                 item->usage_page = USB_HID_EXTENDED_USAGE_PAGE(
    179                                     item->usages[item->value - item->physical_minimum]);
    180 
    181                                 usb_hid_report_set_last_item (item->collection_path,
    182                                     USB_HID_TAG_CLASS_GLOBAL, item->usage_page);
    183 
    184                                 usb_hid_report_set_last_item (item->collection_path,
    185                                     USB_HID_TAG_CLASS_LOCAL, item->usage);
    186                                
     115                                item->value = usb_hid_translate_data(item, data);
     116                            item->usage = (item->value - item->physical_minimum) + item->usage_minimum;
    187117                        }
    188118                        else {
     
    193123                list_item = list_item->next;
    194124        }
    195        
     125           
    196126        return EOK;
    197127       
    198128}
    199129
    200 /*---------------------------------------------------------------------------*/
    201130/**
    202131 * Translate data from the report as specified in report descriptor item
     
    204133 * @param item Report descriptor item with definition of translation
    205134 * @param data Data to translate
     135 * @param j Index of processed field in report descriptor item
    206136 * @return Translated data
    207137 */
     
    272202        }
    273203
    274         return (int)(((value - item->logical_minimum) / resolution) +
    275                 item->physical_minimum);
    276        
    277 }
    278 
    279 /*---------------------------------------------------------------------------*/
    280 /* OUTPUT API */
     204        return (int)(((value - item->logical_minimum) / resolution) + item->physical_minimum);
     205       
     206}
     207
     208/**
     209 * Returns number of items in input report which are accessible by given usage path
     210 *
     211 * @param parser Opaque report descriptor structure
     212 * @param path Usage path specification
     213 * @param flags Usage path comparison flags
     214 * @return Number of items in input report
     215 */
     216size_t usb_hid_report_input_length(const usb_hid_report_t *report,
     217        usb_hid_report_path_t *path, int flags)
     218{       
     219       
     220        size_t ret = 0;
     221
     222        if(report == NULL) {
     223                return 0;
     224        }
     225
     226        usb_hid_report_description_t *report_des;
     227        report_des = usb_hid_report_find_description (report, path->report_id, USB_HID_REPORT_TYPE_INPUT);
     228        if(report_des == NULL) {
     229                return 0;
     230        }
     231
     232        link_t *field_it = report_des->report_items.next;
     233        usb_hid_report_field_t *field;
     234        while(field_it != &report_des->report_items) {
     235
     236                field = list_get_instance(field_it, usb_hid_report_field_t, link);
     237                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
     238                       
     239                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     240                        if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK) {
     241                                ret++;
     242                        }
     243                        usb_hid_report_remove_last_item (field->collection_path);
     244                }
     245               
     246                field_it = field_it->next;
     247        }
     248
     249        return ret;
     250        }
     251
     252/*** OUTPUT API **/
    281253
    282254/**
     
    288260 * @return Returns allocated output buffer for specified output
    289261 */
    290 uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size,
    291         uint8_t report_id)
     262uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, uint8_t report_id)
    292263{
    293264        if(report == NULL) {
     
    299270        usb_hid_report_description_t *report_des = NULL;
    300271        while(report_it != &report->reports) {
    301                 report_des = list_get_instance(report_it,
    302                         usb_hid_report_description_t, link);
    303                
    304                 if((report_des->report_id == report_id) &&
    305                         (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
     272                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
     273                if((report_des->report_id == report_id) && (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
    306274                        break;
    307275                }
     
    334302                free (output);
    335303        }
     304}
     305
     306/** Returns size of output for given usage path
     307 *
     308 * @param parser Opaque report parser structure
     309 * @param path Usage path specified which items will be thought for the output
     310 * @param flags Flags of usage path structure comparison
     311 * @return Number of items matching the given usage path
     312 */
     313size_t usb_hid_report_output_size(usb_hid_report_t *report,
     314                                  usb_hid_report_path_t *path, int flags)
     315{
     316        size_t ret = 0;
     317        usb_hid_report_description_t *report_des;
     318
     319        if(report == NULL) {
     320                return 0;
     321        }
     322
     323        report_des = usb_hid_report_find_description (report, path->report_id, USB_HID_REPORT_TYPE_OUTPUT);
     324        if(report_des == NULL){
     325                return 0;
     326        }
     327       
     328        link_t *field_it = report_des->report_items.next;
     329        usb_hid_report_field_t *field;
     330        while(field_it != &report_des->report_items) {
     331
     332                field = list_get_instance(field_it, usb_hid_report_field_t, link);
     333                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0){
     334                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     335                        if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK) {
     336                                ret++;
     337                        }
     338                        usb_hid_report_remove_last_item (field->collection_path);
     339                }
     340               
     341                field_it = field_it->next;
     342        }
     343
     344        return ret;
     345       
    336346}
    337347
     
    345355 * @return Error code
    346356 */
    347 int usb_hid_report_output_translate(usb_hid_report_t *report,
    348         uint8_t report_id, uint8_t *buffer, size_t size)
     357int usb_hid_report_output_translate(usb_hid_report_t *report, uint8_t report_id,
     358                                    uint8_t *buffer, size_t size)
    349359{
    350360        link_t *item;   
     
    362372        }
    363373
     374        usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
     375       
    364376        usb_hid_report_description_t *report_des;
    365         report_des = usb_hid_report_find_description (report, report_id,
    366                 USB_HID_REPORT_TYPE_OUTPUT);
    367        
     377        report_des = usb_hid_report_find_description (report, report_id, USB_HID_REPORT_TYPE_OUTPUT);
    368378        if(report_des == NULL){
    369379                return EINVAL;
     
    375385                report_item = list_get_instance(item, usb_hid_report_field_t, link);
    376386
    377                 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0) {
     387                        if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0) {
    378388                                       
    379                         // array
    380                         value = usb_hid_translate_data_reverse(report_item,
    381                                 report_item->value);
    382 
    383                         offset = report_item->offset;
    384                         length = report_item->size;
    385                 }
    386                 else {
    387                         // variable item
    388                         value  = usb_hid_translate_data_reverse(report_item,
    389                                 report_item->value);
    390 
    391                         offset = report_item->offset;
    392                         length = report_item->size;
    393                 }
    394 
    395                 usb_log_debug("\ttranslated value: %x\n", value);
    396 
    397                 if((offset/8) == ((offset+length-1)/8)) {
    398                         // je to v jednom bytu
    399                         if(((size_t)(offset/8) >= size) ||
    400                                 ((size_t)(offset+length-1)/8) >= size) {
    401                                 break; // TODO ErrorCode
    402                         }
    403                         size_t shift = 8 - offset%8 - length;
    404                         value = value << shift;                                                 
    405                         value = value & (((1 << length)-1) << shift);
     389                                // array
     390                                value = usb_hid_translate_data_reverse(report_item, report_item->value);
     391                                offset = report_item->offset;
     392                                length = report_item->size;
     393                        }
     394                        else {
     395                                // variable item
     396                                value  = usb_hid_translate_data_reverse(report_item, report_item->value);
     397                                offset = report_item->offset;
     398                                length = report_item->size;
     399                        }
     400
     401                        if((offset/8) == ((offset+length-1)/8)) {
     402                                // je to v jednom bytu
     403                                if(((size_t)(offset/8) >= size) || ((size_t)(offset+length-1)/8) >= size) {
     404                                        break; // TODO ErrorCode
     405                                }
     406
     407                                size_t shift = 8 - offset%8 - length;
     408
     409                                value = value << shift;                                                 
     410                                value = value & (((1 << length)-1) << shift);
    406411                               
    407                         uint8_t mask = 0;
    408                         mask = 0xff - (((1 << length) - 1) << shift);
    409                         buffer[offset/8] = (buffer[offset/8] & mask) | value;
    410                 }
    411                 else {
    412                         int i = 0;
    413                         uint8_t mask = 0;
    414                         for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
    415                                 if(i == (offset/8)) {
    416                                         tmp_value = value;
    417                                         tmp_value = tmp_value &
    418                                                 ((1 << (8-(offset%8)))-1);
    419 
    420                                         tmp_value = tmp_value << (offset%8);
    421        
    422                                         mask = ~(((1 << (8-(offset%8)))-1) <<
    423                                                         (offset%8));
    424 
    425                                         buffer[i] = (buffer[i] & mask) |
    426                                                 tmp_value;
     412                                uint8_t mask = 0;
     413                                mask = 0xff - (((1 << length) - 1) << shift);
     414                                buffer[offset/8] = (buffer[offset/8] & mask) | value;
     415                        }
     416                        else {
     417                                int i = 0;
     418                                uint8_t mask = 0;
     419                                for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
     420                                        if(i == (offset/8)) {
     421                                                tmp_value = value;
     422                                                tmp_value = tmp_value & ((1 << (8-(offset%8)))-1);                             
     423                                                tmp_value = tmp_value << (offset%8);
     424       
     425                                                mask = ~(((1 << (8-(offset%8)))-1) << (offset%8));
     426                                                buffer[i] = (buffer[i] & mask) | tmp_value;                     
     427                                        }
     428                                        else if (i == ((offset + length -1)/8)) {
     429                                               
     430                                                value = value >> (length - ((offset + length) % 8));
     431                                                value = value & ((1 << (length - ((offset + length) % 8))) - 1);
     432                               
     433                                                mask = (1 << (length - ((offset + length) % 8))) - 1;
     434                                                buffer[i] = (buffer[i] & mask) | value;
     435                                        }
     436                                        else {
     437                                                buffer[i] = value & (0xFF << i);
     438                                        }
    427439                                }
    428                                 else if (i == ((offset + length -1)/8)) {
    429                                        
    430                                         value = value >> (length -
    431                                                 ((offset + length) % 8));
    432 
    433                                         value = value & ((1 << (length -
    434                                                 ((offset + length) % 8))) - 1);
    435                                
    436                                         mask = (1 << (length -
    437                                                 ((offset + length) % 8))) - 1;
    438 
    439                                         buffer[i] = (buffer[i] & mask) | value;
    440                                 }
    441                                 else {
    442                                         buffer[i] = value & (0xFF << i);
    443                                 }
    444                         }
    445                 }
     440                        }
     441
    446442
    447443                // reset value
     
    451447        }
    452448       
     449        usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
     450
    453451        return EOK;
    454452}
    455453
    456 /*---------------------------------------------------------------------------*/
    457454/**
    458455 * Translate given data for putting them into the outoput report
     
    461458 * @return ranslated value
    462459 */
    463 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item,
    464         int value)
     460uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, int value)
    465461{
    466462        int ret=0;
     
    476472        }
    477473       
    478         // variable item
    479         if(item->physical_maximum == item->physical_minimum){
    480             resolution = 1;
     474
     475        if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0)) {
     476
     477                // variable item
     478                if(item->physical_maximum == item->physical_minimum){
     479                    resolution = 1;
     480                }
     481                else {
     482                    resolution = (item->logical_maximum - item->logical_minimum) /
     483                        ((item->physical_maximum - item->physical_minimum) *
     484                        (usb_pow(10,(item->unit_exponent))));
     485                }
     486
     487                ret = ((value - item->physical_minimum) * resolution) + item->logical_minimum;
    481488        }
    482489        else {
    483             resolution = (item->logical_maximum - item->logical_minimum) /
    484                 ((item->physical_maximum - item->physical_minimum) *
    485                 (usb_pow(10,(item->unit_exponent))));
    486         }
    487 
    488         ret = ((value - item->physical_minimum) * resolution) +
    489                 item->logical_minimum;
    490 
    491         usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), \
    492                 ret(%x)\n", value, resolution, item->physical_minimum,
    493                 item->logical_minimum, ret);
    494        
     490                // bitmapa
     491                if(value == 0) {
     492                        ret = 0;
     493                }
     494                else {
     495                        size_t bitmap_idx = (value - item->usage_minimum);
     496                        ret = 1 << bitmap_idx;
     497                }
     498        }
     499
    495500        if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
    496501                return USB_HID_INT32_TO_UINT32(ret, item->size);
    497502        }
    498         return (int32_t)0 + ret;
    499 }
    500 
    501 /*---------------------------------------------------------------------------*/
    502 /**
    503  * Clones given state table
    504  *
    505  * @param item State table to clone
    506  * @return Pointer to the cloned item
    507  */
    508 usb_hid_report_item_t *usb_hid_report_item_clone(
    509         const usb_hid_report_item_t *item)
     503        return (int32_t)ret;
     504}
     505
     506usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item)
    510507{
    511508        usb_hid_report_item_t *new_report_item;
     
    520517}
    521518
    522 /*---------------------------------------------------------------------------*/
    523 /**
    524  * Function for sequence walking through the report. Returns next field in the
    525  * report or the first one when no field is given.
    526  *
    527  * @param report Searched report structure
    528  * @param field Current field. If NULL is given, the first one in the report
    529  * is returned. Otherwise the next one i nthe list is returned.
    530  * @param path Usage path specifying which fields wa are interested in.
    531  * @param flags Flags defining mode of usage paths comparison
    532  * @param type Type of report we search.
    533  * @retval NULL if no field is founded
    534  * @retval Pointer to the founded report structure when founded
    535  */
     519
    536520usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report,
    537         usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags,
    538         usb_hid_report_type_t type)
    539 {
    540         usb_hid_report_description_t *report_des =
    541                 usb_hid_report_find_description(report, path->report_id, type);
    542 
     521                                                        usb_hid_report_field_t *field,
     522                            usb_hid_report_path_t *path, int flags,
     523                            usb_hid_report_type_t type)
     524{
     525        usb_hid_report_description_t *report_des = usb_hid_report_find_description (report, path->report_id, type);
    543526        link_t *field_it;
    544527       
     
    548531
    549532        if(field == NULL){
     533                // vezmu prvni co mathuje podle path!!
    550534                field_it = report_des->report_items.next;
    551535        }
     
    555539
    556540        while(field_it != &report_des->report_items) {
    557                 field = list_get_instance(field_it, usb_hid_report_field_t,
    558                         link);
     541                field = list_get_instance(field_it, usb_hid_report_field_t, link);
    559542
    560543                if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
    561                         usb_hid_report_path_append_item (
    562                                 field->collection_path, field->usage_page,
    563                                 field->usage);
    564 
    565                         if(usb_hid_report_compare_usage_path(
    566                                 field->collection_path, path, flags) == EOK){
    567 
    568                                 usb_hid_report_remove_last_item(
    569                                         field->collection_path);
    570 
     544                        usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
     545                        if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK){
     546                                usb_hid_report_remove_last_item (field->collection_path);
    571547                                return field;
    572548                        }
    573                         usb_hid_report_remove_last_item (
    574                                 field->collection_path);
     549                        usb_hid_report_remove_last_item (field->collection_path);
    575550                }
    576551                field_it = field_it->next;
     
    580555}
    581556
    582 /*---------------------------------------------------------------------------*/
    583 /**
    584  * Returns next report_id of report of specified type. If zero is given than
    585  * first report_id of specified type is returned (0 is not legal value for
    586  * repotr_id)
    587  *
    588  * @param report_id Current report_id, 0 if there is no current report_id
    589  * @param type Type of searched report
    590  * @param report Report structure inwhich we search
    591  * @retval 0 if report structure is null or there is no specified report
    592  * @retval report_id otherwise
    593  */
    594 uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report,
    595         uint8_t report_id, usb_hid_report_type_t type)
     557uint8_t usb_hid_report_get_report_id(usb_hid_report_t *report, uint8_t report_id, usb_hid_report_type_t type)
    596558{
    597559        if(report == NULL){
     
    602564        link_t *report_it;
    603565       
    604         if(report_id > 0) {
    605                 report_it = usb_hid_report_find_description(report, report_id,
    606                         type)->link.next;               
     566        if(report_id == 0) {
     567                report_it = usb_hid_report_find_description (report, report_id, type)->link.next;               
    607568        }
    608569        else {
     
    611572
    612573        while(report_it != &report->reports) {
    613                 report_des = list_get_instance(report_it,
    614                         usb_hid_report_description_t, link);
    615 
     574                report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
    616575                if(report_des->type == type){
    617576                        return report_des->report_id;
     
    622581}
    623582
    624 /*---------------------------------------------------------------------------*/
    625 /**
    626  * Reset all local items in given state table
    627  *
    628  * @param report_item State table containing current state of report
    629  * descriptor parsing
    630  *
    631  * @return void
    632  */
    633583void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item)
    634584{
Note: See TracChangeset for help on using the changeset viewer.