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

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

Removed functions for returning size of report for usage path

  • Property mode set to 100644
File size: 13.9 KB
RevLine 
[bf2063e9]1/*
[2571089]2 * Copyright (c) 2011 Matej Klonfar
[bf2063e9]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
[976f546]29/** @addtogroup libusb
[bf2063e9]30 * @{
31 */
32/** @file
[57d9c05e]33 * HID report descriptor and report data parser implementation.
[bf2063e9]34 */
35#include <usb/classes/hidparser.h>
36#include <errno.h>
[976f546]37#include <stdio.h>
[e24e7b1]38#include <malloc.h>
39#include <mem.h>
[b7d9606]40#include <usb/debug.h>
[681f24b3]41#include <assert.h>
[976f546]42
[175ad13e]43
[57d9c05e]44/*
45 * Data translation private functions
46 */
[1553cbf]47uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
[b7d9606]48inline size_t usb_hid_count_item_offset(usb_hid_report_item_t * report_item, size_t offset);
[cfbbe1d3]49int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data);
[175ad13e]50uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, int32_t value);
[fad14d7]51int usb_pow(int a, int b);
52
[2571089]53
[57d9c05e]54// TODO: tohle ma bejt asi jinde
[fad14d7]55int usb_pow(int a, int b)
56{
57 switch(b) {
58 case 0:
59 return 1;
60 break;
61 case 1:
62 return a;
63 break;
64 default:
65 return a * usb_pow(a, b-1);
66 break;
67 }
68}
69
[976f546]70
[bd2394b]71/** Returns size of report of specified report id and type in items
72 *
73 * @param parser Opaque report parser structure
74 * @param report_id
75 * @param type
76 * @return Number of items in specified report
77 */
78size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id,
79 usb_hid_report_type_t type)
80{
81 usb_hid_report_description_t *report_des;
82
83 if(report == NULL) {
84 return 0;
85 }
86
87 report_des = usb_hid_report_find_description (report, report_id, type);
88 if(report_des == NULL){
89 return 0;
90 }
91 else {
92 return report_des->item_length;
93 }
94}
[976f546]95
[c7a2e7e]96
[fad14d7]97/** Parse and act upon a HID report.
98 *
99 * @see usb_hid_parse_report_descriptor
100 *
101 * @param parser Opaque HID report parser structure.
102 * @param data Data for the report.
103 * @return Error code.
104 */
[175ad13e]105int usb_hid_parse_report(const usb_hid_report_t *report,
[cfbbe1d3]106 const uint8_t *data, size_t size, uint8_t *report_id)
[fad14d7]107{
108 link_t *list_item;
[175ad13e]109 usb_hid_report_field_t *item;
110
111 usb_hid_report_description_t *report_des;
112 usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
[fad14d7]113
[175ad13e]114 if(report == NULL) {
[55e388a1]115 return EINVAL;
116 }
[c156c2d]117
[175ad13e]118 if(report->use_report_ids != 0) {
[cfbbe1d3]119 *report_id = data[0];
120 }
121 else {
122 *report_id = 0;
[c156c2d]123 }
124
[cfbbe1d3]125
126 report_des = usb_hid_report_find_description(report, *report_id, type);
[c156c2d]127
[175ad13e]128 /* read data */
129 list_item = report_des->report_items.next;
130 while(list_item != &(report_des->report_items)) {
[fad14d7]131
[175ad13e]132 item = list_get_instance(list_item, usb_hid_report_field_t, link);
[fad14d7]133
[cfbbe1d3]134 if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
[175ad13e]135
[cfbbe1d3]136 if(USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0) {
[175ad13e]137
[cfbbe1d3]138 // array
139 item->value = usb_hid_translate_data(item, data);
140 item->usage = (item->value - item->physical_minimum) + item->usage_minimum;
[fad14d7]141 }
[175ad13e]142 else {
[cfbbe1d3]143 // variable item
144 item->value = usb_hid_translate_data(item, data);
145 }
[fad14d7]146 }
147 list_item = list_item->next;
148 }
149
150 return EOK;
151
152}
153
[57d9c05e]154/**
[c156c2d]155 * Translate data from the report as specified in report descriptor item
[57d9c05e]156 *
157 * @param item Report descriptor item with definition of translation
158 * @param data Data to translate
159 * @param j Index of processed field in report descriptor item
160 * @return Translated data
161 */
[cfbbe1d3]162int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data)
[c7a2e7e]163{
[fad14d7]164 int resolution;
165 int offset;
166 int part_size;
167
[175ad13e]168 int32_t value=0;
[fad14d7]169 int32_t mask;
170 const uint8_t *foo;
[bda06a3]171
[c156c2d]172 // now only shot tags are allowed
[fad14d7]173 if(item->size > 32) {
174 return 0;
175 }
176
[cfbbe1d3]177 if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
[fad14d7]178 item->physical_minimum = item->logical_minimum;
[cfbbe1d3]179 item->physical_maximum = item->logical_maximum;
[fad14d7]180 }
[cfbbe1d3]181
[fad14d7]182
[60a228f]183 if(item->physical_maximum == item->physical_minimum){
184 resolution = 1;
185 }
186 else {
187 resolution = (item->logical_maximum - item->logical_minimum) /
188 ((item->physical_maximum - item->physical_minimum) *
189 (usb_pow(10,(item->unit_exponent))));
190 }
[bda06a3]191
[cfbbe1d3]192 offset = item->offset;
[fad14d7]193 // FIXME
[175ad13e]194 if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
[fad14d7]195
196 part_size = ((offset+item->size)%8);
197
[175ad13e]198 size_t i=0;
199 for(i=(size_t)(offset/8); i<=(size_t)(offset+item->size-1)/8; i++){
200 if(i == (size_t)(offset/8)) {
201 // the higher one
202 foo = data + i;
203 mask = ((1 << (item->size-part_size))-1);
204 value = (*foo & mask) << part_size;
205 }
206 else if(i == ((offset+item->size-1)/8)){
207 // the lower one
208 foo = data + i;
209 mask = ((1 << part_size)-1) << (8-part_size);
210 value += ((*foo & mask) >> (8-part_size));
211 }
212 else {
213 value = value << 8;
214 value += *(data + 1);
215 }
216 }
[fad14d7]217 }
218 else {
219 foo = data+(offset/8);
220 mask = ((1 << item->size)-1) << (8-((offset%8)+item->size));
221 value = (*foo & mask) >> (8-((offset%8)+item->size));
[175ad13e]222 }
[fad14d7]223
[1553cbf]224 if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
225 value = USB_HID_UINT32_TO_INT32(value, item->size);
[fad14d7]226 }
227
[767da0a]228 return (int)(((value - item->logical_minimum) / resolution) + item->physical_minimum);
[fad14d7]229
[c7a2e7e]230}
[0bd4810c]231
[57d9c05e]232/*** OUTPUT API **/
233
[a694a58]234/**
235 * Allocates output report buffer for output report
[57d9c05e]236 *
[a694a58]237 * @param parser Report parsed structure
238 * @param size Size of returned buffer
239 * @param report_id Report id of created output report
240 * @return Returns allocated output buffer for specified output
[57d9c05e]241 */
[175ad13e]242uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size, uint8_t report_id)
[57d9c05e]243{
[175ad13e]244 if(report == NULL) {
[57d9c05e]245 *size = 0;
246 return NULL;
247 }
248
[175ad13e]249 link_t *report_it = report->reports.next;
250 usb_hid_report_description_t *report_des = NULL;
251 while(report_it != &report->reports) {
252 report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
[dc9f122]253 if((report_des->report_id == report_id) && (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
[a694a58]254 break;
[c156c2d]255 }
256
[175ad13e]257 report_it = report_it->next;
258 }
[841e6e5]259
[175ad13e]260 if(report_des == NULL){
261 *size = 0;
262 return NULL;
[57d9c05e]263 }
264 else {
[175ad13e]265 *size = (report_des->bit_length + (8 - 1))/8;
266 uint8_t *ret = malloc((*size) * sizeof(uint8_t));
267 memset(ret, 0, (*size) * sizeof(uint8_t));
268 return ret;
[57d9c05e]269 }
270}
271
272
273/** Frees output report buffer
274 *
275 * @param output Output report buffer
[a694a58]276 * @return void
[57d9c05e]277 */
278void usb_hid_report_output_free(uint8_t *output)
[841e6e5]279
[57d9c05e]280{
281 if(output != NULL) {
282 free (output);
283 }
284}
285
[175ad13e]286/** Makes the output report buffer for data given in the report structure
[57d9c05e]287 *
[a694a58]288 * @param parser Opaque report parser structure
289 * @param path Usage path specifing which parts of output will be set
290 * @param flags Usage path structure comparison flags
291 * @param buffer Output buffer
292 * @param size Size of output buffer
293 * @return Error code
[57d9c05e]294 */
[175ad13e]295int usb_hid_report_output_translate(usb_hid_report_t *report, uint8_t report_id,
296 uint8_t *buffer, size_t size)
[57d9c05e]297{
298 link_t *item;
299 int32_t value=0;
[841e6e5]300 int offset;
301 int length;
302 int32_t tmp_value;
[57d9c05e]303
[175ad13e]304 if(report == NULL) {
[57d9c05e]305 return EINVAL;
306 }
307
[175ad13e]308 if(report->use_report_ids != 0) {
309 buffer[0] = report_id;
[bda06a3]310 }
311
[70a71e5]312 usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
[cfbbe1d3]313
[175ad13e]314 usb_hid_report_description_t *report_des;
315 report_des = usb_hid_report_find_description (report, report_id, USB_HID_REPORT_TYPE_OUTPUT);
316 if(report_des == NULL){
317 return EINVAL;
318 }
[57d9c05e]319
[175ad13e]320 usb_hid_report_field_t *report_item;
321 item = report_des->report_items.next;
322 while(item != &report_des->report_items) {
323 report_item = list_get_instance(item, usb_hid_report_field_t, link);
[841e6e5]324
[cfbbe1d3]325 if(USB_HID_ITEM_FLAG_VARIABLE(report_item->item_flags) == 0) {
[d012590]326
[cfbbe1d3]327 // array
[175ad13e]328 value = usb_hid_translate_data_reverse(report_item, report_item->value);
329 offset = report_item->offset;
[841e6e5]330 length = report_item->size;
331 }
332 else {
[cfbbe1d3]333 // variable item
334 value = usb_hid_translate_data_reverse(report_item, report_item->value);
[175ad13e]335 offset = report_item->offset;
336 length = report_item->size;
[841e6e5]337 }
338
[d012590]339 if((offset/8) == ((offset+length-1)/8)) {
[841e6e5]340 // je to v jednom bytu
[d012590]341 if(((size_t)(offset/8) >= size) || ((size_t)(offset+length-1)/8) >= size) {
[841e6e5]342 break; // TODO ErrorCode
343 }
344
[3b5d5b9d]345 size_t shift = 8 - offset%8 - length;
[841e6e5]346
[d012590]347 value = value << shift;
348 value = value & (((1 << length)-1) << shift);
[70a71e5]349
350 uint8_t mask = 0;
351 mask = 0xff - (((1 << length) - 1) << shift);
352 buffer[offset/8] = (buffer[offset/8] & mask) | value;
[841e6e5]353 }
354 else {
[175ad13e]355 int i = 0;
[70a71e5]356 uint8_t mask = 0;
[175ad13e]357 for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
358 if(i == (offset/8)) {
359 tmp_value = value;
360 tmp_value = tmp_value & ((1 << (8-(offset%8)))-1);
361 tmp_value = tmp_value << (offset%8);
362
363 mask = ~(((1 << (8-(offset%8)))-1) << (offset%8));
364 buffer[i] = (buffer[i] & mask) | tmp_value;
365 }
366 else if (i == ((offset + length -1)/8)) {
367
368 value = value >> (length - ((offset + length) % 8));
369 value = value & ((1 << (length - ((offset + length) % 8))) - 1);
[d012590]370
[175ad13e]371 mask = (1 << (length - ((offset + length) % 8))) - 1;
372 buffer[i] = (buffer[i] & mask) | value;
373 }
374 else {
375 buffer[i] = value & (0xFF << i);
376 }
377 }
[841e6e5]378 }
[57d9c05e]379
[841e6e5]380
[cfbbe1d3]381 // reset value
382 report_item->value = 0;
383
[841e6e5]384 item = item->next;
[57d9c05e]385 }
[cfbbe1d3]386
[70a71e5]387 usb_log_debug("OUTPUT BUFFER: %s\n", usb_debug_str_buffer(buffer,size, 0));
[841e6e5]388
[57d9c05e]389 return EOK;
390}
391
[841e6e5]392/**
[a694a58]393 * Translate given data for putting them into the outoput report
394 * @param item Report item structure
395 * @param value Value to translate
396 * @return ranslated value
[841e6e5]397 */
[175ad13e]398uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item, int value)
[841e6e5]399{
400 int ret=0;
401 int resolution;
402
[70a71e5]403 if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
404 ret = item->logical_minimum;
405 }
406
[cfbbe1d3]407 if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
408 item->physical_minimum = item->logical_minimum;
409 item->physical_maximum = item->logical_maximum;
410 }
411
412
[d012590]413 if((USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0)) {
[841e6e5]414
415 // variable item
416 if(item->physical_maximum == item->physical_minimum){
417 resolution = 1;
418 }
419 else {
420 resolution = (item->logical_maximum - item->logical_minimum) /
421 ((item->physical_maximum - item->physical_minimum) *
422 (usb_pow(10,(item->unit_exponent))));
423 }
424
425 ret = ((value - item->physical_minimum) * resolution) + item->logical_minimum;
426 }
427 else {
428 // bitmapa
429 if(value == 0) {
430 ret = 0;
431 }
432 else {
433 size_t bitmap_idx = (value - item->usage_minimum);
434 ret = 1 << bitmap_idx;
435 }
436 }
437
[1553cbf]438 if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
439 return USB_HID_INT32_TO_UINT32(ret, item->size);
440 }
441 return (int32_t)ret;
[841e6e5]442}
443
[64dbc83]444usb_hid_report_item_t *usb_hid_report_item_clone(const usb_hid_report_item_t *item)
445{
446 usb_hid_report_item_t *new_report_item;
447
448 if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
449 return NULL;
450 }
451 memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
452 link_initialize(&(new_report_item->link));
453
454 return new_report_item;
455}
456
[e50cd7f]457
458usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report,
459 usb_hid_report_field_t *field,
460 usb_hid_report_path_t *path, int flags,
461 usb_hid_report_type_t type)
462{
463 usb_hid_report_description_t *report_des = usb_hid_report_find_description (report, path->report_id, type);
464 link_t *field_it;
465
466 if(report_des == NULL){
467 return NULL;
468 }
469
470 if(field == NULL){
471 // vezmu prvni co mathuje podle path!!
472 field_it = report_des->report_items.next;
473 }
474 else {
475 field_it = field->link.next;
476 }
477
478 while(field_it != &report_des->report_items) {
479 field = list_get_instance(field_it, usb_hid_report_field_t, link);
[c7c0984a]480
481 if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
482 usb_hid_report_path_append_item (field->collection_path, field->usage_page, field->usage);
483 if(usb_hid_report_compare_usage_path (field->collection_path, path, flags) == EOK){
484 usb_hid_report_remove_last_item (field->collection_path);
485 return field;
486 }
[e50cd7f]487 usb_hid_report_remove_last_item (field->collection_path);
488 }
489 field_it = field_it->next;
490 }
491
492 return NULL;
493}
[cfbbe1d3]494
495uint8_t usb_hid_report_get_report_id(usb_hid_report_t *report, uint8_t report_id, usb_hid_report_type_t type)
496{
497 if(report == NULL){
498 return 0;
499 }
500
501 usb_hid_report_description_t *report_des;
502 link_t *report_it;
503
504 if(report_id == 0) {
505 report_it = usb_hid_report_find_description (report, report_id, type)->link.next;
506 }
507 else {
508 report_it = report->reports.next;
509 }
510
511 while(report_it != &report->reports) {
512 report_des = list_get_instance(report_it, usb_hid_report_description_t, link);
513 if(report_des->type == type){
514 return report_des->report_id;
515 }
516 }
517
518 return 0;
519}
520
[2020927]521void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item)
522{
523 if(report_item == NULL) {
524 return;
525 }
526
527 report_item->usages_count = 0;
528 memset(report_item->usages, 0, USB_HID_MAX_USAGES);
529
530 report_item->extended_usage_page = 0;
531 report_item->usage_minimum = 0;
532 report_item->usage_maximum = 0;
533 report_item->designator_index = 0;
534 report_item->designator_minimum = 0;
535 report_item->designator_maximum = 0;
536 report_item->string_index = 0;
537 report_item->string_minimum = 0;
538 report_item->string_maximum = 0;
[cfbbe1d3]539
[2020927]540 return;
541}
[976f546]542/**
543 * @}
[c7a2e7e]544 */
Note: See TracBrowser for help on using the repository browser.