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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since dc12262 was dc12262, checked in by Martin Decky <martin@…>, 9 years ago

add standardized case fallthrough comment annotations, add actual missing breaks

GCC 7.1's attribute((fallthrough)) would be more elegant, but unfortunatelly this annotation is incompatible with previous versions of GCC (it generates an empty declaration error)

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