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

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

Fix error code mixing in usbhid.

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