source: mainline/uspace/lib/usb/src/hiddescriptor.c@ 9d05599

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

usages order fixed

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