hiddescriptor.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Matej Klonfar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <usb/hid/hidparser.h>
00036 #include <errno.h>
00037 #include <stdio.h>
00038 #include <malloc.h>
00039 #include <mem.h>
00040 #include <usb/debug.h>
00041 #include <assert.h>
00042 
00043 /*---------------------------------------------------------------------------*/
00044 /*
00045  * Constants defining current parsing mode for correct parsing of the set of
00046  * local tags (usage) enclosed in delimter tags.
00047  */
00051 #define OUTSIDE_DELIMITER_SET   0
00052 
00056 #define START_DELIMITER_SET     1
00057 
00061 #define INSIDE_DELIMITER_SET    2
00062 
00063 /*---------------------------------------------------------------------------*/
00064         
00068 #define USB_HID_NEW_REPORT_ITEM 1
00069 
00073 #define USB_HID_NO_ACTION       2
00074 
00075 #define USB_HID_RESET_OFFSET    3
00076 
00078 #define USB_HID_UNKNOWN_TAG             -99
00079 
00080 /*---------------------------------------------------------------------------*/
00090 usb_hid_report_path_t *usb_hid_report_path_try_insert(
00091                 usb_hid_report_t *report, usb_hid_report_path_t *cmp_path) {
00092         
00093         link_t *path_it = report->collection_paths.prev->next;
00094         usb_hid_report_path_t *path = NULL;
00095         
00096         if((report == NULL) || (cmp_path == NULL)) {
00097                 return NULL;
00098         }
00099         
00100         while(path_it != &report->collection_paths) {
00101                 path = list_get_instance(path_it, usb_hid_report_path_t,
00102                                 link);
00103                 
00104                 if(usb_hid_report_compare_usage_path(path, cmp_path,
00105                                         USB_HID_PATH_COMPARE_STRICT) == EOK){
00106                         break;
00107                 }                       
00108                 path_it = path_it->next;
00109         }
00110         if(path_it == &report->collection_paths) {
00111                 path = usb_hid_report_path_clone(cmp_path);
00112                 if(path == NULL) {
00113                         return NULL;
00114                 }
00115                 list_append(&path->link, &report->collection_paths);                                    
00116                 report->collection_paths_count++;
00117 
00118                 return path;
00119         }
00120         else {
00121                 return list_get_instance(path_it, usb_hid_report_path_t,
00122                                 link); 
00123         }
00124 }
00125 
00126 /*---------------------------------------------------------------------------*/
00135 int usb_hid_report_init(usb_hid_report_t *report)
00136 {
00137         if(report == NULL) {
00138                 return EINVAL;
00139         }
00140 
00141         memset(report, 0, sizeof(usb_hid_report_t));
00142         list_initialize(&report->reports);
00143         list_initialize(&report->collection_paths);
00144 
00145         report->use_report_ids = 0;
00146     return EOK;   
00147 }
00148 
00149 /*---------------------------------------------------------------------------*/
00150 
00163 int usb_hid_report_append_fields(usb_hid_report_t *report,
00164                 usb_hid_report_item_t *report_item) {
00165 
00166         usb_hid_report_field_t *field;
00167         int i;
00168 
00169         uint32_t *usages;
00170         int usages_used=0;
00171 
00172         if((report == NULL) || (report_item == NULL)) {
00173                 return EINVAL;
00174         }
00175 
00176         if(report_item->usages_count > 0){
00177                 usages = malloc(sizeof(int32_t) * report_item->usages_count);
00178                 memcpy(usages, report_item->usages, sizeof(int32_t) *
00179                                 report_item->usages_count); 
00180         }
00181         else {
00182                 usages = NULL;
00183         }
00184         
00185         usb_hid_report_path_t *path = report_item->usage_path;  
00186         for(i=0; i<report_item->count; i++){
00187 
00188                 field = malloc(sizeof(usb_hid_report_field_t));
00189                 if(field == NULL) {
00190                         return ENOMEM;
00191                 }
00192 
00193                 memset(field, 0, sizeof(usb_hid_report_field_t));
00194                 list_initialize(&field->link);
00195 
00196                 /* fill the attributes */               
00197                 field->logical_minimum = report_item->logical_minimum;
00198                 field->logical_maximum = report_item->logical_maximum;
00199                 field->physical_minimum = report_item->physical_minimum;
00200                 field->physical_maximum = report_item->physical_maximum;
00201 
00202                 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0){
00203                         /* 
00204                         Store usage array. The Correct Usage Page and Usage is
00205                         depending on data in report and will be filled later
00206                         */
00207                         field->usage = 0;
00208                         field->usage_page = 0; //report_item->usage_page;
00209 
00210                         field->usages_count = report_item->usages_count;
00211                         field->usages = usages;
00212                         usages_used = 1;
00213                 }
00214                 else {
00215 
00216                         /* Fill the correct Usage and Usage Page */
00217                         int32_t usage;
00218                         if(i < report_item->usages_count) {
00219                                 usage = report_item->usages[i];
00220                         }
00221                         else {
00222                                 usage = report_item->usages[
00223                                         report_item->usages_count- 1]; 
00224                         }
00225 
00226                         if(USB_HID_IS_EXTENDED_USAGE(usage)){
00227                                 field->usage = USB_HID_EXTENDED_USAGE(usage);
00228                                 field->usage_page = 
00229                                         USB_HID_EXTENDED_USAGE_PAGE(usage);
00230                         }
00231                         else {
00232                                 // should not occur
00233                                 field->usage = usage;
00234                                 field->usage_page = report_item->usage_page;
00235                         }
00236                 }
00237                 
00238                 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_GLOBAL,
00239                                 field->usage_page);
00240                 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_LOCAL,
00241                                 field->usage);
00242 
00243                 field->collection_path =
00244                         usb_hid_report_path_try_insert(report, path);
00245 
00246                 field->size = report_item->size;
00247 
00248                 if(report_item->type == USB_HID_REPORT_TYPE_INPUT) {
00249                         int offset = report_item->offset + report_item->size * i;
00250                         int field_offset = (offset/8)*8 + (offset/8 + 1) * 8 - 
00251                                 offset - report_item->size;
00252                         if(field_offset < 0) {
00253                                 field->offset = 0;
00254                         }
00255                         else {
00256                                 field->offset = field_offset;
00257                         }
00258                 }
00259                 else {
00260                         field->offset = report_item->offset + (i * report_item->size);
00261                 }
00262 
00263 
00264                 if(report->use_report_ids != 0) {
00265                         field->offset += 8;
00266                         report->use_report_ids = 1;
00267                 }
00268 
00269                 field->item_flags = report_item->item_flags;
00270 
00271                 /* find the right report list*/
00272                 usb_hid_report_description_t *report_des;
00273                 report_des = usb_hid_report_find_description(report,
00274                         report_item->id, report_item->type);
00275                 
00276                 if(report_des == NULL){
00277                         report_des = malloc(
00278                                 sizeof(usb_hid_report_description_t));
00279                         if(report_des == NULL) {
00280                                 return ENOMEM;
00281                         }
00282 
00283                         memset(report_des, 0,
00284                                 sizeof(usb_hid_report_description_t));
00285 
00286                         report_des->type = report_item->type;
00287                         report_des->report_id = report_item->id;
00288                         if(report_des->report_id != 0) {
00289                                 /* set up the bit length by report_id field */
00290                                 report_des->bit_length = 8;
00291                         }
00292 
00293                         list_initialize (&report_des->link);
00294                         list_initialize (&report_des->report_items);
00295 
00296                         list_append(&report_des->link, &report->reports);
00297                         report->report_count++;
00298                 }
00299 
00300                 /* append this field to the end of founded report list */
00301                 list_append (&field->link, &report_des->report_items);
00302                 
00303                 /* update the sizes */
00304                 report_des->bit_length += field->size;
00305                 report_des->item_length++;
00306 
00307         }
00308 
00309         // free only when not used!!!
00310         if(usages && usages_used == 0) {
00311                 free(usages);
00312         }
00313 
00314         return EOK;
00315 }
00316 /*---------------------------------------------------------------------------*/
00327 usb_hid_report_description_t * usb_hid_report_find_description(
00328                 const usb_hid_report_t *report, uint8_t report_id,
00329                 usb_hid_report_type_t type) {
00330 
00331         if(report == NULL) {
00332                 return NULL;
00333         }
00334 
00335         link_t *report_it = report->reports.next;
00336         usb_hid_report_description_t *report_des = NULL;
00337         
00338         while(report_it != &report->reports) {
00339                 report_des = list_get_instance(report_it,
00340                                 usb_hid_report_description_t, link);
00341 
00342                 // if report id not set, return the first of the type
00343                 if(((report_des->report_id == report_id) || (report_id == 0)) && 
00344                    (report_des->type == type)) { 
00345                         return report_des;
00346                 }
00347                 
00348                 report_it = report_it->next;
00349         }
00350 
00351         return NULL;
00352 }
00353 /*---------------------------------------------------------------------------*/
00354 
00364 int usb_hid_parse_report_descriptor(usb_hid_report_t *report, 
00365     const uint8_t *data, size_t size)
00366 {
00367         size_t i=0;
00368         uint8_t tag=0;
00369         uint8_t item_size=0;
00370         int class=0;
00371         int ret;
00372         usb_hid_report_item_t *report_item=0;
00373         usb_hid_report_item_t *new_report_item; 
00374         usb_hid_report_path_t *usage_path;
00375 
00376         size_t offset_input=0;
00377         size_t offset_output=0;
00378         size_t offset_feature=0;
00379 
00380         link_t stack;
00381         list_initialize(&stack);        
00382 
00383         /* parser structure initialization*/
00384         if(usb_hid_report_init(report) != EOK) {
00385                 return EINVAL;
00386         }
00387         
00388         /*report item initialization*/
00389         if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
00390                 return ENOMEM;
00391         }
00392         memset(report_item, 0, sizeof(usb_hid_report_item_t));
00393         list_initialize(&(report_item->link));  
00394 
00395         /* usage path context initialization */
00396         if(!(usage_path=usb_hid_report_path())){
00397                 return ENOMEM;
00398         }
00399         usb_hid_report_path_append_item(usage_path, 0, 0);      
00400         
00401         while(i<size){  
00402                 if(!USB_HID_ITEM_IS_LONG(data[i])){
00403 
00404                         if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
00405                                 return EINVAL;
00406                         }
00407                         
00408                         tag = USB_HID_ITEM_TAG(data[i]);
00409                         item_size = USB_HID_ITEM_SIZE(data[i]);
00410                         class = USB_HID_ITEM_TAG_CLASS(data[i]);
00411                         
00412                         ret = usb_hid_report_parse_tag(tag,class,data+i+1,
00413                                 item_size,report_item, usage_path);
00414 
00415                         switch(ret){
00416                         case USB_HID_NEW_REPORT_ITEM:
00417                                 /* store report item to report and create the
00418                                  * new one store current collection path
00419                                  */
00420                                 report_item->usage_path = usage_path;
00421                                         
00422                                 usb_hid_report_path_set_report_id(
00423                                      report_item->usage_path, report_item->id);
00424                                 
00425                                 if(report_item->id != 0){
00426                                         report->use_report_ids = 1;
00427                                 }
00428                                         
00429                                 switch(tag) {
00430                                 case USB_HID_REPORT_TAG_INPUT:
00431                                         report_item->type = 
00432                                             USB_HID_REPORT_TYPE_INPUT;
00433 
00434                                         report_item->offset = offset_input;
00435                                         offset_input += report_item->count * 
00436                                             report_item->size;
00437                                         break;
00438         
00439                                 case USB_HID_REPORT_TAG_OUTPUT:
00440                                         report_item->type = 
00441                                             USB_HID_REPORT_TYPE_OUTPUT;
00442                                         
00443                                         report_item->offset = offset_output;
00444                                         offset_output += report_item->count * 
00445                                             report_item->size;
00446                                         break;
00447         
00448                                 case USB_HID_REPORT_TAG_FEATURE:
00449                                         report_item->type = 
00450                                             USB_HID_REPORT_TYPE_FEATURE;
00451 
00452                                         report_item->offset = offset_feature;
00453                                         offset_feature += report_item->count * 
00454                                                 report_item->size;
00455                                         break;
00456         
00457                                 default:
00458                                         usb_log_debug2(
00459                                             "\tjump over - tag %X\n", tag);
00460                                         break;
00461                                 }
00462                                         
00463                                 /* 
00464                                  * append new fields to the report structure                                     
00465                                  */
00466                                 usb_hid_report_append_fields(report, 
00467                                     report_item);
00468 
00469                                 /* reset local items */
00470                                 usb_hid_report_reset_local_items (report_item);
00471                                 break;
00472 
00473                         case USB_HID_RESET_OFFSET:
00474                                 offset_input = 0;
00475                                 offset_output = 0;
00476                                 offset_feature = 0;
00477                                 usb_hid_report_path_set_report_id (usage_path, 
00478                                     report_item->id);
00479                                 break;
00480 
00481                         case USB_HID_REPORT_TAG_PUSH:
00482                                 // push current state to stack
00483                                 new_report_item = usb_hid_report_item_clone(
00484                                     report_item);
00485                                 
00486                                 usb_hid_report_path_t *tmp_path = 
00487                                     usb_hid_report_path_clone(usage_path);
00488 
00489                                 new_report_item->usage_path = tmp_path; 
00490 
00491                                 list_prepend (&new_report_item->link, &stack);
00492                                 break;
00493                         case USB_HID_REPORT_TAG_POP:
00494                                 // restore current state from stack
00495                                 if(list_empty (&stack)) {
00496                                         return EINVAL;
00497                                 }
00498                                 free(report_item);
00499                                                 
00500                                 report_item = list_get_instance(stack.next, 
00501                                     usb_hid_report_item_t, link);
00502                                         
00503                                 usb_hid_report_usage_path_t *tmp_usage_path;
00504                                 tmp_usage_path = list_get_instance(
00505                                     report_item->usage_path->link.prev, 
00506                                     usb_hid_report_usage_path_t, link);
00507                                         
00508                                 usb_hid_report_set_last_item(usage_path, 
00509                                     USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
00510                                 
00511                                 usb_hid_report_set_last_item(usage_path, 
00512                                     USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
00513 
00514                                 usb_hid_report_path_free(report_item->usage_path);
00515                                 list_initialize(&report_item->usage_path->link);
00516                                 list_remove (stack.next);
00517                                         
00518                                 break;
00519                                         
00520                         default:
00521                                 // nothing special to do                                        
00522                                 break;
00523                         }
00524 
00525                         /* jump over the processed block */
00526                         i += 1 + USB_HID_ITEM_SIZE(data[i]);
00527                 }
00528                 else{
00529                         // TBD
00530                         i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
00531                 }
00532                 
00533 
00534         }
00535         
00536         return EOK;
00537 }
00538 
00539 /*---------------------------------------------------------------------------*/
00540 
00550 int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
00551         size_t item_size, usb_hid_report_item_t *report_item,
00552         usb_hid_report_path_t *usage_path) {    
00553         
00554         int ret;
00555         
00556         switch(class){
00557         case USB_HID_TAG_CLASS_MAIN:
00558 
00559                 if((ret=usb_hid_report_parse_main_tag(tag, data, item_size,
00560                         report_item, usage_path)) == EOK) {
00561 
00562                         return USB_HID_NEW_REPORT_ITEM;
00563                 }
00564                 else {
00565                         return ret;
00566                 }
00567                 break;
00568 
00569         case USB_HID_TAG_CLASS_GLOBAL:  
00570                 return usb_hid_report_parse_global_tag(tag, data, item_size,
00571                         report_item, usage_path);
00572                 break;
00573 
00574         case USB_HID_TAG_CLASS_LOCAL:                   
00575                 return usb_hid_report_parse_local_tag(tag, data, item_size,
00576                         report_item, usage_path);
00577                 break;
00578         
00579         default:
00580                 return USB_HID_NO_ACTION;
00581         }
00582 }
00583 
00594 int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, 
00595         size_t item_size, usb_hid_report_item_t *report_item,
00596         usb_hid_report_path_t *usage_path)
00597 {
00598         usb_hid_report_usage_path_t *path_item;
00599         
00600         switch(tag)
00601         {
00602         case USB_HID_REPORT_TAG_INPUT:
00603         case USB_HID_REPORT_TAG_OUTPUT:
00604         case USB_HID_REPORT_TAG_FEATURE:
00605                 report_item->item_flags = *data;                        
00606                 return EOK;                     
00607                 break;
00608                         
00609         case USB_HID_REPORT_TAG_COLLECTION:
00610 
00611                 /* store collection atributes */
00612                 path_item = list_get_instance(usage_path->head.prev, 
00613                         usb_hid_report_usage_path_t, link);
00614                 path_item->flags = *data;       
00615                         
00616                 /* set last item */
00617                 usb_hid_report_set_last_item(usage_path, 
00618                         USB_HID_TAG_CLASS_GLOBAL, 
00619                         USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[
00620                                 report_item->usages_count-1]));
00621 
00622                 usb_hid_report_set_last_item(usage_path, 
00623                         USB_HID_TAG_CLASS_LOCAL, 
00624                         USB_HID_EXTENDED_USAGE(report_item->usages[
00625                                 report_item->usages_count-1]));
00626                         
00627                 /* append the new one which will be set by common usage/usage
00628                  * page */
00629                 usb_hid_report_path_append_item(usage_path, 
00630                         report_item->usage_page, 
00631                         report_item->usages[report_item->usages_count-1]);
00632 
00633                 usb_hid_report_reset_local_items (report_item);
00634                 return USB_HID_NO_ACTION;
00635                 break;
00636                         
00637         case USB_HID_REPORT_TAG_END_COLLECTION:
00638                 usb_hid_report_remove_last_item(usage_path);
00639                 return USB_HID_NO_ACTION;
00640                 break;
00641 
00642         default:
00643                 return USB_HID_NO_ACTION;
00644         }
00645 
00646         return EOK;
00647 }
00648 
00658 int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, 
00659         size_t item_size, usb_hid_report_item_t *report_item, 
00660         usb_hid_report_path_t *usage_path) { 
00661         
00662         switch(tag)
00663         {
00664         case USB_HID_REPORT_TAG_USAGE_PAGE:
00665                 report_item->usage_page = 
00666                         usb_hid_report_tag_data_uint32(data, item_size);
00667                 break;
00668 
00669         case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
00670                 report_item->logical_minimum = USB_HID_UINT32_TO_INT32(
00671                         usb_hid_report_tag_data_uint32(data,item_size),
00672                         item_size * 8);
00673                 break;
00674 
00675         case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
00676                 report_item->logical_maximum = USB_HID_UINT32_TO_INT32(
00677                         usb_hid_report_tag_data_uint32(data,item_size), 
00678                         item_size * 8);
00679                 break;
00680 
00681         case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
00682                 report_item->physical_minimum = USB_HID_UINT32_TO_INT32(
00683                         usb_hid_report_tag_data_uint32(data,item_size), 
00684                         item_size * 8);
00685                 break;                  
00686 
00687         case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
00688                 report_item->physical_maximum = USB_HID_UINT32_TO_INT32(
00689                         usb_hid_report_tag_data_uint32(data,item_size), 
00690                         item_size * 8);
00691                 break;
00692 
00693         case USB_HID_REPORT_TAG_UNIT_EXPONENT:
00694                 report_item->unit_exponent = usb_hid_report_tag_data_uint32(
00695                         data,item_size);
00696                 break;
00697 
00698         case USB_HID_REPORT_TAG_UNIT:
00699                 report_item->unit = usb_hid_report_tag_data_uint32(
00700                         data,item_size);
00701                 break;
00702 
00703         case USB_HID_REPORT_TAG_REPORT_SIZE:
00704                 report_item->size = usb_hid_report_tag_data_uint32(
00705                         data,item_size);
00706                 break;
00707 
00708         case USB_HID_REPORT_TAG_REPORT_COUNT:
00709                 report_item->count = usb_hid_report_tag_data_uint32(
00710                         data,item_size);
00711                 break;
00712 
00713         case USB_HID_REPORT_TAG_REPORT_ID:
00714                 report_item->id = usb_hid_report_tag_data_uint32(data, 
00715                         item_size);
00716                 return USB_HID_RESET_OFFSET;
00717                 break;
00718         
00719         case USB_HID_REPORT_TAG_PUSH:
00720         case USB_HID_REPORT_TAG_POP:
00721                 /* 
00722                  * stack operations are done in top level parsing
00723                  * function
00724                  */
00725                 return tag;
00726                 break;
00727                         
00728         default:
00729                 return USB_HID_NO_ACTION;
00730         }
00731 
00732         return EOK;
00733 }
00734 
00744 int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, 
00745         size_t item_size, usb_hid_report_item_t *report_item, 
00746         usb_hid_report_path_t *usage_path)
00747 {
00748         int32_t extended_usage;
00749         
00750         switch(tag) {
00751         case USB_HID_REPORT_TAG_USAGE:
00752                 switch(report_item->in_delimiter) {
00753                 case INSIDE_DELIMITER_SET:
00754                         /* nothing to do
00755                          * we catch only the first one
00756                          */
00757                         break;
00758         
00759                 case START_DELIMITER_SET:
00760                         report_item->in_delimiter = INSIDE_DELIMITER_SET;
00761                 case OUTSIDE_DELIMITER_SET:
00762                         extended_usage = ((report_item->usage_page) << 16);
00763                         extended_usage += usb_hid_report_tag_data_uint32(
00764                                 data,item_size);
00765 
00766                         report_item->usages[report_item->usages_count] = 
00767                                 extended_usage;
00768 
00769                         report_item->usages_count++;
00770                         break;
00771                 }
00772                 break;
00773                 
00774         case USB_HID_REPORT_TAG_USAGE_MINIMUM:                  
00775                 if (item_size == 3) {
00776                         // usage extended usages
00777                         report_item->extended_usage_page = 
00778                             USB_HID_EXTENDED_USAGE_PAGE(
00779                             usb_hid_report_tag_data_uint32(data,item_size));
00780                            
00781 
00782                         report_item->usage_minimum = 
00783                             USB_HID_EXTENDED_USAGE(
00784                             usb_hid_report_tag_data_uint32(data,item_size));
00785                 }
00786                 else {
00787                         report_item->usage_minimum = 
00788                             usb_hid_report_tag_data_uint32(data,item_size);
00789                 }
00790                 break;
00791         
00792         case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
00793                 if (item_size == 3) {
00794                         if(report_item->extended_usage_page != 
00795                             USB_HID_EXTENDED_USAGE_PAGE(        
00796                             usb_hid_report_tag_data_uint32(data,item_size))) {
00797                                 
00798                                 return EINVAL;
00799                         }
00800                                 
00801                         // usage extended usages
00802                         report_item->extended_usage_page = 
00803                                 USB_HID_EXTENDED_USAGE_PAGE(
00804                                 usb_hid_report_tag_data_uint32(data,item_size));
00805 
00806                         report_item->usage_maximum = 
00807                                 USB_HID_EXTENDED_USAGE(
00808                                 usb_hid_report_tag_data_uint32(data,item_size));
00809                 }
00810                 else {
00811                         report_item->usage_maximum = 
00812                                 usb_hid_report_tag_data_uint32(data,item_size);
00813                 }
00814 
00815                 // vlozit zaznamy do pole usages
00816                 int32_t i;
00817                 for(i = report_item->usage_minimum; 
00818                     i <= report_item->usage_maximum; i++) {
00819 
00820                         if(report_item->extended_usage_page) {
00821                             report_item->usages[report_item->usages_count++] = 
00822                                 (report_item->extended_usage_page << 16) + i;
00823                         }
00824                         else {                  
00825                             report_item->usages[report_item->usages_count++] = 
00826                                 (report_item->usage_page << 16) + i;
00827                         }
00828                 }
00829                 report_item->extended_usage_page = 0;
00830                         
00831                 break;
00832                 
00833         case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
00834                 report_item->designator_index = 
00835                         usb_hid_report_tag_data_uint32(data,item_size);
00836                 break;
00837         
00838         case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
00839                 report_item->designator_minimum = 
00840                         usb_hid_report_tag_data_uint32(data,item_size);
00841                 break;
00842 
00843         case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
00844                 report_item->designator_maximum = 
00845                         usb_hid_report_tag_data_uint32(data,item_size);
00846                 break;
00847 
00848         case USB_HID_REPORT_TAG_STRING_INDEX:
00849                 report_item->string_index = 
00850                         usb_hid_report_tag_data_uint32(data,item_size);
00851                 break;
00852 
00853         case USB_HID_REPORT_TAG_STRING_MINIMUM:
00854                 report_item->string_minimum = 
00855                         usb_hid_report_tag_data_uint32(data,item_size);
00856                 break;
00857 
00858         case USB_HID_REPORT_TAG_STRING_MAXIMUM:
00859                 report_item->string_maximum = 
00860                         usb_hid_report_tag_data_uint32(data,item_size);
00861                 break;                  
00862 
00863         case USB_HID_REPORT_TAG_DELIMITER:
00864                 report_item->in_delimiter = 
00865                         usb_hid_report_tag_data_uint32(data,item_size);
00866                 break;
00867 
00868         default:
00869                 return USB_HID_NO_ACTION;
00870         }
00871 
00872         return EOK;
00873 }
00874 /*---------------------------------------------------------------------------*/
00875 
00883 uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
00884 {
00885         unsigned int i;
00886         uint32_t result;
00887 
00888         result = 0;
00889         for(i=0; i<size; i++) {
00890                 result = (result | (data[i]) << (i*8));
00891         }
00892 
00893         return result;
00894 }
00895 /*---------------------------------------------------------------------------*/
00896 
00903 void usb_hid_descriptor_print_list(link_t *head)
00904 {
00905         usb_hid_report_field_t *report_item;
00906         link_t *item;
00907 
00908 
00909         if(head == NULL || list_empty(head)) {
00910             usb_log_debug("\tempty\n");
00911             return;
00912         }
00913         
00914         for(item = head->next; item != head; item = item->next) {
00915                 
00916                 report_item = list_get_instance(item, usb_hid_report_field_t, 
00917                                 link);
00918 
00919                 usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
00920                 usb_log_debug("\t\tSIZE: %zu\n", report_item->size);
00921                 usb_log_debug("\t\tLOGMIN: %d\n", 
00922                         report_item->logical_minimum);
00923                 usb_log_debug("\t\tLOGMAX: %d\n", 
00924                         report_item->logical_maximum);          
00925                 usb_log_debug("\t\tPHYMIN: %d\n", 
00926                         report_item->physical_minimum);         
00927                 usb_log_debug("\t\tPHYMAX: %d\n", 
00928                         report_item->physical_maximum);                         
00929                 usb_log_debug("\t\ttUSAGEMIN: %X\n", 
00930                         report_item->usage_minimum);
00931                 usb_log_debug("\t\tUSAGEMAX: %X\n",
00932                                report_item->usage_maximum);
00933                 usb_log_debug("\t\tUSAGES COUNT: %zu\n", 
00934                         report_item->usages_count);
00935 
00936                 usb_log_debug("\t\tVALUE: %X\n", report_item->value);
00937                 usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
00938                 usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
00939                 
00940                 usb_hid_print_usage_path(report_item->collection_path);
00941 
00942                 usb_log_debug("\n");            
00943 
00944         }
00945 
00946 }
00947 /*---------------------------------------------------------------------------*/
00948 
00955 void usb_hid_descriptor_print(usb_hid_report_t *report)
00956 {
00957         if(report == NULL) {
00958                 return;
00959         }
00960 
00961         link_t *report_it = report->reports.next;
00962         usb_hid_report_description_t *report_des;
00963 
00964         while(report_it != &report->reports) {
00965                 report_des = list_get_instance(report_it, 
00966                         usb_hid_report_description_t, link);
00967                 usb_log_debug("Report ID: %d\n", report_des->report_id);
00968                 usb_log_debug("\tType: %d\n", report_des->type);
00969                 usb_log_debug("\tLength: %zu\n", report_des->bit_length);               
00970                 usb_log_debug("\tB Size: %zu\n",
00971                         usb_hid_report_byte_size(report, 
00972                                 report_des->report_id, 
00973                                 report_des->type));
00974                 usb_log_debug("\tItems: %zu\n", report_des->item_length);               
00975 
00976                 usb_hid_descriptor_print_list(&report_des->report_items);
00977 
00978                 report_it = report_it->next;
00979         }
00980 }
00981 /*---------------------------------------------------------------------------*/
00982 
00989 void usb_hid_free_report_list(link_t *head)
00990 {
00991         return; 
00992         
00993         usb_hid_report_item_t *report_item;
00994         link_t *next;
00995         
00996         if(head == NULL || list_empty(head)) {          
00997             return;
00998         }
00999         
01000         next = head->next;
01001         while(next != head) {
01002         
01003             report_item = list_get_instance(next, usb_hid_report_item_t, link);
01004 
01005                 while(!list_empty(&report_item->usage_path->link)) {
01006                     usb_hid_report_remove_last_item(report_item->usage_path);
01007                 }
01008 
01009                 
01010             next = next->next;
01011             
01012             free(report_item);
01013         }
01014         
01015         return;
01016         
01017 }
01018 /*---------------------------------------------------------------------------*/
01019 
01025 void usb_hid_free_report(usb_hid_report_t *report)
01026 {
01027         if(report == NULL){
01028                 return;
01029         }
01030 
01031         // free collection paths
01032         usb_hid_report_path_t *path;
01033         while(!list_empty(&report->collection_paths)) {
01034                 path = list_get_instance(report->collection_paths.next, 
01035                                 usb_hid_report_path_t, link);
01036 
01037                 usb_hid_report_path_free(path);         
01038         }
01039         
01040         // free report items
01041         usb_hid_report_description_t *report_des;
01042         usb_hid_report_field_t *field;
01043         while(!list_empty(&report->reports)) {
01044                 report_des = list_get_instance(report->reports.next, 
01045                                 usb_hid_report_description_t, link);
01046 
01047                 list_remove(&report_des->link);
01048                 
01049                 while(!list_empty(&report_des->report_items)) {
01050                         field = list_get_instance(
01051                                 report_des->report_items.next, 
01052                                 usb_hid_report_field_t, link);
01053 
01054                         list_remove(&field->link);
01055 
01056                         free(field);
01057                 }
01058                 
01059                 free(report_des);
01060         }
01061         
01062         return;
01063 }
01064 /*---------------------------------------------------------------------------*/
01065 

Generated on Thu Jun 2 07:45:48 2011 for HelenOS/USB by  doxygen 1.4.7