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

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

doxygen and coding style update

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