hidparser.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  * Data translation private functions
00046  */
00047 uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
00048 
00049 int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data);
00050 
00051 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 
00052         int32_t value);
00053 
00054 int usb_pow(int a, int b);
00055 
00056 /*---------------------------------------------------------------------------*/
00057 
00058 // TODO: tohle ma bejt asi jinde
00059 int usb_pow(int a, int b)
00060 {
00061         switch(b) {
00062         case 0:
00063                 return 1;
00064                 break;
00065         case 1:
00066                 return a;
00067                 break;
00068         default:
00069                 return a * usb_pow(a, b-1);
00070                 break;
00071         }
00072 }
00073 /*---------------------------------------------------------------------------*/
00074 
00082 size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id, 
00083                            usb_hid_report_type_t type)
00084 {
00085         usb_hid_report_description_t *report_des;
00086 
00087         if(report == NULL) {
00088                 return 0;
00089         }
00090 
00091         report_des = usb_hid_report_find_description (report, report_id, type);
00092         if(report_des == NULL){
00093                 return 0;
00094         }
00095         else {
00096                 return report_des->item_length;
00097         }
00098 }
00099 
00107 size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id, 
00108                            usb_hid_report_type_t type)
00109 {
00110         usb_hid_report_description_t *report_des;
00111 
00112         if(report == NULL) {
00113                 return 0;
00114         }
00115 
00116         report_des = usb_hid_report_find_description (report, report_id, type);
00117         if(report_des == NULL){
00118                 return 0;
00119         }
00120         else {
00121                 return ((report_des->bit_length + 7) / 8) ;
00122         }
00123 }
00124 /*---------------------------------------------------------------------------*/
00125 
00134 int usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data, 
00135         size_t size, uint8_t *report_id)
00136 {
00137         link_t *list_item;
00138         usb_hid_report_field_t *item;
00139 
00140         usb_hid_report_description_t *report_des;
00141         usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
00142         
00143         if(report == NULL) {
00144                 return EINVAL;
00145         }
00146 
00147         if(report->use_report_ids != 0) {
00148                 *report_id = data[0];
00149         }       
00150         else {
00151                 *report_id = 0;
00152         }
00153 
00154 
00155         report_des = usb_hid_report_find_description(report, *report_id, 
00156                 type);
00157 
00158         if(report_des == NULL) {
00159                 return EINVAL;
00160         }
00161 
00162         /* read data */
00163         list_item = report_des->report_items.next;         
00164         while(list_item != &(report_des->report_items)) {
00165 
00166                 item = list_get_instance(list_item, usb_hid_report_field_t, 
00167                                 link);
00168 
00169                 if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
00170                         
00171                         if(USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0){
00172 
00173                                 // array
00174                                 item->value = 
00175                                         usb_hid_translate_data(item, data);
00176                 
00177                                 item->usage = USB_HID_EXTENDED_USAGE(
00178                                     item->usages[
00179                                     item->value - item->physical_minimum]);
00180 
00181                                 item->usage_page = 
00182                                     USB_HID_EXTENDED_USAGE_PAGE(
00183                                     item->usages[
00184                                     item->value - item->physical_minimum]);
00185 
00186                                 usb_hid_report_set_last_item (
00187                                     item->collection_path, 
00188                                     USB_HID_TAG_CLASS_GLOBAL, 
00189                                     item->usage_page);
00190 
00191                                 usb_hid_report_set_last_item (
00192                                     item->collection_path, 
00193                                     USB_HID_TAG_CLASS_LOCAL, item->usage);
00194                                 
00195                         }
00196                         else {
00197                                 // variable item
00198                                 item->value = usb_hid_translate_data(item, 
00199                                     data);                              
00200                         }                       
00201                 }
00202                 list_item = list_item->next;
00203         }
00204         
00205         return EOK;
00206         
00207 }
00208 
00209 /*---------------------------------------------------------------------------*/
00217 int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data)
00218 {
00219         int resolution;
00220         int offset;
00221         int part_size;
00222         
00223         int32_t value=0;
00224         int32_t mask=0;
00225         const uint8_t *foo=0;
00226 
00227         // now only shot tags are allowed
00228         if(item->size > 32) {
00229                 return 0;
00230         }
00231 
00232         if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
00233                 item->physical_minimum = item->logical_minimum;
00234                 item->physical_maximum = item->logical_maximum;                 
00235         }
00236         
00237 
00238         if(item->physical_maximum == item->physical_minimum){
00239             resolution = 1;
00240         }
00241         else {
00242             resolution = (item->logical_maximum - item->logical_minimum) / 
00243                 ((item->physical_maximum - item->physical_minimum) * 
00244                 (usb_pow(10,(item->unit_exponent))));
00245         }
00246 
00247         offset = item->offset;
00248         // FIXME
00249         if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
00250                 
00251                 part_size = 0;
00252 
00253                 size_t i=0;
00254                 for(i=(size_t)(offset/8); i<=(size_t)(offset+item->size-1)/8; i++){
00255                         if(i == (size_t)(offset/8)) {
00256                                 // the higher one
00257                                 part_size = 8 - (offset % 8);
00258                                 foo = data + i;
00259                                 mask =  ((1 << (item->size-part_size))-1);
00260                                 value = (*foo & mask);
00261                         }
00262                         else if(i == ((offset+item->size-1)/8)){
00263                                 // the lower one
00264                                 foo = data + i;
00265                                 mask = ((1 << (item->size - part_size)) - 1) 
00266                                         << (8 - (item->size - part_size));
00267 
00268                                 value = (((*foo & mask) >> (8 - 
00269                                     (item->size - part_size))) << part_size ) 
00270                                     + value;
00271                         }
00272                         else {
00273                                 value = (*(data + 1) << (part_size + 8)) + value;
00274                                 part_size += 8;
00275                         }
00276                 }
00277         }
00278         else {          
00279                 foo = data+(offset/8);
00280                 mask =  ((1 << item->size)-1) << (8-((offset%8)+item->size));
00281                 value = (*foo & mask) >> (8-((offset%8)+item->size));
00282         }
00283 
00284         if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
00285                 value = USB_HID_UINT32_TO_INT32(value, item->size);
00286         }
00287 
00288         return (int)(((value - item->logical_minimum) / resolution) + 
00289                 item->physical_minimum);
00290         
00291 }
00292 
00293 /*---------------------------------------------------------------------------*/
00294 /* OUTPUT API */
00295 
00304 uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, 
00305         uint8_t report_id)
00306 {
00307         if(report == NULL) {
00308                 *size = 0;
00309                 return NULL;
00310         }
00311 
00312         link_t *report_it = report->reports.next;
00313         usb_hid_report_description_t *report_des = NULL;
00314         while(report_it != &report->reports) {
00315                 report_des = list_get_instance(report_it, 
00316                         usb_hid_report_description_t, link);
00317                 
00318                 if((report_des->report_id == report_id) && 
00319                         (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
00320                         break;
00321                 }
00322 
00323                 report_it = report_it->next;
00324         }
00325 
00326         if(report_des == NULL){
00327                 *size = 0;
00328                 return NULL;
00329         }
00330         else {
00331                 *size = (report_des->bit_length + (8 - 1))/8;
00332                 uint8_t *ret = malloc((*size) * sizeof(uint8_t));
00333                 memset(ret, 0, (*size) * sizeof(uint8_t));
00334                 return ret;
00335         }
00336 }
00337 
00338 
00344 void usb_hid_report_output_free(uint8_t *output)
00345 
00346 {
00347         if(output != NULL) {
00348                 free (output);
00349         }
00350 }
00351 
00361 int usb_hid_report_output_translate(usb_hid_report_t *report, 
00362         uint8_t report_id, uint8_t *buffer, size_t size)
00363 {
00364         link_t *item;   
00365         int32_t value=0;
00366         int offset;
00367         int length;
00368         int32_t tmp_value;
00369         
00370         if(report == NULL) {
00371                 return EINVAL;
00372         }
00373 
00374         if(report->use_report_ids != 0) {
00375                 buffer[0] = report_id;          
00376         }
00377 
00378         usb_hid_report_description_t *report_des;
00379         report_des = usb_hid_report_find_description (report, report_id, 
00380                 USB_HID_REPORT_TYPE_OUTPUT);
00381         
00382         if(report_des == NULL){
00383                 return EINVAL;
00384         }
00385 
00386         usb_hid_report_field_t *report_item;    
00387         item = report_des->report_items.next;   
00388         while(item != &report_des->report_items) {
00389                 report_item = list_get_instance(item, usb_hid_report_field_t, link);
00390 
00391                 value = usb_hid_translate_data_reverse(report_item, 
00392                         report_item->value);
00393 
00394                 offset = report_des->bit_length - report_item->offset - 1;
00395                 length = report_item->size;
00396                 
00397                 usb_log_debug("\ttranslated value: %x\n", value);
00398 
00399                 if((offset/8) == ((offset+length-1)/8)) {
00400                         // je to v jednom bytu
00401                         if(((size_t)(offset/8) >= size) || 
00402                                 ((size_t)(offset+length-1)/8) >= size) {
00403                                 break; // TODO ErrorCode
00404                         }
00405                         size_t shift = 8 - offset%8 - length;
00406                         value = value << shift;                                                 
00407                         value = value & (((1 << length)-1) << shift);
00408                                 
00409                         uint8_t mask = 0;
00410                         mask = 0xff - (((1 << length) - 1) << shift);
00411                         buffer[offset/8] = (buffer[offset/8] & mask) | value;
00412                 }
00413                 else {
00414                         int i = 0;
00415                         uint8_t mask = 0;
00416                         for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
00417                                 if(i == (offset/8)) {
00418                                         tmp_value = value;
00419                                         tmp_value = tmp_value & 
00420                                                 ((1 << (8-(offset%8)))-1);
00421 
00422                                         tmp_value = tmp_value << (offset%8);
00423         
00424                                         mask = ~(((1 << (8-(offset%8)))-1) << 
00425                                                         (offset%8));
00426 
00427                                         buffer[i] = (buffer[i] & mask) | 
00428                                                 tmp_value;
00429                                 }
00430                                 else if (i == ((offset + length -1)/8)) {
00431                                         
00432                                         value = value >> (length - 
00433                                                 ((offset + length) % 8));
00434 
00435                                         value = value & ((1 << (length - 
00436                                                 ((offset + length) % 8))) - 1);
00437                                 
00438                                         mask = (1 << (length - 
00439                                                 ((offset + length) % 8))) - 1;
00440 
00441                                         buffer[i] = (buffer[i] & mask) | value;
00442                                 }
00443                                 else {
00444                                         buffer[i] = value & (0xFF << i);
00445                                 }
00446                         }
00447                 }
00448 
00449                 // reset value
00450                 report_item->value = 0;
00451                 
00452                 item = item->next;
00453         }
00454         
00455         return EOK;
00456 }
00457 
00458 /*---------------------------------------------------------------------------*/
00465 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, 
00466         int value)
00467 {
00468         int ret=0;
00469         int resolution;
00470 
00471         if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
00472                 ret = item->logical_minimum;
00473         }
00474 
00475         if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
00476                 item->physical_minimum = item->logical_minimum;
00477                 item->physical_maximum = item->logical_maximum;                 
00478         }
00479         
00480         // variable item
00481         if(item->physical_maximum == item->physical_minimum){
00482             resolution = 1;
00483         }
00484         else {
00485             resolution = (item->logical_maximum - item->logical_minimum) /
00486                 ((item->physical_maximum - item->physical_minimum) *
00487                 (usb_pow(10,(item->unit_exponent))));
00488         }
00489 
00490         ret = ((value - item->physical_minimum) * resolution) + 
00491                 item->logical_minimum;
00492 
00493         usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), \
00494                 ret(%x)\n", value, resolution, item->physical_minimum, 
00495                 item->logical_minimum, ret);
00496         
00497         if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
00498                 return USB_HID_INT32_TO_UINT32(ret, item->size);
00499         }
00500         return (int32_t)0 + ret;
00501 }
00502 
00503 /*---------------------------------------------------------------------------*/
00510 usb_hid_report_item_t *usb_hid_report_item_clone(
00511         const usb_hid_report_item_t *item)
00512 {
00513         usb_hid_report_item_t *new_report_item;
00514         
00515         if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
00516                 return NULL;
00517         }                                       
00518         memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
00519         link_initialize(&(new_report_item->link));
00520 
00521         return new_report_item;
00522 }
00523 
00524 /*---------------------------------------------------------------------------*/
00538 usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report, 
00539         usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags, 
00540         usb_hid_report_type_t type)
00541 {
00542         usb_hid_report_description_t *report_des = 
00543                 usb_hid_report_find_description(report, path->report_id, type);
00544 
00545         link_t *field_it;
00546         
00547         if(report_des == NULL){
00548                 return NULL;
00549         }
00550 
00551         if(field == NULL){
00552                 field_it = report_des->report_items.next;
00553         }
00554         else {
00555                 field_it = field->link.next;
00556         }
00557 
00558         while(field_it != &report_des->report_items) {
00559                 field = list_get_instance(field_it, usb_hid_report_field_t, 
00560                         link);
00561 
00562                 if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
00563                         usb_hid_report_path_append_item (
00564                                 field->collection_path, field->usage_page, 
00565                                 field->usage);
00566 
00567                         if(usb_hid_report_compare_usage_path(
00568                                 field->collection_path, path, flags) == EOK){
00569 
00570                                 usb_hid_report_remove_last_item(
00571                                         field->collection_path);
00572 
00573                                 return field;
00574                         }
00575                         usb_hid_report_remove_last_item (
00576                                 field->collection_path);
00577                 }
00578                 field_it = field_it->next;
00579         }
00580 
00581         return NULL;
00582 }
00583 
00584 /*---------------------------------------------------------------------------*/
00596 uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report, 
00597         uint8_t report_id, usb_hid_report_type_t type)
00598 {
00599         if(report == NULL){
00600                 return 0;
00601         }
00602 
00603         usb_hid_report_description_t *report_des;
00604         link_t *report_it;
00605         
00606         if(report_id > 0) {
00607                 report_des = usb_hid_report_find_description(report, report_id, 
00608                         type);
00609                 if(report_des == NULL) {
00610                         return 0;
00611                 }
00612                 else {
00613                         report_it = report_des->link.next;
00614                 }       
00615         }
00616         else {
00617                 report_it = report->reports.next;
00618         }
00619 
00620         while(report_it != &report->reports) {
00621                 report_des = list_get_instance(report_it, 
00622                         usb_hid_report_description_t, link);
00623 
00624                 if(report_des->type == type){
00625                         return report_des->report_id;
00626                 }
00627 
00628                 report_it = report_it->next;
00629         }
00630 
00631         return 0;
00632 }
00633 
00634 /*---------------------------------------------------------------------------*/
00643 void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item)
00644 {
00645         if(report_item == NULL) {
00646                 return;
00647         }
00648         
00649         report_item->usages_count = 0;
00650         memset(report_item->usages, 0, USB_HID_MAX_USAGES);
00651         
00652         report_item->extended_usage_page = 0;
00653         report_item->usage_minimum = 0;
00654         report_item->usage_maximum = 0;
00655         report_item->designator_index = 0;
00656         report_item->designator_minimum = 0;
00657         report_item->designator_maximum = 0;
00658         report_item->string_index = 0;
00659         report_item->string_minimum = 0;
00660         report_item->string_maximum = 0;
00661 
00662         return;
00663 }

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