00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <usb/hid/hidparser.h>
00036 #include <errno.h>
00037 #include <stdio.h>
00038 #include <malloc.h>
00039 #include <mem.h>
00040 #include <usb/debug.h>
00041 #include <assert.h>
00042
00043
00044
00045
00046
00047 uint32_t usb_hid_report_tag_data_uint32(const uint8_t *data, size_t size);
00048
00049 int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data);
00050
00051 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item,
00052 int32_t value);
00053
00054 int usb_pow(int a, int b);
00055
00056
00057
00058
00059 int usb_pow(int a, int b)
00060 {
00061 switch(b) {
00062 case 0:
00063 return 1;
00064 break;
00065 case 1:
00066 return a;
00067 break;
00068 default:
00069 return a * usb_pow(a, b-1);
00070 break;
00071 }
00072 }
00073
00074
00082 size_t usb_hid_report_size(usb_hid_report_t *report, uint8_t report_id,
00083 usb_hid_report_type_t type)
00084 {
00085 usb_hid_report_description_t *report_des;
00086
00087 if(report == NULL) {
00088 return 0;
00089 }
00090
00091 report_des = usb_hid_report_find_description (report, report_id, type);
00092 if(report_des == NULL){
00093 return 0;
00094 }
00095 else {
00096 return report_des->item_length;
00097 }
00098 }
00099
00107 size_t usb_hid_report_byte_size(usb_hid_report_t *report, uint8_t report_id,
00108 usb_hid_report_type_t type)
00109 {
00110 usb_hid_report_description_t *report_des;
00111
00112 if(report == NULL) {
00113 return 0;
00114 }
00115
00116 report_des = usb_hid_report_find_description (report, report_id, type);
00117 if(report_des == NULL){
00118 return 0;
00119 }
00120 else {
00121 return ((report_des->bit_length + 7) / 8) ;
00122 }
00123 }
00124
00125
00134 int usb_hid_parse_report(const usb_hid_report_t *report, const uint8_t *data,
00135 size_t size, uint8_t *report_id)
00136 {
00137 link_t *list_item;
00138 usb_hid_report_field_t *item;
00139
00140 usb_hid_report_description_t *report_des;
00141 usb_hid_report_type_t type = USB_HID_REPORT_TYPE_INPUT;
00142
00143 if(report == NULL) {
00144 return EINVAL;
00145 }
00146
00147 if(report->use_report_ids != 0) {
00148 *report_id = data[0];
00149 }
00150 else {
00151 *report_id = 0;
00152 }
00153
00154
00155 report_des = usb_hid_report_find_description(report, *report_id,
00156 type);
00157
00158 if(report_des == NULL) {
00159 return EINVAL;
00160 }
00161
00162
00163 list_item = report_des->report_items.next;
00164 while(list_item != &(report_des->report_items)) {
00165
00166 item = list_get_instance(list_item, usb_hid_report_field_t,
00167 link);
00168
00169 if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags) == 0) {
00170
00171 if(USB_HID_ITEM_FLAG_VARIABLE(item->item_flags) == 0){
00172
00173
00174 item->value =
00175 usb_hid_translate_data(item, data);
00176
00177 item->usage = USB_HID_EXTENDED_USAGE(
00178 item->usages[
00179 item->value - item->physical_minimum]);
00180
00181 item->usage_page =
00182 USB_HID_EXTENDED_USAGE_PAGE(
00183 item->usages[
00184 item->value - item->physical_minimum]);
00185
00186 usb_hid_report_set_last_item (
00187 item->collection_path,
00188 USB_HID_TAG_CLASS_GLOBAL,
00189 item->usage_page);
00190
00191 usb_hid_report_set_last_item (
00192 item->collection_path,
00193 USB_HID_TAG_CLASS_LOCAL, item->usage);
00194
00195 }
00196 else {
00197
00198 item->value = usb_hid_translate_data(item,
00199 data);
00200 }
00201 }
00202 list_item = list_item->next;
00203 }
00204
00205 return EOK;
00206
00207 }
00208
00209
00217 int usb_hid_translate_data(usb_hid_report_field_t *item, const uint8_t *data)
00218 {
00219 int resolution;
00220 int offset;
00221 int part_size;
00222
00223 int32_t value=0;
00224 int32_t mask=0;
00225 const uint8_t *foo=0;
00226
00227
00228 if(item->size > 32) {
00229 return 0;
00230 }
00231
00232 if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
00233 item->physical_minimum = item->logical_minimum;
00234 item->physical_maximum = item->logical_maximum;
00235 }
00236
00237
00238 if(item->physical_maximum == item->physical_minimum){
00239 resolution = 1;
00240 }
00241 else {
00242 resolution = (item->logical_maximum - item->logical_minimum) /
00243 ((item->physical_maximum - item->physical_minimum) *
00244 (usb_pow(10,(item->unit_exponent))));
00245 }
00246
00247 offset = item->offset;
00248
00249 if((size_t)(offset/8) != (size_t)((offset+item->size-1)/8)) {
00250
00251 part_size = 0;
00252
00253 size_t i=0;
00254 for(i=(size_t)(offset/8); i<=(size_t)(offset+item->size-1)/8; i++){
00255 if(i == (size_t)(offset/8)) {
00256
00257 part_size = 8 - (offset % 8);
00258 foo = data + i;
00259 mask = ((1 << (item->size-part_size))-1);
00260 value = (*foo & mask);
00261 }
00262 else if(i == ((offset+item->size-1)/8)){
00263
00264 foo = data + i;
00265 mask = ((1 << (item->size - part_size)) - 1)
00266 << (8 - (item->size - part_size));
00267
00268 value = (((*foo & mask) >> (8 -
00269 (item->size - part_size))) << part_size )
00270 + value;
00271 }
00272 else {
00273 value = (*(data + 1) << (part_size + 8)) + value;
00274 part_size += 8;
00275 }
00276 }
00277 }
00278 else {
00279 foo = data+(offset/8);
00280 mask = ((1 << item->size)-1) << (8-((offset%8)+item->size));
00281 value = (*foo & mask) >> (8-((offset%8)+item->size));
00282 }
00283
00284 if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
00285 value = USB_HID_UINT32_TO_INT32(value, item->size);
00286 }
00287
00288 return (int)(((value - item->logical_minimum) / resolution) +
00289 item->physical_minimum);
00290
00291 }
00292
00293
00294
00295
00304 uint8_t *usb_hid_report_output(usb_hid_report_t *report, size_t *size,
00305 uint8_t report_id)
00306 {
00307 if(report == NULL) {
00308 *size = 0;
00309 return NULL;
00310 }
00311
00312 link_t *report_it = report->reports.next;
00313 usb_hid_report_description_t *report_des = NULL;
00314 while(report_it != &report->reports) {
00315 report_des = list_get_instance(report_it,
00316 usb_hid_report_description_t, link);
00317
00318 if((report_des->report_id == report_id) &&
00319 (report_des->type == USB_HID_REPORT_TYPE_OUTPUT)){
00320 break;
00321 }
00322
00323 report_it = report_it->next;
00324 }
00325
00326 if(report_des == NULL){
00327 *size = 0;
00328 return NULL;
00329 }
00330 else {
00331 *size = (report_des->bit_length + (8 - 1))/8;
00332 uint8_t *ret = malloc((*size) * sizeof(uint8_t));
00333 memset(ret, 0, (*size) * sizeof(uint8_t));
00334 return ret;
00335 }
00336 }
00337
00338
00344 void usb_hid_report_output_free(uint8_t *output)
00345
00346 {
00347 if(output != NULL) {
00348 free (output);
00349 }
00350 }
00351
00361 int usb_hid_report_output_translate(usb_hid_report_t *report,
00362 uint8_t report_id, uint8_t *buffer, size_t size)
00363 {
00364 link_t *item;
00365 int32_t value=0;
00366 int offset;
00367 int length;
00368 int32_t tmp_value;
00369
00370 if(report == NULL) {
00371 return EINVAL;
00372 }
00373
00374 if(report->use_report_ids != 0) {
00375 buffer[0] = report_id;
00376 }
00377
00378 usb_hid_report_description_t *report_des;
00379 report_des = usb_hid_report_find_description (report, report_id,
00380 USB_HID_REPORT_TYPE_OUTPUT);
00381
00382 if(report_des == NULL){
00383 return EINVAL;
00384 }
00385
00386 usb_hid_report_field_t *report_item;
00387 item = report_des->report_items.next;
00388 while(item != &report_des->report_items) {
00389 report_item = list_get_instance(item, usb_hid_report_field_t, link);
00390
00391 value = usb_hid_translate_data_reverse(report_item,
00392 report_item->value);
00393
00394 offset = report_des->bit_length - report_item->offset - 1;
00395 length = report_item->size;
00396
00397 usb_log_debug("\ttranslated value: %x\n", value);
00398
00399 if((offset/8) == ((offset+length-1)/8)) {
00400
00401 if(((size_t)(offset/8) >= size) ||
00402 ((size_t)(offset+length-1)/8) >= size) {
00403 break;
00404 }
00405 size_t shift = 8 - offset%8 - length;
00406 value = value << shift;
00407 value = value & (((1 << length)-1) << shift);
00408
00409 uint8_t mask = 0;
00410 mask = 0xff - (((1 << length) - 1) << shift);
00411 buffer[offset/8] = (buffer[offset/8] & mask) | value;
00412 }
00413 else {
00414 int i = 0;
00415 uint8_t mask = 0;
00416 for(i = (offset/8); i <= ((offset+length-1)/8); i++) {
00417 if(i == (offset/8)) {
00418 tmp_value = value;
00419 tmp_value = tmp_value &
00420 ((1 << (8-(offset%8)))-1);
00421
00422 tmp_value = tmp_value << (offset%8);
00423
00424 mask = ~(((1 << (8-(offset%8)))-1) <<
00425 (offset%8));
00426
00427 buffer[i] = (buffer[i] & mask) |
00428 tmp_value;
00429 }
00430 else if (i == ((offset + length -1)/8)) {
00431
00432 value = value >> (length -
00433 ((offset + length) % 8));
00434
00435 value = value & ((1 << (length -
00436 ((offset + length) % 8))) - 1);
00437
00438 mask = (1 << (length -
00439 ((offset + length) % 8))) - 1;
00440
00441 buffer[i] = (buffer[i] & mask) | value;
00442 }
00443 else {
00444 buffer[i] = value & (0xFF << i);
00445 }
00446 }
00447 }
00448
00449
00450 report_item->value = 0;
00451
00452 item = item->next;
00453 }
00454
00455 return EOK;
00456 }
00457
00458
00465 uint32_t usb_hid_translate_data_reverse(usb_hid_report_field_t *item,
00466 int value)
00467 {
00468 int ret=0;
00469 int resolution;
00470
00471 if(USB_HID_ITEM_FLAG_CONSTANT(item->item_flags)) {
00472 ret = item->logical_minimum;
00473 }
00474
00475 if((item->physical_minimum == 0) && (item->physical_maximum == 0)){
00476 item->physical_minimum = item->logical_minimum;
00477 item->physical_maximum = item->logical_maximum;
00478 }
00479
00480
00481 if(item->physical_maximum == item->physical_minimum){
00482 resolution = 1;
00483 }
00484 else {
00485 resolution = (item->logical_maximum - item->logical_minimum) /
00486 ((item->physical_maximum - item->physical_minimum) *
00487 (usb_pow(10,(item->unit_exponent))));
00488 }
00489
00490 ret = ((value - item->physical_minimum) * resolution) +
00491 item->logical_minimum;
00492
00493 usb_log_debug("\tvalue(%x), resolution(%x), phymin(%x) logmin(%x), \
00494 ret(%x)\n", value, resolution, item->physical_minimum,
00495 item->logical_minimum, ret);
00496
00497 if((item->logical_minimum < 0) || (item->logical_maximum < 0)){
00498 return USB_HID_INT32_TO_UINT32(ret, item->size);
00499 }
00500 return (int32_t)0 + ret;
00501 }
00502
00503
00510 usb_hid_report_item_t *usb_hid_report_item_clone(
00511 const usb_hid_report_item_t *item)
00512 {
00513 usb_hid_report_item_t *new_report_item;
00514
00515 if(!(new_report_item = malloc(sizeof(usb_hid_report_item_t)))) {
00516 return NULL;
00517 }
00518 memcpy(new_report_item,item, sizeof(usb_hid_report_item_t));
00519 link_initialize(&(new_report_item->link));
00520
00521 return new_report_item;
00522 }
00523
00524
00538 usb_hid_report_field_t *usb_hid_report_get_sibling(usb_hid_report_t *report,
00539 usb_hid_report_field_t *field, usb_hid_report_path_t *path, int flags,
00540 usb_hid_report_type_t type)
00541 {
00542 usb_hid_report_description_t *report_des =
00543 usb_hid_report_find_description(report, path->report_id, type);
00544
00545 link_t *field_it;
00546
00547 if(report_des == NULL){
00548 return NULL;
00549 }
00550
00551 if(field == NULL){
00552 field_it = report_des->report_items.next;
00553 }
00554 else {
00555 field_it = field->link.next;
00556 }
00557
00558 while(field_it != &report_des->report_items) {
00559 field = list_get_instance(field_it, usb_hid_report_field_t,
00560 link);
00561
00562 if(USB_HID_ITEM_FLAG_CONSTANT(field->item_flags) == 0) {
00563 usb_hid_report_path_append_item (
00564 field->collection_path, field->usage_page,
00565 field->usage);
00566
00567 if(usb_hid_report_compare_usage_path(
00568 field->collection_path, path, flags) == EOK){
00569
00570 usb_hid_report_remove_last_item(
00571 field->collection_path);
00572
00573 return field;
00574 }
00575 usb_hid_report_remove_last_item (
00576 field->collection_path);
00577 }
00578 field_it = field_it->next;
00579 }
00580
00581 return NULL;
00582 }
00583
00584
00596 uint8_t usb_hid_get_next_report_id(usb_hid_report_t *report,
00597 uint8_t report_id, usb_hid_report_type_t type)
00598 {
00599 if(report == NULL){
00600 return 0;
00601 }
00602
00603 usb_hid_report_description_t *report_des;
00604 link_t *report_it;
00605
00606 if(report_id > 0) {
00607 report_des = usb_hid_report_find_description(report, report_id,
00608 type);
00609 if(report_des == NULL) {
00610 return 0;
00611 }
00612 else {
00613 report_it = report_des->link.next;
00614 }
00615 }
00616 else {
00617 report_it = report->reports.next;
00618 }
00619
00620 while(report_it != &report->reports) {
00621 report_des = list_get_instance(report_it,
00622 usb_hid_report_description_t, link);
00623
00624 if(report_des->type == type){
00625 return report_des->report_id;
00626 }
00627
00628 report_it = report_it->next;
00629 }
00630
00631 return 0;
00632 }
00633
00634
00643 void usb_hid_report_reset_local_items(usb_hid_report_item_t *report_item)
00644 {
00645 if(report_item == NULL) {
00646 return;
00647 }
00648
00649 report_item->usages_count = 0;
00650 memset(report_item->usages, 0, USB_HID_MAX_USAGES);
00651
00652 report_item->extended_usage_page = 0;
00653 report_item->usage_minimum = 0;
00654 report_item->usage_maximum = 0;
00655 report_item->designator_index = 0;
00656 report_item->designator_minimum = 0;
00657 report_item->designator_maximum = 0;
00658 report_item->string_index = 0;
00659 report_item->string_minimum = 0;
00660 report_item->string_maximum = 0;
00661
00662 return;
00663 }