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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1b20da0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on non-empty lines, in certain file types.

Command used: tools/srepl '\([^[:space:]]\)\s\+$' '\1' -- *.c *.h *.py *.sh *.s *.S *.ag

  • Property mode set to 100644
File size: 24.8 KB
RevLine 
[9d05599]1/*
2 * Copyright (c) 2011 Matej Klonfar
[e0a5d4c]3 * Copyright (c) 2018 Ondrej Hlavaty
[9d05599]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[160b75e]30/** @addtogroup libusbhid
[9d05599]31 * @{
32 */
33/** @file
34 * HID report descriptor and report data parser implementation.
35 */
[faa44e58]36#include <usb/hid/hidparser.h>
[9d05599]37#include <errno.h>
38#include <stdio.h>
39#include <mem.h>
40#include <usb/debug.h>
41#include <assert.h>
[38d150e]42#include <stdlib.h>
[9d05599]43
[a76b01b4]44
[f3b39b4]45/*
46 * Constants defining current parsing mode for correct parsing of the set of
47 * local tags (usage) enclosed in delimter tags.
48 */
49/**
50 * Second delimiter tag was read. The set of local items (usage) ended.
51 */
[22ded10]52#define OUTSIDE_DELIMITER_SET 0
[f3b39b4]53
54/**
55 * First delimiter tag was read. The set of local items (usage) started.
56 */
[22ded10]57#define START_DELIMITER_SET 1
[f3b39b4]58
59/**
60 * Parser is in the set of local items.
61 */
[22ded10]62#define INSIDE_DELIMITER_SET 2
[f3b39b4]63
[a76b01b4]64
[22ded10]65
[9d05599]66/** The new report item flag. Used to determine when the item is completly
67 * configured and should be added to the report structure
68 */
69#define USB_HID_NEW_REPORT_ITEM 1
70
71/** No special action after the report descriptor tag is processed should be
72 * done
73 */
74#define USB_HID_NO_ACTION 2
75
76#define USB_HID_RESET_OFFSET 3
77
[3ca4ae9]78#define USB_HID_INVALID -98
[9d05599]79/** Unknown tag was founded in report descriptor data*/
80#define USB_HID_UNKNOWN_TAG -99
81
[a76b01b4]82
[f3b39b4]83/**
84 * Checks if given collection path is already present in report structure and
85 * inserts it if not.
86 *
[1b20da0]87 * @param report Report structure
88 * @param cmp_path The collection path
[f3b39b4]89 * @return Pointer to the result collection path in report structure.
90 * @retval NULL If some error occurs
91 */
[b72efe8]92usb_hid_report_path_t *usb_hid_report_path_try_insert(usb_hid_report_t *report,
93 usb_hid_report_path_t *cmp_path)
94{
95 link_t *path_it = report->collection_paths.head.next;
[1519b91]96 usb_hid_report_path_t *path = NULL;
[3a6e423]97
[f3b39b4]98 if((report == NULL) || (cmp_path == NULL)) {
99 return NULL;
100 }
[3a6e423]101
[b72efe8]102 while(path_it != &report->collection_paths.head) {
[f3b39b4]103 path = list_get_instance(path_it, usb_hid_report_path_t,
[b72efe8]104 cpath_link);
[1519b91]105
[f3b39b4]106 if(usb_hid_report_compare_usage_path(path, cmp_path,
[3ca4ae9]107 USB_HID_PATH_COMPARE_STRICT) == 0){
[1519b91]108 break;
[b72efe8]109 }
[1519b91]110 path_it = path_it->next;
111 }
[b72efe8]112 if(path_it == &report->collection_paths.head) {
[f3b39b4]113 path = usb_hid_report_path_clone(cmp_path);
114 if(path == NULL) {
115 return NULL;
116 }
[b72efe8]117 list_append(&path->cpath_link, &report->collection_paths);
[1519b91]118 report->collection_paths_count++;
[b9d7965]119
120 return path;
121 }
122 else {
[f3b39b4]123 return list_get_instance(path_it, usb_hid_report_path_t,
[1b20da0]124 cpath_link);
[1519b91]125 }
126}
[9d05599]127
[a76b01b4]128
[9d05599]129/**
130 * Initialize the report descriptor parser structure
131 *
132 * @param parser Report descriptor parser structure
133 * @return Error code
[f3b39b4]134 * @retval EINVAL If no report structure was given
135 * @retval EOK If report structure was successfully initialized
[9d05599]136 */
[5a6cc679]137errno_t usb_hid_report_init(usb_hid_report_t *report)
[9d05599]138{
[8c62a71]139 if (report == NULL) {
[9d05599]140 return EINVAL;
141 }
142
143 memset(report, 0, sizeof(usb_hid_report_t));
144 list_initialize(&report->reports);
145 list_initialize(&report->collection_paths);
146
147 report->use_report_ids = 0;
[8c62a71]148 return EOK;
[9d05599]149}
150
[a76b01b4]151
[3b5d5b9d]152
[f3b39b4]153/**
[3b5d5b9d]154 *
155 *
[f3b39b4]156 * @param report Report structure in which the new report items should be
157 * stored
[1b20da0]158 * @param report_item Current report descriptor's parsing state table
[f3b39b4]159 * @return Error code
160 * @retval EOK If all fields were successfully append to report
161 * @retval EINVAL If invalid parameters (NULL) was given
162 * @retval ENOMEM If there is no memmory to store new report description
163 *
[3b5d5b9d]164 */
[5a6cc679]165errno_t usb_hid_report_append_fields(usb_hid_report_t *report,
[f3b39b4]166 usb_hid_report_item_t *report_item) {
167
[9d05599]168 usb_hid_report_field_t *field;
169 int i;
170
[3a6e423]171 uint32_t *usages;
172 int usages_used=0;
[f3b39b4]173
174 if((report == NULL) || (report_item == NULL)) {
175 return EINVAL;
176 }
177
[3a6e423]178 if(report_item->usages_count > 0){
[806a779]179 usages = malloc(sizeof(uint32_t) * report_item->usages_count);
[f3b39b4]180 memcpy(usages, report_item->usages, sizeof(int32_t) *
[1b20da0]181 report_item->usages_count);
[9d05599]182 }
[3a6e423]183 else {
184 usages = NULL;
185 }
186
[1b20da0]187 usb_hid_report_path_t *path = report_item->usage_path;
[9d05599]188 for(i=0; i<report_item->count; i++){
189
190 field = malloc(sizeof(usb_hid_report_field_t));
[574f276]191 if(field == NULL) {
192 return ENOMEM;
193 }
194
[9d05599]195 memset(field, 0, sizeof(usb_hid_report_field_t));
[b72efe8]196 link_initialize(&field->ritems_link);
[9d05599]197
[1b20da0]198 /* fill the attributes */
[9d05599]199 field->logical_minimum = report_item->logical_minimum;
200 field->logical_maximum = report_item->logical_maximum;
201 field->physical_minimum = report_item->physical_minimum;
202 field->physical_maximum = report_item->physical_maximum;
203
[3a6e423]204 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0){
[1b20da0]205 /*
[f3b39b4]206 Store usage array. The Correct Usage Page and Usage is
207 depending on data in report and will be filled later
[3a6e423]208 */
209 field->usage = 0;
210 field->usage_page = 0; //report_item->usage_page;
211
212 field->usages_count = report_item->usages_count;
213 field->usages = usages;
214 usages_used = 1;
[9d05599]215 }
216 else {
217
[3a6e423]218 /* Fill the correct Usage and Usage Page */
219 int32_t usage;
220 if(i < report_item->usages_count) {
[3b5d5b9d]221 usage = report_item->usages[i];
[9d05599]222 }
223 else {
[ee7e7c93]224 usage = report_item->usages[
[1b20da0]225 report_item->usages_count- 1];
[9d05599]226 }
227
[3a6e423]228 if(USB_HID_IS_EXTENDED_USAGE(usage)){
229 field->usage = USB_HID_EXTENDED_USAGE(usage);
[1b20da0]230 field->usage_page =
[f3b39b4]231 USB_HID_EXTENDED_USAGE_PAGE(usage);
[9d05599]232 }
233 else {
[3a6e423]234 // should not occur
[9d05599]235 field->usage = usage;
[3a6e423]236 field->usage_page = report_item->usage_page;
[9d05599]237 }
238 }
239
[f3b39b4]240 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_GLOBAL,
241 field->usage_page);
242 usb_hid_report_set_last_item(path, USB_HID_TAG_CLASS_LOCAL,
243 field->usage);
[1519b91]244
[f3b39b4]245 field->collection_path =
246 usb_hid_report_path_try_insert(report, path);
[1519b91]247
[9d05599]248 field->size = report_item->size;
[ee7e7c93]249
[6283cefb]250 field->offset = report_item->offset + (i * report_item->size);
[ee7e7c93]251
[574f276]252 if(report->use_report_ids != 0) {
[9d05599]253 field->offset += 8;
254 report->use_report_ids = 1;
255 }
[ee7e7c93]256
[9d05599]257 field->item_flags = report_item->item_flags;
258
259 /* find the right report list*/
260 usb_hid_report_description_t *report_des;
[f3b39b4]261 report_des = usb_hid_report_find_description(report,
262 report_item->id, report_item->type);
263
[9d05599]264 if(report_des == NULL){
[f3b39b4]265 report_des = malloc(
266 sizeof(usb_hid_report_description_t));
267 if(report_des == NULL) {
268 return ENOMEM;
269 }
270
271 memset(report_des, 0,
272 sizeof(usb_hid_report_description_t));
[9d05599]273
274 report_des->type = report_item->type;
275 report_des->report_id = report_item->id;
[1432fcf3]276 if(report_des->report_id != 0) {
277 /* set up the bit length by report_id field */
278 report_des->bit_length = 8;
279 }
280
[b72efe8]281 link_initialize (&report_des->reports_link);
[9d05599]282 list_initialize (&report_des->report_items);
283
[b72efe8]284 list_append(&report_des->reports_link, &report->reports);
[9d05599]285 report->report_count++;
286 }
287
288 /* append this field to the end of founded report list */
[b72efe8]289 list_append(&field->ritems_link, &report_des->report_items);
[9d05599]290
291 /* update the sizes */
292 report_des->bit_length += field->size;
293 report_des->item_length++;
294
295 }
296
[3a6e423]297 // free only when not used!!!
298 if(usages && usages_used == 0) {
299 free(usages);
300 }
[9d05599]301
302 return EOK;
303}
[a76b01b4]304
[f3b39b4]305/**
306 * Finds description of report with given report_id and of given type in
307 * opaque report structure.
308 *
309 * @param report Opaque structure containing the parsed report descriptor
310 * @param report_id ReportId of report we are searching
311 * @param type Type of report we are searching
312 * @return Pointer to the particular report description
313 * @retval NULL If no description is founded
314 */
315usb_hid_report_description_t * usb_hid_report_find_description(
316 const usb_hid_report_t *report, uint8_t report_id,
317 usb_hid_report_type_t type) {
[9d05599]318
[0dd3e49]319 if(report == NULL) {
320 return NULL;
321 }
322
[feeac0d]323 list_foreach(report->reports, reports_link,
324 usb_hid_report_description_t, report_des) {
[dcb7d7cd]325 // if report id not set, return the first of the type
[1b20da0]326 if(((report_des->report_id == report_id) || (report_id == 0)) &&
327 (report_des->type == type)) {
[9d05599]328 return report_des;
329 }
330 }
331
332 return NULL;
333}
[a76b01b4]334
[9d05599]335
336/** Parse HID report descriptor.
337 *
338 * @param parser Opaque HID report parser structure.
339 * @param data Data describing the report.
340 * @return Error code.
[f3b39b4]341 * @retval ENOMEM If no more memmory is available
342 * @retval EINVAL If invalid data are founded
343 * @retval EOK If report descriptor is successfully parsed
[9d05599]344 */
[1b20da0]345errno_t usb_hid_parse_report_descriptor(usb_hid_report_t *report,
[9d05599]346 const uint8_t *data, size_t size)
347{
348 size_t i=0;
349 uint8_t tag=0;
350 uint8_t item_size=0;
351 int class=0;
352 int ret;
353 usb_hid_report_item_t *report_item=0;
[1b20da0]354 usb_hid_report_item_t *new_report_item;
[9d05599]355 usb_hid_report_path_t *usage_path;
356
357 size_t offset_input=0;
358 size_t offset_output=0;
359 size_t offset_feature=0;
[b72efe8]360
361 link_t *item_link;
[9d05599]362
[b72efe8]363 list_t stack;
364 list_initialize(&stack);
[9d05599]365
366 /* parser structure initialization*/
367 if(usb_hid_report_init(report) != EOK) {
368 return EINVAL;
369 }
370
371 /*report item initialization*/
372 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
373 return ENOMEM;
374 }
375 memset(report_item, 0, sizeof(usb_hid_report_item_t));
[b72efe8]376 link_initialize(&(report_item->link));
[9d05599]377
378 /* usage path context initialization */
379 if(!(usage_path=usb_hid_report_path())){
380 return ENOMEM;
381 }
[1b20da0]382 usb_hid_report_path_append_item(usage_path, 0, 0);
[9d05599]383
[1b20da0]384 while(i<size){
[9d05599]385 if(!USB_HID_ITEM_IS_LONG(data[i])){
386
387 if((i+USB_HID_ITEM_SIZE(data[i]))>= size){
388 return EINVAL;
389 }
390
391 tag = USB_HID_ITEM_TAG(data[i]);
392 item_size = USB_HID_ITEM_SIZE(data[i]);
393 class = USB_HID_ITEM_TAG_CLASS(data[i]);
394
395 ret = usb_hid_report_parse_tag(tag,class,data+i+1,
[f3b39b4]396 item_size,report_item, usage_path);
397
[9d05599]398 switch(ret){
[f3b39b4]399 case USB_HID_NEW_REPORT_ITEM:
400 /* store report item to report and create the
401 * new one store current collection path
402 */
403 report_item->usage_path = usage_path;
[9d05599]404
[f3b39b4]405 usb_hid_report_path_set_report_id(
406 report_item->usage_path, report_item->id);
407
408 if(report_item->id != 0){
409 report->use_report_ids = 1;
410 }
[9d05599]411
[f3b39b4]412 switch(tag) {
413 case USB_HID_REPORT_TAG_INPUT:
[1b20da0]414 report_item->type =
[f3b39b4]415 USB_HID_REPORT_TYPE_INPUT;
416
417 report_item->offset = offset_input;
[1b20da0]418 offset_input += report_item->count *
[f3b39b4]419 report_item->size;
420 break;
421
422 case USB_HID_REPORT_TAG_OUTPUT:
[1b20da0]423 report_item->type =
[f3b39b4]424 USB_HID_REPORT_TYPE_OUTPUT;
[9d05599]425
[f3b39b4]426 report_item->offset = offset_output;
[1b20da0]427 offset_output += report_item->count *
[f3b39b4]428 report_item->size;
[9d05599]429 break;
[f3b39b4]430
431 case USB_HID_REPORT_TAG_FEATURE:
[1b20da0]432 report_item->type =
[f3b39b4]433 USB_HID_REPORT_TYPE_FEATURE;
[9d05599]434
[f3b39b4]435 report_item->offset = offset_feature;
[1b20da0]436 offset_feature += report_item->count *
[f3b39b4]437 report_item->size;
[9d05599]438 break;
[f3b39b4]439
440 default:
441 usb_log_debug2(
442 "\tjump over - tag %X\n", tag);
443 break;
444 }
445
[1b20da0]446 /*
447 * append new fields to the report structure
[f3b39b4]448 */
[1b20da0]449 usb_hid_report_append_fields(report,
[f3b39b4]450 report_item);
451
452 /* reset local items */
453 usb_hid_report_reset_local_items (report_item);
454 break;
455
456 case USB_HID_RESET_OFFSET:
457 offset_input = 0;
458 offset_output = 0;
459 offset_feature = 0;
[1b20da0]460 usb_hid_report_path_set_report_id (usage_path,
[f3b39b4]461 report_item->id);
462 break;
463
464 case USB_HID_REPORT_TAG_PUSH:
465 // push current state to stack
466 new_report_item = usb_hid_report_item_clone(
467 report_item);
468
[1b20da0]469 usb_hid_report_path_t *tmp_path =
[f3b39b4]470 usb_hid_report_path_clone(usage_path);
[9d05599]471
[1b20da0]472 new_report_item->usage_path = tmp_path;
[9d05599]473
[f3b39b4]474 list_prepend (&new_report_item->link, &stack);
475 break;
476 case USB_HID_REPORT_TAG_POP:
477 // restore current state from stack
[b72efe8]478 item_link = list_first(&stack);
479 if (item_link == NULL) {
[f3b39b4]480 return EINVAL;
481 }
482 free(report_item);
[b72efe8]483
484 report_item = list_get_instance(item_link,
[f3b39b4]485 usb_hid_report_item_t, link);
[b72efe8]486
[f3b39b4]487 usb_hid_report_usage_path_t *tmp_usage_path;
488 tmp_usage_path = list_get_instance(
[b72efe8]489 report_item->usage_path->cpath_link.prev,
490 usb_hid_report_usage_path_t, rpath_items_link);
491
[1b20da0]492 usb_hid_report_set_last_item(usage_path,
[f3b39b4]493 USB_HID_TAG_CLASS_GLOBAL, tmp_usage_path->usage_page);
494
[1b20da0]495 usb_hid_report_set_last_item(usage_path,
[f3b39b4]496 USB_HID_TAG_CLASS_LOCAL, tmp_usage_path->usage);
[9d05599]497
[f3b39b4]498 usb_hid_report_path_free(report_item->usage_path);
[b72efe8]499 list_remove (item_link);
[9d05599]500
[f3b39b4]501 break;
[9d05599]502
[f3b39b4]503 default:
[1b20da0]504 // nothing special to do
[f3b39b4]505 break;
[9d05599]506 }
507
508 /* jump over the processed block */
509 i += 1 + USB_HID_ITEM_SIZE(data[i]);
510 }
511 else{
512 // TBD
513 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
514 }
515
516
517 }
518
519 return EOK;
520}
521
[a76b01b4]522
[9d05599]523
524/**
525 * Parse one tag of the report descriptor
526 *
527 * @param Tag to parse
528 * @param Report descriptor buffer
529 * @param Size of data belongs to this tag
530 * @param Current report item structe
531 * @return Code of action to be done next
532 */
[f3b39b4]533int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const uint8_t *data,
534 size_t item_size, usb_hid_report_item_t *report_item,
[1b20da0]535 usb_hid_report_path_t *usage_path) {
[f3b39b4]536
[9d05599]537 int ret;
538
539 switch(class){
[f3b39b4]540 case USB_HID_TAG_CLASS_MAIN:
[9d05599]541
[f3b39b4]542 if((ret=usb_hid_report_parse_main_tag(tag, data, item_size,
[3ca4ae9]543 report_item, usage_path)) == 0) {
[9d05599]544
[f3b39b4]545 return USB_HID_NEW_REPORT_ITEM;
546 }
547 else {
548 return ret;
549 }
550 break;
[9d05599]551
[1b20da0]552 case USB_HID_TAG_CLASS_GLOBAL:
[f3b39b4]553 return usb_hid_report_parse_global_tag(tag, data, item_size,
554 report_item, usage_path);
555 break;
556
[1b20da0]557 case USB_HID_TAG_CLASS_LOCAL:
[f3b39b4]558 return usb_hid_report_parse_local_tag(tag, data, item_size,
559 report_item, usage_path);
560 break;
561
562 default:
563 return USB_HID_NO_ACTION;
[9d05599]564 }
565}
566
567/**
568 * Parse main tags of report descriptor
569 *
570 * @param Tag identifier
571 * @param Data buffer
572 * @param Length of data buffer
573 * @param Current state table
[3ca4ae9]574 * @return 0 or USB_HID_ code
[9d05599]575 */
576
[1b20da0]577int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data,
[f3b39b4]578 size_t item_size, usb_hid_report_item_t *report_item,
579 usb_hid_report_path_t *usage_path)
[674cf89]580{
581 usb_hid_report_usage_path_t *path_item;
582
[9d05599]583 switch(tag)
584 {
[f3b39b4]585 case USB_HID_REPORT_TAG_INPUT:
586 case USB_HID_REPORT_TAG_OUTPUT:
587 case USB_HID_REPORT_TAG_FEATURE:
[1b20da0]588 report_item->item_flags = *data;
589 return 0;
[f3b39b4]590 break;
[9d05599]591
[f3b39b4]592 case USB_HID_REPORT_TAG_COLLECTION:
[3a6e423]593
[f3b39b4]594 /* store collection atributes */
[b72efe8]595 path_item = list_get_instance(list_first(&usage_path->items),
596 usb_hid_report_usage_path_t, rpath_items_link);
597 path_item->flags = *data;
[22ded10]598
[f3b39b4]599 /* set last item */
[1b20da0]600 usb_hid_report_set_last_item(usage_path,
601 USB_HID_TAG_CLASS_GLOBAL,
[f3b39b4]602 USB_HID_EXTENDED_USAGE_PAGE(report_item->usages[
603 report_item->usages_count-1]));
604
[1b20da0]605 usb_hid_report_set_last_item(usage_path,
606 USB_HID_TAG_CLASS_LOCAL,
[f3b39b4]607 USB_HID_EXTENDED_USAGE(report_item->usages[
608 report_item->usages_count-1]));
[674cf89]609
[f3b39b4]610 /* append the new one which will be set by common usage/usage
611 * page */
[1b20da0]612 usb_hid_report_path_append_item(usage_path,
613 report_item->usage_page,
[f3b39b4]614 report_item->usages[report_item->usages_count-1]);
615
616 usb_hid_report_reset_local_items (report_item);
617 return USB_HID_NO_ACTION;
618 break;
[9d05599]619
[f3b39b4]620 case USB_HID_REPORT_TAG_END_COLLECTION:
621 usb_hid_report_remove_last_item(usage_path);
622 return USB_HID_NO_ACTION;
623 break;
624
625 default:
626 return USB_HID_NO_ACTION;
[9d05599]627 }
628
[3ca4ae9]629 return 0;
[9d05599]630}
631
632/**
633 * Parse global tags of report descriptor
634 *
635 * @param Tag identifier
636 * @param Data buffer
637 * @param Length of data buffer
638 * @param Current state table
[3ca4ae9]639 * @return 0 or USB_HID_ code
[9d05599]640 */
[1b20da0]641int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data,
642 size_t item_size, usb_hid_report_item_t *report_item,
643 usb_hid_report_path_t *usage_path) {
[f3b39b4]644
[9d05599]645 switch(tag)
646 {
[f3b39b4]647 case USB_HID_REPORT_TAG_USAGE_PAGE:
[1b20da0]648 report_item->usage_page =
[f3b39b4]649 usb_hid_report_tag_data_uint32(data, item_size);
650 break;
651
652 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
653 report_item->logical_minimum = USB_HID_UINT32_TO_INT32(
654 usb_hid_report_tag_data_uint32(data,item_size),
655 item_size * 8);
656 break;
657
658 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
659 report_item->logical_maximum = USB_HID_UINT32_TO_INT32(
[1b20da0]660 usb_hid_report_tag_data_uint32(data,item_size),
[f3b39b4]661 item_size * 8);
662 break;
663
664 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
665 report_item->physical_minimum = USB_HID_UINT32_TO_INT32(
[1b20da0]666 usb_hid_report_tag_data_uint32(data,item_size),
[f3b39b4]667 item_size * 8);
[1b20da0]668 break;
[f3b39b4]669
670 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
671 report_item->physical_maximum = USB_HID_UINT32_TO_INT32(
[1b20da0]672 usb_hid_report_tag_data_uint32(data,item_size),
[f3b39b4]673 item_size * 8);
674 break;
675
676 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
677 report_item->unit_exponent = usb_hid_report_tag_data_uint32(
678 data,item_size);
679 break;
680
681 case USB_HID_REPORT_TAG_UNIT:
682 report_item->unit = usb_hid_report_tag_data_uint32(
683 data,item_size);
684 break;
685
686 case USB_HID_REPORT_TAG_REPORT_SIZE:
687 report_item->size = usb_hid_report_tag_data_uint32(
688 data,item_size);
689 break;
690
691 case USB_HID_REPORT_TAG_REPORT_COUNT:
692 report_item->count = usb_hid_report_tag_data_uint32(
693 data,item_size);
694 break;
695
696 case USB_HID_REPORT_TAG_REPORT_ID:
[1b20da0]697 report_item->id = usb_hid_report_tag_data_uint32(data,
[f3b39b4]698 item_size);
699 return USB_HID_RESET_OFFSET;
700 break;
701
702 case USB_HID_REPORT_TAG_PUSH:
703 case USB_HID_REPORT_TAG_POP:
[1b20da0]704 /*
[f3b39b4]705 * stack operations are done in top level parsing
706 * function
707 */
708 return tag;
709 break;
[9d05599]710
[f3b39b4]711 default:
712 return USB_HID_NO_ACTION;
[9d05599]713 }
714
[3ca4ae9]715 return 0;
[9d05599]716}
717
718/**
719 * Parse local tags of report descriptor
720 *
721 * @param Tag identifier
722 * @param Data buffer
723 * @param Length of data buffer
724 * @param Current state table
[3ca4ae9]725 * @return 0 or USB_HID_ code
[9d05599]726 */
[e141281]727int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data,
728 size_t item_size, usb_hid_report_item_t *report_item,
729 usb_hid_report_path_t *usage_path)
[9d05599]730{
[3a6e423]731 int32_t extended_usage;
732
[e141281]733 switch (tag) {
[f3b39b4]734 case USB_HID_REPORT_TAG_USAGE:
[e141281]735 switch (report_item->in_delimiter) {
[f3b39b4]736 case INSIDE_DELIMITER_SET:
[e141281]737 /*
738 * Nothing to do.
739 * We catch only the first one
[f3b39b4]740 */
[1be39e9]741 break;
[e141281]742
[f3b39b4]743 case START_DELIMITER_SET:
744 report_item->in_delimiter = INSIDE_DELIMITER_SET;
[dc12262]745 /* Fallthrough */
[f3b39b4]746 case OUTSIDE_DELIMITER_SET:
747 extended_usage = ((report_item->usage_page) << 16);
[e141281]748 extended_usage +=
749 usb_hid_report_tag_data_uint32(data, item_size);
750
751 report_item->usages[report_item->usages_count] =
752 extended_usage;
753
[f3b39b4]754 report_item->usages_count++;
755 break;
756 }
757 break;
758
[e141281]759 case USB_HID_REPORT_TAG_USAGE_MINIMUM:
[f3b39b4]760 if (item_size == 3) {
[e141281]761 /* Usage extended usages */
762 report_item->extended_usage_page =
[f3b39b4]763 USB_HID_EXTENDED_USAGE_PAGE(
[e141281]764 usb_hid_report_tag_data_uint32(data, item_size));
765
766
767 report_item->usage_minimum =
[f3b39b4]768 USB_HID_EXTENDED_USAGE(
[e141281]769 usb_hid_report_tag_data_uint32(data, item_size));
770 } else {
771 report_item->usage_minimum =
772 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]773 }
774 break;
[e141281]775
[f3b39b4]776 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
777 if (item_size == 3) {
[e141281]778 if (report_item->extended_usage_page !=
779 USB_HID_EXTENDED_USAGE_PAGE(
780 usb_hid_report_tag_data_uint32(data, item_size))) {
[3ca4ae9]781 return USB_HID_INVALID;
[1be39e9]782 }
[e141281]783
784 /* Usage extended usages */
785 report_item->extended_usage_page =
786 USB_HID_EXTENDED_USAGE_PAGE(
787 usb_hid_report_tag_data_uint32(data,item_size));
788
789 report_item->usage_maximum =
790 USB_HID_EXTENDED_USAGE(
791 usb_hid_report_tag_data_uint32(data,item_size));
792 } else {
793 report_item->usage_maximum =
794 usb_hid_report_tag_data_uint32(data,item_size);
[f3b39b4]795 }
[e141281]796
797 /* Put the records into the usages array */
798 for (int32_t i = report_item->usage_minimum;
[f3b39b4]799 i <= report_item->usage_maximum; i++) {
[e141281]800
801 if (report_item->extended_usage_page) {
802 report_item->usages[report_item->usages_count++] =
803 (report_item->extended_usage_page << 16) + i;
804 } else {
805 report_item->usages[report_item->usages_count++] =
806 (report_item->usage_page << 16) + i;
[f3b39b4]807 }
808 }
809 report_item->extended_usage_page = 0;
[e141281]810
[f3b39b4]811 break;
812
813 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
[e141281]814 report_item->designator_index =
815 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]816 break;
817
818 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
[e141281]819 report_item->designator_minimum =
820 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]821 break;
[e141281]822
[f3b39b4]823 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
[e141281]824 report_item->designator_maximum =
825 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]826 break;
[e141281]827
[f3b39b4]828 case USB_HID_REPORT_TAG_STRING_INDEX:
[e141281]829 report_item->string_index =
830 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]831 break;
[e141281]832
[f3b39b4]833 case USB_HID_REPORT_TAG_STRING_MINIMUM:
[e141281]834 report_item->string_minimum =
835 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]836 break;
[e141281]837
[f3b39b4]838 case USB_HID_REPORT_TAG_STRING_MAXIMUM:
[e141281]839 report_item->string_maximum =
840 usb_hid_report_tag_data_uint32(data, item_size);
841 break;
842
[f3b39b4]843 case USB_HID_REPORT_TAG_DELIMITER:
[e141281]844 report_item->in_delimiter =
845 usb_hid_report_tag_data_uint32(data, item_size);
[f3b39b4]846 break;
[e141281]847
[f3b39b4]848 default:
849 return USB_HID_NO_ACTION;
[9d05599]850 }
[e141281]851
[3ca4ae9]852 return 0;
[9d05599]853}
[a76b01b4]854
[9d05599]855/**
856 * Converts raw data to uint32 (thats the maximum length of short item data)
857 *
858 * @param Data buffer
859 * @param Size of buffer
860 * @return Converted int32 number
861 */
862uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size)
863{
864 unsigned int i;
865 uint32_t result;
866
867 result = 0;
868 for(i=0; i<size; i++) {
869 result = (result | (data[i]) << (i*8));
870 }
871
872 return result;
873}
[a76b01b4]874
[9d05599]875
876/**
877 * Prints content of given list of report items.
878 *
879 * @param List of report items (usb_hid_report_item_t)
880 * @return void
881 */
[b72efe8]882void usb_hid_descriptor_print_list(list_t *list)
[9d05599]883{
[b72efe8]884 if(list == NULL || list_empty(list)) {
[a1732929]885 usb_log_debug("\tempty");
[9d05599]886 return;
887 }
[b72efe8]888
[feeac0d]889 list_foreach(*list, ritems_link, usb_hid_report_field_t,
890 report_item) {
[a1732929]891 usb_log_debug("\t\tOFFSET: %u", report_item->offset);
892 usb_log_debug("\t\tSIZE: %zu", report_item->size);
893 usb_log_debug("\t\tLOGMIN: %d",
[f3b39b4]894 report_item->logical_minimum);
[a1732929]895 usb_log_debug("\t\tLOGMAX: %d",
[b72efe8]896 report_item->logical_maximum);
[a1732929]897 usb_log_debug("\t\tPHYMIN: %d",
[b72efe8]898 report_item->physical_minimum);
[a1732929]899 usb_log_debug("\t\tPHYMAX: %d",
[b72efe8]900 report_item->physical_maximum);
[a1732929]901 usb_log_debug("\t\ttUSAGEMIN: %X",
[f3b39b4]902 report_item->usage_minimum);
[a1732929]903 usb_log_debug("\t\tUSAGEMAX: %X",
[f3b39b4]904 report_item->usage_maximum);
[a1732929]905 usb_log_debug("\t\tUSAGES COUNT: %zu",
[f3b39b4]906 report_item->usages_count);
[9d05599]907
[a1732929]908 usb_log_debug("\t\tVALUE: %X", report_item->value);
909 usb_log_debug("\t\ttUSAGE: %X", report_item->usage);
910 usb_log_debug("\t\tUSAGE PAGE: %X", report_item->usage_page);
[b72efe8]911
[3a6e423]912 usb_hid_print_usage_path(report_item->collection_path);
[9d05599]913 }
914}
[a76b01b4]915
[f3b39b4]916
[9d05599]917/**
918 * Prints content of given report descriptor in human readable format.
919 *
920 * @param parser Parsed descriptor to print
921 * @return void
922 */
923void usb_hid_descriptor_print(usb_hid_report_t *report)
924{
[feeac0d]925 if (report == NULL)
[9d05599]926 return;
927
[feeac0d]928 list_foreach(report->reports, reports_link,
929 usb_hid_report_description_t, report_des) {
[a1732929]930 usb_log_debug("Report ID: %d", report_des->report_id);
931 usb_log_debug("\tType: %d", report_des->type);
932 usb_log_debug("\tLength: %zu", report_des->bit_length);
933 usb_log_debug("\tB Size: %zu",
[b72efe8]934 usb_hid_report_byte_size(report,
935 report_des->report_id,
[d861c22]936 report_des->type));
[a1732929]937 usb_log_debug("\tItems: %zu", report_des->item_length);
[9d05599]938
939 usb_hid_descriptor_print_list(&report_des->report_items);
940 }
941}
[a76b01b4]942
[9d05599]943
944
[1b20da0]945/** Frees the HID report descriptor parser structure
[9d05599]946 *
947 * @param parser Opaque HID report parser structure
948 * @return void
949 */
[a8c4e871]950void usb_hid_report_deinit(usb_hid_report_t *report)
[9d05599]951{
952 if(report == NULL){
953 return;
954 }
955
956 // free collection paths
[b72efe8]957 link_t *path_link;
[9d05599]958 usb_hid_report_path_t *path;
959 while(!list_empty(&report->collection_paths)) {
[b72efe8]960 path_link = list_first(&report->collection_paths);
961 path = list_get_instance(path_link,
962 usb_hid_report_path_t, cpath_link);
[f3b39b4]963
[b72efe8]964 list_remove(path_link);
965 usb_hid_report_path_free(path);
[9d05599]966 }
967
968 // free report items
969 usb_hid_report_description_t *report_des;
970 usb_hid_report_field_t *field;
971 while(!list_empty(&report->reports)) {
[b72efe8]972 report_des = list_get_instance(list_first(&report->reports),
973 usb_hid_report_description_t, reports_link);
[f3b39b4]974
[b72efe8]975 list_remove(&report_des->reports_link);
[9d05599]976
977 while(!list_empty(&report_des->report_items)) {
[f3b39b4]978 field = list_get_instance(
[b72efe8]979 list_first(&report_des->report_items),
980 usb_hid_report_field_t, ritems_link);
[f3b39b4]981
[b72efe8]982 list_remove(&field->ritems_link);
[9d05599]983
984 free(field);
985 }
986
987 free(report_des);
988 }
989
990 return;
991}
[a76b01b4]992
[9d05599]993
994/**
995 * @}
996 */
Note: See TracBrowser for help on using the repository browser.