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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 24.7 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.