Changes in uspace/lib/usb/src/hidparser.c [c32688d:ad4562c2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/usb/src/hidparser.c
rc32688d rad4562c2 36 36 #include <errno.h> 37 37 #include <stdio.h> 38 #include <malloc.h>39 #include <mem.h>40 #include <usb/debug.h>41 42 #define USB_HID_NEW_REPORT_ITEM 143 #define USB_HID_NO_ACTION 244 #define USB_HID_UNKNOWN_TAG -9945 46 #define BAD_HACK_USAGE_PAGE 0x0747 48 int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,49 usb_hid_report_item_t *report_item);50 int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,51 usb_hid_report_item_t *report_item);52 int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,53 usb_hid_report_item_t *report_item);54 int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,55 usb_hid_report_item_t *report_item);56 57 void usb_hid_descriptor_print_list(link_t *head);58 int usb_hid_report_reset_local_items();59 void usb_hid_free_report_list(link_t *head);60 int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size);61 inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);62 int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j);63 int usb_pow(int a, int b);64 65 int usb_pow(int a, int b)66 {67 switch(b) {68 case 0:69 return 1;70 break;71 case 1:72 return a;73 break;74 default:75 return a * usb_pow(a, b-1);76 break;77 }78 }79 80 /**81 *82 */83 int usb_hid_parser_init(usb_hid_report_parser_t *parser)84 {85 if(parser == NULL) {86 return -1;87 }88 89 list_initialize(&(parser->input));90 list_initialize(&(parser->output));91 list_initialize(&(parser->feature));92 93 return EOK;94 }95 96 38 97 39 /** Parse HID report descriptor. … … 104 46 const uint8_t *data, size_t size) 105 47 { 106 size_t i=0; 107 uint8_t tag=0; 108 uint8_t item_size=0; 109 int class=0; 110 int ret; 111 usb_hid_report_item_t *report_item=0; 112 usb_hid_report_item_t *new_report_item; 48 return ENOTSUP; 49 } 113 50 114 size_t offset_input=0; 115 size_t offset_output=0; 116 size_t offset_feature=0; 51 /** Parse and act upon a HID report. 52 * 53 * @see usb_hid_parse_report_descriptor 54 * 55 * @param parser Opaque HID report parser structure. 56 * @param data Data for the report. 57 * @param callbacks Callbacks for report actions. 58 * @param arg Custom argument (passed through to the callbacks). 59 * @return Error code. 60 */ 61 int usb_hid_parse_report(const usb_hid_report_parser_t *parser, 62 const uint8_t *data, size_t size, 63 const usb_hid_report_in_callbacks_t *callbacks, void *arg) 64 { 65 int i; 117 66 118 119 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){ 120 return ENOMEM; 121 } 122 memset(report_item, 0, sizeof(usb_hid_report_item_t)); 123 124 link_initialize(&(report_item->link)); 125 126 while(i<size){ 127 if(!USB_HID_ITEM_IS_LONG(data[i])){ 128 129 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){ 130 return -1; // TODO ERROR CODE 131 } 132 133 tag = USB_HID_ITEM_TAG(data[i]); 134 item_size = USB_HID_ITEM_SIZE(data[i]); 135 class = USB_HID_ITEM_TAG_CLASS(data[i]); 136 137 usb_log_debug2( 138 "i(%u) data(%X) value(%X): TAG %u, class %u, size %u - ", i, 139 data[i], usb_hid_report_tag_data_int32(data+i+1,item_size), 140 tag, class, item_size); 141 142 ret = usb_hid_report_parse_tag(tag,class,data+i+1, 143 item_size,report_item); 144 usb_log_debug2("ret: %u\n", ret); 145 switch(ret){ 146 case USB_HID_NEW_REPORT_ITEM: 147 // store report item to report and create the new one 148 usb_log_debug("\nNEW REPORT ITEM: %X",tag); 149 150 switch(tag) { 151 case USB_HID_REPORT_TAG_INPUT: 152 report_item->offset = offset_input; 153 offset_input += report_item->count * report_item->size; 154 usb_log_debug(" - INPUT\n"); 155 list_append(&(report_item->link), &(parser->input)); 156 break; 157 case USB_HID_REPORT_TAG_OUTPUT: 158 report_item->offset = offset_output; 159 offset_output += report_item->count * report_item->size; 160 usb_log_debug(" - OUTPUT\n"); 161 list_append(&(report_item->link), &(parser->output)); 162 163 break; 164 case USB_HID_REPORT_TAG_FEATURE: 165 report_item->offset = offset_feature; 166 offset_feature += report_item->count * report_item->size; 167 usb_log_debug(" - FEATURE\n"); 168 list_append(&(report_item->link), &(parser->feature)); 169 break; 170 default: 171 usb_log_debug("\tjump over - tag %X\n", tag); 172 break; 173 } 174 175 /* clone current state table to the new item */ 176 if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) { 177 return ENOMEM; 178 } 179 memcpy(new_report_item,report_item, sizeof(usb_hid_report_item_t)); 180 /* reset local items */ 181 new_report_item->usage_minimum = 0; 182 new_report_item->usage_maximum = 0; 183 184 link_initialize(&(new_report_item->link)); 185 report_item = new_report_item; 186 187 break; 188 case USB_HID_REPORT_TAG_PUSH: 189 // push current state to stack 190 // not yet implemented 191 break; 192 case USB_HID_REPORT_TAG_POP: 193 // restore current state from stack 194 // not yet implemented 195 break; 196 197 default: 198 // nothing special to do 199 break; 200 } 201 202 /* jump over the processed block */ 203 i += 1 + USB_HID_ITEM_SIZE(data[i]); 204 } 205 else{ 206 // TBD 207 i += 3 + USB_HID_ITEM_SIZE(data[i+1]); 208 } 209 210 67 /* main parsing loop */ 68 while(0){ 211 69 } 212 70 71 72 uint8_t keys[6]; 73 74 for (i = 0; i < 6; ++i) { 75 keys[i] = data[i]; 76 } 77 78 callbacks->keyboard(keys, 6, 0, arg); 79 80 return EOK; 81 } 82 83 /** Free the HID report parser structure 84 * 85 * @param parser Opaque HID report parser structure 86 * @return Error code 87 */ 88 int usb_hid_free_report_parser(usb_hid_report_parser_t *parser) 89 { 90 213 91 return EOK; 214 92 } … … 238 116 item.size = 8; 239 117 item.count = 6; 240 item.usage_min imum= 0;241 item.usage_max imum= 255;242 item.logical_min imum= 0;243 item.logical_max imum= 255;118 item.usage_min = 0; 119 item.usage_max = 255; 120 item.logical_min = 0; 121 item.logical_max = 255; 244 122 245 123 if (size != 8) { 246 return -1; //ERANGE;124 return ERANGE; 247 125 } 248 126 … … 266 144 int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size) 267 145 { 268 if (size !=1){146 if (size < 1){ 269 147 return -1; 270 148 } 271 149 272 /* used only first five bits, others are only padding*/ 273 *data = leds; 150 data[0] = leds; 274 151 return EOK; 275 152 } 276 153 277 154 /** 278 *279 * @param Tag to parse280 * @param Report descriptor buffer281 * @param Size of data belongs to this tag282 * @param Current report item structe283 * @return Code of action to be done next284 */285 int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,286 usb_hid_report_item_t *report_item)287 {288 int ret;289 290 switch(class){291 case USB_HID_TAG_CLASS_MAIN:292 293 if((ret=usb_hid_report_parse_main_tag(tag,data,item_size,report_item)) == EOK) {294 return USB_HID_NEW_REPORT_ITEM;295 }296 else {297 /*TODO process the error */298 return ret;299 }300 break;301 302 case USB_HID_TAG_CLASS_GLOBAL:303 return usb_hid_report_parse_global_tag(tag,data,item_size,report_item);304 break;305 306 case USB_HID_TAG_CLASS_LOCAL:307 return usb_hid_report_parse_local_tag(tag,data,item_size,report_item);308 break;309 default:310 return USB_HID_NO_ACTION;311 }312 }313 314 /**315 * Parse main tags of report descriptor316 *317 * @param Tag identifier318 * @param Data buffer319 * @param Length of data buffer320 * @param Current state table321 * @return Error code322 */323 324 int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,325 usb_hid_report_item_t *report_item)326 {327 switch(tag)328 {329 case USB_HID_REPORT_TAG_INPUT:330 case USB_HID_REPORT_TAG_OUTPUT:331 case USB_HID_REPORT_TAG_FEATURE:332 report_item->item_flags = *data;333 return EOK;334 break;335 336 case USB_HID_REPORT_TAG_COLLECTION:337 // TODO338 return USB_HID_NO_ACTION;339 break;340 341 case USB_HID_REPORT_TAG_END_COLLECTION:342 /* should be ignored */343 return USB_HID_NO_ACTION;344 break;345 default:346 return USB_HID_NO_ACTION;347 }348 349 return EOK;350 }351 352 /**353 * Parse global tags of report descriptor354 *355 * @param Tag identifier356 * @param Data buffer357 * @param Length of data buffer358 * @param Current state table359 * @return Error code360 */361 362 int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,363 usb_hid_report_item_t *report_item)364 {365 // TODO take care about the bit length of data366 switch(tag)367 {368 case USB_HID_REPORT_TAG_USAGE_PAGE:369 report_item->usage_page = usb_hid_report_tag_data_int32(data,item_size);370 break;371 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:372 report_item->logical_minimum = usb_hid_report_tag_data_int32(data,item_size);373 break;374 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:375 report_item->logical_maximum = usb_hid_report_tag_data_int32(data,item_size);376 break;377 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:378 report_item->physical_minimum = usb_hid_report_tag_data_int32(data,item_size);379 break;380 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:381 report_item->physical_maximum = usb_hid_report_tag_data_int32(data,item_size);382 break;383 case USB_HID_REPORT_TAG_UNIT_EXPONENT:384 report_item->unit_exponent = usb_hid_report_tag_data_int32(data,item_size);385 break;386 case USB_HID_REPORT_TAG_UNIT:387 report_item->unit = usb_hid_report_tag_data_int32(data,item_size);388 break;389 case USB_HID_REPORT_TAG_REPORT_SIZE:390 report_item->size = usb_hid_report_tag_data_int32(data,item_size);391 break;392 case USB_HID_REPORT_TAG_REPORT_COUNT:393 report_item->count = usb_hid_report_tag_data_int32(data,item_size);394 break;395 case USB_HID_REPORT_TAG_REPORT_ID:396 report_item->id = usb_hid_report_tag_data_int32(data,item_size);397 break;398 case USB_HID_REPORT_TAG_PUSH:399 case USB_HID_REPORT_TAG_POP:400 return tag;401 break;402 403 default:404 return USB_HID_NO_ACTION;405 }406 407 return EOK;408 }409 410 /**411 * Parse local tags of report descriptor412 *413 * @param Tag identifier414 * @param Data buffer415 * @param Length of data buffer416 * @param Current state table417 * @return Error code418 */419 int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,420 usb_hid_report_item_t *report_item)421 {422 switch(tag)423 {424 case USB_HID_REPORT_TAG_USAGE:425 report_item->usage = usb_hid_report_tag_data_int32(data,item_size);426 break;427 case USB_HID_REPORT_TAG_USAGE_MINIMUM:428 report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size);429 break;430 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:431 report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size);432 break;433 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:434 report_item->designator_index = usb_hid_report_tag_data_int32(data,item_size);435 break;436 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:437 report_item->designator_minimum = usb_hid_report_tag_data_int32(data,item_size);438 break;439 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:440 report_item->designator_maximum = usb_hid_report_tag_data_int32(data,item_size);441 break;442 case USB_HID_REPORT_TAG_STRING_INDEX:443 report_item->string_index = usb_hid_report_tag_data_int32(data,item_size);444 break;445 case USB_HID_REPORT_TAG_STRING_MINIMUM:446 report_item->string_minimum = usb_hid_report_tag_data_int32(data,item_size);447 break;448 case USB_HID_REPORT_TAG_STRING_MAXIMUM:449 report_item->string_maximum = usb_hid_report_tag_data_int32(data,item_size);450 break;451 case USB_HID_REPORT_TAG_DELIMITER:452 report_item->delimiter = usb_hid_report_tag_data_int32(data,item_size);453 break;454 455 default:456 return USB_HID_NO_ACTION;457 }458 459 return EOK;460 }461 462 /**463 * Converts raw data to int32 (thats the maximum length of short item data)464 *465 * @param Data buffer466 * @param Size of buffer467 * @return Converted int32 number468 */469 int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size)470 {471 unsigned int i;472 int32_t result;473 474 result = 0;475 for(i=0; i<size; i++) {476 result = (result | (data[i]) << (i*8));477 }478 479 return result;480 }481 482 483 484 /**485 * Prints content of given list of report items.486 *487 * @param List of report items488 * @return void489 */490 void usb_hid_descriptor_print_list(link_t *head)491 {492 usb_hid_report_item_t *report_item;493 link_t *item;494 495 if(head == NULL || list_empty(head)) {496 usb_log_debug("\tempty\n");497 return;498 }499 500 for(item = head->next; item != head; item = item->next) {501 502 report_item = list_get_instance(item, usb_hid_report_item_t, link);503 504 usb_log_debug("\tOFFSET: %X\n", report_item->offset);505 usb_log_debug("\tCOUNT: %X\n", report_item->count);506 usb_log_debug("\tSIZE: %X\n", report_item->size);507 usb_log_debug("\tCONSTANT/VAR: %X\n", USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags));508 usb_log_debug("\tVARIABLE/ARRAY: %X\n", USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags));509 usb_log_debug("\tUSAGE: %X\n", report_item->usage);510 usb_log_debug("\tUSAGE PAGE: %X\n", report_item->usage_page);511 usb_log_debug("\tLOGMIN: %X\n", report_item->logical_minimum);512 usb_log_debug("\tLOGMAX: %X\n", report_item->logical_maximum);513 usb_log_debug("\tPHYMIN: %X\n", report_item->physical_minimum);514 usb_log_debug("\tPHYMAX: %X\n", report_item->physical_maximum);515 usb_log_debug("\tUSAGEMIN: %X\n", report_item->usage_minimum);516 usb_log_debug("\tUSAGEMAX: %X\n", report_item->usage_maximum);517 518 usb_log_debug("\n");519 520 }521 522 523 }524 /**525 * Prints content of given descriptor in human readable format.526 *527 * @param Parsed descriptor to print528 * @return void529 */530 void usb_hid_descriptor_print(usb_hid_report_parser_t *parser)531 {532 usb_log_debug("INPUT:\n");533 usb_hid_descriptor_print_list(&parser->input);534 535 usb_log_debug("OUTPUT: \n");536 usb_hid_descriptor_print_list(&parser->output);537 538 usb_log_debug("FEATURE:\n");539 usb_hid_descriptor_print_list(&parser->feature);540 541 }542 543 /**544 * Releases whole linked list of report items545 *546 *547 */548 void usb_hid_free_report_list(link_t *head)549 {550 return;551 552 usb_hid_report_item_t *report_item;553 link_t *next;554 555 if(head == NULL || list_empty(head)) {556 return;557 }558 559 next = head->next;560 while(next != head) {561 562 report_item = list_get_instance(next, usb_hid_report_item_t, link);563 next = next->next;564 565 free(report_item);566 }567 568 return;569 570 }571 572 /** Free the HID report parser structure573 *574 * @param parser Opaque HID report parser structure575 * @return Error code576 */577 void usb_hid_free_report_parser(usb_hid_report_parser_t *parser)578 {579 if(parser == NULL){580 return;581 }582 583 usb_hid_free_report_list(&parser->input);584 usb_hid_free_report_list(&parser->output);585 usb_hid_free_report_list(&parser->feature);586 587 return;588 }589 590 /** Parse and act upon a HID report.591 *592 * @see usb_hid_parse_report_descriptor593 *594 * @param parser Opaque HID report parser structure.595 * @param data Data for the report.596 * @param callbacks Callbacks for report actions.597 * @param arg Custom argument (passed through to the callbacks).598 * @return Error code.599 */600 int usb_hid_parse_report(const usb_hid_report_parser_t *parser,601 const uint8_t *data, size_t size,602 const usb_hid_report_in_callbacks_t *callbacks, void *arg)603 {604 /*605 *606 * only key codes (usage page 0x07) will be processed607 * other usages will be ignored608 */609 link_t *list_item;610 usb_hid_report_item_t *item;611 uint8_t *keys;612 uint8_t item_value;613 size_t key_count=0;614 size_t i=0;615 size_t j=0;616 617 // get the size of result keycodes array618 usb_hid_report_path_t path;619 path.usage_page = BAD_HACK_USAGE_PAGE;620 key_count = usb_hid_report_input_length(parser, &path);621 622 if(!(keys = malloc(sizeof(uint8_t) * key_count))){623 return ENOMEM;624 }625 626 // read data627 list_item = parser->input.next;628 while(list_item != &(parser->input)) {629 630 item = list_get_instance(list_item, usb_hid_report_item_t, link);631 if(!USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) &&632 (item->usage_page == path.usage_page)) {633 for(j=0; j<(size_t)(item->count); j++) {634 if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) ||635 ((item->usage_minimum == 0) && (item->usage_maximum == 0))) {636 // variable item637 keys[i++] = usb_hid_translate_data(item, data,j);638 }639 else {640 // bitmapa641 if((item_value = usb_hid_translate_data(item, data, j)) != 0) {642 keys[i++] = j + item->usage_minimum;643 }644 else {645 keys[i++] = 0;646 }647 }648 }649 }650 list_item = list_item->next;651 }652 653 callbacks->keyboard(keys, key_count, 0, arg);654 655 free(keys);656 return EOK;657 658 }659 660 661 int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j)662 {663 int resolution;664 int offset;665 int part_size;666 667 int32_t value;668 int32_t mask;669 const uint8_t *foo;670 671 // now only common numbers llowed672 if(item->size > 32) {673 return 0;674 }675 676 if((item->physical_minimum == 0) && (item->physical_maximum == 0)) {677 item->physical_minimum = item->logical_minimum;678 item->physical_maximum = item->logical_maximum;679 }680 681 if(item->physical_maximum == item->physical_minimum){682 resolution = 1;683 }684 else {685 resolution = (item->logical_maximum - item->logical_minimum) /686 ((item->physical_maximum - item->physical_minimum) *687 (usb_pow(10,(item->unit_exponent))));688 }689 offset = item->offset + (j * item->size);690 691 // FIXME692 if((offset/8) != ((offset+item->size)/8)) {693 usb_log_debug2("offset %d\n", offset);694 695 part_size = ((offset+item->size)%8);696 usb_log_debug2("part size %d\n",part_size);697 698 // the higher one699 foo = data+(offset/8);700 mask = ((1 << (item->size-part_size))-1);701 value = (*foo & mask) << part_size;702 703 usb_log_debug2("hfoo %x\n", *foo);704 usb_log_debug2("hmaska %x\n", mask);705 usb_log_debug2("hval %d\n", value);706 707 // the lower one708 foo = data+((offset+item->size)/8);709 mask = ((1 << part_size)-1) << (8-part_size);710 value += ((*foo & mask) >> (8-part_size));711 712 usb_log_debug2("lfoo %x\n", *foo);713 usb_log_debug2("lmaska %x\n", mask);714 usb_log_debug2("lval %d\n", ((*foo & mask) >> (8-(item->size-part_size))));715 usb_log_debug2("val %d\n", value);716 717 718 }719 else {720 foo = data+(offset/8);721 mask = ((1 << item->size)-1) << (8-((offset%8)+item->size));722 value = (*foo & mask) >> (8-((offset%8)+item->size));723 724 usb_log_debug2("offset %d\n", offset);725 726 usb_log_debug2("foo %x\n", *foo);727 usb_log_debug2("maska %x\n", mask);728 usb_log_debug2("val %d\n", value);729 }730 731 usb_log_debug2("---\n\n");732 733 return (int)(((value - item->logical_minimum) / resolution) + item->physical_minimum);734 735 }736 737 int usb_hid_report_input_length(const usb_hid_report_parser_t *parser,738 const usb_hid_report_path_t *path)739 {740 int ret = 0;741 link_t *item;742 usb_hid_report_item_t *report_item;743 744 item = (&parser->input)->next;745 while(&parser->input != item) {746 report_item = list_get_instance(item, usb_hid_report_item_t, link);747 if(!USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags) &&748 (report_item->usage_page == path->usage_page)) {749 ret += report_item->count;750 }751 752 item = item->next;753 }754 755 return ret;756 }757 758 759 760 /**761 155 * @} 762 156 */
Note:
See TracChangeset
for help on using the changeset viewer.