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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0247bd2 was 5a6cc679, checked in by Jenda <jenda.jzqk73@…>, 8 years ago

Merge commit '50f19b7ee8e94570b5c63896736c4eb49cfa18db' into forwardport

Not all ints are converted to errno_t in xhci tree yet, however it compiles and works :)

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