1/* 2 * 3 * @APPLE_LICENSE_HEADER_START@ 4 * 5 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include <TargetConditionals.h> 26 27#include <sys/systm.h> 28#include <sys/proc.h> 29#include <kern/task.h> 30#include <mach/port.h> 31#include <mach/message.h> 32#include <mach/mach_port.h> 33#include <IOKit/IOCommandGate.h> 34#include <IOKit/IOMemoryDescriptor.h> 35#include <IOKit/IOBufferMemoryDescriptor.h> 36#include <IOKit/IOService.h> 37#include <IOKit/IOSyncer.h> 38#include <IOKit/IOWorkLoop.h> 39#include <IOKit/IOKitKeysPrivate.h> 40#include <IOKit/IOUserClient.h> 41#include "IOHIDLibUserClient.h" 42#include "IOHIDDevice.h" 43#include "IOHIDEventQueue.h" 44 45__BEGIN_DECLS 46#include <ipc/ipc_port.h> 47__END_DECLS 48 49#if TARGET_OS_EMBEDDED 50#include <AppleMobileFileIntegrity/AppleMobileFileIntegrity.h> 51#define kIOHIDManagerUserAccessKeyboardEntitlement "com.apple.hid.manager.user-access-keyboard" 52#endif 53 54#define super IOUserClient 55 56struct AsyncParam { 57 OSAsyncReference64 fAsyncRef; 58 UInt32 fMax; 59 IOMemoryDescriptor *fMem; 60 IOHIDReportType reportType; 61 uint32_t fAsyncCount; 62}; 63 64struct AsyncGateParam { 65 OSAsyncReference asyncRef; 66 IOHIDReportType reportType; 67 UInt32 reportID; 68 void * reportBuffer; 69 UInt32 reportBufferSize; 70 UInt32 completionTimeOutMS; 71}; 72 73 74OSDefineMetaClassAndStructors(IOHIDLibUserClient, IOUserClient); 75 76 77const IOExternalMethodDispatch IOHIDLibUserClient:: 78sMethods[kIOHIDLibUserClientNumCommands] = { 79 { // kIOHIDLibUserClientDeviceIsValid 80 (IOExternalMethodAction) &IOHIDLibUserClient::_deviceIsValid, 81 0, 0, 82 2, 0 83 }, 84 { // kIOHIDLibUserClientOpen 85 (IOExternalMethodAction) &IOHIDLibUserClient::_open, 86 1, 0, 87 0, 0 88 }, 89 { // kIOHIDLibUserClientClose 90 (IOExternalMethodAction) &IOHIDLibUserClient::_close, 91 0, 0, 92 0, 0 93 }, 94 { // kIOHIDLibUserClientCreateQueue 95 (IOExternalMethodAction) &IOHIDLibUserClient::_createQueue, 96 2, 0, 97 1, 0 98 }, 99 { // kIOHIDLibUserClientDisposeQueue 100 (IOExternalMethodAction) &IOHIDLibUserClient::_disposeQueue, 101 1, 0, 102 0, 0 103 }, 104 { // kIOHIDLibUserClientAddElementToQueue 105 (IOExternalMethodAction) &IOHIDLibUserClient::_addElementToQueue, 106 3, 0, 107 1, 0 108 }, 109 { // kIOHIDLibUserClientRemoveElementFromQueue 110 (IOExternalMethodAction) &IOHIDLibUserClient::_removeElementFromQueue, 111 2, 0, 112 1, 0 113 }, 114 { // kIOHIDLibUserClientQueueHasElement 115 (IOExternalMethodAction) &IOHIDLibUserClient::_queueHasElement, 116 2, 0, 117 1, 0 118 }, 119 { // kIOHIDLibUserClientStartQueue 120 (IOExternalMethodAction) &IOHIDLibUserClient::_startQueue, 121 1, 0, 122 0, 0 123 }, 124 { // kIOHIDLibUserClientStopQueue 125 (IOExternalMethodAction) &IOHIDLibUserClient::_stopQueue, 126 1, 0, 127 0, 0 128 }, 129 { // kIOHIDLibUserClientUpdateElementValues 130 (IOExternalMethodAction) &IOHIDLibUserClient::_updateElementValues, 131 kIOUCVariableStructureSize, 0, 132 0, 0 133 }, 134 { // kIOHIDLibUserClientPostElementValues 135 (IOExternalMethodAction) &IOHIDLibUserClient::_postElementValues, 136 kIOUCVariableStructureSize, 0, 137 0, 0 138 }, 139 { // kIOHIDLibUserClientGetReport 140 (IOExternalMethodAction) &IOHIDLibUserClient::_getReport, 141 3, 0, 142 0, kIOUCVariableStructureSize 143 }, 144 { // kIOHIDLibUserClientSetReport 145 (IOExternalMethodAction) &IOHIDLibUserClient::_setReport, 146 3, kIOUCVariableStructureSize, 147 0, 0 148 }, 149 { // kIOHIDLibUserClientGetElementCount 150 (IOExternalMethodAction) &IOHIDLibUserClient::_getElementCount, 151 0, 0, 152 2, 0 153 }, 154 { // kIOHIDLibUserClientGetElements 155 (IOExternalMethodAction) &IOHIDLibUserClient::_getElements, 156 1, 0, 157 0, kIOUCVariableStructureSize 158 }, 159 // ASYNC METHODS 160 { // kIOHIDLibUserClientSetQueueAsyncPort 161 (IOExternalMethodAction) &IOHIDLibUserClient::_setQueueAsyncPort, 162 1, 0, 163 0, 0 164 } 165}; 166 167#define kIOHIDLibClientExtendedData "ExtendedData" 168 169static void deflate_vec(uint32_t *dp, uint32_t d, const uint64_t *sp, uint32_t s) 170{ 171 if (d > s) 172 d = s; 173 174 for (uint32_t i = 0; i < d; i++) 175 dp[i] = (uint32_t) sp[i]; 176} 177 178 179bool IOHIDLibUserClient::initWithTask(task_t owningTask, void * /* security_id */, UInt32 /* type */) 180{ 181 if (!super::init()) 182 return false; 183 184 if (IOUserClient::clientHasPrivilege(owningTask, kIOClientPrivilegeAdministrator) != kIOReturnSuccess) { 185 // Preparing for extended data. Set a temporary key. 186 setProperty(kIOHIDLibClientExtendedData, true); 187 } 188 189 fClient = owningTask; 190 task_reference (fClient); 191 192 proc_t p = (proc_t)get_bsdtask_info(fClient); 193 fPid = proc_pid(p); 194 195 fQueueMap = OSArray::withCapacity(4); 196 if (!fQueueMap) 197 return false; 198 199 return true; 200} 201 202IOReturn IOHIDLibUserClient::clientClose(void) 203{ 204 if ( !isInactive() && fGate ) { 205 fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &IOHIDLibUserClient::cleanupGated)); 206 terminate(); 207 } 208 209 return kIOReturnSuccess; 210} 211 212void IOHIDLibUserClient::cleanupGated(void) 213{ 214 if (fClient) { 215 task_deallocate(fClient); 216 fClient = 0; 217 } 218 219 if (fNub) { 220 221 // First clear any remaining queues 222 setStateForQueues(kHIDQueueStateClear); 223 224 // Have been started so we better detach 225 226 // make sure device is closed (especially on crash) 227 // note radar #2729708 for a more comprehensive fix 228 // probably should also subclass clientDied for crash specific code 229 fNub->close(this, fCachedOptionBits); 230 } 231 232 if ( fResourceNotification ) { 233 fResourceNotification->remove(); 234 fResourceNotification = 0; 235 } 236 237 if (fResourceES) { 238 if ( fWL ) 239 fWL->removeEventSource(fResourceES); 240 fResourceES->release(); 241 fResourceES = 0; 242 } 243} 244 245bool IOHIDLibUserClient::start(IOService *provider) 246{ 247 OSDictionary *matching = NULL; 248 if (!super::start(provider)) 249 return false; 250 251 fNub = OSDynamicCast(IOHIDDevice, provider); 252 if (!fNub) 253 return false; 254 255 fWL = getWorkLoop(); 256 if (!fWL) 257 return false; 258 259 fWL->retain(); 260 261 OSNumber *primaryUsage = (OSNumber*)fNub->copyProperty(kIOHIDPrimaryUsageKey); 262 OSNumber *primaryUsagePage = (OSNumber*)fNub->copyProperty(kIOHIDPrimaryUsagePageKey); 263 264 if ((OSDynamicCast(OSNumber, primaryUsagePage) && (primaryUsagePage->unsigned32BitValue() == kHIDPage_GenericDesktop)) && 265 (OSDynamicCast(OSNumber, primaryUsage) && ((primaryUsage->unsigned32BitValue() == kHIDUsage_GD_Keyboard) || (primaryUsage->unsigned32BitValue() == kHIDUsage_GD_Keypad)))) 266 { 267 fNubIsKeyboard = true; 268 } 269 270 OSSafeReleaseNULL(primaryUsage); 271 OSSafeReleaseNULL(primaryUsagePage); 272 273 IOCommandGate * cmdGate = IOCommandGate::commandGate(this); 274 if (!cmdGate) 275 goto ABORT_START; 276 277 fWL->addEventSource(cmdGate); 278 279 fGate = cmdGate; 280 281 fResourceES = IOInterruptEventSource::interruptEventSource 282 (this, OSMemberFunctionCast(IOInterruptEventSource::Action, this, &IOHIDLibUserClient::resourceNotificationGated)); 283 284 if ( !fResourceES ) 285 goto ABORT_START; 286 287 fWL->addEventSource(fResourceES); 288 289 // Get notified everytime Root properties change 290 matching = serviceMatching("IOResources"); 291 fResourceNotification = addMatchingNotification( 292 gIOPublishNotification, 293 matching, 294 OSMemberFunctionCast(IOServiceMatchingNotificationHandler, this, &IOHIDLibUserClient::resourceNotification), 295 this); 296 matching->release(); 297 matching = NULL; 298 299 if ( !fResourceNotification ) 300 goto ABORT_START; 301 302 return true; 303 304ABORT_START: 305 if (fResourceES) { 306 fWL->removeEventSource(fResourceES); 307 fResourceES->release(); 308 fResourceES = 0; 309 } 310 if (fGate) { 311 fWL->removeEventSource(fGate); 312 fGate->release(); 313 fGate = 0; 314 } 315 fWL->release(); 316 fWL = 0; 317 318 return false; 319} 320 321bool IOHIDLibUserClient::resourceNotification(void * refcon __unused, IOService *service __unused, IONotifier *notifier __unused) 322{ 323 #pragma ignore(notifier) 324 325 if (!isInactive() && fResourceES) 326 fResourceES->interruptOccurred(0, 0, 0); 327 328 return true; 329} 330 331void IOHIDLibUserClient::resourceNotificationGated() 332{ 333 IOReturn ret = kIOReturnSuccess; 334 335 do { 336 // We should force success on seize 337 if ( kIOHIDOptionsTypeSeizeDevice & fCachedOptionBits ) 338 break; 339 340#if !TARGET_OS_EMBEDDED 341 OSData * data; 342 IOService * service = getResourceService(); 343 if ( !service ) { 344 ret = kIOReturnError; 345 break; 346 } 347 348 data = (OSData*)service->copyProperty(kIOConsoleUsersSeedKey); 349 350 if ( !OSDynamicCast(OSData, data) || !data->getLength() || !data->getBytesNoCopy() ) { 351 ret = kIOReturnError; 352 OSSafeReleaseNULL(data); 353 break; 354 } 355 356 UInt64 currentSeed = 0; 357 358 switch ( data->getLength() ) { 359 case sizeof(UInt8): 360 currentSeed = *(UInt8*)(data->getBytesNoCopy()); 361 break; 362 case sizeof(UInt16): 363 currentSeed = *(UInt16*)(data->getBytesNoCopy()); 364 break; 365 case sizeof(UInt32): 366 currentSeed = *(UInt32*)(data->getBytesNoCopy()); 367 break; 368 case sizeof(UInt64): 369 default: 370 currentSeed = *(UInt64*)(data->getBytesNoCopy()); 371 break; 372 } 373 OSSafeReleaseNULL(data); 374 375 // We should return rather than break so that previous setting is retained 376 if ( currentSeed == fCachedConsoleUsersSeed ) 377 return; 378 379 fCachedConsoleUsersSeed = currentSeed; 380#endif 381 ret = clientHasPrivilege(fClient, kIOClientPrivilegeAdministrator); 382 if (ret == kIOReturnSuccess) 383 break; 384 385#if TARGET_OS_EMBEDDED 386 if ( fNubIsKeyboard ) { 387 bool result = false; 388 IOReturn kr; 389 proc_t process; 390 391 process = (proc_t)get_bsdtask_info(fClient); 392 if ( process ) { 393 394 kr = AppleMobileFileIntegrity::AMFIEntitlementGetBool(process, kIOHIDManagerUserAccessKeyboardEntitlement, &result); 395 396 if ( kr || !result ) { 397 char name[255]; 398 399 bzero(name, sizeof(name)); 400 proc_name(fPid, name, sizeof(name)); 401 402 IOLog("IOHIDLibUserClient: %s is not entitled\n", name); 403 } 404 405 if (kr == kIOReturnSuccess && result) { 406 ret = kIOReturnSuccess; 407 } 408 } 409 } else { 410 ret = kIOReturnSuccess; 411 } 412#else 413 if ( fNubIsKeyboard ) { 414 IOUCProcessToken token; 415 token.token = fClient; 416 token.pid = fPid; 417 ret = clientHasPrivilege(&token, kIOClientPrivilegeSecureConsoleProcess); 418 } else { 419 ret = clientHasPrivilege(fClient, kIOClientPrivilegeConsoleUser); 420 } 421#endif /* TARGET_OS_EMBEDDED */ 422 423 } while (false); 424 425 setValid(kIOReturnSuccess == ret); 426} 427 428typedef struct HIDCommandGateArgs { 429 uint32_t selector; 430 IOExternalMethodArguments * arguments; 431 IOExternalMethodDispatch * dispatch; 432 OSObject * target; 433 void * reference; 434}HIDCommandGateArgs; 435 436IOReturn IOHIDLibUserClient::externalMethod( 437 uint32_t selector, 438 IOExternalMethodArguments * arguments, 439 IOExternalMethodDispatch * dispatch, 440 OSObject * target, 441 void * reference) 442{ 443 if (fGate) { 444 HIDCommandGateArgs args; 445 446 args.selector = selector; 447 args.arguments = arguments; 448 args.dispatch = dispatch; 449 args.target = target; 450 args.reference = reference; 451 452 return fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, target, &IOHIDLibUserClient::externalMethodGated), (void *)&args); 453 } 454 else { 455 return kIOReturnOffline; 456 } 457} 458 459IOReturn IOHIDLibUserClient::externalMethodGated(void * args) 460{ 461 HIDCommandGateArgs * cArgs = (HIDCommandGateArgs *)args; 462 uint32_t selector = cArgs->selector; 463 IOExternalMethodArguments * arguments = cArgs->arguments; 464 IOExternalMethodDispatch * dispatch = cArgs->dispatch; 465 OSObject * target = cArgs->target; 466 void * reference = cArgs->reference; 467 468 if (selector < (uint32_t) kIOHIDLibUserClientNumCommands) 469 { 470 dispatch = (IOExternalMethodDispatch *) &sMethods[selector]; 471 472 if (!target) 473 target = this; 474 } 475 476 return super::externalMethod(selector, arguments, dispatch, target, reference); 477} 478 479IOReturn IOHIDLibUserClient::_setQueueAsyncPort(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 480{ 481 return target->setQueueAsyncPort(target->getQueueForToken(arguments->scalarInput[0]), arguments->asyncWakePort); 482} 483 484IOReturn IOHIDLibUserClient::setQueueAsyncPort(IOHIDEventQueue * queue, mach_port_t port) 485{ 486 if ( !queue ) 487 return kIOReturnBadArgument; 488 489 queue->setNotificationPort(port); 490 491 return kIOReturnSuccess; 492} 493 494IOReturn IOHIDLibUserClient::_open(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 495{ 496 return target->open((IOOptionBits)arguments->scalarInput[0]); 497} 498 499IOReturn IOHIDLibUserClient::open(IOOptionBits options) 500{ 501 IOReturn ret = kIOReturnNotPrivileged; 502 503 do { 504 ret = clientHasPrivilege(fClient, kIOClientPrivilegeAdministrator); 505 if ( ret == kIOReturnSuccess ) 506 break; 507 508 // RY: If this is a keyboard and the client is attempting to seize, 509 // the client needs to be admin 510 if ( !fNubIsKeyboard || ((options & kIOHIDOptionsTypeSeizeDevice) == 0) ) { 511#if TARGET_OS_EMBEDDED 512 ret = kIOReturnSuccess; 513#else 514 ret = clientHasPrivilege(fClient, kIOClientPrivilegeLocalUser); 515#endif 516 } 517 } while (false); 518 519 if (ret != kIOReturnSuccess) 520 return ret; 521 522 if (!fNub->open(this, options)) 523 return kIOReturnExclusiveAccess; 524 525 fCachedOptionBits = options; 526 527 fCachedConsoleUsersSeed = 0; 528 resourceNotificationGated(); 529 530 return kIOReturnSuccess; 531} 532 533 534IOReturn IOHIDLibUserClient::_close(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments __unused) 535{ 536 return target->close(); 537} 538 539IOReturn IOHIDLibUserClient::close() 540{ 541 fNub->close(this, fCachedOptionBits); 542 543 setValid(false); 544 545 fCachedOptionBits = 0; 546 547 // @@@ gvdl: release fWakePort leak them for the time being 548 549 return kIOReturnSuccess; 550} 551 552bool 553IOHIDLibUserClient::didTerminate( IOService * provider, IOOptionBits options, bool * defer ) 554{ 555 if (fGate) { 556 fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &IOHIDLibUserClient::cleanupGated)); 557 } 558 559 return super::didTerminate(provider, options, defer); 560} 561 562void IOHIDLibUserClient::free() 563{ 564 if (fQueueMap) { 565 fQueueMap->release(); 566 fQueueMap = 0; 567 } 568 569 if (fNub) { 570 fNub = 0; 571 } 572 573 if (fResourceES) { 574 if (fWL) 575 fWL->removeEventSource(fResourceES); 576 fResourceES->release(); 577 fResourceES = 0; 578 } 579 580 if (fGate) { 581 if (fWL) 582 fWL->removeEventSource(fGate); 583 584 fGate->release(); 585 fGate = 0; 586 } 587 588 if ( fWL ) { 589 fWL->release(); 590 fWL = 0; 591 } 592 593 if ( fValidMessage ) { 594 IOFree(fValidMessage, sizeof (struct _notifyMsg)); 595 fValidMessage = NULL; 596 } 597 598 if (fWakePort != MACH_PORT_NULL) { 599 ipc_port_release_send(fWakePort); 600 fWakePort = MACH_PORT_NULL; 601 } 602 603 if (fValidPort != MACH_PORT_NULL) { 604 ipc_port_release_send(fValidPort); 605 fValidPort = MACH_PORT_NULL; 606 } 607 super::free(); 608} 609 610IOReturn IOHIDLibUserClient::message(UInt32 type, IOService * provider, void * argument ) 611{ 612 if ( !isInactive() && fGate ) { 613 fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, 614 this, 615 &IOHIDLibUserClient::messageGated), 616 (void*)(intptr_t)type, 617 provider, 618 argument); 619 } 620 return super::message(type, provider, argument); 621} 622 623IOReturn IOHIDLibUserClient::messageGated(UInt32 type, IOService * provider __unused, void * argument ) 624{ 625 IOOptionBits options = (uintptr_t)argument; 626 switch ( type ) { 627 case kIOMessageServiceIsRequestingClose: 628 if ((options & kIOHIDOptionsTypeSeizeDevice) && (options != fCachedOptionBits)) 629 setValid(false); 630 break; 631 632 case kIOMessageServiceWasClosed: 633 if ((options & kIOHIDOptionsTypeSeizeDevice) && (options != fCachedOptionBits)) { 634 // instead of calling set valid, let's make sure we still have 635 // permission through the resource notification 636 fCachedConsoleUsersSeed = 0; 637 resourceNotificationGated(); 638 } 639 break; 640 }; 641 642 return kIOReturnSuccess; 643} 644 645IOReturn IOHIDLibUserClient::registerNotificationPort(mach_port_t port, UInt32 type, UInt32 refCon) 646{ 647 if (fGate) { 648 return fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, 649 this, 650 &IOHIDLibUserClient::registerNotificationPortGated), 651 (void *)port, 652 (void*)(intptr_t)type, 653 (void*)(intptr_t)refCon); 654 } 655 else { 656 return kIOReturnOffline; 657 } 658} 659 660IOReturn IOHIDLibUserClient::registerNotificationPortGated(mach_port_t port, UInt32 type, UInt32 refCon __unused) 661{ 662 IOReturn kr = kIOReturnSuccess; 663 664 switch ( type ) { 665 case kIOHIDLibUserClientAsyncPortType: 666 if (fWakePort != MACH_PORT_NULL) { 667 ipc_port_release_send(fWakePort); 668 fWakePort = MACH_PORT_NULL; 669 } 670 fWakePort = port; 671 break; 672 case kIOHIDLibUserClientDeviceValidPortType: 673 if (fValidPort != MACH_PORT_NULL) { 674 ipc_port_release_send(fValidPort); 675 fValidPort = MACH_PORT_NULL; 676 } 677 fValidPort = port; 678 679 static struct _notifyMsg init_msg = { { 680 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0), 681 sizeof (struct _notifyMsg), 682 MACH_PORT_NULL, 683 MACH_PORT_NULL, 684 0, 685 0 686 } }; 687 688 if ( fValidMessage ) { 689 IOFree(fValidMessage, sizeof (struct _notifyMsg)); 690 fValidMessage = NULL; 691 } 692 693 if ( !fValidPort ) 694 break; 695 696 if ( !(fValidMessage = IOMalloc( sizeof(struct _notifyMsg))) ) { 697 kr = kIOReturnNoMemory; 698 break; 699 } 700 701 // Initialize the events available message. 702 *((struct _notifyMsg *)fValidMessage) = init_msg; 703 704 ((struct _notifyMsg *)fValidMessage)->h.msgh_remote_port = fValidPort; 705 706 dispatchMessage(fValidMessage); 707 708 break; 709 default: 710 kr = kIOReturnUnsupported; 711 break; 712 }; 713 714 return kr; 715} 716 717void IOHIDLibUserClient::setValid(bool state) 718{ 719 if (fValid == state) 720 return; 721 722 if ( !state ) { 723 // unmap this memory 724 if (fNub && !isInactive()) { 725 IOMemoryDescriptor * mem; 726 IOMemoryMap * map; 727 728 mem = fNub->getMemoryWithCurrentElementValues(); 729 730 if ( mem ) { 731 map = removeMappingForDescriptor(mem); 732 733 if ( map ) 734 map->release(); 735 } 736 } 737 fGeneration++; 738 } 739 740 // set the queue states 741 setStateForQueues(state ? kHIDQueueStateEnable : kHIDQueueStateDisable); 742 743 // dispatch message 744 dispatchMessage(fValidMessage); 745 746 fValid = state; 747} 748 749IOReturn IOHIDLibUserClient::dispatchMessage(void * messageIn) 750{ 751 IOReturn ret = kIOReturnError; 752 mach_msg_header_t * msgh = (mach_msg_header_t *)messageIn; 753 if( msgh) { 754 ret = mach_msg_send_from_kernel( msgh, msgh->msgh_size); 755 switch ( ret ) { 756 case MACH_SEND_TIMED_OUT:/* Already has a message posted */ 757 case MACH_MSG_SUCCESS: /* Message is posted */ 758 break; 759 }; 760 } 761 return ret; 762} 763 764void IOHIDLibUserClient::setStateForQueues(UInt32 state, IOOptionBits options __unused) 765{ 766 for (u_int token = getNextTokenForToken(0); token != 0; token = getNextTokenForToken(token)) 767 { 768 // this cannot return a NULL queue because of the above code 769 IOHIDEventQueue *queue = getQueueForToken(token); 770 switch (state) { 771 case kHIDQueueStateEnable: 772 queue->enable(); 773 break; 774 case kHIDQueueStateDisable: 775 queue->disable(); 776 break; 777 case kHIDQueueStateClear: 778 fNub->stopEventDelivery(queue); 779 break; 780 } 781 } 782} 783 784IOReturn IOHIDLibUserClient::clientMemoryForType ( 785 UInt32 type, 786 IOOptionBits * options, 787 IOMemoryDescriptor ** memory ) 788{ 789 if (fGate) { 790 return fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, 791 this, 792 &IOHIDLibUserClient::clientMemoryForTypeGated), 793 (void*)(intptr_t)type, 794 (void *)options, 795 (void *)memory); 796 } 797 else { 798 return kIOReturnOffline; 799 } 800} 801 802IOReturn IOHIDLibUserClient::clientMemoryForTypeGated( 803 UInt32 token, 804 IOOptionBits * options, 805 IOMemoryDescriptor ** memory ) 806{ 807 IOReturn ret = kIOReturnNoMemory; 808 IOMemoryDescriptor *memoryToShare = NULL; 809 IOHIDEventQueue *queue = NULL; 810 811 // if the type is element values, then get that 812 if (token == kIOHIDLibUserClientElementValuesType) 813 { 814 // if we can get an element values ptr 815 if (fValid && fNub && !isInactive()) 816 memoryToShare = fNub->getMemoryWithCurrentElementValues(); 817 } 818 // otherwise, the type is token 819 else if (NULL != (queue = getQueueForToken(token))) 820 { 821 memoryToShare = queue->getMemoryDescriptor(); 822 } 823 // if we got some memory 824 if (memoryToShare) 825 { 826 // Memory will be released by user client 827 // when last map is destroyed. 828 829 memoryToShare->retain(); 830 831 ret = kIOReturnSuccess; 832 } 833 834 // set the result 835 *options = 0; 836 *memory = memoryToShare; 837 838 return ret; 839} 840 841 842IOReturn IOHIDLibUserClient::_getElementCount(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 843{ 844 return target->getElementCount(&(arguments->scalarOutput[0]), &(arguments->scalarOutput[1])); 845} 846 847IOReturn IOHIDLibUserClient::getElementCount(uint64_t * pOutElementCount, uint64_t * pOutReportElementCount) 848{ 849 uint32_t outElementCount, outReportElementCount; 850 851 if (!pOutElementCount || !pOutReportElementCount) 852 return kIOReturnBadArgument; 853 854 getElements(kHIDElementType, (void *)NULL, &outElementCount); 855 getElements(kHIDReportHandlerType, (void*)NULL, &outReportElementCount); 856 857 *pOutElementCount = outElementCount / sizeof(IOHIDElementStruct); 858 *pOutReportElementCount = outReportElementCount / sizeof(IOHIDElementStruct); 859 860 return kIOReturnSuccess; 861} 862 863IOReturn IOHIDLibUserClient::_getElements(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 864{ 865 if ( arguments->structureOutputDescriptor ) 866 return target->getElements((uint32_t)arguments->scalarInput[0], arguments->structureOutputDescriptor, &(arguments->structureOutputDescriptorSize)); 867 else 868 return target->getElements((uint32_t)arguments->scalarInput[0], arguments->structureOutput, &(arguments->structureOutputSize)); 869} 870 871IOReturn IOHIDLibUserClient::getElements (uint32_t elementType, void *elementBuffer, uint32_t *elementBufferSize) 872{ 873 OSArray * array; 874 uint32_t i, bi, count; 875 IOHIDElementPrivate * element; 876 IOHIDElementStruct * elementStruct; 877 878 if (elementBuffer && elementBufferSize && !*elementBufferSize) 879 return kIOReturnBadArgument; 880 881 if (!fNub || isInactive()) 882 return kIOReturnNotAttached; 883 884 if ( elementType == kHIDElementType ) 885 array = fNub->_reserved->hierarchElements; 886 else 887 array = fNub->_reserved->inputInterruptElementArray; 888 889 if ( !array ) 890 return kIOReturnError; 891 892 if ( elementBuffer ) 893 bzero(elementBuffer, *elementBufferSize); 894 895 count = array->getCount(); 896 bi = 0; 897 898 for ( i=0; i<count; i++ ) 899 { 900 element = OSDynamicCast(IOHIDElementPrivate, array->getObject(i)); 901 902 if (!element) continue; 903 904 // Passing elementBuffer=0 means we are just attempting to get the count; 905 elementStruct = elementBuffer ? &(((IOHIDElementStruct *)elementBuffer)[bi]) : 0; 906 907 if ( element->fillElementStruct(elementStruct) ) 908 bi++; 909 } 910 911 if (elementBufferSize) 912 *elementBufferSize = bi * sizeof(IOHIDElementStruct); 913 914 return kIOReturnSuccess; 915} 916 917IOReturn IOHIDLibUserClient::getElements(uint32_t elementType, IOMemoryDescriptor * mem, uint32_t *elementBufferSize) 918{ 919 IOReturn ret = kIOReturnNoMemory; 920 921 if (!fNub || isInactive()) 922 return kIOReturnNotAttached; 923 924 ret = mem->prepare(); 925 926 if(ret == kIOReturnSuccess) 927 { 928 void * elementData; 929 uint32_t elementLength; 930 931 elementLength = mem->getLength(); 932 if ( elementLength ) 933 { 934 elementData = IOMalloc( elementLength ); 935 936 if ( elementData ) 937 { 938 bzero(elementData, elementLength); 939 940 ret = getElements(elementType, elementData, &elementLength); 941 942 if ( elementBufferSize ) 943 *elementBufferSize = elementLength; 944 945 mem->writeBytes( 0, elementData, elementLength ); 946 947 IOFree( elementData, elementLength ); 948 } 949 else 950 ret = kIOReturnNoMemory; 951 } 952 else 953 ret = kIOReturnBadArgument; 954 955 mem->complete(); 956 } 957 958 return ret; 959} 960 961IOReturn IOHIDLibUserClient::_deviceIsValid(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 962{ 963 IOReturn kr; 964 bool status; 965 uint64_t generation; 966 967 kr = target->deviceIsValid(&status, &generation); 968 969 arguments->scalarOutput[0] = status; 970 arguments->scalarOutput[1] = generation; 971 972 return kr; 973} 974 975IOReturn IOHIDLibUserClient::deviceIsValid(bool *status, uint64_t *generation) 976{ 977 if ( status ) 978 *status = fValid; 979 980 if ( generation ) 981 *generation = fGeneration; 982 983 return kIOReturnSuccess; 984} 985 986IOReturn IOHIDLibUserClient::_createQueue(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 987{ 988 return target->createQueue((uint32_t)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1], &(arguments->scalarOutput[0])); 989} 990 991IOReturn IOHIDLibUserClient::createQueue(uint32_t flags, uint32_t depth, uint64_t * outQueue) 992{ 993 // create the queue (fudge it a bit bigger than requested) 994 IOHIDEventQueue * eventQueue = IOHIDEventQueue::withEntries (depth+1, DEFAULT_HID_ENTRY_SIZE); 995 996 if ( !eventQueue ) 997 return kIOReturnNoMemory; 998 999 eventQueue->setOptions(flags); 1000 1001 if ( !fValid ) 1002 eventQueue->disable(); 1003 1004 // add the queue to the map and set out queue 1005 *outQueue = (uint64_t)createTokenForQueue(eventQueue); 1006 1007 eventQueue->release(); 1008 1009 return kIOReturnSuccess; 1010} 1011 1012 1013IOReturn IOHIDLibUserClient::_disposeQueue(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1014{ 1015 return target->disposeQueue(target->getQueueForToken(arguments->scalarInput[0])); 1016} 1017 1018IOReturn IOHIDLibUserClient::disposeQueue(IOHIDEventQueue * queue) 1019{ 1020 IOReturn ret = kIOReturnSuccess; 1021 1022 // remove this queue from all elements that use it 1023 if (fNub && !isInactive()) 1024 ret = fNub->stopEventDelivery (queue); 1025 1026 // remove the queue from the map 1027 removeQueueFromMap(queue); 1028 1029 // This should really return an actual result 1030 return kIOReturnSuccess; 1031} 1032 1033 // Add an element to a queue 1034IOReturn IOHIDLibUserClient::_addElementToQueue(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1035{ 1036 return target->addElementToQueue(target->getQueueForToken(arguments->scalarInput[0]), (IOHIDElementCookie)arguments->scalarInput[1], (uint32_t)arguments->scalarInput[2], &(arguments->scalarOutput[0])); 1037} 1038 1039IOReturn IOHIDLibUserClient::addElementToQueue(IOHIDEventQueue * queue, IOHIDElementCookie elementCookie, uint32_t flags __unused, uint64_t *pSizeChange) 1040{ 1041 IOReturn ret = kIOReturnSuccess; 1042 UInt32 size = 0; 1043 1044 size = (queue) ? queue->getEntrySize() : 0; 1045 1046 // add the queue to the element's queues 1047 if (fNub && !isInactive()) 1048 ret = fNub->startEventDelivery (queue, elementCookie); 1049 1050 *pSizeChange = (queue && (size != queue->getEntrySize())); 1051 1052 return ret; 1053} 1054 // remove an element from a queue 1055IOReturn IOHIDLibUserClient::_removeElementFromQueue (IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1056{ 1057 return target->removeElementFromQueue(target->getQueueForToken(arguments->scalarInput[0]), (IOHIDElementCookie)arguments->scalarInput[1], &(arguments->scalarOutput[0])); 1058} 1059 1060IOReturn IOHIDLibUserClient::removeElementFromQueue (IOHIDEventQueue * queue, IOHIDElementCookie elementCookie, uint64_t *pSizeChange) 1061{ 1062 IOReturn ret = kIOReturnSuccess; 1063 UInt32 size = 0; 1064 1065 size = (queue) ? queue->getEntrySize() : 0; 1066 1067 // remove the queue from the element's queues 1068 if (fNub && !isInactive()) 1069 ret = fNub->stopEventDelivery (queue, elementCookie); 1070 1071 *pSizeChange = (queue && (size != queue->getEntrySize())); 1072 1073 return ret; 1074} 1075 // Check to see if a queue has an element 1076IOReturn IOHIDLibUserClient::_queueHasElement (IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1077{ 1078 return target->queueHasElement(target->getQueueForToken(arguments->scalarInput[0]), (IOHIDElementCookie)arguments->scalarInput[1], &(arguments->scalarOutput[0])); 1079} 1080 1081IOReturn IOHIDLibUserClient::queueHasElement (IOHIDEventQueue * queue, IOHIDElementCookie elementCookie, uint64_t * pHasElement) 1082{ 1083 IOReturn ret = kIOReturnSuccess; 1084 1085 // check to see if that element is feeding that queue 1086 bool hasElement = false; 1087 1088 if (fNub && !isInactive()) 1089 ret = fNub->checkEventDelivery (queue, elementCookie, &hasElement); 1090 1091 // set return 1092 *pHasElement = hasElement; 1093 1094 return ret; 1095} 1096 // start a queue 1097IOReturn IOHIDLibUserClient::_startQueue (IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1098{ 1099 return target->startQueue(target->getQueueForToken(arguments->scalarInput[0])); 1100} 1101 1102IOReturn IOHIDLibUserClient::startQueue (IOHIDEventQueue * queue) 1103{ 1104 // start the queue 1105 if (queue) { 1106 queue->start(); 1107 return kIOReturnSuccess; 1108} 1109 return kIOReturnBadArgument; 1110} 1111 1112 // stop a queue 1113IOReturn IOHIDLibUserClient::_stopQueue (IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1114{ 1115 return target->stopQueue(target->getQueueForToken(arguments->scalarInput[0])); 1116} 1117 1118IOReturn IOHIDLibUserClient::stopQueue (IOHIDEventQueue * queue) 1119{ 1120 // stop the queue 1121 if (queue) { 1122 queue->stop(); 1123 return kIOReturnSuccess; 1124 } 1125 return kIOReturnBadArgument; 1126} 1127 1128 // update the feature element value 1129IOReturn IOHIDLibUserClient::_updateElementValues (IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1130{ 1131 return target->updateElementValues(arguments->scalarInput, arguments->scalarInputCount); 1132} 1133 1134IOReturn IOHIDLibUserClient::updateElementValues (const uint64_t * lCookies, uint32_t cookieCount) 1135{ 1136 IOReturn ret = kIOReturnError; 1137 1138 if (fNub && !isInactive()) { 1139 uint32_t cookies[cookieCount]; 1140 1141 deflate_vec(cookies, cookieCount, lCookies, cookieCount); 1142 1143 ret = fNub->updateElementValues((IOHIDElementCookie *)cookies, cookieCount); 1144 } 1145 1146 return ret; 1147} 1148 1149 // Set the element values 1150IOReturn IOHIDLibUserClient::_postElementValues (IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1151{ 1152 return target->postElementValues(arguments->scalarInput, arguments->scalarInputCount); 1153} 1154 1155IOReturn IOHIDLibUserClient::postElementValues (const uint64_t * lCookies, uint32_t cookieCount) 1156{ 1157 IOReturn ret = kIOReturnError; 1158 1159 if (fNub && !isInactive()) { 1160 uint32_t cookies[cookieCount]; 1161 1162 deflate_vec(cookies, cookieCount, lCookies, cookieCount); 1163 1164 ret = fNub->postElementValues((IOHIDElementCookie *)cookies, cookieCount); 1165 } 1166 1167 return ret; 1168} 1169 1170IOReturn IOHIDLibUserClient::_getReport(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1171{ 1172 if ( arguments->asyncWakePort ) { 1173 IOReturn ret; 1174 IOHIDCompletion tap; 1175 AsyncParam * pb = (AsyncParam *)IOMalloc(sizeof(AsyncParam)); 1176 1177 if(!pb) 1178 return kIOReturnNoMemory; 1179 target->retain(); 1180 1181 bcopy(arguments->asyncReference, pb->fAsyncRef, sizeof(OSAsyncReference64)); 1182 pb->fAsyncCount = arguments->asyncReferenceCount; 1183 tap.target = target; 1184 tap.action = OSMemberFunctionCast(IOHIDCompletionAction, target, &IOHIDLibUserClient::ReqComplete); 1185 tap.parameter = pb; 1186 1187 if ( arguments->structureOutputDescriptor ) 1188 ret = target->getReport(arguments->structureOutputDescriptor, &(arguments->structureOutputDescriptorSize), (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1], (uint32_t)arguments->scalarInput[2], &tap); 1189 else 1190 ret = target->getReport(arguments->structureOutput, &(arguments->structureOutputSize), (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1], (uint32_t)arguments->scalarInput[2], &tap); 1191 1192 if ( ret ) { 1193 if ( pb ) 1194 IOFree(pb, sizeof(*pb)); 1195 target->release(); 1196 } 1197 } 1198 if ( arguments->structureOutputDescriptor ) 1199 return target->getReport(arguments->structureOutputDescriptor, &(arguments->structureOutputDescriptorSize), (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1]); 1200 else 1201 return target->getReport(arguments->structureOutput, &(arguments->structureOutputSize), (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1]); 1202} 1203 1204IOReturn IOHIDLibUserClient::getReport(void *reportBuffer, uint32_t *pOutsize, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout, IOHIDCompletion * completion) 1205{ 1206 IOReturn ret = kIOReturnBadArgument; 1207 IOMemoryDescriptor * mem; 1208 1209 // VTN3: Is there a real maximum report size? It looks like the current limit is around 1210 // 1024 bytes, but that will (or has) changed. 65536 is above every upper limit 1211 // I have seen by a few factors. 1212 if (*pOutsize > 0x10000) { 1213 IOLog("IOHIDLibUserClient::getReport called with an irrationally large output size: %lu\n", (long unsigned) *pOutsize); 1214 } 1215 else { 1216 mem = IOBufferMemoryDescriptor::withCapacity(*pOutsize, kIODirectionInOut); 1217 if(mem) { 1218 mem->prepare(kIODirectionInOut); 1219 ret = getReport(mem, pOutsize, reportType, reportID, timeout, completion); 1220 mem->readBytes(0, reportBuffer, *pOutsize); 1221 mem->complete(); 1222 mem->release(); 1223 } 1224 else { 1225 ret = kIOReturnNoMemory; 1226 } 1227 } 1228 return ret; 1229} 1230 1231IOReturn IOHIDLibUserClient::getReport(IOMemoryDescriptor * mem, uint32_t * pOutsize, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout, IOHIDCompletion * completion) 1232{ 1233 IOReturn ret = kIOReturnBadArgument; 1234 1235 // VTN3: Is there a real maximum report size? It looks like the current limit is around 1236 // 1024 bytes, but that will (or has) changed. 65536 is above every upper limit 1237 // I have seen by a few factors. 1238 if (*pOutsize > 0x10000) { 1239 IOLog("IOHIDLibUserClient::getReport called with an irrationally large output size: %lu\n", (long unsigned) *pOutsize); 1240 } 1241 else if (fNub && !isInactive()) { 1242 ret = mem->prepare(); 1243 if(ret == kIOReturnSuccess) { 1244 if (completion) { 1245 AsyncParam * pb = (AsyncParam *)completion->parameter; 1246 pb->fMax = *pOutsize; 1247 pb->fMem = mem; 1248 pb->reportType = reportType; 1249 1250 mem->retain(); 1251 1252 ret = fNub->getReport(mem, reportType, reportID, timeout, completion); 1253 } 1254 else { 1255 ret = fNub->getReport(mem, reportType, reportID); 1256 1257 // make sure the element values are updated. 1258 if (ret == kIOReturnSuccess) 1259 fNub->handleReport(mem, reportType, kIOHIDReportOptionNotInterrupt); 1260 1261 *pOutsize = mem->getLength(); 1262 mem->complete(); 1263 } 1264 } 1265 } 1266 else { 1267 ret = kIOReturnNotAttached; 1268 } 1269 1270 return ret; 1271 1272} 1273 1274IOReturn IOHIDLibUserClient::_setReport(IOHIDLibUserClient * target, void * reference __unused, IOExternalMethodArguments * arguments) 1275{ 1276 IOReturn ret = kIOReturnError; 1277 1278 if ( arguments->asyncWakePort ) { 1279 IOHIDCompletion tap; 1280 AsyncParam * pb = (AsyncParam *)IOMalloc(sizeof(AsyncParam)); 1281 1282 if(!pb) 1283 return kIOReturnNoMemory; 1284 1285 target->retain(); 1286 1287 bcopy(arguments->asyncReference, pb->fAsyncRef, sizeof(OSAsyncReference64)); 1288 pb->fAsyncCount = arguments->asyncReferenceCount; 1289 tap.target = target; 1290 tap.action = OSMemberFunctionCast(IOHIDCompletionAction, target, &IOHIDLibUserClient::ReqComplete); 1291 tap.parameter = pb; 1292 1293 if ( arguments->structureInputDescriptor ) 1294 ret = target->setReport( arguments->structureInputDescriptor, (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1],(uint32_t)arguments->scalarInput[2], &tap); 1295 else 1296 ret = target->setReport(arguments->structureInput, arguments->structureInputSize, (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1], (uint32_t)arguments->scalarInput[2], &tap); 1297 1298 if ( ret ) { 1299 if ( pb ) 1300 IOFree(pb, sizeof(*pb)); 1301 1302 target->release(); 1303 } 1304 } 1305 else 1306 if ( arguments->structureInputDescriptor ) 1307 ret = target->setReport( arguments->structureInputDescriptor, (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1]); 1308 else 1309 ret = target->setReport(arguments->structureInput, arguments->structureInputSize, (IOHIDReportType)arguments->scalarInput[0], (uint32_t)arguments->scalarInput[1]); 1310 1311 return ret; 1312} 1313 1314IOReturn IOHIDLibUserClient::setReport(const void *reportBuffer, uint32_t reportBufferSize, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout, IOHIDCompletion * completion) 1315{ 1316 IOReturn ret; 1317 IOMemoryDescriptor * mem; 1318 1319 mem = IOMemoryDescriptor::withAddress((void *)reportBuffer, reportBufferSize, kIODirectionOut); 1320 if(mem) { 1321 ret = setReport(mem, reportType, reportID, timeout, completion); 1322 mem->release(); 1323 } 1324 else 1325 ret = kIOReturnNoMemory; 1326 1327 return ret; 1328} 1329 1330IOReturn IOHIDLibUserClient::setReport(IOMemoryDescriptor * mem, IOHIDReportType reportType, uint32_t reportID, uint32_t timeout, IOHIDCompletion * completion) 1331{ 1332 IOReturn ret; 1333 1334 if (fNub && !isInactive()) { 1335 ret = mem->prepare(); 1336 if(ret == kIOReturnSuccess) { 1337 OSArray *extended = (OSArray*)copyProperty(kIOHIDLibClientExtendedData); 1338 if (OSDynamicCast(OSArray, extended) && extended->getCount()) { 1339 OSCollectionIterator *itr = OSCollectionIterator::withCollection(extended); 1340 if (itr) { 1341 bool done = false; 1342 while (!done) { 1343 OSObject *obj; 1344 while (!done && (NULL != (obj = itr->getNextObject()))) { 1345 OSNumber *num = OSDynamicCast(OSNumber, obj); 1346 if (num) { 1347 uint8_t excludedReportID = (num->unsigned64BitValue() >> 16) & 0xff; 1348 uint8_t excludedReportType =(num->unsigned64BitValue() >> 24) & 0xff; 1349 1350 if ((excludedReportID == reportID) && (excludedReportType == (reportType + 1))) { 1351 // Block 1352 IOLog("IOHIDLibUserClient::setReport %02x/%02x blocked due to lack of privileges\n", reportID, reportType); 1353 done = true; 1354 ret = kIOReturnNotPrivileged; 1355 } 1356 } 1357 } 1358 if (itr->isValid()) { 1359 // Do not block 1360 done = true; 1361 } 1362 else { 1363 // Someone changed the array. Check again. 1364 itr->reset(); 1365 } 1366 } 1367 itr->release(); 1368 } 1369 } 1370 OSSafeReleaseNULL(extended); 1371 if (ret == kIOReturnSuccess) { 1372 if ( completion ) { 1373 AsyncParam * pb = (AsyncParam *)completion->parameter; 1374 pb->fMax = mem->getLength(); 1375 pb->fMem = mem; 1376 pb->reportType = reportType; 1377 1378 mem->retain(); 1379 1380 ret = fNub->setReport(mem, reportType, reportID, timeout, completion); 1381 } 1382 else { 1383 ret = fNub->setReport(mem, reportType, reportID); 1384 1385 // make sure the element values are updated. 1386 if (ret == kIOReturnSuccess) 1387 fNub->handleReport(mem, reportType, kIOHIDReportOptionNotInterrupt); 1388 1389 mem->complete(); 1390 } 1391 } 1392 } 1393 } 1394 else 1395 ret = kIOReturnNotAttached; 1396 1397 return ret; 1398} 1399 1400void IOHIDLibUserClient::ReqComplete(void *param, IOReturn res, UInt32 remaining) 1401{ 1402 fGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, 1403 this, 1404 &IOHIDLibUserClient::ReqCompleteGated), 1405 param, 1406 (void*)(intptr_t)res, 1407 (void*)(intptr_t)remaining); 1408} 1409 1410IOReturn IOHIDLibUserClient::ReqCompleteGated(void *param, IOReturn res, UInt32 remaining) 1411{ 1412 io_user_reference_t args[1]; 1413 AsyncParam * pb = (AsyncParam *)param; 1414 1415 if(res == kIOReturnSuccess) { 1416 args[0] = (io_user_reference_t)(pb->fMax - remaining); 1417 1418 // make sure the element values are updated. 1419 if (fNub && !isInactive()) 1420 fNub->handleReport(pb->fMem, pb->reportType, kIOHIDReportOptionNotInterrupt); 1421 } else { 1422 args[0] = 0; 1423 } 1424 1425 if (pb->fMem) { 1426 pb->fMem->complete(); 1427 pb->fMem->release(); 1428 } 1429 1430 sendAsyncResult64(pb->fAsyncRef, res, args, 1); 1431 1432 IOFree(pb, sizeof(*pb)); 1433 1434 release(); 1435 1436 return kIOReturnSuccess; 1437} 1438 1439 1440// This section is to track all user queues and hand out unique tokens for 1441// particular queues. vtn3 1442// rdar://5957582 start 1443 1444enum { kIOHIDLibUserClientQueueTokenOffset = 200 }; 1445 1446 1447u_int IOHIDLibUserClient::createTokenForQueue(IOHIDEventQueue *queue) 1448{ 1449 u_int index = 0; 1450 u_int result = 0; 1451 1452 while (OSDynamicCast(IOHIDEventQueue, fQueueMap->getObject(index))) 1453 index++; 1454 1455 if (index < (UINT_MAX - kIOHIDLibUserClientQueueTokenOffset)) { 1456 fQueueMap->setObject(index, queue); 1457 result = index + kIOHIDLibUserClientQueueTokenOffset; 1458 } 1459 else { 1460 IOLog("IOHIDLibUserClient::createTokenForQueue generated out-of-range index: %d\n", index); 1461 } 1462 1463 return (result); 1464} 1465 1466 1467void IOHIDLibUserClient::removeQueueFromMap(IOHIDEventQueue *queue) 1468{ 1469 OSObject *obj = NULL; 1470 1471 for (u_int index = 0; NULL != (obj = fQueueMap->getObject(index)); index++) 1472 if (obj == queue) { 1473 fQueueMap->replaceObject(index, kOSBooleanFalse); 1474 } 1475} 1476 1477 1478IOHIDEventQueue* IOHIDLibUserClient::getQueueForToken(u_int token) 1479{ 1480 IOHIDEventQueue *result = NULL; 1481 1482 if (token >= kIOHIDLibUserClientQueueTokenOffset) { 1483 result = OSDynamicCast(IOHIDEventQueue, fQueueMap->getObject(token - kIOHIDLibUserClientQueueTokenOffset)); 1484 } 1485 else { 1486 IOLog("IOHIDLibUserClient::getQueueForToken received out-of-range token: %d\n", token); 1487 } 1488 1489 return (result); 1490} 1491 1492 1493u_int IOHIDLibUserClient::getNextTokenForToken(u_int token) 1494{ 1495 u_int next_token = (token < kIOHIDLibUserClientQueueTokenOffset) ? 1496 kIOHIDLibUserClientQueueTokenOffset - 1 : token; 1497 1498 IOHIDEventQueue *queue = NULL; 1499 1500 do { 1501 queue = getQueueForToken(++next_token); 1502 } 1503 while ((next_token < fQueueMap->getCount() + kIOHIDLibUserClientQueueTokenOffset) && (queue == NULL)); 1504 1505 if (next_token >= fQueueMap->getCount() + kIOHIDLibUserClientQueueTokenOffset) 1506 next_token = 0; 1507 1508 return next_token; 1509} 1510 1511// rdar://5957582 end 1512 1513bool 1514IOHIDLibUserClient::attach(IOService * provider) 1515{ 1516 if (!super::attach(provider)) { 1517 return false; 1518 } 1519 if (provider && getProperty(kIOHIDLibClientExtendedData)) { 1520 // Check for extended data 1521 OSArray *extended = (OSArray*)provider->copyProperty(kIOHIDLibClientExtendedData, gIOServicePlane); 1522 if (OSDynamicCast(OSArray, extended) && extended->getCount()) { 1523 // Extended data found. Replace the temporary key. 1524 setProperty(kIOHIDLibClientExtendedData, extended); 1525 } 1526 else { 1527 // No extended data found. Remove the temporary key. 1528 removeProperty(kIOHIDLibClientExtendedData); 1529 } 1530 OSSafeReleaseNULL(extended); 1531 } 1532 return true; 1533} 1534