source: mainline/uspace/lib/usb/src/hidparser.c@ 96bfe76

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 96bfe76 was 96bfe76, checked in by Matej Klonfar <maklf@…>, 14 years ago

Output report API

  • Property mode set to 100644
File size: 26.6 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusb
30 * @{
31 */
32/** @file
33 * @brief HID parser implementation.
34 */
35#include <usb/classes/hidparser.h>
36#include <errno.h>
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 1
43#define USB_HID_NO_ACTION 2
44#define USB_HID_UNKNOWN_TAG -99
45
46#define BAD_HACK_USAGE_PAGE 0x07
47
48int 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, usb_hid_report_path_t *usage_path);
50int 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, usb_hid_report_path_t *usage_path);
52int 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, usb_hid_report_path_t *usage_path);
54int 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, usb_hid_report_path_t *usage_path);
56
57void usb_hid_descriptor_print_list(link_t *head);
58int usb_hid_report_reset_local_items();
59void usb_hid_free_report_list(link_t *head);
60int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size);
61inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
62int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j);
63int usb_pow(int a, int b);
64
65
66int usb_pow(int a, int b)
67{
68 switch(b) {
69 case 0:
70 return 1;
71 break;
72 case 1:
73 return a;
74 break;
75 default:
76 return a * usb_pow(a, b-1);
77 break;
78 }
79}
80
81/**
82 *
83 */
84int usb_hid_parser_init(usb_hid_report_parser_t *parser)
85{
86 if(parser == NULL) {
87 return EINVAL;
88 }
89
90 list_initialize(&(parser->input));
91 list_initialize(&(parser->output));
92 list_initialize(&(parser->feature));
93
94 return EOK;
95}
96
97
98/** Parse HID report descriptor.
99 *
100 * @param parser Opaque HID report parser structure.
101 * @param data Data describing the report.
102 * @return Error code.
103 */
104int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser,
105 const uint8_t *data, size_t size)
106{
107 size_t i=0;
108 uint8_t tag=0;
109 uint8_t item_size=0;
110 int class=0;
111 int ret;
112 usb_hid_report_item_t *report_item=0;
113 usb_hid_report_item_t *new_report_item;
114 usb_hid_report_path_t *usage_path;
115 usb_hid_report_path_t *tmp_usage_path;
116
117 size_t offset_input=0;
118 size_t offset_output=0;
119 size_t offset_feature=0;
120
121
122 /* parser structure initialization*/
123 if(usb_hid_parser_init(parser) != EOK) {
124 return EINVAL;
125 }
126
127
128 /*report item initialization*/
129 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
130 return ENOMEM;
131 }
132 memset(report_item, 0, sizeof(usb_hid_report_item_t));
133 list_initialize(&(report_item->link));
134
135 /* usage path context initialization */
136 if(!(usage_path=usb_hid_report_path())){
137 return ENOMEM;
138 }
139
140 while(i<size){
141 if(!USB_HID_ITEM_IS_LONG(data[i])){
142
143 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
144 return EINVAL; // TODO ERROR CODE
145 }
146
147 tag = USB_HID_ITEM_TAG(data[i]);
148 item_size = USB_HID_ITEM_SIZE(data[i]);
149 class = USB_HID_ITEM_TAG_CLASS(data[i]);
150
151 usb_log_debug2(
152 "i(%u) data(%X) value(%X): TAG %u, class %u, size %u - ", i,
153 data[i], usb_hid_report_tag_data_int32(data+i+1,item_size),
154 tag, class, item_size);
155
156 ret = usb_hid_report_parse_tag(tag,class,data+i+1,
157 item_size,report_item, usage_path);
158 usb_log_debug2("ret: %u\n", ret);
159 switch(ret){
160 case USB_HID_NEW_REPORT_ITEM:
161 // store report item to report and create the new one
162 usb_log_debug("\nNEW REPORT ITEM: %X",ret);
163
164 // store current usage path
165 report_item->usage_path = usage_path;
166
167 // clone path to the new one
168 tmp_usage_path = usb_hid_report_path_clone(usage_path);
169
170 // swap
171 usage_path = tmp_usage_path;
172 tmp_usage_path = NULL;
173
174
175 switch(tag) {
176 case USB_HID_REPORT_TAG_INPUT:
177 report_item->offset = offset_input;
178 offset_input += report_item->count * report_item->size;
179 usb_log_debug(" - INPUT\n");
180 list_append(&(report_item->link), &(parser->input));
181 break;
182 case USB_HID_REPORT_TAG_OUTPUT:
183 report_item->offset = offset_output;
184 offset_output += report_item->count * report_item->size;
185 usb_log_debug(" - OUTPUT\n");
186 list_append(&(report_item->link), &(parser->output));
187
188 break;
189 case USB_HID_REPORT_TAG_FEATURE:
190 report_item->offset = offset_feature;
191 offset_feature += report_item->count * report_item->size;
192 usb_log_debug(" - FEATURE\n");
193 list_append(&(report_item->link), &(parser->feature));
194 break;
195 default:
196 usb_log_debug("\tjump over - tag %X\n", tag);
197 break;
198 }
199
200 /* clone current state table to the new item */
201 if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
202 return ENOMEM;
203 }
204 memcpy(new_report_item,report_item, sizeof(usb_hid_report_item_t));
205 /* reset local items */
206 new_report_item->usage_minimum = 0;
207 new_report_item->usage_maximum = 0;
208
209 link_initialize(&(new_report_item->link));
210 report_item = new_report_item;
211
212 break;
213 case USB_HID_REPORT_TAG_PUSH:
214 // push current state to stack
215 // not yet implemented
216 break;
217 case USB_HID_REPORT_TAG_POP:
218 // restore current state from stack
219 // not yet implemented
220 break;
221
222 default:
223 // nothing special to do
224 break;
225 }
226
227 /* jump over the processed block */
228 i += 1 + USB_HID_ITEM_SIZE(data[i]);
229 }
230 else{
231 // TBD
232 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
233 }
234
235
236 }
237
238 return EOK;
239}
240
241
242/**
243 * Parse input report.
244 *
245 * @param data Data for report
246 * @param size Size of report
247 * @param callbacks Callbacks for report actions
248 * @param arg Custom arguments
249 *
250 * @return Error code
251 */
252int usb_hid_boot_keyboard_input_report(const uint8_t *data, size_t size,
253 const usb_hid_report_in_callbacks_t *callbacks, void *arg)
254{
255 int i;
256 usb_hid_report_item_t item;
257
258 /* fill item due to the boot protocol report descriptor */
259 // modifier keys are in the first byte
260 uint8_t modifiers = data[0];
261
262 item.offset = 2; /* second byte is reserved */
263 item.size = 8;
264 item.count = 6;
265 item.usage_minimum = 0;
266 item.usage_maximum = 255;
267 item.logical_minimum = 0;
268 item.logical_maximum = 255;
269
270 if (size != 8) {
271 return -1; //ERANGE;
272 }
273
274 uint8_t keys[6];
275 for (i = 0; i < item.count; i++) {
276 keys[i] = data[i + item.offset];
277 }
278
279 callbacks->keyboard(keys, 6, modifiers, arg);
280 return EOK;
281}
282
283/**
284 * Makes output report for keyboard boot protocol
285 *
286 * @param leds
287 * @param output Output report data buffer
288 * @param size Size of the output buffer
289 * @return Error code
290 */
291int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size)
292{
293 if(size != 1){
294 return -1;
295 }
296
297 /* used only first five bits, others are only padding*/
298 *data = leds;
299 return EOK;
300}
301
302/**
303 *
304 * @param Tag to parse
305 * @param Report descriptor buffer
306 * @param Size of data belongs to this tag
307 * @param Current report item structe
308 * @return Code of action to be done next
309 */
310int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
311 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
312{
313 int ret;
314
315 switch(class){
316 case USB_HID_TAG_CLASS_MAIN:
317
318 if((ret=usb_hid_report_parse_main_tag(tag,data,item_size,report_item, usage_path)) == EOK) {
319 return USB_HID_NEW_REPORT_ITEM;
320 }
321 else {
322 /*TODO process the error */
323 return ret;
324 }
325 break;
326
327 case USB_HID_TAG_CLASS_GLOBAL:
328 return usb_hid_report_parse_global_tag(tag,data,item_size,report_item, usage_path);
329 break;
330
331 case USB_HID_TAG_CLASS_LOCAL:
332 return usb_hid_report_parse_local_tag(tag,data,item_size,report_item, usage_path);
333 break;
334 default:
335 return USB_HID_NO_ACTION;
336 }
337}
338
339/**
340 * Parse main tags of report descriptor
341 *
342 * @param Tag identifier
343 * @param Data buffer
344 * @param Length of data buffer
345 * @param Current state table
346 * @return Error code
347 */
348
349int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
350 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
351{
352 switch(tag)
353 {
354 case USB_HID_REPORT_TAG_INPUT:
355 case USB_HID_REPORT_TAG_OUTPUT:
356 case USB_HID_REPORT_TAG_FEATURE:
357 report_item->item_flags = *data;
358 return EOK;
359 break;
360
361 case USB_HID_REPORT_TAG_COLLECTION:
362 usb_hid_report_path_append_item(usage_path, 0, 0);
363
364 return USB_HID_NO_ACTION;
365 break;
366
367 case USB_HID_REPORT_TAG_END_COLLECTION:
368 // TODO
369 // znici posledni uroven ve vsech usage paths
370 // otazka jestli nema nicit dve, respektive novou posledni vynulovat?
371 usb_hid_report_remove_last_item(usage_path);
372 return USB_HID_NO_ACTION;
373 break;
374 default:
375 return USB_HID_NO_ACTION;
376 }
377
378 return EOK;
379}
380
381/**
382 * Parse global tags of report descriptor
383 *
384 * @param Tag identifier
385 * @param Data buffer
386 * @param Length of data buffer
387 * @param Current state table
388 * @return Error code
389 */
390
391int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
392 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
393{
394 // TODO take care about the bit length of data
395 switch(tag)
396 {
397 case USB_HID_REPORT_TAG_USAGE_PAGE:
398 // zmeni to jenom v poslednim poli aktualni usage path
399 usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_GLOBAL,
400 usb_hid_report_tag_data_int32(data,item_size));
401 break;
402 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
403 report_item->logical_minimum = usb_hid_report_tag_data_int32(data,item_size);
404 break;
405 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
406 report_item->logical_maximum = usb_hid_report_tag_data_int32(data,item_size);
407 break;
408 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
409 report_item->physical_minimum = usb_hid_report_tag_data_int32(data,item_size);
410 break;
411 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
412 report_item->physical_maximum = usb_hid_report_tag_data_int32(data,item_size);
413 break;
414 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
415 report_item->unit_exponent = usb_hid_report_tag_data_int32(data,item_size);
416 break;
417 case USB_HID_REPORT_TAG_UNIT:
418 report_item->unit = usb_hid_report_tag_data_int32(data,item_size);
419 break;
420 case USB_HID_REPORT_TAG_REPORT_SIZE:
421 report_item->size = usb_hid_report_tag_data_int32(data,item_size);
422 break;
423 case USB_HID_REPORT_TAG_REPORT_COUNT:
424 report_item->count = usb_hid_report_tag_data_int32(data,item_size);
425 break;
426 case USB_HID_REPORT_TAG_REPORT_ID:
427 report_item->id = usb_hid_report_tag_data_int32(data,item_size);
428 break;
429 case USB_HID_REPORT_TAG_PUSH:
430 case USB_HID_REPORT_TAG_POP:
431 return tag;
432 break;
433
434 default:
435 return USB_HID_NO_ACTION;
436 }
437
438 return EOK;
439}
440
441/**
442 * Parse local tags of report descriptor
443 *
444 * @param Tag identifier
445 * @param Data buffer
446 * @param Length of data buffer
447 * @param Current state table
448 * @return Error code
449 */
450int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
451 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
452{
453 switch(tag)
454 {
455 case USB_HID_REPORT_TAG_USAGE:
456 usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_LOCAL,
457 usb_hid_report_tag_data_int32(data,item_size));
458 break;
459 case USB_HID_REPORT_TAG_USAGE_MINIMUM:
460 report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size);
461 break;
462 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
463 report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size);
464 break;
465 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
466 report_item->designator_index = usb_hid_report_tag_data_int32(data,item_size);
467 break;
468 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
469 report_item->designator_minimum = usb_hid_report_tag_data_int32(data,item_size);
470 break;
471 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
472 report_item->designator_maximum = usb_hid_report_tag_data_int32(data,item_size);
473 break;
474 case USB_HID_REPORT_TAG_STRING_INDEX:
475 report_item->string_index = usb_hid_report_tag_data_int32(data,item_size);
476 break;
477 case USB_HID_REPORT_TAG_STRING_MINIMUM:
478 report_item->string_minimum = usb_hid_report_tag_data_int32(data,item_size);
479 break;
480 case USB_HID_REPORT_TAG_STRING_MAXIMUM:
481 report_item->string_maximum = usb_hid_report_tag_data_int32(data,item_size);
482 break;
483 case USB_HID_REPORT_TAG_DELIMITER:
484 report_item->delimiter = usb_hid_report_tag_data_int32(data,item_size);
485 break;
486
487 default:
488 return USB_HID_NO_ACTION;
489 }
490
491 return EOK;
492}
493
494/**
495 * Converts raw data to int32 (thats the maximum length of short item data)
496 *
497 * @param Data buffer
498 * @param Size of buffer
499 * @return Converted int32 number
500 */
501int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size)
502{
503 unsigned int i;
504 int32_t result;
505
506 result = 0;
507 for(i=0; i<size; i++) {
508 result = (result | (data[i]) << (i*8));
509 }
510
511 return result;
512}
513
514
515
516/**
517 * Prints content of given list of report items.
518 *
519 * @param List of report items
520 * @return void
521 */
522void usb_hid_descriptor_print_list(link_t *head)
523{
524 usb_hid_report_item_t *report_item;
525 usb_hid_report_usage_path_t *path_item;
526 link_t *path;
527 link_t *item;
528
529 if(head == NULL || list_empty(head)) {
530 usb_log_debug("\tempty\n");
531 return;
532 }
533
534 for(item = head->next; item != head; item = item->next) {
535
536 report_item = list_get_instance(item, usb_hid_report_item_t, link);
537
538 usb_log_debug("\tOFFSET: %X\n", report_item->offset);
539 usb_log_debug("\tCOUNT: %X\n", report_item->count);
540 usb_log_debug("\tSIZE: %X\n", report_item->size);
541 usb_log_debug("\tCONSTANT/VAR: %X\n", USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags));
542 usb_log_debug("\tVARIABLE/ARRAY: %X\n", USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags));
543 usb_log_debug("\tUSAGE PATH:\n");
544
545 path = report_item->usage_path->link.next;
546 while(path != &report_item->usage_path->link) {
547 path_item = list_get_instance(path, usb_hid_report_usage_path_t, link);
548 usb_log_debug("\t\tUSAGE PAGE: %X, USAGE: %X\n", path_item->usage_page, path_item->usage);
549 path = path->next;
550 }
551
552
553// usb_log_debug("\tUSAGE: %X\n", report_item->usage);
554// usb_log_debug("\tUSAGE PAGE: %X\n", report_item->usage_page);
555 usb_log_debug("\tLOGMIN: %X\n", report_item->logical_minimum);
556 usb_log_debug("\tLOGMAX: %X\n", report_item->logical_maximum);
557 usb_log_debug("\tPHYMIN: %X\n", report_item->physical_minimum);
558 usb_log_debug("\tPHYMAX: %X\n", report_item->physical_maximum);
559 usb_log_debug("\tUSAGEMIN: %X\n", report_item->usage_minimum);
560 usb_log_debug("\tUSAGEMAX: %X\n", report_item->usage_maximum);
561
562 usb_log_debug("\n");
563
564 }
565
566
567}
568/**
569 * Prints content of given descriptor in human readable format.
570 *
571 * @param Parsed descriptor to print
572 * @return void
573 */
574void usb_hid_descriptor_print(usb_hid_report_parser_t *parser)
575{
576 if(parser == NULL) {
577 return;
578 }
579
580 usb_log_debug("INPUT:\n");
581 usb_hid_descriptor_print_list(&parser->input);
582
583 usb_log_debug("OUTPUT: \n");
584 usb_hid_descriptor_print_list(&parser->output);
585
586 usb_log_debug("FEATURE:\n");
587 usb_hid_descriptor_print_list(&parser->feature);
588
589}
590
591/**
592 * Releases whole linked list of report items
593 *
594 *
595 */
596void usb_hid_free_report_list(link_t *head)
597{
598 return;
599
600 usb_hid_report_item_t *report_item;
601 link_t *next;
602
603 if(head == NULL || list_empty(head)) {
604 return;
605 }
606
607 next = head->next;
608 while(next != head) {
609
610 report_item = list_get_instance(next, usb_hid_report_item_t, link);
611
612 while(!list_empty(&report_item->usage_path->link)) {
613 usb_hid_report_remove_last_item(report_item->usage_path);
614 }
615
616
617 next = next->next;
618
619 free(report_item);
620 }
621
622 return;
623
624}
625
626/** Free the HID report parser structure
627 *
628 * @param parser Opaque HID report parser structure
629 * @return Error code
630 */
631void usb_hid_free_report_parser(usb_hid_report_parser_t *parser)
632{
633 if(parser == NULL){
634 return;
635 }
636
637 usb_hid_free_report_list(&parser->input);
638 usb_hid_free_report_list(&parser->output);
639 usb_hid_free_report_list(&parser->feature);
640
641 return;
642}
643
644/** Parse and act upon a HID report.
645 *
646 * @see usb_hid_parse_report_descriptor
647 *
648 * @param parser Opaque HID report parser structure.
649 * @param data Data for the report.
650 * @param callbacks Callbacks for report actions.
651 * @param arg Custom argument (passed through to the callbacks).
652 * @return Error code.
653 */
654int usb_hid_parse_report(const usb_hid_report_parser_t *parser,
655 const uint8_t *data, size_t size,
656 usb_hid_report_path_t *path, int flags,
657 const usb_hid_report_in_callbacks_t *callbacks, void *arg)
658{
659 /*
660 *
661 * only key codes (usage page 0x07) will be processed
662 * other usages will be ignored
663 */
664 link_t *list_item;
665 usb_hid_report_item_t *item;
666 uint8_t *keys;
667 uint8_t item_value;
668 size_t key_count=0;
669 size_t i=0;
670 size_t j=0;
671
672 if(parser == NULL) {
673 return EINVAL;
674 }
675
676
677 // get the size of result keycodes array
678 key_count = usb_hid_report_input_length(parser, path, flags);
679
680 if(!(keys = malloc(sizeof(uint8_t) * key_count))){
681 return ENOMEM;
682 }
683
684 // read data
685 list_item = parser->input.next;
686 while(list_item != &(parser->input)) {
687
688 item = list_get_instance(list_item, usb_hid_report_item_t, link);
689 if(!USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) &&
690 (usb_hid_report_compare_usage_path(item->usage_path, path, flags) == EOK)) {
691 for(j=0; j<(size_t)(item->count); j++) {
692 if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) ||
693 ((item->usage_minimum == 0) && (item->usage_maximum == 0))) {
694 // variable item
695 keys[i++] = usb_hid_translate_data(item, data,j);
696 }
697 else {
698 // bitmapa
699 if((item_value = usb_hid_translate_data(item, data, j)) != 0) {
700 keys[i++] = (item->count - 1 - j) + item->usage_minimum;
701 }
702 else {
703 keys[i++] = 0;
704 }
705 }
706 }
707 }
708 list_item = list_item->next;
709 }
710
711 callbacks->keyboard(keys, key_count, 0, arg);
712
713 free(keys);
714 return EOK;
715
716}
717
718
719int usb_hid_translate_data(usb_hid_report_item_t *item, const uint8_t *data, size_t j)
720{
721 int resolution;
722 int offset;
723 int part_size;
724
725 int32_t value;
726 int32_t mask;
727 const uint8_t *foo;
728
729 // now only common numbers llowed
730 if(item->size > 32) {
731 return 0;
732 }
733
734 if((item->physical_minimum == 0) && (item->physical_maximum == 0)) {
735 item->physical_minimum = item->logical_minimum;
736 item->physical_maximum = item->logical_maximum;
737 }
738
739 if(item->physical_maximum == item->physical_minimum){
740 resolution = 1;
741 }
742 else {
743 resolution = (item->logical_maximum - item->logical_minimum) /
744 ((item->physical_maximum - item->physical_minimum) *
745 (usb_pow(10,(item->unit_exponent))));
746 }
747 offset = item->offset + (j * item->size);
748
749 // FIXME
750 if((offset/8) != ((offset+item->size)/8)) {
751 usb_log_debug2("offset %d\n", offset);
752
753 part_size = ((offset+item->size)%8);
754 usb_log_debug2("part size %d\n",part_size);
755
756 // the higher one
757 foo = data+(offset/8);
758 mask = ((1 << (item->size-part_size))-1);
759 value = (*foo & mask) << part_size;
760
761 usb_log_debug2("hfoo %x\n", *foo);
762 usb_log_debug2("hmaska %x\n", mask);
763 usb_log_debug2("hval %d\n", value);
764
765 // the lower one
766 foo = data+((offset+item->size)/8);
767 mask = ((1 << part_size)-1) << (8-part_size);
768 value += ((*foo & mask) >> (8-part_size));
769
770 usb_log_debug2("lfoo %x\n", *foo);
771 usb_log_debug2("lmaska %x\n", mask);
772 usb_log_debug2("lval %d\n", ((*foo & mask) >> (8-(item->size-part_size))));
773 usb_log_debug2("val %d\n", value);
774
775
776 }
777 else {
778 foo = data+(offset/8);
779 mask = ((1 << item->size)-1) << (8-((offset%8)+item->size));
780 value = (*foo & mask) >> (8-((offset%8)+item->size));
781
782 usb_log_debug2("offset %d\n", offset);
783
784 usb_log_debug2("foo %x\n", *foo);
785 usb_log_debug2("maska %x\n", mask);
786 usb_log_debug2("val %d\n", value);
787 }
788
789 usb_log_debug2("---\n\n");
790
791 return (int)(((value - item->logical_minimum) / resolution) + item->physical_minimum);
792
793}
794
795size_t usb_hid_report_input_length(const usb_hid_report_parser_t *parser,
796 usb_hid_report_path_t *path, int flags)
797{
798 int ret = 0;
799 link_t *item;
800 usb_hid_report_item_t *report_item;
801
802 if(parser == NULL) {
803 return EINVAL;
804 }
805
806 item = (&parser->input)->next;
807 while(&parser->input != item) {
808 report_item = list_get_instance(item, usb_hid_report_item_t, link);
809 if(!USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags) &&
810 (usb_hid_report_compare_usage_path(report_item->usage_path, path, flags) == EOK)) {
811 ret += report_item->count;
812 }
813
814 item = item->next;
815 }
816
817 return ret;
818}
819
820
821/**
822 *
823 */
824int usb_hid_report_path_append_item(usb_hid_report_path_t *usage_path,
825 int32_t usage_page, int32_t usage)
826{
827 usb_hid_report_usage_path_t *item;
828
829 if(!(item=malloc(sizeof(usb_hid_report_usage_path_t)))) {
830 return ENOMEM;
831 }
832 list_initialize(&item->link);
833
834 item->usage = usage;
835 item->usage_page = usage_page;
836
837 list_append (&usage_path->link, &item->link);
838 usage_path->depth++;
839 return EOK;
840}
841
842/**
843 *
844 */
845void usb_hid_report_remove_last_item(usb_hid_report_path_t *usage_path)
846{
847 usb_hid_report_usage_path_t *item;
848
849 if(!list_empty(&usage_path->link)){
850 item = list_get_instance(usage_path->link.prev, usb_hid_report_usage_path_t, link);
851 list_remove(usage_path->link.prev);
852 usage_path->depth--;
853 free(item);
854 }
855}
856
857/**
858 *
859 */
860void usb_hid_report_null_last_item(usb_hid_report_path_t *usage_path)
861{
862 usb_hid_report_usage_path_t *item;
863
864 if(!list_empty(&usage_path->link)){
865 item = list_get_instance(usage_path->link.prev, usb_hid_report_usage_path_t, link);
866 memset(item, 0, sizeof(usb_hid_report_usage_path_t));
867 }
868}
869
870/**
871 *
872 */
873void usb_hid_report_set_last_item(usb_hid_report_path_t *usage_path, int32_t tag, int32_t data)
874{
875 usb_hid_report_usage_path_t *item;
876
877 if(!list_empty(&usage_path->link)){
878 item = list_get_instance(usage_path->link.prev, usb_hid_report_usage_path_t, link);
879
880 switch(tag) {
881 case USB_HID_TAG_CLASS_GLOBAL:
882 item->usage_page = data;
883 break;
884 case USB_HID_TAG_CLASS_LOCAL:
885 item->usage = data;
886 break;
887 }
888 }
889
890}
891
892/**
893 *
894 */
895int usb_hid_report_compare_usage_path(usb_hid_report_path_t *report_path,
896 usb_hid_report_path_t *path,
897 int flags)
898{
899 usb_hid_report_usage_path_t *report_item;
900 usb_hid_report_usage_path_t *path_item;
901
902 link_t *report_link;
903 link_t *path_link;
904
905 int only_page;
906
907 if(path->depth == 0){
908 return EOK;
909 }
910
911
912 if((only_page = flags & USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY) != 0){
913 flags -= USB_HID_PATH_COMPARE_USAGE_PAGE_ONLY;
914 }
915
916 switch(flags){
917 /* path must be completly identical */
918 case USB_HID_PATH_COMPARE_STRICT:
919 if(report_path->depth != path->depth){
920 return 1;
921 }
922
923 report_link = report_path->link.next;
924 path_link = path->link.next;
925
926 while((report_link != &report_path->link) && (path_link != &path->link)) {
927 report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
928 path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
929
930 if((report_item->usage_page != path_item->usage_page) ||
931 ((only_page == 0) && (report_item->usage != path_item->usage))) {
932 return 1;
933 } else {
934 report_link = report_link->next;
935 path_link = path_link->next;
936 }
937
938 }
939
940 if((report_link == &report_path->link) && (path_link == &path->link)) {
941 return EOK;
942 }
943 else {
944 return 1;
945 }
946 break;
947
948 /* compare with only the end of path*/
949 case USB_HID_PATH_COMPARE_END:
950 report_link = report_path->link.prev;
951 path_link = path->link.prev;
952
953 if(list_empty(&path->link)){
954 return EOK;
955 }
956
957 while((report_link != &report_path->link) && (path_link != &path->link)) {
958 report_item = list_get_instance(report_link, usb_hid_report_usage_path_t, link);
959 path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
960
961 if((report_item->usage_page != path_item->usage_page) ||
962 ((only_page == 0) && (report_item->usage != path_item->usage))) {
963 return 1;
964 } else {
965 report_link = report_link->prev;
966 path_link = path_link->prev;
967 }
968
969 }
970
971 if(path_link == &path->link) {
972 return EOK;
973 }
974 else {
975 return 1;
976 }
977
978 break;
979
980 default:
981 return EINVAL;
982 }
983
984
985
986
987}
988
989/**
990 *
991 */
992usb_hid_report_path_t *usb_hid_report_path(void)
993{
994 usb_hid_report_path_t *path;
995 path = malloc(sizeof(usb_hid_report_path_t));
996 if(!path){
997 return NULL;
998 }
999 else {
1000 path->depth = 0;
1001 list_initialize(&path->link);
1002 return path;
1003 }
1004}
1005
1006/**
1007 *
1008 */
1009void usb_hid_report_path_free(usb_hid_report_path_t *path)
1010{
1011 while(!list_empty(&path->link)){
1012 usb_hid_report_remove_last_item(path);
1013 }
1014}
1015
1016
1017/**
1018 * Clone content of given usage path to the new one
1019 *
1020 */
1021usb_hid_report_path_t *usb_hid_report_path_clone(usb_hid_report_path_t *usage_path)
1022{
1023 usb_hid_report_usage_path_t *path_item;
1024 link_t *path_link;
1025 usb_hid_report_path_t *new_usage_path = usb_hid_report_path ();
1026
1027 if(new_usage_path == NULL){
1028 return NULL;
1029 }
1030
1031 if(list_empty(&usage_path->link)){
1032 return new_usage_path;
1033 }
1034
1035 path_link = usage_path->link.next;
1036 while(path_link != &usage_path->link) {
1037 path_item = list_get_instance(path_link, usb_hid_report_usage_path_t, link);
1038 usb_hid_report_path_append_item (new_usage_path, path_item->usage_page, path_item->usage);
1039
1040 path_link = path_link->next;
1041 }
1042
1043 return new_usage_path;
1044}
1045
1046
1047/**
1048 * @}
1049 */
Note: See TracBrowser for help on using the repository browser.