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