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