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

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

Simplify use of list_foreach.

  • Property mode set to 100644
File size: 25.1 KB
RevLine 
[9d05599]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
[160b75e]29/** @addtogroup libusbhid
[9d05599]30 * @{
31 */
32/** @file
33 * HID report descriptor and report data parser implementation.
34 */
[faa44e58]35#include <usb/hid/hidparser.h>
[9d05599]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
[a76b01b4]43
[f3b39b4]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 */
[22ded10]51#define OUTSIDE_DELIMITER_SET 0
[f3b39b4]52
53/**
54 * First delimiter tag was read. The set of local items (usage) started.
55 */
[22ded10]56#define START_DELIMITER_SET 1
[f3b39b4]57
58/**
59 * Parser is in the set of local items.
60 */
[22ded10]61#define INSIDE_DELIMITER_SET 2
[f3b39b4]62
[a76b01b4]63
[22ded10]64
[9d05599]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
[a76b01b4]80
[f3b39b4]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 */
[b72efe8]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;
[1519b91]94 usb_hid_report_path_t *path = NULL;
[3a6e423]95
[f3b39b4]96 if((report == NULL) || (cmp_path == NULL)) {
97 return NULL;
98 }
[3a6e423]99
[b72efe8]100 while(path_it != &report->collection_paths.head) {
[f3b39b4]101 path = list_get_instance(path_it, usb_hid_report_path_t,
[b72efe8]102 cpath_link);
[1519b91]103
[f3b39b4]104 if(usb_hid_report_compare_usage_path(path, cmp_path,
105 USB_HID_PATH_COMPARE_STRICT) == EOK){
[1519b91]106 break;
[b72efe8]107 }
[1519b91]108 path_it = path_it->next;
109 }
[b72efe8]110 if(path_it == &report->collection_paths.head) {
[f3b39b4]111 path = usb_hid_report_path_clone(cmp_path);
112 if(path == NULL) {
113 return NULL;
114 }
[b72efe8]115 list_append(&path->cpath_link, &report->collection_paths);
[1519b91]116 report->collection_paths_count++;
[b9d7965]117
118 return path;
119 }
120 else {
[f3b39b4]121 return list_get_instance(path_it, usb_hid_report_path_t,
[b72efe8]122 cpath_link);
[1519b91]123 }
124}
[9d05599]125
[a76b01b4]126
[9d05599]127/**
128 * Initialize the report descriptor parser structure
129 *
130 * @param parser Report descriptor parser structure
131 * @return Error code
[f3b39b4]132 * @retval EINVAL If no report structure was given
133 * @retval EOK If report structure was successfully initialized
[9d05599]134 */
135int usb_hid_report_init(usb_hid_report_t *report)
136{
[8c62a71]137 if (report == NULL) {
[9d05599]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;
[8c62a71]146 return EOK;
[9d05599]147}
148
[a76b01b4]149
[3b5d5b9d]150
[f3b39b4]151/**
[3b5d5b9d]152 *
153 *
[f3b39b4]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 *
[3b5d5b9d]162 */
[f3b39b4]163int usb_hid_report_append_fields(usb_hid_report_t *report,
164 usb_hid_report_item_t *report_item) {
165
[9d05599]166 usb_hid_report_field_t *field;
167 int i;
168
[3a6e423]169 uint32_t *usages;
170 int usages_used=0;
[f3b39b4]171
172 if((report == NULL) || (report_item == NULL)) {
173 return EINVAL;
174 }
175
[3a6e423]176 if(report_item->usages_count > 0){
177 usages = malloc(sizeof(int32_t) * report_item->usages_count);
[f3b39b4]178 memcpy(usages, report_item->usages, sizeof(int32_t) *
179 report_item->usages_count);
[9d05599]180 }
[3a6e423]181 else {
182 usages = NULL;
183 }
184
[1519b91]185 usb_hid_report_path_t *path = report_item->usage_path;
[9d05599]186 for(i=0; i<report_item->count; i++){
187
188 field = malloc(sizeof(usb_hid_report_field_t));
[574f276]189 if(field == NULL) {
190 return ENOMEM;
191 }
192
[9d05599]193 memset(field, 0, sizeof(usb_hid_report_field_t));
[b72efe8]194 link_initialize(&field->ritems_link);
[9d05599]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
[3a6e423]202 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0){
203 /*
[f3b39b4]204 Store usage array. The Correct Usage Page and Usage is
205 depending on data in report and will be filled later
[3a6e423]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;
[9d05599]213 }
214 else {
215
[3a6e423]216 /* Fill the correct Usage and Usage Page */
217 int32_t usage;
218 if(i < report_item->usages_count) {
[3b5d5b9d]219 usage = report_item->usages[i];
[9d05599]220 }
221 else {
[ee7e7c93]222 usage = report_item->usages[
[f3b39b4]223 report_item->usages_count- 1];
[9d05599]224 }
225
[3a6e423]226 if(USB_HID_IS_EXTENDED_USAGE(usage)){
227 field->usage = USB_HID_EXTENDED_USAGE(usage);
[f3b39b4]228 field->usage_page =
229 USB_HID_EXTENDED_USAGE_PAGE(usage);
[9d05599]230 }
231 else {
[3a6e423]232 // should not occur
[9d05599]233 field->usage = usage;
[3a6e423]234 field->usage_page = report_item->usage_page;
[9d05599]235 }
236 }
237
[f3b39b4]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);
[1519b91]242
[f3b39b4]243 field->collection_path =
244 usb_hid_report_path_try_insert(report, path);
[1519b91]245
[9d05599]246 field->size = report_item->size;
[ee7e7c93]247
[574f276]248 if(report_item->type == USB_HID_REPORT_TYPE_INPUT) {
[ee7e7c93]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 }
[574f276]258 }
259 else {
260 field->offset = report_item->offset + (i * report_item->size);
261 }
[3b5d5b9d]262
[ee7e7c93]263
[574f276]264 if(report->use_report_ids != 0) {
[9d05599]265 field->offset += 8;
266 report->use_report_ids = 1;
267 }
[ee7e7c93]268
[9d05599]269 field->item_flags = report_item->item_flags;
270
271 /* find the right report list*/
272 usb_hid_report_description_t *report_des;
[f3b39b4]273 report_des = usb_hid_report_find_description(report,
274 report_item->id, report_item->type);
275
[9d05599]276 if(report_des == NULL){
[f3b39b4]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));
[9d05599]285
286 report_des->type = report_item->type;
287 report_des->report_id = report_item->id;
[1432fcf3]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
[b72efe8]293 link_initialize (&report_des->reports_link);
[9d05599]294 list_initialize (&report_des->report_items);
295
[b72efe8]296 list_append(&report_des->reports_link, &report->reports);
[9d05599]297 report->report_count++;
298 }
299
300 /* append this field to the end of founded report list */
[b72efe8]301 list_append(&field->ritems_link, &report_des->report_items);
[9d05599]302
303 /* update the sizes */
304 report_des->bit_length += field->size;
305 report_des->item_length++;
306
307 }
308
[3a6e423]309 // free only when not used!!!
310 if(usages && usages_used == 0) {
311 free(usages);
312 }
[9d05599]313
314 return EOK;
315}
[a76b01b4]316
[f3b39b4]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) {
[9d05599]330
[0dd3e49]331 if(report == NULL) {
332 return NULL;
333 }
334
[feeac0d]335 list_foreach(report->reports, reports_link,
336 usb_hid_report_description_t, report_des) {
[dcb7d7cd]337 // if report id not set, return the first of the type
338 if(((report_des->report_id == report_id) || (report_id == 0)) &&
[f3b39b4]339 (report_des->type == type)) {
[9d05599]340 return report_des;
341 }
342 }
343
344 return NULL;
345}
[a76b01b4]346
[9d05599]347
348/** Parse HID report descriptor.
349 *
350 * @param parser Opaque HID report parser structure.
351 * @param data Data describing the report.
352 * @return Error code.
[f3b39b4]353 * @retval ENOMEM If no more memmory is available
354 * @retval EINVAL If invalid data are founded
355 * @retval EOK If report descriptor is successfully parsed
[9d05599]356 */
357int usb_hid_parse_report_descriptor(usb_hid_report_t *report,
358 const uint8_t *data, size_t size)
359{
360 size_t i=0;
361 uint8_t tag=0;
362 uint8_t item_size=0;
363 int class=0;
364 int ret;
365 usb_hid_report_item_t *report_item=0;
366 usb_hid_report_item_t *new_report_item;
367 usb_hid_report_path_t *usage_path;
368
369 size_t offset_input=0;
370 size_t offset_output=0;
371 size_t offset_feature=0;
[b72efe8]372
373 link_t *item_link;
[9d05599]374
[b72efe8]375 list_t stack;
376 list_initialize(&stack);
[9d05599]377
378 /* parser structure initialization*/
379 if(usb_hid_report_init(report) != EOK) {
380 return EINVAL;
381 }
382
383 /*report item initialization*/
384 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
385 return ENOMEM;
386 }
387 memset(report_item, 0, sizeof(usb_hid_report_item_t));
[b72efe8]388 link_initialize(&(report_item->link));
[9d05599]389
390 /* usage path context initialization */
391 if(!(usage_path=usb_hid_report_path())){
392 return ENOMEM;
393 }
[22ded10]394 usb_hid_report_path_append_item(usage_path, 0, 0);
[9d05599]395
396 while(i<size){
397 if(!USB_HID_ITEM_IS_LONG(data[i])){
398
399 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
400 return EINVAL;
401 }
402
403 tag = USB_HID_ITEM_TAG(data[i]);
404 item_size = USB_HID_ITEM_SIZE(data[i]);
405 class = USB_HID_ITEM_TAG_CLASS(data[i]);
406
407 ret = usb_hid_report_parse_tag(tag,class,data+i+1,
[f3b39b4]408 item_size,report_item, usage_path);
409
[9d05599]410 switch(ret){
[f3b39b4]411 case USB_HID_NEW_REPORT_ITEM:
412 /* store report item to report and create the
413 * new one store current collection path
414 */
415 report_item->usage_path = usage_path;
[9d05599]416
[f3b39b4]417 usb_hid_report_path_set_report_id(
418 report_item->usage_path, report_item->id);
419
420 if(report_item->id != 0){
421 report->use_report_ids = 1;
422 }
[9d05599]423
[f3b39b4]424 switch(tag) {
425 case USB_HID_REPORT_TAG_INPUT:
426 report_item->type =
427 USB_HID_REPORT_TYPE_INPUT;
428
429 report_item->offset = offset_input;
430 offset_input += report_item->count *
431 report_item->size;
432 break;
433
434 case USB_HID_REPORT_TAG_OUTPUT:
435 report_item->type =
436 USB_HID_REPORT_TYPE_OUTPUT;
[9d05599]437
[f3b39b4]438 report_item->offset = offset_output;
439 offset_output += report_item->count *
440 report_item->size;
[9d05599]441 break;
[f3b39b4]442
443 case USB_HID_REPORT_TAG_FEATURE:
444 report_item->type =
445 USB_HID_REPORT_TYPE_FEATURE;
[9d05599]446
[f3b39b4]447 report_item->offset = offset_feature;
448 offset_feature += report_item->count *
449 report_item->size;
[9d05599]450 break;
[f3b39b4]451
452 default:
453 usb_log_debug2(
454 "\tjump over - tag %X\n", tag);
455 break;
456 }
457
458 /*
459 * append new fields to the report structure
460 */
461 usb_hid_report_append_fields(report,
462 report_item);
463
464 /* reset local items */
465 usb_hid_report_reset_local_items (report_item);
466 break;
467
468 case USB_HID_RESET_OFFSET:
469 offset_input = 0;
470 offset_output = 0;
471 offset_feature = 0;
472 usb_hid_report_path_set_report_id (usage_path,
473 report_item->id);
474 break;
475
476 case USB_HID_REPORT_TAG_PUSH:
477 // push current state to stack
478 new_report_item = usb_hid_report_item_clone(
479 report_item);
480
481 usb_hid_report_path_t *tmp_path =
482 usb_hid_report_path_clone(usage_path);
[9d05599]483
[f3b39b4]484 new_report_item->usage_path = tmp_path;
[9d05599]485
[f3b39b4]486 list_prepend (&new_report_item->link, &stack);
487 break;
488 case USB_HID_REPORT_TAG_POP:
489 // restore current state from stack
[b72efe8]490 item_link = list_first(&stack);
491 if (item_link == NULL) {
[f3b39b4]492 return EINVAL;
493 }
494 free(report_item);
[b72efe8]495
496 report_item = list_get_instance(item_link,
[f3b39b4]497 usb_hid_report_item_t, link);
[b72efe8]498
[f3b39b4]499 usb_hid_report_usage_path_t *tmp_usage_path;
500 tmp_usage_path = list_get_instance(
[b72efe8]501 report_item->usage_path->cpath_link.prev,
502 usb_hid_report_usage_path_t, rpath_items_link);
503
[f3b39b4]504 usb_hid_report_set_last_item(usage_path,
505 USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
506
507 usb_hid_report_set_last_item(usage_path,
508 USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
[9d05599]509
[f3b39b4]510 usb_hid_report_path_free(report_item->usage_path);
[b72efe8]511 list_remove (item_link);
[9d05599]512
[f3b39b4]513 break;
[9d05599]514
[f3b39b4]515 default:
516 // nothing special to do
517 break;
[9d05599]518 }
519
520 /* jump over the processed block */
521 i += 1 + USB_HID_ITEM_SIZE(data[i]);
522 }
523 else{
524 // TBD
525 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
526 }
527
528
529 }
530
531 return EOK;
532}
533
[a76b01b4]534
[9d05599]535
536/**
537 * Parse one tag of the report descriptor
538 *
539 * @param Tag to parse
540 * @param Report descriptor buffer
541 * @param Size of data belongs to this tag
542 * @param Current report item structe
543 * @return Code of action to be done next
544 */
[f3b39b4]545int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
546 size_t item_size, usb_hid_report_item_t *report_item,
547 usb_hid_report_path_t *usage_path) {
548
[9d05599]549 int ret;
550
551 switch(class){
[f3b39b4]552 case USB_HID_TAG_CLASS_MAIN:
[9d05599]553
[f3b39b4]554 if((ret=usb_hid_report_parse_main_tag(tag, data, item_size,
555 report_item, usage_path)) == EOK) {
[9d05599]556
[f3b39b4]557 return USB_HID_NEW_REPORT_ITEM;
558 }
559 else {
560 return ret;
561 }
562 break;
[9d05599]563
[f3b39b4]564 case USB_HID_TAG_CLASS_GLOBAL:
565 return usb_hid_report_parse_global_tag(tag, data, item_size,
566 report_item, usage_path);
567 break;
568
569 case USB_HID_TAG_CLASS_LOCAL:
570 return usb_hid_report_parse_local_tag(tag, data, item_size,
571 report_item, usage_path);
572 break;
573
574 default:
575 return USB_HID_NO_ACTION;
[9d05599]576 }
577}
578
579/**
580 * Parse main tags of report descriptor
581 *
582 * @param Tag identifier
583 * @param Data buffer
584 * @param Length of data buffer
585 * @param Current state table
586 * @return Error code
587 */
588
[f3b39b4]589int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data,
590 size_t item_size, usb_hid_report_item_t *report_item,
591 usb_hid_report_path_t *usage_path)
[674cf89]592{
593 usb_hid_report_usage_path_t *path_item;
594
[9d05599]595 switch(tag)
596 {
[f3b39b4]597 case USB_HID_REPORT_TAG_INPUT:
598 case USB_HID_REPORT_TAG_OUTPUT:
599 case USB_HID_REPORT_TAG_FEATURE:
600 report_item->item_flags = *data;
601 return EOK;
602 break;
[9d05599]603
[f3b39b4]604 case USB_HID_REPORT_TAG_COLLECTION:
[3a6e423]605
[f3b39b4]606 /* store collection atributes */
[b72efe8]607 path_item = list_get_instance(list_first(&usage_path->items),
608 usb_hid_report_usage_path_t, rpath_items_link);
609 path_item->flags = *data;
[22ded10]610
[f3b39b4]611 /* set last item */
612 usb_hid_report_set_last_item(usage_path,
613 USB_HID_TAG_CLASS_GLOBAL,
614 USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[
615 report_item->usages_count-1]));
616
617 usb_hid_report_set_last_item(usage_path,
618 USB_HID_TAG_CLASS_LOCAL,
619 USB_HID_EXTENDED_USAGE(report_item->usages[
620 report_item->usages_count-1]));
[674cf89]621
[f3b39b4]622 /* append the new one which will be set by common usage/usage
623 * page */
624 usb_hid_report_path_append_item(usage_path,
625 report_item->usage_page,
626 report_item->usages[report_item->usages_count-1]);
627
628 usb_hid_report_reset_local_items (report_item);
629 return USB_HID_NO_ACTION;
630 break;
[9d05599]631
[f3b39b4]632 case USB_HID_REPORT_TAG_END_COLLECTION:
633 usb_hid_report_remove_last_item(usage_path);
634 return USB_HID_NO_ACTION;
635 break;
636
637 default:
638 return USB_HID_NO_ACTION;
[9d05599]639 }
640
641 return EOK;
642}
643
644/**
645 * Parse global tags of report descriptor
646 *
647 * @param Tag identifier
648 * @param Data buffer
649 * @param Length of data buffer
650 * @param Current state table
651 * @return Error code
652 */
[f3b39b4]653int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data,
654 size_t item_size, usb_hid_report_item_t *report_item,
655 usb_hid_report_path_t *usage_path) {
656
[9d05599]657 switch(tag)
658 {
[f3b39b4]659 case USB_HID_REPORT_TAG_USAGE_PAGE:
660 report_item->usage_page =
661 usb_hid_report_tag_data_uint32(data, item_size);
662 break;
663
664 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
665 report_item->logical_minimum = USB_HID_UINT32_TO_INT32(
666 usb_hid_report_tag_data_uint32(data,item_size),
667 item_size * 8);
668 break;
669
670 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
671 report_item->logical_maximum = USB_HID_UINT32_TO_INT32(
672 usb_hid_report_tag_data_uint32(data,item_size),
673 item_size * 8);
674 break;
675
676 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
677 report_item->physical_minimum = USB_HID_UINT32_TO_INT32(
678 usb_hid_report_tag_data_uint32(data,item_size),
679 item_size * 8);
680 break;
681
682 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
683 report_item->physical_maximum = USB_HID_UINT32_TO_INT32(
684 usb_hid_report_tag_data_uint32(data,item_size),
685 item_size * 8);
686 break;
687
688 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
689 report_item->unit_exponent = usb_hid_report_tag_data_uint32(
690 data,item_size);
691 break;
692
693 case USB_HID_REPORT_TAG_UNIT:
694 report_item->unit = usb_hid_report_tag_data_uint32(
695 data,item_size);
696 break;
697
698 case USB_HID_REPORT_TAG_REPORT_SIZE:
699 report_item->size = usb_hid_report_tag_data_uint32(
700 data,item_size);
701 break;
702
703 case USB_HID_REPORT_TAG_REPORT_COUNT:
704 report_item->count = usb_hid_report_tag_data_uint32(
705 data,item_size);
706 break;
707
708 case USB_HID_REPORT_TAG_REPORT_ID:
709 report_item->id = usb_hid_report_tag_data_uint32(data,
710 item_size);
711 return USB_HID_RESET_OFFSET;
712 break;
713
714 case USB_HID_REPORT_TAG_PUSH:
715 case USB_HID_REPORT_TAG_POP:
716 /*
717 * stack operations are done in top level parsing
718 * function
719 */
720 return tag;
721 break;
[9d05599]722
[f3b39b4]723 default:
724 return USB_HID_NO_ACTION;
[9d05599]725 }
726
727 return EOK;
728}
729
730/**
731 * Parse local tags of report descriptor
732 *
733 * @param Tag identifier
734 * @param Data buffer
735 * @param Length of data buffer
736 * @param Current state table
737 * @return Error code
738 */
[f3b39b4]739int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data,
740 size_t item_size, usb_hid_report_item_t *report_item,
741 usb_hid_report_path_t *usage_path)
[9d05599]742{
[3a6e423]743 int32_t extended_usage;
744
[1be39e9]745 switch(tag) {
[f3b39b4]746 case USB_HID_REPORT_TAG_USAGE:
747 switch(report_item->in_delimiter) {
748 case INSIDE_DELIMITER_SET:
749 /* nothing to do
750 * we catch only the first one
751 */
[1be39e9]752 break;
[f3b39b4]753
754 case START_DELIMITER_SET:
755 report_item->in_delimiter = INSIDE_DELIMITER_SET;
756 case OUTSIDE_DELIMITER_SET:
757 extended_usage = ((report_item->usage_page) << 16);
758 extended_usage += usb_hid_report_tag_data_uint32(
759 data,item_size);
[3a6e423]760
[f3b39b4]761 report_item->usages[report_item->usages_count] =
762 extended_usage;
763
764 report_item->usages_count++;
765 break;
766 }
767 break;
768
769 case USB_HID_REPORT_TAG_USAGE_MINIMUM:
770 if (item_size == 3) {
771 // usage extended usages
772 report_item->extended_usage_page =
773 USB_HID_EXTENDED_USAGE_PAGE(
774 usb_hid_report_tag_data_uint32(data,item_size));
775
776
777 report_item->usage_minimum =
778 USB_HID_EXTENDED_USAGE(
779 usb_hid_report_tag_data_uint32(data,item_size));
780 }
781 else {
782 report_item->usage_minimum =
783 usb_hid_report_tag_data_uint32(data,item_size);
784 }
785 break;
786
787 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
788 if (item_size == 3) {
789 if(report_item->extended_usage_page !=
790 USB_HID_EXTENDED_USAGE_PAGE(
791 usb_hid_report_tag_data_uint32(data,item_size))) {
[3a6e423]792
[f3b39b4]793 return EINVAL;
[1be39e9]794 }
[f3b39b4]795
796 // usage extended usages
797 report_item->extended_usage_page =
798 USB_HID_EXTENDED_USAGE_PAGE(
799 usb_hid_report_tag_data_uint32(data,item_size));
800
801 report_item->usage_maximum =
802 USB_HID_EXTENDED_USAGE(
803 usb_hid_report_tag_data_uint32(data,item_size));
804 }
805 else {
806 report_item->usage_maximum =
807 usb_hid_report_tag_data_uint32(data,item_size);
808 }
[3a6e423]809
[f3b39b4]810 // vlozit zaznamy do pole usages
811 int32_t i;
812 for(i = report_item->usage_minimum;
813 i <= report_item->usage_maximum; i++) {
814
815 if(report_item->extended_usage_page) {
816 report_item->usages[report_item->usages_count++] =
817 (report_item->extended_usage_page << 16) + i;
[3a6e423]818 }
[f3b39b4]819 else {
820 report_item->usages[report_item->usages_count++] =
821 (report_item->usage_page << 16) + i;
822 }
823 }
824 report_item->extended_usage_page = 0;
[3a6e423]825
[f3b39b4]826 break;
827
828 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
829 report_item->designator_index =
830 usb_hid_report_tag_data_uint32(data,item_size);
831 break;
832
833 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
834 report_item->designator_minimum =
835 usb_hid_report_tag_data_uint32(data,item_size);
836 break;
837
838 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
839 report_item->designator_maximum =
840 usb_hid_report_tag_data_uint32(data,item_size);
841 break;
842
843 case USB_HID_REPORT_TAG_STRING_INDEX:
844 report_item->string_index =
845 usb_hid_report_tag_data_uint32(data,item_size);
846 break;
847
848 case USB_HID_REPORT_TAG_STRING_MINIMUM:
849 report_item->string_minimum =
850 usb_hid_report_tag_data_uint32(data,item_size);
851 break;
852
853 case USB_HID_REPORT_TAG_STRING_MAXIMUM:
854 report_item->string_maximum =
855 usb_hid_report_tag_data_uint32(data,item_size);
856 break;
857
858 case USB_HID_REPORT_TAG_DELIMITER:
859 report_item->in_delimiter =
860 usb_hid_report_tag_data_uint32(data,item_size);
861 break;
862
863 default:
864 return USB_HID_NO_ACTION;
[9d05599]865 }
[1be39e9]866
[9d05599]867 return EOK;
868}
[a76b01b4]869
[9d05599]870
871/**
872 * Converts raw data to uint32 (thats the maximum length of short item data)
873 *
874 * @param Data buffer
875 * @param Size of buffer
876 * @return Converted int32 number
877 */
878uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
879{
880 unsigned int i;
881 uint32_t result;
882
883 result = 0;
884 for(i=0; i<size; i++) {
885 result = (result | (data[i]) << (i*8));
886 }
887
888 return result;
889}
[a76b01b4]890
[9d05599]891
892/**
893 * Prints content of given list of report items.
894 *
895 * @param List of report items (usb_hid_report_item_t)
896 * @return void
897 */
[b72efe8]898void usb_hid_descriptor_print_list(list_t *list)
[9d05599]899{
[b72efe8]900 if(list == NULL || list_empty(list)) {
[9d05599]901 usb_log_debug("\tempty\n");
902 return;
903 }
[b72efe8]904
[feeac0d]905 list_foreach(*list, ritems_link, usb_hid_report_field_t,
906 report_item) {
[9d05599]907 usb_log_debug("\t\tOFFSET: %X\n", report_item->offset);
[f3b39b4]908 usb_log_debug("\t\tSIZE: %zu\n", report_item->size);
[b72efe8]909 usb_log_debug("\t\tLOGMIN: %d\n",
[f3b39b4]910 report_item->logical_minimum);
[b72efe8]911 usb_log_debug("\t\tLOGMAX: %d\n",
912 report_item->logical_maximum);
913 usb_log_debug("\t\tPHYMIN: %d\n",
914 report_item->physical_minimum);
915 usb_log_debug("\t\tPHYMAX: %d\n",
916 report_item->physical_maximum);
917 usb_log_debug("\t\ttUSAGEMIN: %X\n",
[f3b39b4]918 report_item->usage_minimum);
919 usb_log_debug("\t\tUSAGEMAX: %X\n",
920 report_item->usage_maximum);
[b72efe8]921 usb_log_debug("\t\tUSAGES COUNT: %zu\n",
[f3b39b4]922 report_item->usages_count);
[9d05599]923
924 usb_log_debug("\t\tVALUE: %X\n", report_item->value);
925 usb_log_debug("\t\ttUSAGE: %X\n", report_item->usage);
926 usb_log_debug("\t\tUSAGE PAGE: %X\n", report_item->usage_page);
[b72efe8]927
[3a6e423]928 usb_hid_print_usage_path(report_item->collection_path);
[b9d7965]929
[b72efe8]930 usb_log_debug("\n");
[9d05599]931 }
932}
[a76b01b4]933
[f3b39b4]934
[9d05599]935/**
936 * Prints content of given report descriptor in human readable format.
937 *
938 * @param parser Parsed descriptor to print
939 * @return void
940 */
941void usb_hid_descriptor_print(usb_hid_report_t *report)
942{
[feeac0d]943 if (report == NULL)
[9d05599]944 return;
945
[feeac0d]946 list_foreach(report->reports, reports_link,
947 usb_hid_report_description_t, report_des) {
[9d05599]948 usb_log_debug("Report ID: %d\n", report_des->report_id);
949 usb_log_debug("\tType: %d\n", report_des->type);
[b72efe8]950 usb_log_debug("\tLength: %zu\n", report_des->bit_length);
[d861c22]951 usb_log_debug("\tB Size: %zu\n",
[b72efe8]952 usb_hid_report_byte_size(report,
953 report_des->report_id,
[d861c22]954 report_des->type));
[b72efe8]955 usb_log_debug("\tItems: %zu\n", report_des->item_length);
[9d05599]956
957 usb_hid_descriptor_print_list(&report_des->report_items);
958 }
959}
[a76b01b4]960
[9d05599]961
962
963/** Frees the HID report descriptor parser structure
964 *
965 * @param parser Opaque HID report parser structure
966 * @return void
967 */
[a8c4e871]968void usb_hid_report_deinit(usb_hid_report_t *report)
[9d05599]969{
970 if(report == NULL){
971 return;
972 }
973
974 // free collection paths
[b72efe8]975 link_t *path_link;
[9d05599]976 usb_hid_report_path_t *path;
977 while(!list_empty(&report->collection_paths)) {
[b72efe8]978 path_link = list_first(&report->collection_paths);
979 path = list_get_instance(path_link,
980 usb_hid_report_path_t, cpath_link);
[f3b39b4]981
[b72efe8]982 list_remove(path_link);
983 usb_hid_report_path_free(path);
[9d05599]984 }
985
986 // free report items
987 usb_hid_report_description_t *report_des;
988 usb_hid_report_field_t *field;
989 while(!list_empty(&report->reports)) {
[b72efe8]990 report_des = list_get_instance(list_first(&report->reports),
991 usb_hid_report_description_t, reports_link);
[f3b39b4]992
[b72efe8]993 list_remove(&report_des->reports_link);
[9d05599]994
995 while(!list_empty(&report_des->report_items)) {
[f3b39b4]996 field = list_get_instance(
[b72efe8]997 list_first(&report_des->report_items),
998 usb_hid_report_field_t, ritems_link);
[f3b39b4]999
[b72efe8]1000 list_remove(&field->ritems_link);
[9d05599]1001
1002 free(field);
1003 }
1004
1005 free(report_des);
1006 }
1007
1008 return;
1009}
[a76b01b4]1010
[9d05599]1011
1012/**
1013 * @}
1014 */
Note: See TracBrowser for help on using the repository browser.