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

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

Basic version of usb hid report descriptor parser

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