source: mainline/uspace/lib/usbhid/src/hiddescriptor.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1b20da0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

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