1 /* 2 * Copyright 2009-2011, Michael Lotz, mmlr@mlotz.ch. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #ifndef USERLAND_HID 7 #include "Driver.h" 8 #else 9 #include "UserlandHID.h" 10 #endif 11 12 #include "HIDCollection.h" 13 #include "HIDParser.h" 14 #include "HIDReport.h" 15 16 #include <new> 17 #include <stdlib.h> 18 #include <string.h> 19 20 21 static uint8 sItemSize[4] = { 0, 1, 2, 4 }; 22 static int8 sUnitExponent[16] = { 23 // really just a 4 bit signed value 24 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 25 }; 26 27 28 HIDParser::HIDParser(HIDDevice *device) 29 : fDevice(device), 30 fUsesReportIDs(false), 31 fReportCount(0), 32 fReports(NULL), 33 fRootCollection(NULL) 34 { 35 } 36 37 38 HIDParser::~HIDParser() 39 { 40 _Reset(); 41 } 42 43 44 status_t 45 HIDParser::ParseReportDescriptor(const uint8 *reportDescriptor, 46 size_t descriptorLength) 47 { 48 _Reset(); 49 50 global_item_state globalState; 51 memset(&globalState, 0, sizeof(global_item_state)); 52 53 local_item_state localState; 54 memset(&localState, 0, sizeof(local_item_state)); 55 56 uint32 usageStackUsed = 0; 57 uint32 usageStackSize = 10; 58 usage_value *usageStack = (usage_value *)malloc(usageStackSize 59 * sizeof(usage_value)); 60 if (usageStack == NULL) { 61 TRACE_ALWAYS("no memory to allocate usage stack\n"); 62 return B_NO_MEMORY; 63 } 64 65 fRootCollection = new(std::nothrow) HIDCollection(NULL, COLLECTION_LOGICAL, 66 localState); 67 if (fRootCollection == NULL) { 68 TRACE_ALWAYS("no memory to allocate root collection\n"); 69 free(usageStack); 70 return B_NO_MEMORY; 71 } 72 73 HIDCollection *collection = fRootCollection; 74 const uint8 *pointer = reportDescriptor; 75 const uint8 *end = pointer + descriptorLength; 76 77 while (pointer < end) { 78 const item_prefix *item = (item_prefix *)pointer; 79 size_t itemSize = sItemSize[item->size]; 80 uint32 data = 0; 81 82 if (item->type == ITEM_TYPE_LONG) { 83 long_item *longItem = (long_item *)item; 84 itemSize += longItem->data_size; 85 } else { 86 short_item *shortItem = (short_item *)item; 87 switch (itemSize) { 88 case 1: 89 data = shortItem->data.as_uint8[0]; 90 break; 91 92 case 2: 93 data = shortItem->data.as_uint16[0]; 94 break; 95 96 case 4: 97 data = shortItem->data.as_uint32; 98 break; 99 100 default: 101 break; 102 } 103 } 104 105 TRACE("got item: type: %s; size: %lu; tag: %u; data: %" B_PRIu32 "\n", 106 item->type == ITEM_TYPE_MAIN ? "main" 107 : item->type == ITEM_TYPE_GLOBAL ? "global" 108 : item->type == ITEM_TYPE_LOCAL ? "local" : "long", 109 itemSize, item->tag, data); 110 111 switch (item->type) { 112 case ITEM_TYPE_MAIN: 113 { 114 // preprocess the local state if relevant (usages for 115 // collections and report items) 116 if (item->tag != ITEM_TAG_MAIN_END_COLLECTION) { 117 // make all usages extended for easier later processing 118 for (uint32 i = 0; i < usageStackUsed; i++) { 119 if (usageStack[i].is_extended) 120 continue; 121 usageStack[i].u.s.usage_page = globalState.usage_page; 122 usageStack[i].is_extended = true; 123 } 124 125 if (!localState.usage_minimum.is_extended) { 126 // the specs say if one of them is extended they must 127 // both be extended, so if the minimum isn't, the 128 // maximum mustn't either. 129 localState.usage_minimum.u.s.usage_page 130 = localState.usage_maximum.u.s.usage_page 131 = globalState.usage_page; 132 localState.usage_minimum.is_extended 133 = localState.usage_maximum.is_extended = true; 134 } 135 136 localState.usage_stack = usageStack; 137 localState.usage_stack_used = usageStackUsed; 138 } 139 140 if (item->tag == ITEM_TAG_MAIN_COLLECTION) { 141 HIDCollection *newCollection 142 = new(std::nothrow) HIDCollection(collection, 143 (uint8)data, localState); 144 if (newCollection == NULL) { 145 TRACE_ALWAYS("no memory to allocate new collection\n"); 146 break; 147 } 148 149 collection->AddChild(newCollection); 150 collection = newCollection; 151 } else if (item->tag == ITEM_TAG_MAIN_END_COLLECTION) { 152 if (collection == fRootCollection) { 153 TRACE_ALWAYS("end collection with no open one\n"); 154 break; 155 } 156 157 collection = collection->Parent(); 158 } else { 159 uint8 reportType = HID_REPORT_TYPE_ANY; 160 switch (item->tag) { 161 case ITEM_TAG_MAIN_INPUT: 162 reportType = HID_REPORT_TYPE_INPUT; 163 break; 164 165 case ITEM_TAG_MAIN_OUTPUT: 166 reportType = HID_REPORT_TYPE_OUTPUT; 167 break; 168 169 case ITEM_TAG_MAIN_FEATURE: 170 reportType = HID_REPORT_TYPE_FEATURE; 171 break; 172 173 default: 174 TRACE_ALWAYS("unknown main item tag: 0x%02x\n", 175 item->tag); 176 break; 177 } 178 179 if (reportType == HID_REPORT_TYPE_ANY) 180 break; 181 182 HIDReport *target = _FindOrCreateReport(reportType, 183 globalState.report_id); 184 if (target == NULL) 185 break; 186 187 // fill in a sensible default if the index isn't set 188 if (!localState.designator_index_set) { 189 localState.designator_index 190 = localState.designator_minimum; 191 } 192 193 if (!localState.string_index_set) 194 localState.string_index = localState.string_minimum; 195 196 main_item_data *mainData = (main_item_data *)&data; 197 target->AddMainItem(globalState, localState, *mainData, 198 collection); 199 } 200 201 // reset the local item state 202 memset(&localState, 0, sizeof(local_item_state)); 203 usageStackUsed = 0; 204 break; 205 } 206 207 case ITEM_TYPE_GLOBAL: 208 { 209 switch (item->tag) { 210 case ITEM_TAG_GLOBAL_USAGE_PAGE: 211 globalState.usage_page = data; 212 break; 213 214 case ITEM_TAG_GLOBAL_LOGICAL_MINIMUM: 215 globalState.logical_minimum = data; 216 break; 217 218 case ITEM_TAG_GLOBAL_LOGICAL_MAXIMUM: 219 globalState.logical_maximum = data; 220 break; 221 222 case ITEM_TAG_GLOBAL_PHYSICAL_MINIMUM: 223 globalState.physical_minimum = data; 224 break; 225 226 case ITEM_TAG_GLOBAL_PHYSICAL_MAXIMUM: 227 globalState.physical_maximum = data; 228 break; 229 230 case ITEM_TAG_GLOBAL_UNIT_EXPONENT: 231 globalState.unit_exponent = data; 232 break; 233 234 case ITEM_TAG_GLOBAL_UNIT: 235 globalState.unit = data; 236 break; 237 238 case ITEM_TAG_GLOBAL_REPORT_SIZE: 239 globalState.report_size = data; 240 break; 241 242 case ITEM_TAG_GLOBAL_REPORT_ID: 243 globalState.report_id = data; 244 fUsesReportIDs = true; 245 break; 246 247 case ITEM_TAG_GLOBAL_REPORT_COUNT: 248 globalState.report_count = data; 249 break; 250 251 case ITEM_TAG_GLOBAL_PUSH: 252 { 253 global_item_state *copy = (global_item_state *)malloc( 254 sizeof(global_item_state)); 255 if (copy == NULL) { 256 TRACE_ALWAYS("out of memory for global push\n"); 257 break; 258 } 259 260 memcpy(copy, &globalState, sizeof(global_item_state)); 261 globalState.link = copy; 262 break; 263 } 264 265 case ITEM_TAG_GLOBAL_POP: 266 { 267 if (globalState.link == NULL) { 268 TRACE_ALWAYS("global pop without item on stack\n"); 269 break; 270 } 271 272 global_item_state *link = globalState.link; 273 memcpy(&globalState, link, sizeof(global_item_state)); 274 free(link); 275 break; 276 } 277 278 default: 279 TRACE_ALWAYS("unknown global item tag: 0x%02x\n", 280 item->tag); 281 break; 282 } 283 284 break; 285 } 286 287 case ITEM_TYPE_LOCAL: 288 { 289 switch (item->tag) { 290 case ITEM_TAG_LOCAL_USAGE: 291 { 292 if (usageStackUsed >= usageStackSize) { 293 usageStackSize += 10; 294 usage_value *newUsageStack 295 = (usage_value *)realloc(usageStack, 296 usageStackSize * sizeof(usage_value)); 297 if (newUsageStack == NULL) { 298 TRACE_ALWAYS("no memory when growing usages\n"); 299 usageStackSize -= 10; 300 break; 301 } 302 303 usageStack = newUsageStack; 304 } 305 306 usage_value *value = &usageStack[usageStackUsed]; 307 value->is_extended = itemSize == sizeof(uint32); 308 value->u.extended = data; 309 usageStackUsed++; 310 break; 311 } 312 313 case ITEM_TAG_LOCAL_USAGE_MINIMUM: 314 localState.usage_minimum.u.extended = data; 315 localState.usage_minimum.is_extended 316 = itemSize == sizeof(uint32); 317 localState.usage_minimum_set = true; 318 break; 319 320 case ITEM_TAG_LOCAL_USAGE_MAXIMUM: 321 localState.usage_maximum.u.extended = data; 322 localState.usage_maximum.is_extended 323 = itemSize == sizeof(uint32); 324 localState.usage_maximum_set = true; 325 break; 326 327 case ITEM_TAG_LOCAL_DESIGNATOR_INDEX: 328 localState.designator_index = data; 329 localState.designator_index_set = true; 330 break; 331 332 case ITEM_TAG_LOCAL_DESIGNATOR_MINIMUM: 333 localState.designator_minimum = data; 334 break; 335 336 case ITEM_TAG_LOCAL_DESIGNATOR_MAXIMUM: 337 localState.designator_maximum = data; 338 break; 339 340 case ITEM_TAG_LOCAL_STRING_INDEX: 341 localState.string_index = data; 342 localState.string_index_set = true; 343 break; 344 345 case ITEM_TAG_LOCAL_STRING_MINIMUM: 346 localState.string_minimum = data; 347 break; 348 349 case ITEM_TAG_LOCAL_STRING_MAXIMUM: 350 localState.string_maximum = data; 351 break; 352 353 default: 354 TRACE_ALWAYS("unknown local item tag: 0x%02x\n", 355 item->tag); 356 break; 357 } 358 359 break; 360 } 361 362 case ITEM_TYPE_LONG: 363 { 364 long_item *longItem = (long_item *)item; 365 366 // no long items are defined yet 367 switch (longItem->long_item_tag) { 368 default: 369 TRACE_ALWAYS("unknown long item tag: 0x%02x\n", 370 longItem->long_item_tag); 371 break; 372 } 373 374 break; 375 } 376 } 377 378 pointer += itemSize + sizeof(item_prefix); 379 } 380 381 global_item_state *state = globalState.link; 382 while (state != NULL) { 383 global_item_state *next = state->link; 384 free(state); 385 state = next; 386 } 387 388 free(usageStack); 389 return B_OK; 390 } 391 392 393 HIDReport * 394 HIDParser::FindReport(uint8 type, uint8 id) 395 { 396 for (uint8 i = 0; i < fReportCount; i++) { 397 HIDReport *report = fReports[i]; 398 if (report == NULL) 399 continue; 400 401 if ((report->Type() & type) != 0 && report->ID() == id) 402 return report; 403 } 404 405 return NULL; 406 } 407 408 409 uint8 410 HIDParser::CountReports(uint8 type) 411 { 412 uint8 count = 0; 413 for (uint8 i = 0; i < fReportCount; i++) { 414 HIDReport *report = fReports[i]; 415 if (report == NULL) 416 continue; 417 418 if (report->Type() & type) 419 count++; 420 } 421 422 return count; 423 } 424 425 426 HIDReport * 427 HIDParser::ReportAt(uint8 type, uint8 index) 428 { 429 for (uint8 i = 0; i < fReportCount; i++) { 430 HIDReport *report = fReports[i]; 431 if (report == NULL || (report->Type() & type) == 0) 432 continue; 433 434 if (index-- == 0) 435 return report; 436 } 437 438 return NULL; 439 } 440 441 442 size_t 443 HIDParser::MaxReportSize() 444 { 445 size_t maxSize = 0; 446 for (uint32 i = 0; i < fReportCount; i++) { 447 HIDReport *report = fReports[i]; 448 if (report == NULL) 449 continue; 450 451 if (report->ReportSize() > maxSize) 452 maxSize = report->ReportSize(); 453 } 454 455 if (fUsesReportIDs) 456 maxSize++; 457 458 return maxSize; 459 } 460 461 462 void 463 HIDParser::SetReport(status_t status, uint8 *report, size_t length) 464 { 465 if (status != B_OK || length == 0) { 466 if (status == B_OK) 467 status = B_ERROR; 468 469 report = NULL; 470 length = 0; 471 } 472 473 uint8 targetID = 0; 474 if (fUsesReportIDs && status == B_OK) { 475 targetID = report[0]; 476 report++; 477 length--; 478 } 479 480 // We need to notify all input reports, as we don't know who has waiting 481 // listeners. Anyone other than the target report also waiting for a 482 // transfer to happen needs to reschedule one now. 483 for (uint32 i = 0; i < fReportCount; i++) { 484 if (fReports[i] == NULL 485 || fReports[i]->Type() != HID_REPORT_TYPE_INPUT) 486 continue; 487 488 if (fReports[i]->ID() == targetID) 489 fReports[i]->SetReport(status, report, length); 490 else 491 fReports[i]->SetReport(B_INTERRUPTED, NULL, 0); 492 } 493 } 494 495 496 void 497 HIDParser::PrintToStream() 498 { 499 for (uint8 i = 0; i < fReportCount; i++) { 500 HIDReport *report = fReports[i]; 501 if (report == NULL) 502 continue; 503 504 report->PrintToStream(); 505 } 506 507 fRootCollection->PrintToStream(); 508 } 509 510 511 HIDReport * 512 HIDParser::_FindOrCreateReport(uint8 type, uint8 id) 513 { 514 HIDReport *report = FindReport(type, id); 515 if (report != NULL) 516 return report; 517 518 report = new(std::nothrow) HIDReport(this, type, id); 519 if (report == NULL) { 520 TRACE_ALWAYS("no memory when allocating report\n"); 521 return NULL; 522 } 523 524 HIDReport **newReports = (HIDReport **)realloc(fReports, 525 (fReportCount + 1) * sizeof(HIDReport *)); 526 if (newReports == NULL) { 527 TRACE_ALWAYS("no memory when growing report list\n"); 528 delete report; 529 return NULL; 530 } 531 532 fReports = newReports; 533 fReports[fReportCount++] = report; 534 return report; 535 } 536 537 538 float 539 HIDParser::_CalculateResolution(global_item_state *state) 540 { 541 int64 physicalMinimum = state->physical_minimum; 542 int64 physicalMaximum = state->physical_maximum; 543 if (physicalMinimum == 0 && physicalMaximum == 0) { 544 physicalMinimum = state->logical_minimum; 545 physicalMaximum = state->logical_maximum; 546 } 547 548 int8 unitExponent = sUnitExponent[state->unit_exponent]; 549 550 float power = 1; 551 if (unitExponent < 0) { 552 while (unitExponent++ < 0) 553 power /= 10; 554 } else { 555 while (unitExponent-- > 0) 556 power *= 10; 557 } 558 559 float divisor = (physicalMaximum - physicalMinimum) * power; 560 if (divisor == 0.0) 561 return 0.0; 562 563 return (state->logical_maximum - state->logical_minimum) / divisor; 564 } 565 566 567 void 568 HIDParser::_Reset() 569 { 570 for (uint8 i = 0; i < fReportCount; i++) 571 delete fReports[i]; 572 573 delete fRootCollection; 574 free(fReports); 575 576 fUsesReportIDs = false; 577 fReportCount = 0; 578 fReports = NULL; 579 fRootCollection = NULL; 580 } 581