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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b72efe8 was b72efe8, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Separate list_t typedef from link_t (user-space part).

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