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

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

subdrivers matching without specified report_id

  • Property mode set to 100644
File size: 27.0 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 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 list_initialize (&report_des->link);
294 list_initialize (&report_des->report_items);
295
296 list_append(&report_des->link, &report->reports);
297 report->report_count++;
298 }
299
300 /* append this field to the end of founded report list */
301 list_append (&field->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 link_t *report_it = report->reports.next;
332 usb_hid_report_description_t *report_des = NULL;
333
334 while(report_it != &report->reports) {
335 report_des = list_get_instance(report_it,
336 usb_hid_report_description_t, link);
337
338 // if report id not set, return the first of the type
339 if(((report_des->report_id == report_id) || (report_id == 0)) &&
340 (report_des->type == type)) {
341 return report_des;
342 }
343
344 report_it = report_it->next;
345 }
346
347 return NULL;
348}
349/*---------------------------------------------------------------------------*/
350
351/** Parse HID report descriptor.
352 *
353 * @param parser Opaque HID report parser structure.
354 * @param data Data describing the report.
355 * @return Error code.
356 * @retval ENOMEM If no more memmory is available
357 * @retval EINVAL If invalid data are founded
358 * @retval EOK If report descriptor is successfully parsed
359 */
360int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
361 const uint8_t *data, size_t size)
362{
363 size_t i=0;
364 uint8_t tag=0;
365 uint8_t item_size=0;
366 int class=0;
367 int ret;
368 usb_hid_report_item_t *report_item=0;
369 usb_hid_report_item_t *new_report_item;
370 usb_hid_report_path_t *usage_path;
371
372 size_t offset_input=0;
373 size_t offset_output=0;
374 size_t offset_feature=0;
375
376 link_t stack;
377 list_initialize(&stack);
378
379 /* parser structure initialization*/
380 if(usb_hid_report_init(report) != EOK) {
381 return EINVAL;
382 }
383
384 /*report item initialization*/
385 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
386 return ENOMEM;
387 }
388 memset(report_item, 0, sizeof(usb_hid_report_item_t));
389 list_initialize(&(report_item->link));
390
391 /* usage path context initialization */
392 if(!(usage_path=usb_hid_report_path())){
393 return ENOMEM;
394 }
395 usb_hid_report_path_append_item(usage_path, 0, 0);
396
397 while(i<size){
398 if(!USB_HID_ITEM_IS_LONG(data[i])){
399
400 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
401 return EINVAL;
402 }
403
404 tag = USB_HID_ITEM_TAG(data[i]);
405 item_size = USB_HID_ITEM_SIZE(data[i]);
406 class = USB_HID_ITEM_TAG_CLASS(data[i]);
407
408 ret = usb_hid_report_parse_tag(tag,class,data+i+1,
409 item_size,report_item, usage_path);
410
411 switch(ret){
412 case USB_HID_NEW_REPORT_ITEM:
413 /* store report item to report and create the
414 * new one store current collection path
415 */
416 report_item->usage_path = usage_path;
417
418 usb_hid_report_path_set_report_id(
419 report_item->usage_path, report_item->id);
420
421 if(report_item->id != 0){
422 report->use_report_ids = 1;
423 }
424
425 switch(tag) {
426 case USB_HID_REPORT_TAG_INPUT:
427 report_item->type =
428 USB_HID_REPORT_TYPE_INPUT;
429
430 report_item->offset = offset_input;
431 offset_input += report_item->count *
432 report_item->size;
433 break;
434
435 case USB_HID_REPORT_TAG_OUTPUT:
436 report_item->type =
437 USB_HID_REPORT_TYPE_OUTPUT;
438
439 report_item->offset = offset_output;
440 offset_output += report_item->count *
441 report_item->size;
442 break;
443
444 case USB_HID_REPORT_TAG_FEATURE:
445 report_item->type =
446 USB_HID_REPORT_TYPE_FEATURE;
447
448 report_item->offset = offset_feature;
449 offset_feature += report_item->count *
450 report_item->size;
451 break;
452
453 default:
454 usb_log_debug2(
455 "\tjump over - tag %X\n", tag);
456 break;
457 }
458
459 /*
460 * append new fields to the report structure
461 */
462 usb_hid_report_append_fields(report,
463 report_item);
464
465 /* reset local items */
466 usb_hid_report_reset_local_items (report_item);
467 break;
468
469 case USB_HID_RESET_OFFSET:
470 offset_input = 0;
471 offset_output = 0;
472 offset_feature = 0;
473 usb_hid_report_path_set_report_id (usage_path,
474 report_item->id);
475 break;
476
477 case USB_HID_REPORT_TAG_PUSH:
478 // push current state to stack
479 new_report_item = usb_hid_report_item_clone(
480 report_item);
481
482 usb_hid_report_path_t *tmp_path =
483 usb_hid_report_path_clone(usage_path);
484
485 new_report_item->usage_path = tmp_path;
486
487 list_prepend (&new_report_item->link, &stack);
488 break;
489 case USB_HID_REPORT_TAG_POP:
490 // restore current state from stack
491 if(list_empty (&stack)) {
492 return EINVAL;
493 }
494 free(report_item);
495
496 report_item = list_get_instance(stack.next,
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->link.prev,
502 usb_hid_report_usage_path_t, 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_initialize(&report_item->usage_path->link);
512 list_remove (stack.next);
513
514 break;
515
516 default:
517 // nothing special to do
518 break;
519 }
520
521 /* jump over the processed block */
522 i += 1 + USB_HID_ITEM_SIZE(data[i]);
523 }
524 else{
525 // TBD
526 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
527 }
528
529
530 }
531
532 return EOK;
533}
534
535/*---------------------------------------------------------------------------*/
536
537/**
538 * Parse one tag of the report descriptor
539 *
540 * @param Tag to parse
541 * @param Report descriptor buffer
542 * @param Size of data belongs to this tag
543 * @param Current report item structe
544 * @return Code of action to be done next
545 */
546int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
547 size_t item_size, usb_hid_report_item_t *report_item,
548 usb_hid_report_path_t *usage_path) {
549
550 int ret;
551
552 switch(class){
553 case USB_HID_TAG_CLASS_MAIN:
554
555 if((ret=usb_hid_report_parse_main_tag(tag, data, item_size,
556 report_item, usage_path)) == EOK) {
557
558 return USB_HID_NEW_REPORT_ITEM;
559 }
560 else {
561 return ret;
562 }
563 break;
564
565 case USB_HID_TAG_CLASS_GLOBAL:
566 return usb_hid_report_parse_global_tag(tag, data, item_size,
567 report_item, usage_path);
568 break;
569
570 case USB_HID_TAG_CLASS_LOCAL:
571 return usb_hid_report_parse_local_tag(tag, data, item_size,
572 report_item, usage_path);
573 break;
574
575 default:
576 return USB_HID_NO_ACTION;
577 }
578}
579
580/**
581 * Parse main tags of report descriptor
582 *
583 * @param Tag identifier
584 * @param Data buffer
585 * @param Length of data buffer
586 * @param Current state table
587 * @return Error code
588 */
589
590int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data,
591 size_t item_size, usb_hid_report_item_t *report_item,
592 usb_hid_report_path_t *usage_path)
593{
594 usb_hid_report_usage_path_t *path_item;
595
596 switch(tag)
597 {
598 case USB_HID_REPORT_TAG_INPUT:
599 case USB_HID_REPORT_TAG_OUTPUT:
600 case USB_HID_REPORT_TAG_FEATURE:
601 report_item->item_flags = *data;
602 return EOK;
603 break;
604
605 case USB_HID_REPORT_TAG_COLLECTION:
606
607 /* store collection atributes */
608 path_item = list_get_instance(usage_path->head.prev,
609 usb_hid_report_usage_path_t, link);
610 path_item->flags = *data;
611
612 /* set last item */
613 usb_hid_report_set_last_item(usage_path,
614 USB_HID_TAG_CLASS_GLOBAL,
615 USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[
616 report_item->usages_count-1]));
617
618 usb_hid_report_set_last_item(usage_path,
619 USB_HID_TAG_CLASS_LOCAL,
620 USB_HID_EXTENDED_USAGE(report_item->usages[
621 report_item->usages_count-1]));
622
623 /* append the new one which will be set by common usage/usage
624 * page */
625 usb_hid_report_path_append_item(usage_path,
626 report_item->usage_page,
627 report_item->usages[report_item->usages_count-1]);
628
629 usb_hid_report_reset_local_items (report_item);
630 return USB_HID_NO_ACTION;
631 break;
632
633 case USB_HID_REPORT_TAG_END_COLLECTION:
634 usb_hid_report_remove_last_item(usage_path);
635 return USB_HID_NO_ACTION;
636 break;
637
638 default:
639 return USB_HID_NO_ACTION;
640 }
641
642 return EOK;
643}
644
645/**
646 * Parse global tags of report descriptor
647 *
648 * @param Tag identifier
649 * @param Data buffer
650 * @param Length of data buffer
651 * @param Current state table
652 * @return Error code
653 */
654int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data,
655 size_t item_size, usb_hid_report_item_t *report_item,
656 usb_hid_report_path_t *usage_path) {
657
658 switch(tag)
659 {
660 case USB_HID_REPORT_TAG_USAGE_PAGE:
661 report_item->usage_page =
662 usb_hid_report_tag_data_uint32(data, item_size);
663 break;
664
665 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
666 report_item->logical_minimum = USB_HID_UINT32_TO_INT32(
667 usb_hid_report_tag_data_uint32(data,item_size),
668 item_size * 8);
669 break;
670
671 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
672 report_item->logical_maximum = USB_HID_UINT32_TO_INT32(
673 usb_hid_report_tag_data_uint32(data,item_size),
674 item_size * 8);
675 break;
676
677 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
678 report_item->physical_minimum = USB_HID_UINT32_TO_INT32(
679 usb_hid_report_tag_data_uint32(data,item_size),
680 item_size * 8);
681 break;
682
683 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
684 report_item->physical_maximum = USB_HID_UINT32_TO_INT32(
685 usb_hid_report_tag_data_uint32(data,item_size),
686 item_size * 8);
687 break;
688
689 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
690 report_item->unit_exponent = usb_hid_report_tag_data_uint32(
691 data,item_size);
692 break;
693
694 case USB_HID_REPORT_TAG_UNIT:
695 report_item->unit = usb_hid_report_tag_data_uint32(
696 data,item_size);
697 break;
698
699 case USB_HID_REPORT_TAG_REPORT_SIZE:
700 report_item->size = usb_hid_report_tag_data_uint32(
701 data,item_size);
702 break;
703
704 case USB_HID_REPORT_TAG_REPORT_COUNT:
705 report_item->count = usb_hid_report_tag_data_uint32(
706 data,item_size);
707 break;
708
709 case USB_HID_REPORT_TAG_REPORT_ID:
710 report_item->id = usb_hid_report_tag_data_uint32(data,
711 item_size);
712 return USB_HID_RESET_OFFSET;
713 break;
714
715 case USB_HID_REPORT_TAG_PUSH:
716 case USB_HID_REPORT_TAG_POP:
717 /*
718 * stack operations are done in top level parsing
719 * function
720 */
721 return tag;
722 break;
723
724 default:
725 return USB_HID_NO_ACTION;
726 }
727
728 return EOK;
729}
730
731/**
732 * Parse local tags of report descriptor
733 *
734 * @param Tag identifier
735 * @param Data buffer
736 * @param Length of data buffer
737 * @param Current state table
738 * @return Error code
739 */
740int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data,
741 size_t item_size, usb_hid_report_item_t *report_item,
742 usb_hid_report_path_t *usage_path)
743{
744 int32_t extended_usage;
745
746 switch(tag) {
747 case USB_HID_REPORT_TAG_USAGE:
748 switch(report_item->in_delimiter) {
749 case INSIDE_DELIMITER_SET:
750 /* nothing to do
751 * we catch only the first one
752 */
753 break;
754
755 case START_DELIMITER_SET:
756 report_item->in_delimiter = INSIDE_DELIMITER_SET;
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(link_t *head)
900{
901 usb_hid_report_field_t *report_item;
902 link_t *item;
903
904
905 if(head == NULL || list_empty(head)) {
906 usb_log_debug("\tempty\n");
907 return;
908 }
909
910 for(item = head->next; item != head; item = item->next) {
911
912 report_item = list_get_instance(item, usb_hid_report_field_t,
913 link);
914
915 usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
916 usb_log_debug("\t\tSIZE: %zu\n", report_item->size);
917 usb_log_debug("\t\tLOGMIN: %d\n",
918 report_item->logical_minimum);
919 usb_log_debug("\t\tLOGMAX: %d\n",
920 report_item->logical_maximum);
921 usb_log_debug("\t\tPHYMIN: %d\n",
922 report_item->physical_minimum);
923 usb_log_debug("\t\tPHYMAX: %d\n",
924 report_item->physical_maximum);
925 usb_log_debug("\t\ttUSAGEMIN: %X\n",
926 report_item->usage_minimum);
927 usb_log_debug("\t\tUSAGEMAX: %X\n",
928 report_item->usage_maximum);
929 usb_log_debug("\t\tUSAGES COUNT: %zu\n",
930 report_item->usages_count);
931
932 usb_log_debug("\t\tVALUE: %X\n", report_item->value);
933 usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
934 usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
935
936 usb_hid_print_usage_path(report_item->collection_path);
937
938 usb_log_debug("\n");
939
940 }
941
942}
943/*---------------------------------------------------------------------------*/
944
945/**
946 * Prints content of given report descriptor in human readable format.
947 *
948 * @param parser Parsed descriptor to print
949 * @return void
950 */
951void usb_hid_descriptor_print(usb_hid_report_t *report)
952{
953 if(report == NULL) {
954 return;
955 }
956
957 link_t *report_it = report->reports.next;
958 usb_hid_report_description_t *report_des;
959
960 while(report_it != &report->reports) {
961 report_des = list_get_instance(report_it,
962 usb_hid_report_description_t, link);
963 usb_log_debug("Report ID: %d\n", report_des->report_id);
964 usb_log_debug("\tType: %d\n", report_des->type);
965 usb_log_debug("\tLength: %zu\n", report_des->bit_length);
966 usb_log_debug("\tB Size: %zu\n",
967 usb_hid_report_byte_size(report,
968 report_des->report_id,
969 report_des->type));
970 usb_log_debug("\tItems: %zu\n", report_des->item_length);
971
972 usb_hid_descriptor_print_list(&report_des->report_items);
973
974 report_it = report_it->next;
975 }
976}
977/*---------------------------------------------------------------------------*/
978
979/**
980 * Releases whole linked list of report items
981 *
982 * @param head Head of list of report descriptor items (usb_hid_report_item_t)
983 * @return void
984 */
985void usb_hid_free_report_list(link_t *head)
986{
987 return;
988
989 usb_hid_report_item_t *report_item;
990 link_t *next;
991
992 if(head == NULL || list_empty(head)) {
993 return;
994 }
995
996 next = head->next;
997 while(next != head) {
998
999 report_item = list_get_instance(next, usb_hid_report_item_t, link);
1000
1001 while(!list_empty(&report_item->usage_path->link)) {
1002 usb_hid_report_remove_last_item(report_item->usage_path);
1003 }
1004
1005
1006 next = next->next;
1007
1008 free(report_item);
1009 }
1010
1011 return;
1012
1013}
1014/*---------------------------------------------------------------------------*/
1015
1016/** Frees the HID report descriptor parser structure
1017 *
1018 * @param parser Opaque HID report parser structure
1019 * @return void
1020 */
1021void usb_hid_free_report(usb_hid_report_t *report)
1022{
1023 if(report == NULL){
1024 return;
1025 }
1026
1027 // free collection paths
1028 usb_hid_report_path_t *path;
1029 while(!list_empty(&report->collection_paths)) {
1030 path = list_get_instance(report->collection_paths.next,
1031 usb_hid_report_path_t, link);
1032
1033 usb_hid_report_path_free(path);
1034 }
1035
1036 // free report items
1037 usb_hid_report_description_t *report_des;
1038 usb_hid_report_field_t *field;
1039 while(!list_empty(&report->reports)) {
1040 report_des = list_get_instance(report->reports.next,
1041 usb_hid_report_description_t, link);
1042
1043 list_remove(&report_des->link);
1044
1045 while(!list_empty(&report_des->report_items)) {
1046 field = list_get_instance(
1047 report_des->report_items.next,
1048 usb_hid_report_field_t, link);
1049
1050 list_remove(&field->link);
1051
1052 free(field);
1053 }
1054
1055 free(report_des);
1056 }
1057
1058 return;
1059}
1060/*---------------------------------------------------------------------------*/
1061
1062/**
1063 * @}
1064 */
Note: See TracBrowser for help on using the repository browser.