source: mainline/uspace/lib/usbhid/src/hiddescriptor.c@ 1bab1c8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1bab1c8 was a1732929, checked in by Ondřej Hlavatý <aearsis@…>, 8 years ago

usb: unified logging

Use logger instead of printf. Logger adds newlines automatically.

  • Property mode set to 100644
File size: 24.8 KB
Line 
1/*
2 * Copyright (c) 2011 Matej Klonfar
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 libusbhid
30 * @{
31 */
32/** @file
33 * HID report descriptor and report data parser implementation.
34 */
35#include <usb/hid/hidparser.h>
36#include <errno.h>
37#include <stdio.h>
38#include <malloc.h>
39#include <mem.h>
40#include <usb/debug.h>
41#include <assert.h>
42
43
44/*
45 * Constants defining current parsing mode for correct parsing of the set of
46 * local tags (usage) enclosed in delimter tags.
47 */
48/**
49 * Second delimiter tag was read. The set of local items (usage) ended.
50 */
51#define OUTSIDE_DELIMITER_SET 0
52
53/**
54 * First delimiter tag was read. The set of local items (usage) started.
55 */
56#define START_DELIMITER_SET 1
57
58/**
59 * Parser is in the set of local items.
60 */
61#define INSIDE_DELIMITER_SET 2
62
63
64
65/** The new report item flag. Used to determine when the item is completly
66 * configured and should be added to the report structure
67 */
68#define USB_HID_NEW_REPORT_ITEM 1
69
70/** No special action after the report descriptor tag is processed should be
71 * done
72 */
73#define USB_HID_NO_ACTION 2
74
75#define USB_HID_RESET_OFFSET 3
76
77/** Unknown tag was founded in report descriptor data*/
78#define USB_HID_UNKNOWN_TAG -99
79
80
81/**
82 * Checks if given collection path is already present in report structure and
83 * inserts it if not.
84 *
85 * @param report Report structure
86 * @param cmp_path The collection path
87 * @return Pointer to the result collection path in report structure.
88 * @retval NULL If some error occurs
89 */
90usb_hid_report_path_t *usb_hid_report_path_try_insert(usb_hid_report_t *report,
91 usb_hid_report_path_t *cmp_path)
92{
93 link_t *path_it = report->collection_paths.head.next;
94 usb_hid_report_path_t *path = NULL;
95
96 if((report == NULL) || (cmp_path == NULL)) {
97 return NULL;
98 }
99
100 while(path_it != &report->collection_paths.head) {
101 path = list_get_instance(path_it, usb_hid_report_path_t,
102 cpath_link);
103
104 if(usb_hid_report_compare_usage_path(path, cmp_path,
105 USB_HID_PATH_COMPARE_STRICT) == EOK){
106 break;
107 }
108 path_it = path_it->next;
109 }
110 if(path_it == &report->collection_paths.head) {
111 path = usb_hid_report_path_clone(cmp_path);
112 if(path == NULL) {
113 return NULL;
114 }
115 list_append(&path->cpath_link, &report->collection_paths);
116 report->collection_paths_count++;
117
118 return path;
119 }
120 else {
121 return list_get_instance(path_it, usb_hid_report_path_t,
122 cpath_link);
123 }
124}
125
126
127/**
128 * Initialize the report descriptor parser structure
129 *
130 * @param parser Report descriptor parser structure
131 * @return Error code
132 * @retval EINVAL If no report structure was given
133 * @retval EOK If report structure was successfully initialized
134 */
135int usb_hid_report_init(usb_hid_report_t *report)
136{
137 if (report == NULL) {
138 return EINVAL;
139 }
140
141 memset(report, 0, sizeof(usb_hid_report_t));
142 list_initialize(&report->reports);
143 list_initialize(&report->collection_paths);
144
145 report->use_report_ids = 0;
146 return EOK;
147}
148
149
150
151/**
152 *
153 *
154 * @param report Report structure in which the new report items should be
155 * stored
156 * @param report_item Current report descriptor's parsing state table
157 * @return Error code
158 * @retval EOK If all fields were successfully append to report
159 * @retval EINVAL If invalid parameters (NULL) was given
160 * @retval ENOMEM If there is no memmory to store new report description
161 *
162 */
163int usb_hid_report_append_fields(usb_hid_report_t *report,
164 usb_hid_report_item_t *report_item) {
165
166 usb_hid_report_field_t *field;
167 int i;
168
169 uint32_t *usages;
170 int usages_used=0;
171
172 if((report == NULL) || (report_item == NULL)) {
173 return EINVAL;
174 }
175
176 if(report_item->usages_count > 0){
177 usages = malloc(sizeof(uint32_t) * report_item->usages_count);
178 memcpy(usages, report_item->usages, sizeof(int32_t) *
179 report_item->usages_count);
180 }
181 else {
182 usages = NULL;
183 }
184
185 usb_hid_report_path_t *path = report_item->usage_path;
186 for(i=0; i<report_item->count; i++){
187
188 field = malloc(sizeof(usb_hid_report_field_t));
189 if(field == NULL) {
190 return ENOMEM;
191 }
192
193 memset(field, 0, sizeof(usb_hid_report_field_t));
194 link_initialize(&field->ritems_link);
195
196 /* fill the attributes */
197 field->logical_minimum = report_item->logical_minimum;
198 field->logical_maximum = report_item->logical_maximum;
199 field->physical_minimum = report_item->physical_minimum;
200 field->physical_maximum = report_item->physical_maximum;
201
202 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0){
203 /*
204 Store usage array. The Correct Usage Page and Usage is
205 depending on data in report and will be filled later
206 */
207 field->usage = 0;
208 field->usage_page = 0; //report_item->usage_page;
209
210 field->usages_count = report_item->usages_count;
211 field->usages = usages;
212 usages_used = 1;
213 }
214 else {
215
216 /* Fill the correct Usage and Usage Page */
217 int32_t usage;
218 if(i < report_item->usages_count) {
219 usage = report_item->usages[i];
220 }
221 else {
222 usage = report_item->usages[
223 report_item->usages_count- 1];
224 }
225
226 if(USB_HID_IS_EXTENDED_USAGE(usage)){
227 field->usage = USB_HID_EXTENDED_USAGE(usage);
228 field->usage_page =
229 USB_HID_EXTENDED_USAGE_PAGE(usage);
230 }
231 else {
232 // should not occur
233 field->usage = usage;
234 field->usage_page = report_item->usage_page;
235 }
236 }
237
238 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_GLOBAL,
239 field->usage_page);
240 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_LOCAL,
241 field->usage);
242
243 field->collection_path =
244 usb_hid_report_path_try_insert(report, path);
245
246 field->size = report_item->size;
247
248 field->offset = report_item->offset + (i * report_item->size);
249
250 if(report->use_report_ids != 0) {
251 field->offset += 8;
252 report->use_report_ids = 1;
253 }
254
255 field->item_flags = report_item->item_flags;
256
257 /* find the right report list*/
258 usb_hid_report_description_t *report_des;
259 report_des = usb_hid_report_find_description(report,
260 report_item->id, report_item->type);
261
262 if(report_des == NULL){
263 report_des = malloc(
264 sizeof(usb_hid_report_description_t));
265 if(report_des == NULL) {
266 return ENOMEM;
267 }
268
269 memset(report_des, 0,
270 sizeof(usb_hid_report_description_t));
271
272 report_des->type = report_item->type;
273 report_des->report_id = report_item->id;
274 if(report_des->report_id != 0) {
275 /* set up the bit length by report_id field */
276 report_des->bit_length = 8;
277 }
278
279 link_initialize (&report_des->reports_link);
280 list_initialize (&report_des->report_items);
281
282 list_append(&report_des->reports_link, &report->reports);
283 report->report_count++;
284 }
285
286 /* append this field to the end of founded report list */
287 list_append(&field->ritems_link, &report_des->report_items);
288
289 /* update the sizes */
290 report_des->bit_length += field->size;
291 report_des->item_length++;
292
293 }
294
295 // free only when not used!!!
296 if(usages && usages_used == 0) {
297 free(usages);
298 }
299
300 return EOK;
301}
302
303/**
304 * Finds description of report with given report_id and of given type in
305 * opaque report structure.
306 *
307 * @param report Opaque structure containing the parsed report descriptor
308 * @param report_id ReportId of report we are searching
309 * @param type Type of report we are searching
310 * @return Pointer to the particular report description
311 * @retval NULL If no description is founded
312 */
313usb_hid_report_description_t * usb_hid_report_find_description(
314 const usb_hid_report_t *report, uint8_t report_id,
315 usb_hid_report_type_t type) {
316
317 if(report == NULL) {
318 return NULL;
319 }
320
321 list_foreach(report->reports, reports_link,
322 usb_hid_report_description_t, report_des) {
323 // if report id not set, return the first of the type
324 if(((report_des->report_id == report_id) || (report_id == 0)) &&
325 (report_des->type == type)) {
326 return report_des;
327 }
328 }
329
330 return NULL;
331}
332
333
334/** Parse HID report descriptor.
335 *
336 * @param parser Opaque HID report parser structure.
337 * @param data Data describing the report.
338 * @return Error code.
339 * @retval ENOMEM If no more memmory is available
340 * @retval EINVAL If invalid data are founded
341 * @retval EOK If report descriptor is successfully parsed
342 */
343int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
344 const uint8_t *data, size_t size)
345{
346 size_t i=0;
347 uint8_t tag=0;
348 uint8_t item_size=0;
349 int class=0;
350 int ret;
351 usb_hid_report_item_t *report_item=0;
352 usb_hid_report_item_t *new_report_item;
353 usb_hid_report_path_t *usage_path;
354
355 size_t offset_input=0;
356 size_t offset_output=0;
357 size_t offset_feature=0;
358
359 link_t *item_link;
360
361 list_t stack;
362 list_initialize(&stack);
363
364 /* parser structure initialization*/
365 if(usb_hid_report_init(report) != EOK) {
366 return EINVAL;
367 }
368
369 /*report item initialization*/
370 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
371 return ENOMEM;
372 }
373 memset(report_item, 0, sizeof(usb_hid_report_item_t));
374 link_initialize(&(report_item->link));
375
376 /* usage path context initialization */
377 if(!(usage_path=usb_hid_report_path())){
378 return ENOMEM;
379 }
380 usb_hid_report_path_append_item(usage_path, 0, 0);
381
382 while(i<size){
383 if(!USB_HID_ITEM_IS_LONG(data[i])){
384
385 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
386 return EINVAL;
387 }
388
389 tag = USB_HID_ITEM_TAG(data[i]);
390 item_size = USB_HID_ITEM_SIZE(data[i]);
391 class = USB_HID_ITEM_TAG_CLASS(data[i]);
392
393 ret = usb_hid_report_parse_tag(tag,class,data+i+1,
394 item_size,report_item, usage_path);
395
396 switch(ret){
397 case USB_HID_NEW_REPORT_ITEM:
398 /* store report item to report and create the
399 * new one store current collection path
400 */
401 report_item->usage_path = usage_path;
402
403 usb_hid_report_path_set_report_id(
404 report_item->usage_path, report_item->id);
405
406 if(report_item->id != 0){
407 report->use_report_ids = 1;
408 }
409
410 switch(tag) {
411 case USB_HID_REPORT_TAG_INPUT:
412 report_item->type =
413 USB_HID_REPORT_TYPE_INPUT;
414
415 report_item->offset = offset_input;
416 offset_input += report_item->count *
417 report_item->size;
418 break;
419
420 case USB_HID_REPORT_TAG_OUTPUT:
421 report_item->type =
422 USB_HID_REPORT_TYPE_OUTPUT;
423
424 report_item->offset = offset_output;
425 offset_output += report_item->count *
426 report_item->size;
427 break;
428
429 case USB_HID_REPORT_TAG_FEATURE:
430 report_item->type =
431 USB_HID_REPORT_TYPE_FEATURE;
432
433 report_item->offset = offset_feature;
434 offset_feature += report_item->count *
435 report_item->size;
436 break;
437
438 default:
439 usb_log_debug2(
440 "\tjump over - tag %X\n", tag);
441 break;
442 }
443
444 /*
445 * append new fields to the report structure
446 */
447 usb_hid_report_append_fields(report,
448 report_item);
449
450 /* reset local items */
451 usb_hid_report_reset_local_items (report_item);
452 break;
453
454 case USB_HID_RESET_OFFSET:
455 offset_input = 0;
456 offset_output = 0;
457 offset_feature = 0;
458 usb_hid_report_path_set_report_id (usage_path,
459 report_item->id);
460 break;
461
462 case USB_HID_REPORT_TAG_PUSH:
463 // push current state to stack
464 new_report_item = usb_hid_report_item_clone(
465 report_item);
466
467 usb_hid_report_path_t *tmp_path =
468 usb_hid_report_path_clone(usage_path);
469
470 new_report_item->usage_path = tmp_path;
471
472 list_prepend (&new_report_item->link, &stack);
473 break;
474 case USB_HID_REPORT_TAG_POP:
475 // restore current state from stack
476 item_link = list_first(&stack);
477 if (item_link == NULL) {
478 return EINVAL;
479 }
480 free(report_item);
481
482 report_item = list_get_instance(item_link,
483 usb_hid_report_item_t, link);
484
485 usb_hid_report_usage_path_t *tmp_usage_path;
486 tmp_usage_path = list_get_instance(
487 report_item->usage_path->cpath_link.prev,
488 usb_hid_report_usage_path_t, rpath_items_link);
489
490 usb_hid_report_set_last_item(usage_path,
491 USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
492
493 usb_hid_report_set_last_item(usage_path,
494 USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
495
496 usb_hid_report_path_free(report_item->usage_path);
497 list_remove (item_link);
498
499 break;
500
501 default:
502 // nothing special to do
503 break;
504 }
505
506 /* jump over the processed block */
507 i += 1 + USB_HID_ITEM_SIZE(data[i]);
508 }
509 else{
510 // TBD
511 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
512 }
513
514
515 }
516
517 return EOK;
518}
519
520
521
522/**
523 * Parse one tag of the report descriptor
524 *
525 * @param Tag to parse
526 * @param Report descriptor buffer
527 * @param Size of data belongs to this tag
528 * @param Current report item structe
529 * @return Code of action to be done next
530 */
531int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
532 size_t item_size, usb_hid_report_item_t *report_item,
533 usb_hid_report_path_t *usage_path) {
534
535 int ret;
536
537 switch(class){
538 case USB_HID_TAG_CLASS_MAIN:
539
540 if((ret=usb_hid_report_parse_main_tag(tag, data, item_size,
541 report_item, usage_path)) == EOK) {
542
543 return USB_HID_NEW_REPORT_ITEM;
544 }
545 else {
546 return ret;
547 }
548 break;
549
550 case USB_HID_TAG_CLASS_GLOBAL:
551 return usb_hid_report_parse_global_tag(tag, data, item_size,
552 report_item, usage_path);
553 break;
554
555 case USB_HID_TAG_CLASS_LOCAL:
556 return usb_hid_report_parse_local_tag(tag, data, item_size,
557 report_item, usage_path);
558 break;
559
560 default:
561 return USB_HID_NO_ACTION;
562 }
563}
564
565/**
566 * Parse main tags of report descriptor
567 *
568 * @param Tag identifier
569 * @param Data buffer
570 * @param Length of data buffer
571 * @param Current state table
572 * @return Error code
573 */
574
575int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data,
576 size_t item_size, usb_hid_report_item_t *report_item,
577 usb_hid_report_path_t *usage_path)
578{
579 usb_hid_report_usage_path_t *path_item;
580
581 switch(tag)
582 {
583 case USB_HID_REPORT_TAG_INPUT:
584 case USB_HID_REPORT_TAG_OUTPUT:
585 case USB_HID_REPORT_TAG_FEATURE:
586 report_item->item_flags = *data;
587 return EOK;
588 break;
589
590 case USB_HID_REPORT_TAG_COLLECTION:
591
592 /* store collection atributes */
593 path_item = list_get_instance(list_first(&usage_path->items),
594 usb_hid_report_usage_path_t, rpath_items_link);
595 path_item->flags = *data;
596
597 /* set last item */
598 usb_hid_report_set_last_item(usage_path,
599 USB_HID_TAG_CLASS_GLOBAL,
600 USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[
601 report_item->usages_count-1]));
602
603 usb_hid_report_set_last_item(usage_path,
604 USB_HID_TAG_CLASS_LOCAL,
605 USB_HID_EXTENDED_USAGE(report_item->usages[
606 report_item->usages_count-1]));
607
608 /* append the new one which will be set by common usage/usage
609 * page */
610 usb_hid_report_path_append_item(usage_path,
611 report_item->usage_page,
612 report_item->usages[report_item->usages_count-1]);
613
614 usb_hid_report_reset_local_items (report_item);
615 return USB_HID_NO_ACTION;
616 break;
617
618 case USB_HID_REPORT_TAG_END_COLLECTION:
619 usb_hid_report_remove_last_item(usage_path);
620 return USB_HID_NO_ACTION;
621 break;
622
623 default:
624 return USB_HID_NO_ACTION;
625 }
626
627 return EOK;
628}
629
630/**
631 * Parse global tags of report descriptor
632 *
633 * @param Tag identifier
634 * @param Data buffer
635 * @param Length of data buffer
636 * @param Current state table
637 * @return Error code
638 */
639int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data,
640 size_t item_size, usb_hid_report_item_t *report_item,
641 usb_hid_report_path_t *usage_path) {
642
643 switch(tag)
644 {
645 case USB_HID_REPORT_TAG_USAGE_PAGE:
646 report_item->usage_page =
647 usb_hid_report_tag_data_uint32(data, item_size);
648 break;
649
650 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
651 report_item->logical_minimum = USB_HID_UINT32_TO_INT32(
652 usb_hid_report_tag_data_uint32(data,item_size),
653 item_size * 8);
654 break;
655
656 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
657 report_item->logical_maximum = USB_HID_UINT32_TO_INT32(
658 usb_hid_report_tag_data_uint32(data,item_size),
659 item_size * 8);
660 break;
661
662 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
663 report_item->physical_minimum = USB_HID_UINT32_TO_INT32(
664 usb_hid_report_tag_data_uint32(data,item_size),
665 item_size * 8);
666 break;
667
668 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
669 report_item->physical_maximum = USB_HID_UINT32_TO_INT32(
670 usb_hid_report_tag_data_uint32(data,item_size),
671 item_size * 8);
672 break;
673
674 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
675 report_item->unit_exponent = usb_hid_report_tag_data_uint32(
676 data,item_size);
677 break;
678
679 case USB_HID_REPORT_TAG_UNIT:
680 report_item->unit = usb_hid_report_tag_data_uint32(
681 data,item_size);
682 break;
683
684 case USB_HID_REPORT_TAG_REPORT_SIZE:
685 report_item->size = usb_hid_report_tag_data_uint32(
686 data,item_size);
687 break;
688
689 case USB_HID_REPORT_TAG_REPORT_COUNT:
690 report_item->count = usb_hid_report_tag_data_uint32(
691 data,item_size);
692 break;
693
694 case USB_HID_REPORT_TAG_REPORT_ID:
695 report_item->id = usb_hid_report_tag_data_uint32(data,
696 item_size);
697 return USB_HID_RESET_OFFSET;
698 break;
699
700 case USB_HID_REPORT_TAG_PUSH:
701 case USB_HID_REPORT_TAG_POP:
702 /*
703 * stack operations are done in top level parsing
704 * function
705 */
706 return tag;
707 break;
708
709 default:
710 return USB_HID_NO_ACTION;
711 }
712
713 return EOK;
714}
715
716/**
717 * Parse local tags of report descriptor
718 *
719 * @param Tag identifier
720 * @param Data buffer
721 * @param Length of data buffer
722 * @param Current state table
723 * @return Error code
724 */
725int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data,
726 size_t item_size, usb_hid_report_item_t *report_item,
727 usb_hid_report_path_t *usage_path)
728{
729 int32_t extended_usage;
730
731 switch (tag) {
732 case USB_HID_REPORT_TAG_USAGE:
733 switch (report_item->in_delimiter) {
734 case INSIDE_DELIMITER_SET:
735 /*
736 * Nothing to do.
737 * We catch only the first one
738 */
739 break;
740
741 case START_DELIMITER_SET:
742 report_item->in_delimiter = INSIDE_DELIMITER_SET;
743 /* Fallthrough */
744 case OUTSIDE_DELIMITER_SET:
745 extended_usage = ((report_item->usage_page) << 16);
746 extended_usage +=
747 usb_hid_report_tag_data_uint32(data, item_size);
748
749 report_item->usages[report_item->usages_count] =
750 extended_usage;
751
752 report_item->usages_count++;
753 break;
754 }
755 break;
756
757 case USB_HID_REPORT_TAG_USAGE_MINIMUM:
758 if (item_size == 3) {
759 /* Usage extended usages */
760 report_item->extended_usage_page =
761 USB_HID_EXTENDED_USAGE_PAGE(
762 usb_hid_report_tag_data_uint32(data, item_size));
763
764
765 report_item->usage_minimum =
766 USB_HID_EXTENDED_USAGE(
767 usb_hid_report_tag_data_uint32(data, item_size));
768 } else {
769 report_item->usage_minimum =
770 usb_hid_report_tag_data_uint32(data, item_size);
771 }
772 break;
773
774 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
775 if (item_size == 3) {
776 if (report_item->extended_usage_page !=
777 USB_HID_EXTENDED_USAGE_PAGE(
778 usb_hid_report_tag_data_uint32(data, item_size))) {
779 return EINVAL;
780 }
781
782 /* Usage extended usages */
783 report_item->extended_usage_page =
784 USB_HID_EXTENDED_USAGE_PAGE(
785 usb_hid_report_tag_data_uint32(data,item_size));
786
787 report_item->usage_maximum =
788 USB_HID_EXTENDED_USAGE(
789 usb_hid_report_tag_data_uint32(data,item_size));
790 } else {
791 report_item->usage_maximum =
792 usb_hid_report_tag_data_uint32(data,item_size);
793 }
794
795 /* Put the records into the usages array */
796 for (int32_t i = report_item->usage_minimum;
797 i <= report_item->usage_maximum; i++) {
798
799 if (report_item->extended_usage_page) {
800 report_item->usages[report_item->usages_count++] =
801 (report_item->extended_usage_page << 16) + i;
802 } else {
803 report_item->usages[report_item->usages_count++] =
804 (report_item->usage_page << 16) + i;
805 }
806 }
807 report_item->extended_usage_page = 0;
808
809 break;
810
811 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
812 report_item->designator_index =
813 usb_hid_report_tag_data_uint32(data, item_size);
814 break;
815
816 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
817 report_item->designator_minimum =
818 usb_hid_report_tag_data_uint32(data, item_size);
819 break;
820
821 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
822 report_item->designator_maximum =
823 usb_hid_report_tag_data_uint32(data, item_size);
824 break;
825
826 case USB_HID_REPORT_TAG_STRING_INDEX:
827 report_item->string_index =
828 usb_hid_report_tag_data_uint32(data, item_size);
829 break;
830
831 case USB_HID_REPORT_TAG_STRING_MINIMUM:
832 report_item->string_minimum =
833 usb_hid_report_tag_data_uint32(data, item_size);
834 break;
835
836 case USB_HID_REPORT_TAG_STRING_MAXIMUM:
837 report_item->string_maximum =
838 usb_hid_report_tag_data_uint32(data, item_size);
839 break;
840
841 case USB_HID_REPORT_TAG_DELIMITER:
842 report_item->in_delimiter =
843 usb_hid_report_tag_data_uint32(data, item_size);
844 break;
845
846 default:
847 return USB_HID_NO_ACTION;
848 }
849
850 return EOK;
851}
852
853/**
854 * Converts raw data to uint32 (thats the maximum length of short item data)
855 *
856 * @param Data buffer
857 * @param Size of buffer
858 * @return Converted int32 number
859 */
860uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
861{
862 unsigned int i;
863 uint32_t result;
864
865 result = 0;
866 for(i=0; i<size; i++) {
867 result = (result | (data[i]) << (i*8));
868 }
869
870 return result;
871}
872
873
874/**
875 * Prints content of given list of report items.
876 *
877 * @param List of report items (usb_hid_report_item_t)
878 * @return void
879 */
880void usb_hid_descriptor_print_list(list_t *list)
881{
882 if(list == NULL || list_empty(list)) {
883 usb_log_debug("\tempty");
884 return;
885 }
886
887 list_foreach(*list, ritems_link, usb_hid_report_field_t,
888 report_item) {
889 usb_log_debug("\t\tOFFSET: %u", report_item->offset);
890 usb_log_debug("\t\tSIZE: %zu", report_item->size);
891 usb_log_debug("\t\tLOGMIN: %d",
892 report_item->logical_minimum);
893 usb_log_debug("\t\tLOGMAX: %d",
894 report_item->logical_maximum);
895 usb_log_debug("\t\tPHYMIN: %d",
896 report_item->physical_minimum);
897 usb_log_debug("\t\tPHYMAX: %d",
898 report_item->physical_maximum);
899 usb_log_debug("\t\ttUSAGEMIN: %X",
900 report_item->usage_minimum);
901 usb_log_debug("\t\tUSAGEMAX: %X",
902 report_item->usage_maximum);
903 usb_log_debug("\t\tUSAGES COUNT: %zu",
904 report_item->usages_count);
905
906 usb_log_debug("\t\tVALUE: %X", report_item->value);
907 usb_log_debug("\t\ttUSAGE: %X", report_item->usage);
908 usb_log_debug("\t\tUSAGE PAGE: %X", report_item->usage_page);
909
910 usb_hid_print_usage_path(report_item->collection_path);
911 }
912}
913
914
915/**
916 * Prints content of given report descriptor in human readable format.
917 *
918 * @param parser Parsed descriptor to print
919 * @return void
920 */
921void usb_hid_descriptor_print(usb_hid_report_t *report)
922{
923 if (report == NULL)
924 return;
925
926 list_foreach(report->reports, reports_link,
927 usb_hid_report_description_t, report_des) {
928 usb_log_debug("Report ID: %d", report_des->report_id);
929 usb_log_debug("\tType: %d", report_des->type);
930 usb_log_debug("\tLength: %zu", report_des->bit_length);
931 usb_log_debug("\tB Size: %zu",
932 usb_hid_report_byte_size(report,
933 report_des->report_id,
934 report_des->type));
935 usb_log_debug("\tItems: %zu", report_des->item_length);
936
937 usb_hid_descriptor_print_list(&report_des->report_items);
938 }
939}
940
941
942
943/** Frees the HID report descriptor parser structure
944 *
945 * @param parser Opaque HID report parser structure
946 * @return void
947 */
948void usb_hid_report_deinit(usb_hid_report_t *report)
949{
950 if(report == NULL){
951 return;
952 }
953
954 // free collection paths
955 link_t *path_link;
956 usb_hid_report_path_t *path;
957 while(!list_empty(&report->collection_paths)) {
958 path_link = list_first(&report->collection_paths);
959 path = list_get_instance(path_link,
960 usb_hid_report_path_t, cpath_link);
961
962 list_remove(path_link);
963 usb_hid_report_path_free(path);
964 }
965
966 // free report items
967 usb_hid_report_description_t *report_des;
968 usb_hid_report_field_t *field;
969 while(!list_empty(&report->reports)) {
970 report_des = list_get_instance(list_first(&report->reports),
971 usb_hid_report_description_t, reports_link);
972
973 list_remove(&report_des->reports_link);
974
975 while(!list_empty(&report_des->report_items)) {
976 field = list_get_instance(
977 list_first(&report_des->report_items),
978 usb_hid_report_field_t, ritems_link);
979
980 list_remove(&field->ritems_link);
981
982 free(field);
983 }
984
985 free(report_des);
986 }
987
988 return;
989}
990
991
992/**
993 * @}
994 */
Note: See TracBrowser for help on using the repository browser.