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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 574f276 was 574f276, checked in by Matej Klonfar <maklf@…>, 14 years ago

parsing of customer controls bug fixed

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