source: mainline/uspace/lib/usb/src/hiddescriptor.c@ 3a6e423

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

Parsing of usages in case of array items repaired

  • Property mode set to 100644
File size: 23.7 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 libusb
30 * @{
31 */
32/** @file
33 * HID report descriptor and report data parser implementation.
34 */
35#include <usb/classes/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#define OUTSIDE_DELIMITER_SET 0
45#define START_DELIMITER_SET 1
46#define INSIDE_DELIMITER_SET 2
47
48/** The new report item flag. Used to determine when the item is completly
49 * configured and should be added to the report structure
50 */
51#define USB_HID_NEW_REPORT_ITEM 1
52
53/** No special action after the report descriptor tag is processed should be
54 * done
55 */
56#define USB_HID_NO_ACTION 2
57
58#define USB_HID_RESET_OFFSET 3
59
60/** Unknown tag was founded in report descriptor data*/
61#define USB_HID_UNKNOWN_TAG -99
62
63usb_hid_report_path_t *usb_hid_report_path_try_insert(usb_hid_report_t *report, usb_hid_report_path_t *cmp_path)
64{
65 /* find or append current collection path to the list */
66 //link_t *path_it = report->collection_paths.next;
67 link_t *path_it = report->collection_paths.prev->next;
68 usb_hid_report_path_t *path = NULL;
69
70
71 while(path_it != &report->collection_paths) {
72 path = list_get_instance(path_it, usb_hid_report_path_t, link);
73
74 if(usb_hid_report_compare_usage_path(path, cmp_path, USB_HID_PATH_COMPARE_STRICT) == EOK){
75 break;
76 }
77 path_it = path_it->next;
78 }
79 if(path_it == &report->collection_paths) {
80 path = usb_hid_report_path_clone(cmp_path);
81 list_append(&path->link, &report->collection_paths);
82 report->collection_paths_count++;
83
84 return path;
85 }
86 else {
87 return list_get_instance(path_it, usb_hid_report_path_t, link);
88 }
89}
90
91/**
92 * Initialize the report descriptor parser structure
93 *
94 * @param parser Report descriptor parser structure
95 * @return Error code
96 */
97int usb_hid_report_init(usb_hid_report_t *report)
98{
99 if(report == NULL) {
100 return EINVAL;
101 }
102
103 memset(report, 0, sizeof(usb_hid_report_t));
104 list_initialize(&report->reports);
105 list_initialize(&report->collection_paths);
106
107 report->use_report_ids = 0;
108 return EOK;
109}
110
111
112/*
113 *
114 *
115 */
116int usb_hid_report_append_fields(usb_hid_report_t *report, usb_hid_report_item_t *report_item)
117{
118 usb_hid_report_field_t *field;
119 int i;
120
121 uint32_t *usages;
122 int usages_used=0;
123 if(report_item->usages_count > 0){
124 usages = malloc(sizeof(int32_t) * report_item->usages_count);
125 memcpy(usages, report_item->usages, sizeof(int32_t) * report_item->usages_count);
126 }
127 else {
128 usages = NULL;
129 }
130
131 usb_hid_report_path_t *path = report_item->usage_path;
132 for(i=0; i<report_item->count; i++){
133
134 field = malloc(sizeof(usb_hid_report_field_t));
135 memset(field, 0, sizeof(usb_hid_report_field_t));
136 list_initialize(&field->link);
137
138 /* fill the attributes */
139 field->logical_minimum = report_item->logical_minimum;
140 field->logical_maximum = report_item->logical_maximum;
141 field->physical_minimum = report_item->physical_minimum;
142 field->physical_maximum = report_item->physical_maximum;
143
144 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0){
145 /*
146 Store usage array. The Correct Usage Page and Usage is depending
147 on data in report and will be filled later
148 */
149 field->usage = 0;
150 field->usage_page = 0; //report_item->usage_page;
151
152 field->usages_count = report_item->usages_count;
153 field->usages = usages;
154 usages_used = 1;
155 }
156 else {
157
158 /* Fill the correct Usage and Usage Page */
159 int32_t usage;
160 if(i < report_item->usages_count) {
161 usage = report_item->usages[i];
162 }
163 else {
164 usage = report_item->usages[report_item->usages_count - 1];
165 }
166
167 if(USB_HID_IS_EXTENDED_USAGE(usage)){
168 field->usage = USB_HID_EXTENDED_USAGE(usage);
169 field->usage_page = USB_HID_EXTENDED_USAGE_PAGE(usage);
170 }
171 else {
172 // should not occur
173 field->usage = usage;
174 field->usage_page = report_item->usage_page;
175 }
176 }
177
178 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_GLOBAL, field->usage_page);
179 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_LOCAL, field->usage);
180
181 field->collection_path = usb_hid_report_path_try_insert(report, path);
182
183 field->size = report_item->size;
184
185 size_t offset_byte = (report_item->offset + (i * report_item->size)) / 8;
186 size_t offset_bit = 8 - ((report_item->offset + (i * report_item->size)) % 8) - report_item->size;
187
188 field->offset = 8 * offset_byte + offset_bit;
189 if(report_item->id != 0) {
190 field->offset += 8;
191 report->use_report_ids = 1;
192 }
193 field->item_flags = report_item->item_flags;
194
195 /* find the right report list*/
196 usb_hid_report_description_t *report_des;
197 report_des = usb_hid_report_find_description(report, report_item->id, report_item->type);
198 if(report_des == NULL){
199 report_des = malloc(sizeof(usb_hid_report_description_t));
200 memset(report_des, 0, sizeof(usb_hid_report_description_t));
201
202 report_des->type = report_item->type;
203 report_des->report_id = report_item->id;
204 list_initialize (&report_des->link);
205 list_initialize (&report_des->report_items);
206
207 list_append(&report_des->link, &report->reports);
208 report->report_count++;
209 }
210
211 /* append this field to the end of founded report list */
212 list_append (&field->link, &report_des->report_items);
213
214 /* update the sizes */
215 report_des->bit_length += field->size;
216 report_des->item_length++;
217
218 }
219
220 // free only when not used!!!
221 if(usages && usages_used == 0) {
222 free(usages);
223 }
224
225 return EOK;
226}
227
228usb_hid_report_description_t * usb_hid_report_find_description(const usb_hid_report_t *report, uint8_t report_id, usb_hid_report_type_t type)
229{
230 link_t *report_it = report->reports.next;
231 usb_hid_report_description_t *report_des = NULL;
232
233 while(report_it != &report->reports) {
234 report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
235
236 if((report_des->report_id == report_id) && (report_des->type == type)){
237 return report_des;
238 }
239
240 report_it = report_it->next;
241 }
242
243 return NULL;
244}
245
246/** Parse HID report descriptor.
247 *
248 * @param parser Opaque HID report parser structure.
249 * @param data Data describing the report.
250 * @return Error code.
251 */
252int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
253 const uint8_t *data, size_t size)
254{
255 size_t i=0;
256 uint8_t tag=0;
257 uint8_t item_size=0;
258 int class=0;
259 int ret;
260 usb_hid_report_item_t *report_item=0;
261 usb_hid_report_item_t *new_report_item;
262 usb_hid_report_path_t *usage_path;
263
264 size_t offset_input=0;
265 size_t offset_output=0;
266 size_t offset_feature=0;
267
268 link_t stack;
269 list_initialize(&stack);
270
271 /* parser structure initialization*/
272 if(usb_hid_report_init(report) != EOK) {
273 return EINVAL;
274 }
275
276 /*report item initialization*/
277 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
278 return ENOMEM;
279 }
280 memset(report_item, 0, sizeof(usb_hid_report_item_t));
281 list_initialize(&(report_item->link));
282
283 /* usage path context initialization */
284 if(!(usage_path=usb_hid_report_path())){
285 return ENOMEM;
286 }
287 usb_hid_report_path_append_item(usage_path, 0, 0);
288
289 while(i<size){
290 if(!USB_HID_ITEM_IS_LONG(data[i])){
291
292 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
293 return EINVAL;
294 }
295
296 tag = USB_HID_ITEM_TAG(data[i]);
297 item_size = USB_HID_ITEM_SIZE(data[i]);
298 class = USB_HID_ITEM_TAG_CLASS(data[i]);
299
300 ret = usb_hid_report_parse_tag(tag,class,data+i+1,
301 item_size,report_item, usage_path);
302 switch(ret){
303 case USB_HID_NEW_REPORT_ITEM:
304 // store report item to report and create the new one
305 // store current collection path
306 report_item->usage_path = usage_path;
307
308 usb_hid_report_path_set_report_id(report_item->usage_path, report_item->id);
309 if(report_item->id != 0){
310 report->use_report_ids = 1;
311 }
312
313 switch(tag) {
314 case USB_HID_REPORT_TAG_INPUT:
315 report_item->type = USB_HID_REPORT_TYPE_INPUT;
316 report_item->offset = offset_input;
317 offset_input += report_item->count * report_item->size;
318 break;
319 case USB_HID_REPORT_TAG_OUTPUT:
320 report_item->type = USB_HID_REPORT_TYPE_OUTPUT;
321 report_item->offset = offset_output;
322 offset_output += report_item->count * report_item->size;
323
324 break;
325 case USB_HID_REPORT_TAG_FEATURE:
326 report_item->type = USB_HID_REPORT_TYPE_FEATURE;
327 report_item->offset = offset_feature;
328 offset_feature += report_item->count * report_item->size;
329 break;
330 default:
331 usb_log_debug("\tjump over - tag %X\n", tag);
332 break;
333 }
334
335 /*
336 * append new fields to the report
337 * structure
338 */
339 usb_hid_report_append_fields(report, report_item);
340
341 /* reset local items */
342 usb_hid_report_reset_local_items (report_item);
343
344 break;
345
346 case USB_HID_RESET_OFFSET:
347 offset_input = 0;
348 offset_output = 0;
349 offset_feature = 0;
350 usb_hid_report_path_set_report_id (usage_path, report_item->id);
351 break;
352
353 case USB_HID_REPORT_TAG_PUSH:
354 // push current state to stack
355 new_report_item = usb_hid_report_item_clone(report_item);
356 usb_hid_report_path_t *tmp_path = usb_hid_report_path_clone(usage_path);
357 new_report_item->usage_path = tmp_path;
358
359 list_prepend (&new_report_item->link, &stack);
360 break;
361 case USB_HID_REPORT_TAG_POP:
362 // restore current state from stack
363 if(list_empty (&stack)) {
364 return EINVAL;
365 }
366 free(report_item);
367
368 report_item = list_get_instance(stack.next, usb_hid_report_item_t, link);
369
370 usb_hid_report_usage_path_t *tmp_usage_path;
371 tmp_usage_path = list_get_instance(report_item->usage_path->link.prev, usb_hid_report_usage_path_t, link);
372
373 usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
374 usb_hid_report_set_last_item(usage_path, USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
375
376 usb_hid_report_path_free(report_item->usage_path);
377 list_initialize(&report_item->usage_path->link);
378 list_remove (stack.next);
379
380 break;
381
382 default:
383 // nothing special to do
384 break;
385 }
386
387 /* jump over the processed block */
388 i += 1 + USB_HID_ITEM_SIZE(data[i]);
389 }
390 else{
391 // TBD
392 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
393 }
394
395
396 }
397
398 return EOK;
399}
400
401
402/**
403 * Parse one tag of the report descriptor
404 *
405 * @param Tag to parse
406 * @param Report descriptor buffer
407 * @param Size of data belongs to this tag
408 * @param Current report item structe
409 * @return Code of action to be done next
410 */
411int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data, size_t item_size,
412 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
413{
414 int ret;
415
416 switch(class){
417 case USB_HID_TAG_CLASS_MAIN:
418
419 if((ret=usb_hid_report_parse_main_tag(tag,data,item_size,report_item, usage_path)) == EOK) {
420 return USB_HID_NEW_REPORT_ITEM;
421 }
422 else {
423 /*TODO process the error */
424 return ret;
425 }
426 break;
427
428 case USB_HID_TAG_CLASS_GLOBAL:
429 return usb_hid_report_parse_global_tag(tag,data,item_size,report_item, usage_path);
430 break;
431
432 case USB_HID_TAG_CLASS_LOCAL:
433 return usb_hid_report_parse_local_tag(tag,data,item_size,report_item, usage_path);
434 break;
435 default:
436 return USB_HID_NO_ACTION;
437 }
438}
439
440/**
441 * Parse main tags of report descriptor
442 *
443 * @param Tag identifier
444 * @param Data buffer
445 * @param Length of data buffer
446 * @param Current state table
447 * @return Error code
448 */
449
450int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
451 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
452{
453 usb_hid_report_usage_path_t *path_item;
454
455 switch(tag)
456 {
457 case USB_HID_REPORT_TAG_INPUT:
458 case USB_HID_REPORT_TAG_OUTPUT:
459 case USB_HID_REPORT_TAG_FEATURE:
460 report_item->item_flags = *data;
461 return EOK;
462 break;
463
464 case USB_HID_REPORT_TAG_COLLECTION:
465
466 // store collection atributes
467 path_item = list_get_instance(usage_path->head.prev, usb_hid_report_usage_path_t, link);
468 path_item->flags = *data;
469
470 // set last item
471 usb_hid_report_set_last_item(usage_path,
472 USB_HID_TAG_CLASS_GLOBAL,
473 USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[report_item->usages_count-1]));
474 usb_hid_report_set_last_item(usage_path,
475 USB_HID_TAG_CLASS_LOCAL,
476 USB_HID_EXTENDED_USAGE(report_item->usages[report_item->usages_count-1]));
477
478 // append the new one which will be set by common
479 // usage/usage page
480 usb_hid_report_path_append_item(usage_path, report_item->usage_page, report_item->usages[report_item->usages_count-1]);
481 usb_hid_report_reset_local_items (report_item);
482 return USB_HID_NO_ACTION;
483 break;
484
485 case USB_HID_REPORT_TAG_END_COLLECTION:
486 usb_hid_report_remove_last_item(usage_path);
487 return USB_HID_NO_ACTION;
488 break;
489 default:
490 return USB_HID_NO_ACTION;
491 }
492
493 return EOK;
494}
495
496/**
497 * Parse global tags of report descriptor
498 *
499 * @param Tag identifier
500 * @param Data buffer
501 * @param Length of data buffer
502 * @param Current state table
503 * @return Error code
504 */
505int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
506 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
507{
508 // TODO take care about the bit length of data
509 switch(tag)
510 {
511 case USB_HID_REPORT_TAG_USAGE_PAGE:
512 report_item->usage_page = usb_hid_report_tag_data_uint32(data, item_size);
513 break;
514 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
515 report_item->logical_minimum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
516 break;
517 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
518 report_item->logical_maximum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
519 break;
520 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
521 report_item->physical_minimum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
522 break;
523 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
524 report_item->physical_maximum = USB_HID_UINT32_TO_INT32(usb_hid_report_tag_data_uint32(data,item_size), item_size * 8);
525
526 break;
527 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
528 report_item->unit_exponent = usb_hid_report_tag_data_uint32(data,item_size);
529 break;
530 case USB_HID_REPORT_TAG_UNIT:
531 report_item->unit = usb_hid_report_tag_data_uint32(data,item_size);
532 break;
533 case USB_HID_REPORT_TAG_REPORT_SIZE:
534 report_item->size = usb_hid_report_tag_data_uint32(data,item_size);
535 break;
536 case USB_HID_REPORT_TAG_REPORT_COUNT:
537 report_item->count = usb_hid_report_tag_data_uint32(data,item_size);
538 break;
539 case USB_HID_REPORT_TAG_REPORT_ID:
540 report_item->id = usb_hid_report_tag_data_uint32(data,item_size);
541 return USB_HID_RESET_OFFSET;
542 break;
543 case USB_HID_REPORT_TAG_PUSH:
544 case USB_HID_REPORT_TAG_POP:
545 /*
546 * stack operations are done in top level parsing
547 * function
548 */
549 return tag;
550 break;
551
552 default:
553 return USB_HID_NO_ACTION;
554 }
555
556 return EOK;
557}
558
559/**
560 * Parse local tags of report descriptor
561 *
562 * @param Tag identifier
563 * @param Data buffer
564 * @param Length of data buffer
565 * @param Current state table
566 * @return Error code
567 */
568int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
569 usb_hid_report_item_t *report_item, usb_hid_report_path_t *usage_path)
570{
571 int32_t extended_usage;
572
573 switch(tag) {
574 case USB_HID_REPORT_TAG_USAGE:
575 switch(report_item->in_delimiter) {
576 case INSIDE_DELIMITER_SET:
577 // nothing to do
578 break;
579 case START_DELIMITER_SET:
580 report_item->in_delimiter = INSIDE_DELIMITER_SET;
581 case OUTSIDE_DELIMITER_SET:
582 extended_usage = ((report_item->usage_page) << 16);
583 extended_usage += usb_hid_report_tag_data_uint32(data,item_size);
584 report_item->usages[report_item->usages_count] = extended_usage;
585 report_item->usages_count++;
586 break;
587 }
588 break;
589 case USB_HID_REPORT_TAG_USAGE_MINIMUM:
590 if (item_size == 3) {
591 // usage extended usages
592 report_item->extended_usage_page = (usb_hid_report_tag_data_uint32(data,item_size) & 0xFF00) >> 16;
593 report_item->usage_minimum = usb_hid_report_tag_data_uint32(data,item_size) & 0xFF;
594 }
595 else {
596 report_item->usage_minimum = usb_hid_report_tag_data_uint32(data,item_size);
597 }
598 break;
599 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
600 if (item_size == 3) {
601
602 if(report_item->extended_usage_page != ((usb_hid_report_tag_data_uint32(data,item_size) & 0xFF00) >> 16)) {
603 return EINVAL;
604 }
605
606 // usage extended usages
607 report_item->extended_usage_page = (usb_hid_report_tag_data_uint32(data,item_size) & 0xFF00) >> 16;
608 report_item->usage_maximum = usb_hid_report_tag_data_uint32(data,item_size) & 0xFF;
609 }
610 else {
611 report_item->usage_maximum = usb_hid_report_tag_data_uint32(data,item_size);
612 }
613
614 // vlozit zaznamy do pole usages
615 int32_t i;
616 for(i=report_item->usage_minimum; i<=report_item->usage_maximum; i++) {
617 if(report_item->extended_usage_page) {
618 report_item->usages[report_item->usages_count++] = (report_item->extended_usage_page << 16) + i;
619 }
620 else {
621
622 report_item->usages[report_item->usages_count++] = (report_item->usage_page << 16) + i;
623 }
624 }
625 report_item->extended_usage_page = 0;
626
627 break;
628 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
629 report_item->designator_index = usb_hid_report_tag_data_uint32(data,item_size);
630 break;
631 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
632 report_item->designator_minimum = usb_hid_report_tag_data_uint32(data,item_size);
633 break;
634 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
635 report_item->designator_maximum = usb_hid_report_tag_data_uint32(data,item_size);
636 break;
637 case USB_HID_REPORT_TAG_STRING_INDEX:
638 report_item->string_index = usb_hid_report_tag_data_uint32(data,item_size);
639 break;
640 case USB_HID_REPORT_TAG_STRING_MINIMUM:
641 report_item->string_minimum = usb_hid_report_tag_data_uint32(data,item_size);
642 break;
643 case USB_HID_REPORT_TAG_STRING_MAXIMUM:
644 report_item->string_maximum = usb_hid_report_tag_data_uint32(data,item_size);
645 break;
646 case USB_HID_REPORT_TAG_DELIMITER:
647 report_item->in_delimiter = usb_hid_report_tag_data_uint32(data,item_size);
648 break;
649
650 default:
651 return USB_HID_NO_ACTION;
652 }
653
654 return EOK;
655}
656
657/**
658 * Converts raw data to uint32 (thats the maximum length of short item data)
659 *
660 * @param Data buffer
661 * @param Size of buffer
662 * @return Converted int32 number
663 */
664uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
665{
666 unsigned int i;
667 uint32_t result;
668
669 result = 0;
670 for(i=0; i<size; i++) {
671 result = (result | (data[i]) << (i*8));
672 }
673
674 return result;
675}
676
677/**
678 * Prints content of given list of report items.
679 *
680 * @param List of report items (usb_hid_report_item_t)
681 * @return void
682 */
683void usb_hid_descriptor_print_list(link_t *head)
684{
685 usb_hid_report_field_t *report_item;
686 link_t *item;
687
688
689 if(head == NULL || list_empty(head)) {
690 usb_log_debug("\tempty\n");
691 return;
692 }
693
694 for(item = head->next; item != head; item = item->next) {
695
696 report_item = list_get_instance(item, usb_hid_report_field_t, link);
697
698 usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
699 usb_log_debug("\t\tSIZE: %zu\n", report_item->size);
700 usb_log_debug("\t\tLOGMIN: %d\n", report_item->logical_minimum);
701 usb_log_debug("\t\tLOGMAX: %d\n", report_item->logical_maximum);
702 usb_log_debug("\t\tPHYMIN: %d\n", report_item->physical_minimum);
703 usb_log_debug("\t\tPHYMAX: %d\n", report_item->physical_maximum);
704 usb_log_debug("\t\ttUSAGEMIN: %X\n", report_item->usage_minimum);
705 usb_log_debug("\t\tUSAGEMAX: %X\n", report_item->usage_maximum);
706 usb_log_debug("\t\tUSAGES COUNT: %zu\n", report_item->usages_count);
707
708 usb_log_debug("\t\tVALUE: %X\n", report_item->value);
709 usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
710 usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
711
712 usb_hid_print_usage_path(report_item->collection_path);
713
714 usb_log_debug("\n");
715
716 }
717
718
719}
720/**
721 * Prints content of given report descriptor in human readable format.
722 *
723 * @param parser Parsed descriptor to print
724 * @return void
725 */
726void usb_hid_descriptor_print(usb_hid_report_t *report)
727{
728 if(report == NULL) {
729 return;
730 }
731
732 link_t *report_it = report->reports.next;
733 usb_hid_report_description_t *report_des;
734
735 while(report_it != &report->reports) {
736 report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
737 usb_log_debug("Report ID: %d\n", report_des->report_id);
738 usb_log_debug("\tType: %d\n", report_des->type);
739 usb_log_debug("\tLength: %zu\n", report_des->bit_length);
740 usb_log_debug("\tItems: %zu\n", report_des->item_length);
741
742 usb_hid_descriptor_print_list(&report_des->report_items);
743
744/*
745 link_t *path_it = report->collection_paths.next;
746 while(path_it != &report->collection_paths) {
747 usb_hid_print_usage_path (list_get_instance(path_it, usb_hid_report_path_t, link));
748 path_it = path_it->next;
749 }
750*/
751 report_it = report_it->next;
752 }
753}
754
755/**
756 * Releases whole linked list of report items
757 *
758 * @param head Head of list of report descriptor items (usb_hid_report_item_t)
759 * @return void
760 */
761void usb_hid_free_report_list(link_t *head)
762{
763 return;
764
765 usb_hid_report_item_t *report_item;
766 link_t *next;
767
768 if(head == NULL || list_empty(head)) {
769 return;
770 }
771
772 next = head->next;
773 while(next != head) {
774
775 report_item = list_get_instance(next, usb_hid_report_item_t, link);
776
777 while(!list_empty(&report_item->usage_path->link)) {
778 usb_hid_report_remove_last_item(report_item->usage_path);
779 }
780
781
782 next = next->next;
783
784 free(report_item);
785 }
786
787 return;
788
789}
790
791/** Frees the HID report descriptor parser structure
792 *
793 * @param parser Opaque HID report parser structure
794 * @return void
795 */
796void usb_hid_free_report(usb_hid_report_t *report)
797{
798 if(report == NULL){
799 return;
800 }
801
802 // free collection paths
803 usb_hid_report_path_t *path;
804 while(!list_empty(&report->collection_paths)) {
805 path = list_get_instance(report->collection_paths.next, usb_hid_report_path_t, link);
806 usb_hid_report_path_free(path);
807 }
808
809 // free report items
810 usb_hid_report_description_t *report_des;
811 usb_hid_report_field_t *field;
812 while(!list_empty(&report->reports)) {
813 report_des = list_get_instance(report->reports.next, usb_hid_report_description_t, link);
814 list_remove(&report_des->link);
815
816 while(!list_empty(&report_des->report_items)) {
817 field = list_get_instance(report_des->report_items.next, usb_hid_report_field_t, link);
818 list_remove(&field->link);
819
820 free(field);
821 }
822
823 free(report_des);
824 }
825
826 return;
827}
828
829/**
830 * @}
831 */
Note: See TracBrowser for help on using the repository browser.