source: mainline/uspace/lib/usb/src/hidparser.c@ c7a2e7e

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

report item offset

  • Property mode set to 100644
File size: 14.8 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
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 * @brief HID parser implementation.
34 */
35#include <usb/classes/hidparser.h>
36#include <errno.h>
37#include <stdio.h>
38#include <adt/list.h>
39#include <malloc.h>
40#include <mem.h>
41
42#define USB_HID_NEW_REPORT_ITEM 0
43
44
45int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const const uint8_t *data, size_t item_size,
46 usb_hid_report_item_t *report_item);
47int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
48 usb_hid_report_item_t *report_item);
49int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
50 usb_hid_report_item_t *report_item);
51int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
52 usb_hid_report_item_t *report_item);
53
54void usb_hid_descriptor_print_list(link_t *head);
55int usb_hid_report_reset_local_items();
56void usb_hid_free_report_list(link_t *head);
57int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size);
58size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
59/**
60 *
61 */
62int usb_hid_parser_init(usb_hid_report_parser_t *parser)
63{
64 if(parser == NULL) {
65 return -1;
66 }
67
68 list_initialize(&(parser->input));
69 list_initialize(&(parser->output));
70 list_initialize(&(parser->feature));
71
72 return EOK;
73}
74
75
76/** Parse HID report descriptor.
77 *
78 * @param parser Opaque HID report parser structure.
79 * @param data Data describing the report.
80 * @return Error code.
81 */
82int usb_hid_parse_report_descriptor(usb_hid_report_parser_t *parser,
83 const const uint8_t *data, size_t size)
84{
85 size_t i=0;
86 uint8_t tag=0;
87 uint8_t item_size=0;
88 int class=0;
89 int ret;
90 usb_hid_report_item_t *report_item=0;
91 usb_hid_report_item_t *new_report_item;
92
93 size_t offset=0;
94
95
96 if(!(report_item=malloc(sizeof(usb_hid_report_item_t)))){
97 return ENOMEM;
98 }
99 link_initialize(&(report_item->link));
100
101 while(i<size){
102
103 if(!USB_HID_ITEM_IS_LONG(data[i])){
104 tag = USB_HID_ITEM_TAG(data[i]);
105 item_size = USB_HID_ITEM_SIZE(data[i]);
106 class = USB_HID_ITEM_TAG_CLASS(data[i]);
107
108 ret = usb_hid_report_parse_tag(tag,class,(data + (i+1)),
109 item_size,report_item);
110 switch(ret){
111 case USB_HID_NEW_REPORT_ITEM:
112 // store report item to report and create the new one
113 printf("\nNEW REPORT ITEM: %X",tag);
114
115 offset = usb_hid_count_item_offset(report_item, offset);
116 report_item->offset = offset;
117 switch(tag) {
118 case USB_HID_REPORT_TAG_INPUT:
119 printf(" - INPUT\n");
120 list_append(&(report_item->link), &(parser->input));
121 break;
122 case USB_HID_REPORT_TAG_OUTPUT:
123 printf(" - OUTPUT\n");
124 list_append(&(report_item->link), &(parser->output));
125
126 break;
127 case USB_HID_REPORT_TAG_FEATURE:
128 printf(" - FEATURE\n");
129 list_append(&(report_item->link), &(parser->feature));
130 break;
131 default:
132 printf("\tjump over tag: %X\n", tag q);
133 break;
134 }
135
136 /* clone current state table to the new item */
137 if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
138 return ENOMEM;
139 }
140 memcpy(new_report_item,report_item, sizeof(usb_hid_report_item_t));
141 link_initialize(&(new_report_item->link));
142 report_item = new_report_item;
143
144 break;
145 case USB_HID_REPORT_TAG_PUSH:
146 // push current state to stack
147 // not yet implemented
148 break;
149 case USB_HID_REPORT_TAG_POP:
150 // restore current state from stack
151 // not yet implemented
152 break;
153
154 default:
155 // nothing special to do
156 break;
157 }
158
159 /* jump over the processed block */
160 i += 1 + USB_HID_ITEM_SIZE(data[i]);
161 }
162 else{
163 // TBD
164 i += 3 + USB_HID_ITEM_SIZE(data[i+1]);
165 }
166
167
168 }
169
170
171 return EOK;
172}
173
174/** Parse and act upon a HID report.
175 *
176 * @see usb_hid_parse_report_descriptor
177 *
178 * @param parser Opaque HID report parser structure.
179 * @param data Data for the report.
180 * @param callbacks Callbacks for report actions.
181 * @param arg Custom argument (passed through to the callbacks).
182 * @return Error code.
183 */
184int usb_hid_parse_report(const usb_hid_report_parser_t *parser,
185 const const uint8_t *data, size_t size,
186 const usb_hid_report_in_callbacks_t *callbacks, void *arg)
187{
188 int i;
189
190 /* main parsing loop */
191 while(0){
192 }
193
194
195 uint8_t keys[6];
196
197 for (i = 0; i < 6; ++i) {
198 keys[i] = data[i];
199 }
200
201 callbacks->keyboard(keys, 6, 0, arg);
202
203 return EOK;
204}
205
206
207/**
208 * Parse input report.
209 *
210 * @param data Data for report
211 * @param size Size of report
212 * @param callbacks Callbacks for report actions
213 * @param arg Custom arguments
214 *
215 * @return Error code
216 */
217int usb_hid_boot_keyboard_input_report(const const uint8_t *data, size_t size,
218 const usb_hid_report_in_callbacks_t *callbacks, void *arg)
219{
220 int i;
221 usb_hid_report_item_t item;
222
223 /* fill item due to the boot protocol report descriptor */
224 // modifier keys are in the first byte
225 uint8_t modifiers = data[0];
226
227 item.offset = 2; /* second byte is reserved */
228 item.size = 8;
229 item.count = 6;
230 item.usage_minimum = 0;
231 item.usage_maximum = 255;
232 item.logical_minimum = 0;
233 item.logical_maximum = 255;
234
235 if (size != 8) {
236 return -1; //ERANGE;
237 }
238
239 uint8_t keys[6];
240 for (i = 0; i < item.count; i++) {
241 keys[i] = data[i + item.offset];
242 }
243
244 callbacks->keyboard(keys, 6, modifiers, arg);
245 return EOK;
246}
247
248/**
249 * Makes output report for keyboard boot protocol
250 *
251 * @param leds
252 * @param output Output report data buffer
253 * @param size Size of the output buffer
254 * @return Error code
255 */
256int usb_hid_boot_keyboard_output_report(uint8_t leds, uint8_t *data, size_t size)
257{
258 if(size != 1){
259 return -1;
260 }
261
262 /* used only first five bits, others are only padding*/
263 *data = leds;
264 return EOK;
265}
266
267/**
268 *
269 * @param Tag to parse
270 * @param Report descriptor buffer
271 * @param Size of data belongs to this tag
272 * @param Current report item structe
273 * @return Code of action to be done next
274 */
275int usb_hid_report_parse_tag(uint8_t tag, uint8_t class, const const uint8_t *data, size_t item_size,
276 usb_hid_report_item_t *report_item)
277{
278 switch(class){
279 case USB_HID_TAG_CLASS_MAIN:
280
281 if(usb_hid_report_parse_main_tag(tag,data,item_size,report_item) == EOK) {
282 return USB_HID_NEW_REPORT_ITEM;
283 }
284 else {
285 /*TODO process the error */
286 return -1;
287 }
288 break;
289
290 case USB_HID_TAG_CLASS_GLOBAL:
291 return usb_hid_report_parse_global_tag(tag,data,item_size,report_item);
292 break;
293
294 case USB_HID_TAG_CLASS_LOCAL:
295 return usb_hid_report_parse_local_tag(tag,data,item_size,report_item);
296 break;
297 default:
298 return -1; /* TODO ERROR CODE - UNKNOWN TAG CODE */
299 }
300}
301
302/**
303 * Parse main tags of report descriptor
304 *
305 * @param Tag identifier
306 * @param Data buffer
307 * @param Length of data buffer
308 * @param Current state table
309 * @return Error code
310 */
311
312int usb_hid_report_parse_main_tag(uint8_t tag, const uint8_t *data, size_t item_size,
313 usb_hid_report_item_t *report_item)
314{
315 switch(tag)
316 {
317 case USB_HID_REPORT_TAG_INPUT:
318 case USB_HID_REPORT_TAG_OUTPUT:
319 case USB_HID_REPORT_TAG_FEATURE:
320 report_item->item_flags = *data;
321 return USB_HID_NEW_REPORT_ITEM;
322 break;
323
324 case USB_HID_REPORT_TAG_COLLECTION:
325 // TODO
326 break;
327
328 case USB_HID_REPORT_TAG_END_COLLECTION:
329 /* should be ignored */
330 break;
331 default:
332 return -1; //TODO ERROR CODE
333 }
334
335 return EOK;
336}
337
338/**
339 * Parse global tags of report descriptor
340 *
341 * @param Tag identifier
342 * @param Data buffer
343 * @param Length of data buffer
344 * @param Current state table
345 * @return Error code
346 */
347
348int usb_hid_report_parse_global_tag(uint8_t tag, const uint8_t *data, size_t item_size,
349 usb_hid_report_item_t *report_item)
350{
351 // TODO take care about the bit length of data
352 switch(tag)
353 {
354 case USB_HID_REPORT_TAG_USAGE_PAGE:
355 report_item->usage_page = usb_hid_report_tag_data_int32(data,item_size);
356 break;
357 case USB_HID_REPORT_TAG_LOGICAL_MINIMUM:
358 report_item->logical_minimum = usb_hid_report_tag_data_int32(data,item_size);
359 break;
360 case USB_HID_REPORT_TAG_LOGICAL_MAXIMUM:
361 report_item->logical_maximum = usb_hid_report_tag_data_int32(data,item_size);
362 break;
363 case USB_HID_REPORT_TAG_PHYSICAL_MINIMUM:
364 report_item->physical_minimum = usb_hid_report_tag_data_int32(data,item_size);
365 break;
366 case USB_HID_REPORT_TAG_PHYSICAL_MAXIMUM:
367 report_item->physical_maximum = usb_hid_report_tag_data_int32(data,item_size);
368 break;
369 case USB_HID_REPORT_TAG_UNIT_EXPONENT:
370 report_item->unit_exponent = usb_hid_report_tag_data_int32(data,item_size);
371 break;
372 case USB_HID_REPORT_TAG_UNIT:
373 report_item->unit = usb_hid_report_tag_data_int32(data,item_size);
374 break;
375 case USB_HID_REPORT_TAG_REPORT_SIZE:
376 report_item->size = usb_hid_report_tag_data_int32(data,item_size);
377 break;
378 case USB_HID_REPORT_TAG_REPORT_COUNT:
379 report_item->count = usb_hid_report_tag_data_int32(data,item_size);
380 break;
381 case USB_HID_REPORT_TAG_REPORT_ID:
382 report_item->id = usb_hid_report_tag_data_int32(data,item_size);
383 break;
384 case USB_HID_REPORT_TAG_PUSH:
385 case USB_HID_REPORT_TAG_POP:
386 return tag;
387 break;
388
389 default:
390 return -1; //TODO ERROR CODE INVALID GLOBAL TAG
391 }
392
393 return EOK;
394}
395
396/**
397 * Parse local tags of report descriptor
398 *
399 * @param Tag identifier
400 * @param Data buffer
401 * @param Length of data buffer
402 * @param Current state table
403 * @return Error code
404 */
405int usb_hid_report_parse_local_tag(uint8_t tag, const uint8_t *data, size_t item_size,
406 usb_hid_report_item_t *report_item)
407{
408 switch(tag)
409 {
410 case USB_HID_REPORT_TAG_USAGE:
411 report_item->usage = usb_hid_report_tag_data_int32(data,item_size);
412 break;
413 case USB_HID_REPORT_TAG_USAGE_MINIMUM:
414 report_item->usage_minimum = usb_hid_report_tag_data_int32(data,item_size);
415 break;
416 case USB_HID_REPORT_TAG_USAGE_MAXIMUM:
417 report_item->usage_maximum = usb_hid_report_tag_data_int32(data,item_size);
418 break;
419 case USB_HID_REPORT_TAG_DESIGNATOR_INDEX:
420 report_item->designator_index = usb_hid_report_tag_data_int32(data,item_size);
421 break;
422 case USB_HID_REPORT_TAG_DESIGNATOR_MINIMUM:
423 report_item->designator_minimum = usb_hid_report_tag_data_int32(data,item_size);
424 break;
425 case USB_HID_REPORT_TAG_DESIGNATOR_MAXIMUM:
426 report_item->designator_maximum = usb_hid_report_tag_data_int32(data,item_size);
427 break;
428 case USB_HID_REPORT_TAG_STRING_INDEX:
429 report_item->string_index = usb_hid_report_tag_data_int32(data,item_size);
430 break;
431 case USB_HID_REPORT_TAG_STRING_MINIMUM:
432 report_item->string_minimum = usb_hid_report_tag_data_int32(data,item_size);
433 break;
434 case USB_HID_REPORT_TAG_STRING_MAXIMUM:
435 report_item->string_maximum = usb_hid_report_tag_data_int32(data,item_size);
436 break;
437/*
438 case USB_HID_REPORT_TAG_DELIMITER:
439 report_item->delimiter = usb_hid_report_tag_data_int32(data,item_size);
440 break;
441*/
442 default:
443 return -1; //TODO ERROR CODE INVALID LOCAL TAG NOW IS ONLY UNSUPPORTED
444 }
445
446 return EOK;
447}
448
449/**
450 * Converts raw data to int32 (thats the maximum length of short item data)
451 *
452 * @param Data buffer
453 * @param Size of buffer
454 * @return Converted int32 number
455 */
456int32_t usb_hid_report_tag_data_int32(const uint8_t *data, size_t size)
457{
458 unsigned int i;
459 int32_t result;
460
461 result = 0;
462 for(i=0; i<size; i++) {
463 result = (result | (data[i]) << (i*8));
464 }
465
466 return result;
467}
468
469
470
471/**
472 * Prints content of given list of report items.
473 *
474 * @param List of report items
475 * @return void
476 */
477void usb_hid_descriptor_print_list(link_t *head)
478{
479 usb_hid_report_item_t *report_item;
480 link_t *item;
481
482 if(head == NULL || list_empty(head)) {
483 printf("\tempty\n");
484 return;
485 }
486
487
488 printf("\tHEAD %p\n",head);
489 for(item = head->next; item != head; item = item->next) {
490
491 report_item = list_get_instance(item, usb_hid_report_item_t, link);
492
493 printf("\tOFFSET: %X\n", report_item->offset);
494 printf("\tCOUNT: %X\n", report_item->count);
495 printf("\tSIZE: %X\n", report_item->size);
496 printf("\tCONSTANT: %X\n", USB_HID_ITEM_FLAG_CONSTANT(report_item->item_flags));
497 printf("\tUSAGE: %X\n", report_item->usage);
498 printf("\tUSAGE PAGE: %X\n", report_item->usage_page);
499 printf("\n");
500
501 }
502
503
504}
505/**
506 * Prints content of given descriptor in human readable format.
507 *
508 * @param Parsed descriptor to print
509 * @return void
510 */
511void usb_hid_descriptor_print(usb_hid_report_parser_t *parser)
512{
513 printf("INPUT:\n");
514 usb_hid_descriptor_print_list(&parser->input);
515
516 printf("OUTPUT: \n");
517 usb_hid_descriptor_print_list(&parser->output);
518
519 printf("FEATURE:\n");
520 usb_hid_descriptor_print_list(&parser->feature);
521
522}
523
524/**
525 * Releases whole linked list of report items
526 *
527 *
528 */
529void usb_hid_free_report_list(link_t *head)
530{
531 return;
532
533 usb_hid_report_item_t *report_item;
534 link_t *next;
535
536 if(head == NULL || list_empty(head)) {
537 return;
538 }
539
540 next = head->next;
541 while(next != head) {
542
543 report_item = list_get_instance(next, usb_hid_report_item_t, link);
544 next = next->next;
545
546 free(report_item);
547 }
548
549 return;
550
551}
552
553/** Free the HID report parser structure
554 *
555 * @param parser Opaque HID report parser structure
556 * @return Error code
557 */
558void usb_hid_free_report_parser(usb_hid_report_parser_t *parser)
559{
560 if(parser == NULL){
561 return;
562 }
563
564 usb_hid_free_report_list(&parser->input);
565 usb_hid_free_report_list(&parser->output);
566 usb_hid_free_report_list(&parser->feature);
567
568 return;
569}
570
571inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset)
572{
573 return offset += (report_item->count * report_item->size);
574}
575/**
576 * @}
577 */
Note: See TracBrowser for help on using the repository browser.