source: mainline/uspace/lib/usb/src/hiddescriptor.c@ 1519b91

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

#209 - correct usage paths for decomposed items

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