1/* 2 * 3 * @APPLE_LICENSE_HEADER_START@ 4 * 5 * Copyright (c) 1999-2012 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#define CFRUNLOOP_NEW_API 1 25 26#include <CoreFoundation/CFMachPort.h> 27#include <CoreFoundation/CFPriv.h> 28//#include <IOKit/hid/IOHIDLib.h> 29//#include <unistd.h> 30#include "IOHIDDeviceClass.h" 31#include "IOHIDQueueClass.h" 32#include "IOHIDTransactionClass.h" 33#include "IOHIDPrivateKeys.h" 34#include "IOHIDParserPriv.h" 35 36__BEGIN_DECLS 37#include <asl.h> 38#include <mach/mach.h> 39#include <mach/mach_interface.h> 40#include <IOKit/iokitmig.h> 41#include <IOKit/IOMessage.h> 42#include <IOKit/IODataQueueClient.h> 43#include <System/libkern/OSCrossEndian.h> 44__END_DECLS 45 46#define connectCheck() do { \ 47 if (!fConnection) \ 48 return kIOReturnNoDevice; \ 49} while (0) 50 51#define openCheck() do { \ 52 if (!fIsOpen) \ 53 return kIOReturnNotOpen; \ 54} while (0) 55 56#define terminatedCheck() do { \ 57 if (fIsTerminated) \ 58 return kIOReturnNotAttached;\ 59} while (0) 60 61#define seizeCheck() do { \ 62 if (!isValid()) \ 63 return kIOReturnExclusiveAccess; \ 64} while (0) 65 66#define allChecks() do { \ 67 connectCheck(); \ 68 openCheck(); \ 69 seizeCheck(); \ 70 terminatedCheck(); \ 71} while (0) 72 73#ifndef max 74#define max(a, b) \ 75 ((a > b) ? a:b) 76#endif 77 78#ifndef min 79#define min(a, b) \ 80 ((a < b) ? a:b) 81#endif 82 83typedef struct _IOHIDObsoleteCallbackArgs { 84 IOHIDObsoleteDeviceClass * self; 85 void * callback; 86 void * target; 87 void * refcon; 88 uint32_t * pLength; 89}IOHIDObsoleteCallbackArgs; 90 91enum { 92 kCreateMatchingHIDElementsWithDictionaries = 0x1000 93}; 94 95static void ElementCacheApplierFunction(const void *key __unused, const void *value, void *context) 96{ 97 _IOHIDElementSetDeviceInterface((IOHIDElementRef)value, (IOHIDDeviceDeviceInterface**)context); 98} 99 100IOCFPlugInInterface ** IOHIDDeviceClass::alloc() 101{ 102 IOHIDDeviceClass *me; 103 104 me = new IOHIDDeviceClass; 105 if (me) 106 return (IOCFPlugInInterface **) &me->iunknown.pseudoVTable; 107 else 108 return 0; 109} 110 111IOHIDDeviceClass::IOHIDDeviceClass() 112: IOHIDIUnknown(&sIOCFPlugInInterfaceV1) 113{ 114 fHIDDevice.pseudoVTable = (IUnknownVTbl *) &sHIDDeviceInterfaceV2; 115 fHIDDevice.obj = this; 116 117 fService = MACH_PORT_NULL; 118 fConnection = MACH_PORT_NULL; 119 fAsyncPort = NULL; 120 fNotifyPort = NULL; 121 fDeviceValidPort = MACH_PORT_NULL; 122 fRunLoop = NULL; 123 fAsyncCFMachPort = NULL; 124 fAsyncCFSource = NULL; 125 fNotifyCFSource = NULL; 126 fIsOpen = false; 127 fIsLUNZero = false; 128 fIsTerminated = false; 129 fAsyncPortSetupDone = false; 130 fAsyncPrivateDataRef = NULL; 131 fNotifyPrivateDataRef = NULL; 132 fRemovalCallback = NULL; 133 fRemovalTarget = NULL; 134 fRemovalRefcon = NULL; 135 fQueues = NULL; 136 fElementCache = NULL; 137 fProperties = NULL; 138 fCurrentValuesMappedMemory = 0; 139 fCurrentValuesMappedMemorySize = 0; 140 fElementCount = 0; 141 fElementData = NULL; 142 fElements = NULL; 143 fReportHandlerElementCount = 0; 144 fReportHandlerElementData = NULL; 145 fReportHandlerElements = NULL; 146 fReportHandlerQueue = NULL; 147 fInputReportCallback= NULL; 148 fInputReportRefcon = NULL; 149 fInputReportBuffer = NULL; 150 fInputReportBufferSize = 0; 151 fInputReportOptions = 0; 152 fGeneration = -1; 153} 154 155IOHIDDeviceClass::~IOHIDDeviceClass() 156{ 157 if (fConnection) { 158 IOServiceClose(fConnection); 159 fConnection = MACH_PORT_NULL; 160 } 161 162 if (fService) { 163 IOObjectRelease(fService); 164 fService = MACH_PORT_NULL; 165 } 166 167 if ( fProperties ) { 168 CFRelease(fProperties); 169 fProperties = NULL; 170 } 171 172 if (fReportHandlerQueue){ 173 delete fReportHandlerQueue; 174 fReportHandlerQueue = 0; 175 } 176 177 if (fElementCache) { 178 CFDictionaryApplyFunction(fElementCache, ElementCacheApplierFunction, NULL); 179 CFRelease(fElementCache); 180 } 181 182 if (fReportHandlerElementData) 183 CFRelease(fReportHandlerElementData); 184 185 if (fElementData) 186 CFRelease(fElementData); 187 188 if (fQueues) 189 CFRelease(fQueues); 190 191 if ( fDeviceValidPort ) 192 mach_port_mod_refs(mach_task_self(), fDeviceValidPort, MACH_PORT_RIGHT_RECEIVE, -1); 193 194 if (fNotifyCFSource) { 195 if ( fRunLoop ) 196 CFRunLoopRemoveSource(fRunLoop, fNotifyCFSource, kCFRunLoopDefaultMode); 197 // Per IOKit documentation, this run loop source should not be retained/released 198 fNotifyCFSource = NULL; 199 } 200 201 if (fNotifyPort) 202 IONotificationPortDestroy(fNotifyPort); 203 204 if (fRunLoop) 205 CFRelease(fRunLoop); 206 fRunLoop = NULL; 207 208 // Even though we are leveraging IONotificationPort, we don't actually uses it's event source or CFMachPort 209 // because we wanted to filter the message. As such, we need to manually clean up our CFMachPort and source. 210 if ( fAsyncCFMachPort ) { 211 CFMachPortInvalidate(fAsyncCFMachPort); 212 CFRelease(fAsyncCFMachPort); 213 } 214 215 if (fAsyncCFSource) 216 CFRelease(fAsyncCFSource); 217 218 if (fAsyncPort) 219 IONotificationPortDestroy(fAsyncPort); 220 221 if (fAsyncPrivateDataRef) { 222 IOObjectRelease(fAsyncPrivateDataRef->notification); 223 free(fAsyncPrivateDataRef); 224 } 225 226 if (fNotifyPrivateDataRef) { 227 IOObjectRelease(fNotifyPrivateDataRef->notification); 228 free(fNotifyPrivateDataRef); 229 } 230} 231 232HRESULT IOHIDDeviceClass::attachQueue (IOHIDQueueClass * iohidQueue, bool reportHandler) 233{ 234 HRESULT res = S_OK; 235 236 iohidQueue->setOwningDevice(this); 237 238 // ���� todo add to list 239 if ( !reportHandler && ( fQueues || 240 ( fQueues = CFSetCreateMutable(kCFAllocatorDefault, 0, 0) ) ) ) 241 { 242 CFSetAddValue(fQueues, (void *)iohidQueue); 243 } 244 245 return res; 246} 247 248HRESULT IOHIDDeviceClass::detachQueue (IOHIDQueueClass * iohidQueue) 249{ 250 HRESULT res = S_OK; 251 252 iohidQueue->setOwningDevice(NULL); 253 254 // ���� todo remove from list 255 if ( fQueues ) 256 { 257 CFSetRemoveValue(fQueues, (void *)iohidQueue); 258 } 259 260 return res; 261} 262 263HRESULT IOHIDDeviceClass::attachTransaction (IOHIDTransactionClass * transaction) 264{ 265 HRESULT res = S_OK; 266 267 transaction->setOwningDevice(this); 268 269 // ���� todo add to list 270 271 return res; 272 273} 274 275HRESULT IOHIDDeviceClass::detachTransaction (IOHIDTransactionClass * transaction) 276{ 277 HRESULT res = S_OK; 278 279 transaction->setOwningDevice(NULL); 280 281 // ���� todo remove from list 282 283 return res; 284} 285 286IOHIDQueueClass * IOHIDDeviceClass::createQueue(bool reportHandler) 287{ 288 IOHIDQueueClass * newQueue = new IOHIDQueueClass; 289 290 // attach the queue to us 291 attachQueue (newQueue, reportHandler); 292 293 return newQueue; 294} 295 296HRESULT IOHIDDeviceClass::queryInterfaceQueue (CFUUIDRef uuid __unused, void **ppv) 297{ 298 HRESULT res = S_OK; 299 300 // create the queue class 301 IOHIDQueueClass * newQueue = createQueue(); 302 303 // add a ref for the one we return 304// newQueue->addRef(); 305 306 // set the return 307 *ppv = newQueue->getInterfaceMap(); 308 309 return res; 310} 311 312HRESULT IOHIDDeviceClass::queryInterfaceTransaction (CFUUIDRef uuid __unused, void **ppv) 313{ 314 HRESULT res = S_OK; 315 316 IOHIDTransactionClass * transaction = new IOHIDTransactionClass; 317 318 attachTransaction(transaction); 319 320 transaction->create(); 321 322 *ppv = transaction->getInterfaceMap(); 323 324 return res; 325} 326 327 328HRESULT IOHIDDeviceClass::queryInterface(REFIID iid, void **ppv) 329{ 330 CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid); 331 HRESULT res = S_OK; 332 333 if (CFEqual(uuid, kIOHIDDeviceQueueInterfaceID)) 334 res = queryInterfaceQueue(uuid, ppv); 335 else if (CFEqual(uuid, kIOHIDDeviceTransactionInterfaceID)) 336 res = queryInterfaceTransaction(uuid, ppv); 337 else if (CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOCFPlugInInterfaceID)) 338 { 339 *ppv = &iunknown; 340 addRef(); 341 } 342 else if (CFEqual(uuid, kIOHIDDeviceDeviceInterfaceID)) 343 { 344 *ppv = &fHIDDevice; 345 addRef(); 346 } 347 else { 348 *ppv = 0; 349 HIDLog ("not found\n"); 350 } 351 352 if (!*ppv) 353 res = E_NOINTERFACE; 354 355 CFRelease(uuid); 356 return res; 357} 358 359IOReturn IOHIDDeviceClass:: 360probe(CFDictionaryRef propertyTable __unused, io_service_t inService, SInt32 *order __unused) 361{ 362 if (!inService || !IOObjectConformsTo(inService, "IOHIDDevice")) 363 return kIOReturnBadArgument; 364 365 return kIOReturnSuccess; 366} 367 368IOReturn IOHIDDeviceClass::start(CFDictionaryRef propertyTable __unused, io_service_t inService) 369{ 370 IOReturn res; 371 kern_return_t kr; 372 CFMutableDictionaryRef properties; 373 374 fService = inService; 375 IOObjectRetain(fService); 376 377 res = IOServiceOpen(fService, mach_task_self(), kIOHIDLibUserClientConnectManager, &fConnection); 378 if (res != kIOReturnSuccess) 379 return res; 380 381 connectCheck(); 382 383 fNotifyPort = IONotificationPortCreate(kIOMasterPortDefault); 384 385 // Per IOKit documentation, this run loop source should not be retained/released 386 fNotifyCFSource = IONotificationPortGetRunLoopSource(fNotifyPort); 387 388 fRunLoop = CFRunLoopGetMain(); 389 CFRetain(fRunLoop); 390 CFRunLoopAddSource(fRunLoop, fNotifyCFSource, kCFRunLoopDefaultMode); 391 392 fNotifyPrivateDataRef = (MyPrivateData *)malloc(sizeof(MyPrivateData)); 393 bzero(fNotifyPrivateDataRef, sizeof(MyPrivateData)); 394 395 fNotifyPrivateDataRef->self = this; 396 397 // Register for an interest notification of this device being removed. Use a reference to our 398 // private data as the refCon which will be passed to the notification callback. 399 kr = IOServiceAddInterestNotification( fNotifyPort, 400 fService, 401 kIOGeneralInterest, 402 IOHIDDeviceClass::_deviceNotification, 403 fNotifyPrivateDataRef, 404 &(fNotifyPrivateDataRef->notification)); 405 406 407 // Create port to determine if mem maps are valid. Use 408 // IODataQueueAllocateNotificationPort cause that limits the msg queue to 409 // one entry. 410 fDeviceValidPort = IODataQueueAllocateNotificationPort(); 411 if (fDeviceValidPort == MACH_PORT_NULL) 412 return kIOReturnNoMemory; 413 414 kr = IOConnectSetNotificationPort(fConnection, kIOHIDLibUserClientDeviceValidPortType, fDeviceValidPort, NULL); 415 if (kr != kIOReturnSuccess) 416 return kr; 417 418 uint64_t output[2]; 419 uint32_t len = 2; 420 421 kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientGetElementCount, 0, 0, output, &len); 422 if (kr != kIOReturnSuccess) 423 return kr; 424 425 HIDLog("IOHIDDeviceClass::start: elementCount=%lld reportHandlerCount=%lld\n", output[0], output[1]); 426 427 fElementCount = output[0]; 428 fReportHandlerElementCount = output[1]; 429 430 431 buildElements(kHIDElementType, &fElementData, &fElements, &fElementCount); 432 buildElements(kHIDReportHandlerType, &fReportHandlerElementData, &fReportHandlerElements, &fReportHandlerElementCount); 433 434 fElementCache = CFDictionaryCreateMutable( 435 kCFAllocatorDefault, 436 0, 437 &kCFTypeDictionaryKeyCallBacks, 438 &kCFTypeDictionaryValueCallBacks); 439 440 if ( !fElementCache ) 441 return kIOReturnNoMemory; 442 443 fProperties = CFDictionaryCreateMutable( 444 kCFAllocatorDefault, 445 0, 446 &kCFTypeDictionaryKeyCallBacks, 447 &kCFTypeDictionaryValueCallBacks); 448 449 if ( !fProperties ) 450 return kIOReturnNoMemory; 451 452 return kIOReturnSuccess; 453} 454 455IOReturn IOHIDDeviceClass::createSharedMemory(uint64_t generation) 456{ 457 // get the shared memory 458 if ( generation == fGeneration ) 459 return kIOReturnSuccess; 460 461#if !__LP64__ 462 vm_address_t address = nil; 463 vm_size_t size = 0; 464#else 465 mach_vm_address_t address = nil; 466 mach_vm_size_t size = 0; 467#endif 468 IOReturn ret = IOConnectMapMemory ( 469 fConnection, 470 kIOHIDLibUserClientElementValuesType, 471 mach_task_self(), 472 &address, 473 &size, 474 kIOMapAnywhere ); 475 476 if (ret != kIOReturnSuccess) 477 return kIOReturnError; 478 479 fCurrentValuesMappedMemory = address; 480 fCurrentValuesMappedMemorySize = size; 481 482 if ( !fCurrentValuesMappedMemory ) 483 return kIOReturnNoMemory; 484 485 fGeneration = generation; 486 487 return kIOReturnSuccess; 488} 489 490IOReturn IOHIDDeviceClass::releaseSharedMemory() 491{ 492 // finished with the shared memory 493 if (!fCurrentValuesMappedMemory) 494 return kIOReturnSuccess; 495 496 IOReturn ret = IOConnectUnmapMemory ( 497 fConnection, 498 kIOHIDLibUserClientElementValuesType, 499 mach_task_self(), 500 fCurrentValuesMappedMemory); 501 502 fCurrentValuesMappedMemory = 0; 503 fCurrentValuesMappedMemorySize = 0; 504 505 return ret; 506} 507 508Boolean IOHIDDeviceClass::isValid() 509{ 510 IOReturn kr; 511 512 struct { 513 mach_msg_header_t msgHdr; 514 OSNotificationHeader notifyHeader; 515 mach_msg_trailer_t trailer; 516 } msg; 517 518 kr = mach_msg(&msg.msgHdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), fDeviceValidPort, 0, MACH_PORT_NULL); 519 520 switch ( kr ) { 521 case MACH_MSG_SUCCESS: 522 uint64_t args[2]; 523 uint32_t len = 2; 524 525 args[0] = 1; 526 args[1] = fGeneration; 527 528 kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientDeviceIsValid, 0, 0, args, &len); 529 530 if ( args[0] /*valid*/ ) 531 kr = createSharedMemory(args[1] /*generation */); 532 else { 533 fCurrentValuesMappedMemory = 0; 534 fCurrentValuesMappedMemorySize = 0; 535 } 536 break; 537 }; 538 539 return fCurrentValuesMappedMemory != 0; 540} 541 542 543IOReturn IOHIDDeviceClass::getProperty(CFStringRef key, CFTypeRef * pProperty) 544{ 545 CFTypeRef property = CFDictionaryGetValue(fProperties, key); 546 547 if ( !property ) { 548 property = IORegistryEntrySearchCFProperty(fService, kIOServicePlane, key, kCFAllocatorDefault, kIORegistryIterateRecursively| kIORegistryIterateParents); 549 if ( property ) { 550 CFDictionarySetValue(fProperties, key, property); 551 CFRelease(property); 552 } 553 } 554 555 if ( pProperty ) 556 *pProperty = property; 557 558 return kIOReturnSuccess; 559} 560 561IOReturn IOHIDDeviceClass::setProperty(CFStringRef key, CFTypeRef property) 562{ 563 CFDictionarySetValue(fProperties, key, property); 564 565 return kIOReturnSuccess; 566} 567 568// RY: There are 2 General Interest notification event sources. 569// One is operating on the main run loop via fNotifyPort and is internal 570// to the IOHIDDeviceClass. The other is used by the client to get removal 571// notification via fAsyncPort. This method is used by both and disguished 572// by the port in the refcon. 573void IOHIDDeviceClass::_deviceNotification(void *refCon, io_service_t service __unused, natural_t messageType, void * messageArgument ) 574{ 575 IOHIDDeviceClass * self; 576 MyPrivateData * privateDataRef = (MyPrivateData *) refCon; 577 IOOptionBits options = (IOOptionBits)((addr64_t)messageArgument); 578 579 if (!privateDataRef) 580 return; 581 582 self = privateDataRef->self; 583 584 if (!self || (messageType != kIOMessageServiceIsTerminated)) 585 return; 586 587 self->fIsTerminated = true; 588 589 if ( privateDataRef != self->fAsyncPrivateDataRef) 590 return; 591 592 if (self->fRemovalCallback) 593 { 594 ((IOHIDCallbackFunction)self->fRemovalCallback)( 595 self->fRemovalTarget, 596 kIOReturnSuccess, 597 self->fRemovalRefcon, 598 (void *)&(self->fHIDDevice)); 599 } 600 // Free up the notificaiton 601 IOObjectRelease(privateDataRef->notification); 602 free(self->fAsyncPrivateDataRef); 603 self->fAsyncPrivateDataRef = 0; 604} 605 606IOReturn IOHIDDeviceClass::getAsyncEventSource(CFTypeRef *source) 607{ 608 connectCheck(); 609 610 if (!fAsyncPort) { 611 IOReturn ret; 612 ret = getAsyncPort(0); 613 if (kIOReturnSuccess != ret) 614 return ret; 615 } 616 617 if (!fAsyncCFMachPort) { 618 CFMachPortContext context; 619 Boolean shouldFreeInfo = FALSE; 620 621 context.version = 1; 622 context.info = this; 623 context.retain = NULL; 624 context.release = NULL; 625 context.copyDescription = NULL; 626 627 fAsyncCFMachPort = CFMachPortCreateWithPort(NULL, IONotificationPortGetMachPort(fAsyncPort), 628 (CFMachPortCallBack) _cfmachPortCallback, 629 &context, &shouldFreeInfo); 630 631 if ( shouldFreeInfo ) { 632 // The CFMachPort we got might not work, but we'll proceed with it anyway. 633 asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s received an unexpected reused CFMachPort", __func__); 634 } 635 636 if (!fAsyncCFMachPort) 637 return kIOReturnNoMemory; 638 } 639 640 if ( !fAsyncCFSource ) { 641 fAsyncCFSource = CFMachPortCreateRunLoopSource(NULL, fAsyncCFMachPort, 0); 642 if (!fAsyncCFSource) 643 return kIOReturnNoMemory; 644 } 645 646 if (source) 647 *source = fAsyncCFSource; 648 649 return kIOReturnSuccess; 650} 651 652IOReturn IOHIDDeviceClass::getAsyncPort(mach_port_t *port) 653{ 654 IOReturn ret = kIOReturnSuccess; 655 656 connectCheck(); 657 658 if ( !fAsyncPort ) { 659 660 fAsyncPort = IONotificationPortCreate(kIOMasterPortDefault); 661 if (!fAsyncPort) 662 return kIOReturnNoMemory; 663 664 if (fIsOpen) 665 ret = finishAsyncPortSetup(); 666 } 667 668 if (port) 669 *port = IONotificationPortGetMachPort(fAsyncPort); 670 671 return ret; 672} 673 674IOReturn IOHIDDeviceClass::finishAsyncPortSetup() 675{ 676 finishReportHandlerQueueSetup(); 677 678 fAsyncPortSetupDone = true; 679 680 return IOConnectSetNotificationPort(fConnection, kIOHIDLibUserClientAsyncPortType, IONotificationPortGetMachPort(fAsyncPort), NULL); 681} 682 683IOReturn IOHIDDeviceClass::open(IOOptionBits options) 684{ 685 IOReturn ret = kIOReturnSuccess; 686 687 connectCheck(); 688 689 do { 690 // ���todo, check flags to see if different (if so, we might need to reopen) 691 if (fIsOpen) 692 break; 693 694 uint32_t len = 0; 695 uint64_t input = options; 696 697 ret = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientOpen, &input, 1, 0, &len); 698 699 if (ret != kIOReturnSuccess) 700 break; 701 702 fIsOpen = true; 703 704 if (!fAsyncPortSetupDone && fAsyncPort) { 705 ret = finishAsyncPortSetup(); 706 707 if (ret != kIOReturnSuccess) { 708 close(); 709 break; 710 } 711 } 712 713 isValid(); 714 715 } while (false); 716 717 return ret; 718} 719 720IOReturn IOHIDDeviceClass::close(IOOptionBits options __unused) 721{ 722 IOReturn ret; 723 724 openCheck(); 725 connectCheck(); 726 727 ret = releaseSharedMemory(); 728 729 uint32_t len = 0; 730 731 ret = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientClose, 0, 0, 0, &len); 732 733 fIsOpen = false; 734 fIsLUNZero = false; 735 736 return ret; 737} 738 739IOReturn IOHIDDeviceClass::getElementValue(IOHIDElementRef element, IOHIDValueRef * pEvent, uint32_t timeout __unused, IOHIDValueCallback callback __unused, void * refcon __unused, IOOptionBits options) 740{ 741 uint32_t generation = 0; 742 IOReturn kr = getCurrentElementValueAndGeneration(element, pEvent, &generation); 743 744 // If the generation is 0, this element has never 745 // been processed. We should query the element 746 // to get the current value. 747 if ((kr == kIOReturnSuccess) && ((options & kHIDGetElementValuePreventPoll) == 0) && ((options & kHIDGetElementValueForcePoll) || ((IOHIDElementGetType(element) == kIOHIDElementTypeFeature) && (generation == 0)))) 748 { 749 uint64_t input = (uint64_t) IOHIDElementGetCookie(element); 750 size_t outputCount = 0; 751 752 allChecks(); 753 754 kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientUpdateElementValues, &input, 1, 0, 0); 755 756 if (kr == kIOReturnSuccess) 757 kr = getCurrentElementValueAndGeneration(element, pEvent); 758 } 759 760 return kr; 761} 762 763IOReturn IOHIDDeviceClass::setElementValue(IOHIDElementRef element, IOHIDValueRef event, uint32_t timeout __unused, IOHIDValueCallback callback __unused, void * refcon __unused, IOOptionBits options) 764{ 765 kern_return_t kr = kIOReturnBadArgument; 766 IOHIDElementStruct elementStruct; 767 768 allChecks(); 769 770 if (!getElementStruct(IOHIDElementGetCookie(element), &elementStruct)) 771 return kr; 772 773 // we are only interested feature and output elements 774 if ((elementStruct.type != kIOHIDElementTypeFeature) && (elementStruct.type != kIOHIDElementTypeOutput)) 775 return kr; 776 777 // get ptr to shared memory for this element 778 if (elementStruct.valueLocation < fCurrentValuesMappedMemorySize) 779 { 780 IOHIDElementValue * elementValue = (IOHIDElementValue *)(fCurrentValuesMappedMemory + elementStruct.valueLocation); 781 782 _IOHIDValueCopyToElementValuePtr(event, elementValue); 783 784 // See if the value is pended 785 if ( options & kHIDSetElementValuePendEvent ) 786 return kIOReturnSuccess; 787 788 uint64_t input = (uint64_t)IOHIDElementGetCookie(element); 789 uint32_t outputCount = 0; 790 791 kr = IOConnectCallScalarMethod(fConnection, kIOHIDLibUserClientPostElementValues, &input, 1, 0, &outputCount); 792 } 793 794 return kr; 795} 796 797IOReturn IOHIDDeviceClass::getCurrentElementValueAndGeneration(IOHIDElementRef element, IOHIDValueRef *pEvent, uint32_t * pGeneration) 798{ 799 IOHIDElementStruct elementStruct; 800 IOHIDEventStruct valueEvent; 801 IOHIDValueRef valueRef; 802 803 allChecks(); 804 805 if (!element || !getElementStruct(IOHIDElementGetCookie(element), &elementStruct) || (elementStruct.type == kIOHIDElementTypeCollection)) 806 return kIOReturnBadArgument; 807 808 // get the value 809 // get ptr to shared memory for this elementStruct 810 if (elementStruct.valueLocation < fCurrentValuesMappedMemorySize) 811 { 812 IOHIDElementValue * elementValue = (IOHIDElementValue *)(fCurrentValuesMappedMemory + elementStruct.valueLocation); 813 uint64_t timeStamp = *((uint64_t *)&(elementValue->timestamp)); 814 uint32_t generation = elementValue->generation; 815 816 ROSETTA_ONLY( 817 timeStamp = OSSwapInt64(timeStamp); 818 generation = OSSwapInt32(generation); 819 ); 820 821 valueRef = _IOHIDElementGetValue(element); 822 823 if ( !valueRef || (IOHIDValueGetTimeStamp(valueRef) < timeStamp) ) 824 { 825 valueRef = _IOHIDValueCreateWithElementValuePtr(kCFAllocatorDefault, element, elementValue); 826 827 if (valueRef) { 828 _IOHIDElementSetValue(element, valueRef); 829 CFRelease(valueRef); // Should be retained by the element 830 } 831 } 832 833 if (pEvent) 834 *pEvent = valueRef; 835 836 if ( pGeneration ) 837 *pGeneration = generation; 838 } 839 840 return kIOReturnSuccess; 841 842} 843 844struct IOHIDReportRefCon { 845 IOHIDReportType type; 846 uint8_t * buffer; 847 uint32_t reportID; 848 IOHIDReportCallback callback; 849 void * callbackRefcon; 850 void * sender; 851}; 852 853IOReturn IOHIDDeviceClass::setReport(IOHIDReportType reportType, 854 uint32_t reportID, 855 const uint8_t *report, 856 CFIndex reportLength, 857 uint32_t timeout, 858 IOHIDReportCallback callback, 859 void *refcon, 860 IOOptionBits options __unused) 861{ 862 uint64_t in[3]; 863 IOReturn ret; 864 865 allChecks(); 866 867 // Async setReport 868 if (callback) 869 { 870 if (!fAsyncPort) 871 return kIOReturnError; //kIOUSBNoAsyncPortErr; 872 873 io_async_ref64_t asyncRef; 874 IOHIDReportRefCon * hidRefcon = 0; 875 876 877 in[0] = reportType; 878 in[1] = reportID; 879 in[2] = timeout; 880 881 hidRefcon = (IOHIDReportRefCon *)malloc(sizeof(IOHIDReportRefCon)); 882 883 if (!hidRefcon) 884 return kIOReturnError; 885 886 hidRefcon->type = reportType; 887 hidRefcon->reportID = reportID; 888 hidRefcon->buffer = (uint8_t *)report; 889 hidRefcon->callback = callback; 890 hidRefcon->callbackRefcon = refcon; 891 hidRefcon->sender = &fHIDDevice; 892 893 asyncRef[kIOAsyncCalloutFuncIndex] = (uint64_t)_hidReportCallback; 894 asyncRef[kIOAsyncCalloutRefconIndex] = (uint64_t)hidRefcon; 895 896 ret = IOConnectCallAsyncMethod(fConnection, kIOHIDLibUserClientSetReport, IONotificationPortGetMachPort(fAsyncPort), asyncRef, kIOAsyncCalloutCount, in, 3, report, reportLength, 0, 0, 0, 0); 897 898 } 899 else 900 { 901 in[0] = reportType; 902 in[1] = reportID; 903 in[2] = 0; 904 ret = IOConnectCallMethod(fConnection, kIOHIDLibUserClientSetReport, in, 3, report, (size_t)reportLength, 0, 0, 0, 0); 905 } 906 907 if (ret == MACH_SEND_INVALID_DEST) 908 { 909 fIsOpen = false; 910 fConnection = MACH_PORT_NULL; 911 ret = kIOReturnNoDevice; 912 } 913 return ret; 914 915} 916 917 918IOReturn 919IOHIDDeviceClass::getReport(IOHIDReportType reportType, 920 uint32_t reportID, 921 uint8_t *report, 922 CFIndex *pReportLength, 923 uint32_t timeout, 924 IOHIDReportCallback callback, 925 void *refcon, 926 IOOptionBits options __unused) 927{ 928 uint64_t in[3]; 929 IOReturn ret; 930 size_t reportLength = *pReportLength; 931 932 allChecks(); 933 934 if (!pReportLength || (*pReportLength < 0)) 935 return kIOReturnNoMemory; 936 937 // Async getReport 938 if (callback) 939 { 940 if (!fAsyncPort) 941 return kIOReturnError; //kIOUSBNoAsyncPortErr; 942 943 io_async_ref64_t asyncRef; 944 IOHIDReportRefCon * hidRefcon = 0; 945 946 947 in[0] = reportType; 948 in[1] = reportID; 949 in[2] = timeout; 950 951 hidRefcon = (IOHIDReportRefCon *)malloc(sizeof(IOHIDReportRefCon)); 952 953 if (!hidRefcon) 954 return kIOReturnError; 955 956 hidRefcon->type = reportType; 957 hidRefcon->reportID = reportID; 958 hidRefcon->buffer = report; 959 hidRefcon->callback = callback; 960 hidRefcon->callbackRefcon = refcon; 961 hidRefcon->sender = &fHIDDevice; 962 963 asyncRef[kIOAsyncCalloutFuncIndex] = (uint64_t)_hidReportCallback; 964 asyncRef[kIOAsyncCalloutRefconIndex] = (uint64_t)hidRefcon; 965 966 967 ret = IOConnectCallAsyncMethod(fConnection, kIOHIDLibUserClientGetReport, IONotificationPortGetMachPort(fAsyncPort), asyncRef, kIOAsyncCalloutCount, in, 3, 0, 0, 0, 0, report, &reportLength); 968 } 969 else 970 { 971 in[0] = reportType; 972 in[1] = reportID; 973 in[2] = 0; 974 ret = IOConnectCallMethod(fConnection, kIOHIDLibUserClientGetReport, in, 3, 0, 0, 0, 0, report, &reportLength); 975 } 976 977 *pReportLength = reportLength; 978 979 if (ret == MACH_SEND_INVALID_DEST) 980 { 981 fIsOpen = false; 982 fConnection = MACH_PORT_NULL; 983 ret = kIOReturnNoDevice; 984 } 985 return ret; 986} 987 988 989bool IOHIDDeviceClass::getElementDictIntValue(CFDictionaryRef element, CFStringRef key, uint32_t * value) 990{ 991 CFTypeRef object = CFDictionaryGetValue (element, key); 992 uint32_t number = 0; 993 CFTypeID typeID = object ? CFGetTypeID(object) : 0; // _kCFRuntimeNotATypeID 994 995 if (!value) { 996 char buff[64] = "unknown"; 997 if (key) 998 CFStringGetCString(key, buff, 64, kCFStringEncodingUTF8); 999 asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s called with no value for %s\n", __PRETTY_FUNCTION__, buff); 1000 } 1001 else { 1002 if (typeID == CFNumberGetTypeID()) 1003 { 1004 if (CFNumberGetValue((CFNumberRef) object, kCFNumberLongType, &number)) 1005 { 1006 *value = number; 1007 return true; 1008 } 1009 } 1010 else if (typeID == CFBooleanGetTypeID()) 1011 { 1012 *value = (object == kCFBooleanTrue); 1013 return true; 1014 } 1015 } 1016 return false; 1017} 1018 1019void IOHIDDeviceClass::setElementDictIntValue(CFMutableDictionaryRef element, CFStringRef key, uint32_t value) 1020{ 1021 CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value); 1022 1023 if ( !number ) 1024 return; 1025 1026 CFDictionarySetValue(element, key, number); 1027 CFRelease(number); 1028} 1029 1030void IOHIDDeviceClass::setElementDictBoolValue( CFMutableDictionaryRef element, CFStringRef key, bool value) 1031{ 1032 CFBooleanRef boolVal = (value) ? kCFBooleanTrue : kCFBooleanFalse; 1033 CFDictionarySetValue(element, key, boolVal); 1034} 1035 1036 1037CFTypeRef IOHIDDeviceClass::createElement(CFDataRef data, IOHIDElementStruct * element, uint32_t index, CFTypeRef parentElement, CFMutableDictionaryRef elementCache, bool * isElementCached, IOOptionBits options) 1038{ 1039 CFTypeRef type = 0; 1040 CFNumberRef key = 0; 1041 uint32_t cookie = element->cookieMin + index; 1042 1043 if ( elementCache ) 1044 { 1045 key = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &cookie); 1046 1047 if ( key ) 1048 { 1049 type = CFDictionaryGetValue(elementCache, key); 1050 1051 if ( type ) 1052 { 1053 if (isElementCached) 1054 *isElementCached = true; 1055 1056 CFRetain(type); 1057 CFRelease(key); 1058 1059 return type; 1060 } 1061 } 1062 } 1063 1064 if ( options & kCreateMatchingHIDElementsWithDictionaries ) 1065 { 1066 CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1067 1068 if (dictionary) 1069 { 1070 uint32_t reportCount = element->reportCount; 1071 uint32_t size = element->size; 1072 1073 do { 1074 if ( parentElement ) 1075 CFDictionarySetValue(dictionary, CFSTR(kIOHIDElementParentCollectionKey), parentElement); 1076 1077 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementCookieKey), cookie); 1078 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementCollectionCookieKey), element->parentCookie); 1079 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementTypeKey), element->type); 1080 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUsageKey), element->usageMin + ((element->usageMin!=element->usageMax) ? index : 0)); 1081 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUsagePageKey), element->usagePage); 1082 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementReportIDKey), element->reportID); 1083 1084 if ( element->type == kIOHIDElementTypeCollection ) 1085 { 1086 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementCollectionTypeKey), element->collectionType); 1087 break; 1088 } 1089 1090 if ( element->duplicateValueSize && (element->duplicateIndex != 0xffffffff)) 1091 { 1092 reportCount = 1; 1093 size = element->reportSize; 1094 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementDuplicateIndexKey), element->duplicateIndex + ((index>0) ? index-1: 0)); 1095 } 1096 1097 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementSizeKey), size); 1098 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementReportSizeKey), element->reportSize); 1099 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementReportCountKey), reportCount); 1100 1101 setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementHasNullStateKey), (element->flags & kHIDDataNullStateBit) == kHIDDataNullState); 1102 setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementHasPreferredStateKey), (element->flags & kHIDDataNoPreferredBit) != kHIDDataNoPreferred); 1103 setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsNonLinearKey), (element->flags & kHIDDataNonlinearBit) == kHIDDataNonlinear); 1104 setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsRelativeKey), (element->flags & kHIDDataRelativeBit) == kHIDDataRelative); 1105 setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsWrappingKey), (element->flags & kHIDDataWrapBit) == kHIDDataWrap); 1106 setElementDictBoolValue(dictionary, CFSTR(kIOHIDElementIsArrayKey), (element->flags & kHIDDataArrayBit) == kHIDDataArray); 1107 1108 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementMaxKey), element->max); 1109 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementMinKey), element->min); 1110 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementScaledMaxKey), element->scaledMax); 1111 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementScaledMinKey), element->scaledMin); 1112 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUnitKey), element->unit); 1113 setElementDictIntValue(dictionary, CFSTR(kIOHIDElementUnitExponentKey), element->unitExponent); 1114 1115 } while (false); 1116 1117 type = dictionary; 1118 } 1119 } 1120 else 1121 { 1122 type = _IOHIDElementCreateWithParentAndData(kCFAllocatorDefault, (IOHIDElementRef)parentElement, data, element, index); 1123 1124 if (type) 1125 _IOHIDElementSetDeviceInterface((IOHIDElementRef)type, (IOHIDDeviceDeviceInterface **)&fHIDDevice); 1126 } 1127 1128 if ( key && type && elementCache ) 1129 CFDictionarySetValue(elementCache, key, type); 1130 1131 if (key) 1132 CFRelease(key); 1133 1134 if (isElementCached) 1135 *isElementCached = false; 1136 1137 return type; 1138} 1139 1140IOReturn 1141IOHIDDeviceClass::copyMatchingElements(CFDictionaryRef matchingDict, CFArrayRef * elements, CFTypeRef parentElement, CFMutableDictionaryRef elementCache, IOOptionBits options) 1142{ 1143 if (!elements) 1144 return kIOReturnBadArgument; 1145 1146 IOHIDElementStruct element; 1147 CFMutableArrayRef tempElements = 0; 1148 CFMutableArrayRef subElements = 0; 1149 CFTypeRef elementType = 0; 1150 CFTypeRef object = 0; 1151 uint32_t number = 0; 1152 uint32_t index = 0; 1153 uint32_t matchingCookieMin = 0; 1154 uint32_t matchingCookieMax = 0; 1155 uint32_t matchingUsageMin = 0; 1156 uint32_t matchingUsageMax = 0; 1157 uint32_t matchingDupIndex = 0; 1158 bool isMatchingCookieMin = false; 1159 bool isMatchingCookieMax = false; 1160 bool isMatchingUsageMin = false; 1161 bool isMatchingUsageMax = false; 1162 bool isMatchingDupIndex = false; 1163 bool isElementCached = false; 1164 bool isDuplicateRoot = false; 1165 1166 1167 if (!(tempElements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks))) 1168 { 1169 *elements = 0; 1170 return kIOReturnNoMemory; 1171 } 1172 1173 for (index=0; index<fElementCount; index++) 1174 { 1175 isMatchingCookieMin = isMatchingCookieMax = false; 1176 isMatchingUsageMax = isMatchingUsageMin = false; 1177 matchingCookieMin = matchingCookieMax = 0; 1178 matchingUsageMin = matchingUsageMax = 0; 1179 isDuplicateRoot = (fElements[index].duplicateValueSize != 0); 1180 1181 if ( matchingDict ) 1182 { 1183 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCookieKey), &number) ) 1184 { 1185 if ((number < fElements[index].cookieMin) || (number > fElements[index].cookieMax)) 1186 continue; 1187 1188 matchingCookieMin = number; 1189 matchingCookieMax = number; 1190 isMatchingCookieMin = true; 1191 isMatchingCookieMax = true; 1192 } 1193 else 1194 { 1195 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCookieMinKey), &number) ) 1196 { 1197 if ( number < fElements[index].cookieMin ) 1198 continue; 1199 1200 matchingCookieMin = number; 1201 isMatchingCookieMin = true; 1202 } 1203 1204 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCookieMaxKey), &number) ) 1205 { 1206 if ( number > fElements[index].cookieMax ) 1207 continue; 1208 1209 matchingCookieMax = number; 1210 isMatchingCookieMax = true; 1211 } 1212 } 1213 1214 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCollectionCookieKey), &number) && 1215 (number != fElements[index].parentCookie)) 1216 continue; 1217 1218 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementTypeKey), &number) && 1219 (number != fElements[index].type)) 1220 continue; 1221 1222 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementCollectionTypeKey), &number) && 1223 (number != fElements[index].collectionType)) 1224 continue; 1225 1226 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementReportIDKey), &number) && 1227 (number != fElements[index].reportID)) 1228 continue; 1229 1230 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsageKey), &number) ) 1231 { 1232 if ((number < fElements[index].usageMin) || (number > fElements[index].usageMax)) 1233 continue; 1234 1235 matchingUsageMin = number; 1236 matchingUsageMax = number; 1237 isMatchingUsageMin = true; 1238 isMatchingUsageMax = true; 1239 } 1240 else 1241 { 1242 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsageMinKey), &number) ) 1243 { 1244 if ( number < fElements[index].usageMin ) 1245 continue; 1246 1247 matchingUsageMin = number; 1248 isMatchingUsageMin = true; 1249 } 1250 1251 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsageMaxKey), &number) ) 1252 { 1253 if ( number > fElements[index].usageMax ) 1254 continue; 1255 1256 matchingUsageMax = number; 1257 isMatchingUsageMax = true; 1258 } 1259 } 1260 1261 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUsagePageKey), &number) && 1262 (number != fElements[index].usagePage)) 1263 continue; 1264 1265 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementMinKey), &number) && 1266 ((int32_t)number != fElements[index].min)) 1267 continue; 1268 1269 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementMaxKey), &number) && 1270 ((int32_t)number != fElements[index].max)) 1271 continue; 1272 1273 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementScaledMinKey), &number) && 1274 ((int32_t)number != fElements[index].scaledMin)) 1275 continue; 1276 1277 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementScaledMaxKey), &number) && 1278 ((int32_t)number != fElements[index].scaledMax)) 1279 continue; 1280 1281 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementSizeKey), &number) && 1282 (number != fElements[index].size)) 1283 continue; 1284 1285 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementReportSizeKey), &number) && 1286 (number != fElements[index].reportSize)) 1287 continue; 1288 1289 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementReportCountKey), &number) && 1290 (number != fElements[index].reportCount)) 1291 continue; 1292 1293 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsRelativeKey), &number) && 1294 (number != ((fElements[index].flags & kHIDDataRelativeBit) == kHIDDataRelative))) 1295 continue; 1296 1297 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsWrappingKey), &number) && 1298 (number != ((fElements[index].flags & kHIDDataWrapBit) == kHIDDataWrap))) 1299 continue; 1300 1301 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsNonLinearKey), &number) && 1302 (number != ((fElements[index].flags & kHIDDataNonlinearBit) == kHIDDataNonlinear))) 1303 continue; 1304 1305 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementHasPreferredStateKey), &number) && 1306 (number != ((fElements[index].flags & kHIDDataNoPreferredBit) != kHIDDataNoPreferred))) 1307 continue; 1308 1309 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementHasNullStateKey), &number) && 1310 (number != ((fElements[index].flags & kHIDDataNullStateBit) == kHIDDataNullState))) 1311 continue; 1312 1313 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementIsArrayKey), &number) && 1314 (number != ((fElements[index].flags & kHIDDataArrayBit) == kHIDDataArray))) 1315 continue; 1316 1317 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUnitKey), &number) && 1318 (number != fElements[index].unit)) 1319 continue; 1320 1321 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementUnitExponentKey), &number) && 1322 (number != fElements[index].unitExponent)) 1323 continue; 1324 1325 if ( getElementDictIntValue(matchingDict, CFSTR(kIOHIDElementDuplicateIndexKey), &number) ) 1326 { 1327 if ( !isDuplicateRoot ) 1328 continue; 1329 1330 matchingDupIndex = number; 1331 isMatchingDupIndex = true; 1332 } 1333 } 1334 1335 uint32_t rangeIndex = 0; 1336 uint32_t usageIndex = 0; 1337 uint32_t duplicateIndex = 0; 1338 1339 while ((fElements[index].cookieMin+rangeIndex)<= fElements[index].cookieMax) 1340 { 1341 // Break out once we are out of the usage range 1342 if (isMatchingUsageMax && (matchingUsageMax < (fElements[index].usageMin+usageIndex))) 1343 break; 1344 1345 // Break out once we are out of the cookie range 1346 if (isMatchingCookieMax && (matchingCookieMax < (fElements[index].cookieMin+rangeIndex))) 1347 break; 1348 1349 // create guy 1350 if ((!isMatchingCookieMin || (isMatchingCookieMin && (matchingCookieMin <= (fElements[index].cookieMin+rangeIndex)))) && 1351 (!isMatchingUsageMin || (isMatchingUsageMin && (matchingUsageMin <= (fElements[index].usageMin+usageIndex)))) && 1352 // The container element is always going to be the first 1353 // element in a duplicate range and should be ignored when 1354 // matching on a specific index. 1355 (!isMatchingDupIndex || 1356 (((fElements[index].cookieMin+rangeIndex) != fElements[index].cookieMin) && 1357 isMatchingDupIndex && (matchingDupIndex == (fElements[index].duplicateIndex+duplicateIndex))))) 1358 { 1359 isElementCached = false; 1360 elementType = createElement(fElementData, &fElements[index], (fElements[index].duplicateValueSize&&!isDuplicateRoot) ? duplicateIndex : rangeIndex, parentElement, elementCache, &isElementCached, options); 1361 1362 if ( elementType ) 1363 { 1364 CFArrayAppendValue(tempElements, elementType); 1365 CFRelease(elementType); 1366 1367 // RY: Adding a non-cached collection requires digging for the sub elements 1368 // Ideally, I would like to be able to generate these objects only when 1369 // requested via CFDictionaryGetValue on kIOHIDElementKey. Unfortunately, 1370 // CF does not provide a callback method for CFDictionaryGetValue. There 1371 // are ways to work with the CFEqual callback, but you need to handle 1372 // recursively calling back into yourself on a SetValue. Spoke to CTP on 1373 // CF team and requested the ability to have a faulting CFDictionary. This 1374 // appears to be desired by other teams as well and is planned for Leopard. 1375 // Utill then, just populate like normal. 1376 if ((CFDictionaryGetTypeID()==CFGetTypeID(elementType)) && !isElementCached && (fElements[index].type==kIOHIDElementTypeCollection)) 1377 { 1378 CFMutableDictionaryRef tempMatchingDict; 1379 tempMatchingDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1380 1381 if ( tempMatchingDict ) 1382 { 1383 CFArrayRef tempSubElements = 0; 1384 1385 setElementDictIntValue(tempMatchingDict, CFSTR(kIOHIDElementCollectionCookieKey), fElements[index].cookieMin+rangeIndex); 1386 copyMatchingElements(tempMatchingDict, &tempSubElements, elementType, elementCache, options); 1387 1388 if (tempSubElements) 1389 { 1390 CFDictionarySetValue((CFMutableDictionaryRef)elementType, CFSTR(kIOHIDElementKey), tempSubElements); 1391 CFRelease(tempSubElements); 1392 } 1393 1394 CFRelease(tempMatchingDict); 1395 } 1396 } 1397 } 1398 1399 // Matched on duplicate index so we can break out of the loop 1400 if ( isMatchingDupIndex ) 1401 break; 1402 1403 // Break out of both loops if we are looking for a single cookie 1404 if (isMatchingCookieMin && (matchingCookieMin == fElements[index].cookieMin) && 1405 isMatchingCookieMax && (matchingCookieMax == matchingCookieMin)) 1406 goto FINISH_ELEMENT_SEARCH; 1407 } 1408 1409 rangeIndex++; 1410 1411 if ((fElements[index].usageMin+usageIndex) != fElements[index].usageMax ) 1412 usageIndex++; 1413 1414 // if a duplicate adjust the other stuff as well 1415 if ( fElements[index].duplicateValueSize && !isDuplicateRoot) 1416 duplicateIndex++; 1417 1418 isDuplicateRoot = false; 1419 } 1420 } 1421 1422FINISH_ELEMENT_SEARCH: 1423 *elements = tempElements; 1424 1425 if (CFArrayGetCount(*elements) == 0) 1426 { 1427 CFRelease(*elements); 1428 *elements = 0; 1429 } 1430 1431 return kIOReturnSuccess; 1432} 1433 1434IOReturn IOHIDDeviceClass::setInterruptReportCallback(uint8_t * report, CFIndex reportLength, IOHIDReportCallback callback, void * refcon, IOOptionBits options) 1435 1436{ 1437 IOReturn ret = kIOReturnSuccess; 1438 1439 fInputReportCallback = callback; 1440 fInputReportRefcon = refcon; 1441 fInputReportBuffer = report; 1442 fInputReportBufferSize = reportLength; 1443 fInputReportOptions = options; 1444 1445 // Lazy set up of the queue. 1446 if ( !fReportHandlerQueue ) 1447 { 1448 fReportHandlerQueue = createQueue(true); 1449 1450 ret = fReportHandlerQueue->create(0, 8); 1451 1452 if (ret != kIOReturnSuccess) 1453 goto SET_REPORT_HANDLER_CLEANUP; 1454 1455 for (uint32_t i=0; i<fReportHandlerElementCount; i++) 1456 { 1457 ret = fReportHandlerQueue->addElement(getElement((IOHIDElementCookie)fReportHandlerElements[i].cookieMin), 0); 1458 1459 if (ret != kIOReturnSuccess) 1460 goto SET_REPORT_HANDLER_CLEANUP; 1461 } 1462 1463 1464 if ( fAsyncPort && fIsOpen ) 1465 { 1466 ret = finishReportHandlerQueueSetup(); 1467 if (ret != kIOReturnSuccess) 1468 goto SET_REPORT_HANDLER_CLEANUP; 1469 } 1470 } 1471 1472 return kIOReturnSuccess; 1473 1474SET_REPORT_HANDLER_CLEANUP: 1475 delete fReportHandlerQueue; 1476 fReportHandlerQueue = 0; 1477 1478 return ret; 1479} 1480 1481IOReturn IOHIDDeviceClass::finishReportHandlerQueueSetup() 1482{ 1483 IOReturn ret = kIOReturnError; 1484 1485 if ( fReportHandlerQueue ) 1486 { 1487 do { 1488 ret = fReportHandlerQueue->setEventCallback(_hidReportHandlerCallback, this); 1489 1490 if (ret != kIOReturnSuccess) break; 1491 1492 ret = fReportHandlerQueue->setAsyncPort(IONotificationPortGetMachPort(fAsyncPort)); 1493 1494 if (ret != kIOReturnSuccess) break; 1495 1496 ret = fReportHandlerQueue->start(); 1497 1498 if (ret != kIOReturnSuccess) break; 1499 1500 } while ( false ); 1501 } 1502 return ret; 1503} 1504 1505void IOHIDDeviceClass::_cfmachPortCallback(CFMachPortRef cfPort, mach_msg_header_t *msg, CFIndex size, void *info) 1506{ 1507 mach_msg_header_t * msgh = (mach_msg_header_t *)msg; 1508 IOHIDDeviceClass * self = (IOHIDDeviceClass *) info; 1509 1510 if ( !self ) 1511 return; 1512 1513 if( msgh->msgh_id == kOSNotificationMessageID) 1514 IODispatchCalloutFromMessage(cfPort, msg, info); 1515 else if ( self->fReportHandlerQueue ) 1516 IOHIDQueueClass::queueEventSourceCallback(cfPort, msg, size, self->fReportHandlerQueue); 1517} 1518 1519void IOHIDDeviceClass::_hidReportHandlerCallback(void * refcon, IOReturn result, void * sender __unused) 1520{ 1521 IOHIDValueRef event; 1522 IOHIDDeviceClass * self = (IOHIDDeviceClass *)refcon; 1523 IOHIDQueueClass * queue = self->fReportHandlerQueue; 1524 uint32_t value, size = 0; 1525 1526 if (!self || !self->fIsOpen) 1527 return; 1528 1529 while ((result = queue->copyNextEventValue( &event, 0, 0)) == kIOReturnSuccess) 1530 { 1531 if (IOHIDValueGetBytePtr(event) && IOHIDValueGetLength(event)) 1532 { 1533 size = min(self->fInputReportBufferSize, IOHIDValueGetLength(event)); 1534 bcopy(IOHIDValueGetBytePtr(event), self->fInputReportBuffer, size); 1535 } 1536 1537 if (self->fInputReportCallback) 1538 (self->fInputReportCallback)( 1539 self->fInputReportRefcon, 1540 result, 1541 &(self->fHIDDevice), 1542 kIOHIDReportTypeInput, 1543 IOHIDElementGetReportID(IOHIDValueGetElement(event)), 1544 self->fInputReportBuffer, 1545 size); 1546 1547 CFRelease(event); 1548 } 1549} 1550 1551 1552void 1553IOHIDDeviceClass::_hidReportCallback(void *refcon, IOReturn result, uint32_t bufferSize) 1554{ 1555 IOHIDReportRefCon *hidRefcon = (IOHIDReportRefCon *)refcon; 1556 1557 if (!hidRefcon || !hidRefcon->callback) 1558 return; 1559 1560 ((IOHIDReportCallback)hidRefcon->callback)( hidRefcon->callbackRefcon, 1561 result, 1562 hidRefcon->sender, 1563 hidRefcon->type, 1564 hidRefcon->reportID, 1565 hidRefcon->buffer, 1566 bufferSize); 1567 1568 free(hidRefcon); 1569} 1570 1571IOReturn IOHIDDeviceClass::startAllQueues() 1572{ 1573 IOReturn ret = kIOReturnSuccess; 1574 1575 if ( fQueues ) 1576 { 1577 int queueCount = CFSetGetCount(fQueues); 1578 IOHIDQueueClass ** queues = NULL; 1579 1580 queues = (IOHIDQueueClass **)malloc(sizeof(IOHIDQueueClass *) * queueCount); 1581 1582 CFSetGetValues(fQueues, (const void **)queues); 1583 1584 for (int i=0; queues && i<queueCount; i++) 1585 { 1586 ret = queues[i]->start(); 1587 } 1588 1589 if (queues) 1590 free(queues); 1591 1592 } 1593 1594 return ret; 1595} 1596 1597IOReturn IOHIDDeviceClass::stopAllQueues() 1598{ 1599 IOReturn ret = kIOReturnSuccess; 1600 1601 if ( fQueues ) 1602 { 1603 int queueCount = CFSetGetCount(fQueues); 1604 IOHIDQueueClass ** queues = NULL; 1605 1606 queues = (IOHIDQueueClass **)malloc(sizeof(IOHIDQueueClass *) * queueCount); 1607 1608 CFSetGetValues(fQueues, (const void **)queues); 1609 1610 for (int i=0; queues && i<queueCount && ret==kIOReturnSuccess; i++) 1611 { 1612 ret = queues[i]->stop(); 1613 } 1614 1615 if (queues) 1616 free(queues); 1617 } 1618 1619 return ret; 1620} 1621 1622IOCFPlugInInterface IOHIDDeviceClass::sIOCFPlugInInterfaceV1 = 1623{ 1624 0, 1625 &IOHIDIUnknown::genericQueryInterface, 1626 &IOHIDIUnknown::genericAddRef, 1627 &IOHIDIUnknown::genericRelease, 1628 1, 0, // version/revision 1629 &IOHIDDeviceClass::_probe, 1630 &IOHIDDeviceClass::_start, 1631 &IOHIDDeviceClass::_stop 1632}; 1633 1634IOHIDDeviceDeviceInterface IOHIDDeviceClass::sHIDDeviceInterfaceV2 = 1635{ 1636 0, 1637 &IOHIDIUnknown::genericQueryInterface, 1638 &IOHIDIUnknown::genericAddRef, 1639 &IOHIDIUnknown::genericRelease, 1640 &IOHIDDeviceClass::_open, 1641 &IOHIDDeviceClass::_close, 1642 &IOHIDDeviceClass::_getProperty, 1643 &IOHIDDeviceClass::_setProperty, 1644 &IOHIDDeviceClass::_getAsyncEventSource, 1645 &IOHIDDeviceClass::_copyMatchingElements, 1646 &IOHIDDeviceClass::_setElementValue, 1647 &IOHIDDeviceClass::_getElementValue, 1648 &IOHIDDeviceClass::_setInterruptReportCallback, 1649 &IOHIDDeviceClass::_setReport, 1650 &IOHIDDeviceClass::_getReport 1651}; 1652 1653// Methods for routing iocfplugin interface 1654IOReturn IOHIDDeviceClass:: _probe(void *self, CFDictionaryRef propertyTable, io_service_t inService, SInt32 *order) 1655 { return getThis(self)->probe(propertyTable, inService, order); } 1656 1657IOReturn IOHIDDeviceClass::_start(void *self, CFDictionaryRef propertyTable, io_service_t inService) 1658 { return getThis(self)->start(propertyTable, inService); } 1659 1660IOReturn IOHIDDeviceClass::_stop(void *self) 1661 { return getThis(self)->close(); } 1662 1663IOReturn IOHIDDeviceClass::_open(void * self, IOOptionBits options) 1664{ return getThis(self)->open(options); } 1665 1666IOReturn IOHIDDeviceClass::_close(void * self, IOOptionBits options) 1667{ return getThis(self)->close(options); } 1668 1669IOReturn IOHIDDeviceClass::_getProperty(void * self, CFStringRef key, CFTypeRef * pProperty) 1670{ return getThis(self)->getProperty(key, pProperty); } 1671 1672IOReturn IOHIDDeviceClass::_setProperty(void * self, CFStringRef key, CFTypeRef property) 1673{ return getThis(self)->setProperty(key, property); } 1674 1675IOReturn IOHIDDeviceClass::_getAsyncPort(void * self, mach_port_t * port) 1676{ return getThis(self)->getAsyncPort(port); } 1677 1678IOReturn IOHIDDeviceClass::_getAsyncEventSource(void * self, CFTypeRef * pSource) 1679{ return getThis(self)->getAsyncEventSource(pSource); } 1680 1681IOReturn IOHIDDeviceClass::_copyMatchingElements(void * self, CFDictionaryRef matchingDict, CFArrayRef * elements, IOOptionBits options) 1682{ 1683 IOReturn ret = kIOReturnNoMemory; 1684 IOHIDDeviceClass * selfRef = getThis(self); 1685 1686 return selfRef->copyMatchingElements(matchingDict, elements, 0, selfRef->fElementCache, options); 1687} 1688 1689IOReturn IOHIDDeviceClass::_setInterruptReportCallback(void * self, uint8_t * report, CFIndex reportLength, 1690 IOHIDReportCallback callback, void * refcon, IOOptionBits options) 1691{ return getThis(self)->setInterruptReportCallback(report, reportLength, callback, refcon, options); } 1692 1693IOReturn IOHIDDeviceClass::_getReport(void * self, IOHIDReportType reportType, uint32_t reportID, uint8_t * report, CFIndex * pReportLength, 1694 uint32_t timeout, IOHIDReportCallback callback, void * refcon, IOOptionBits options) 1695{ return getThis(self)->getReport(reportType, reportID, report, pReportLength, timeout, callback, refcon, options);} 1696 1697IOReturn IOHIDDeviceClass::_setReport(void * self, IOHIDReportType reportType, uint32_t reportID, const uint8_t * report, CFIndex reportLength, 1698 uint32_t timeout, IOHIDReportCallback callback, void * refcon, IOOptionBits options) 1699{ return getThis(self)->setReport(reportType, reportID, report, reportLength, timeout, callback, refcon, options);} 1700 1701IOReturn IOHIDDeviceClass::_getElementValue(void * self, IOHIDElementRef element, IOHIDValueRef * pEvent, 1702 uint32_t timeout, IOHIDValueCallback callback, void * refcon, IOOptionBits options) 1703{ return getThis(self)->getElementValue(element, pEvent, timeout, callback, refcon, options); }; 1704 1705IOReturn IOHIDDeviceClass::_setElementValue(void * self, IOHIDElementRef element, IOHIDValueRef event, 1706 uint32_t timeout, IOHIDValueCallback callback, void * refcon, IOOptionBits options) 1707{ return getThis(self)->setElementValue(element, event, timeout, callback, refcon, options);}; 1708 1709 1710#define SWAP_KERNEL_ELEMENT(element) \ 1711{ \ 1712 element.cookieMin = OSSwapInt32(element.cookieMin); \ 1713 element.cookieMax = OSSwapInt32(element.cookieMax); \ 1714 element.parentCookie = OSSwapInt32(element.parentCookie); \ 1715 element.type = OSSwapInt32(element.type); \ 1716 element.collectionType = OSSwapInt32(element.collectionType); \ 1717 element.flags = OSSwapInt32(element.flags); \ 1718 element.usagePage = OSSwapInt32(element.usagePage); \ 1719 element.usageMin = OSSwapInt32(element.usageMin); \ 1720 element.usageMax = OSSwapInt32(element.usageMax); \ 1721 element.min = OSSwapInt32(element.min); \ 1722 element.max = OSSwapInt32(element.max); \ 1723 element.scaledMin = OSSwapInt32(element.scaledMin); \ 1724 element.scaledMax = OSSwapInt32(element.scaledMax); \ 1725 element.size = OSSwapInt32(element.size); \ 1726 element.reportSize = OSSwapInt32(element.reportSize); \ 1727 element.reportCount = OSSwapInt32(element.reportCount); \ 1728 element.reportID = OSSwapInt32(element.reportID); \ 1729 element.unit = OSSwapInt32(element.unit); \ 1730 element.unitExponent = OSSwapInt32(element.unitExponent); \ 1731 element.duplicateValueSize = OSSwapInt32(element.duplicateValueSize); \ 1732 element.bytes = OSSwapInt32(element.bytes); \ 1733 element.valueLocation = OSSwapInt32(element.valueLocation); \ 1734 element.valueSize = OSSwapInt32(element.valueSize); \ 1735} 1736 1737IOReturn IOHIDDeviceClass::buildElements( uint32_t type, CFMutableDataRef * pDataRef, IOHIDElementStruct ** buffer, uint32_t * count ) 1738{ 1739 size_t size; 1740 IOReturn kr; 1741 1742 1743 size = sizeof(IOHIDElementStruct) * *count; 1744 1745 *pDataRef = CFDataCreateMutable(kCFAllocatorDefault, size); 1746 1747 if (!*pDataRef) 1748 return kIOReturnNoMemory; 1749 1750 // count the number of leaves and allocate 1751 *buffer = (IOHIDElementStruct*)CFDataGetMutableBytePtr(*pDataRef); 1752 1753 HIDLog ("IOHIDDeviceClass::buildElements: type=%d *buffer=%4.4x *count=%d size=%d\n", type, *buffer, *count, size); 1754 1755 bzero(*buffer, size); 1756 1757 uint64_t input = type; 1758 1759 kr = IOConnectCallMethod(fConnection, kIOHIDLibUserClientGetElements, &input, 1, 0, 0, 0, 0, *buffer, &size); 1760 1761 *count = size / sizeof(IOHIDElementStruct); 1762 1763 ROSETTA_ONLY( 1764 for ( uint32_t i=0; i<*count; i++) 1765 { 1766 SWAP_KERNEL_ELEMENT((*buffer)[i]); 1767 } 1768 ); 1769 1770#if 0 1771 for (uint32_t index = 0; index < *count; index++) 1772 { 1773 HIDLog ("IOHIDDeviceClass::buildElements: CookieMin=%d CookieMax=%d Min=%d Max=%d UsagePage=0x%x UsageMin=0x%x UsageMax=0x%x Type=%d\n", (*buffer)[index].cookieMin, (*buffer)[index].cookieMax, (*buffer)[index].min, (*buffer)[index].max, (*buffer)[index].usagePage, (*buffer)[index].usageMin, (*buffer)[index].usageMax, (*buffer)[index].type); 1774 } 1775#endif 1776 1777 return kr; 1778} 1779 1780IOHIDElementRef IOHIDDeviceClass::getElement(IOHIDElementCookie cookie) 1781{ 1782 IOHIDElementStruct *elementStruct = 0; 1783 IOHIDElementRef element=NULL; 1784 CFDataRef dataRef=NULL; 1785 uint32_t index=0; 1786 1787 if ( getElementStructPtr(cookie, &elementStruct, &index, &dataRef) ) 1788 { 1789 element = (IOHIDElementRef)createElement(dataRef, elementStruct, index, 0, fElementCache); 1790 1791 if (element) CFRelease(element); // element should be cached so we can release it 1792 } 1793 1794 return element; 1795} 1796 1797uint32_t IOHIDDeviceClass::getElementByteSize(IOHIDElementCookie elementCookie) 1798{ 1799 uint32_t size = 0; 1800 IOHIDElementStruct element; 1801 1802 if (getElementStruct(elementCookie, &element)) 1803 size = element.bytes; 1804 1805 return size; 1806} 1807 1808bool IOHIDDeviceClass::getElementStructPtr(IOHIDElementCookie elementCookie, IOHIDElementStruct ** ppElementStruct, uint32_t * pIndex, CFDataRef * pData) 1809{ 1810 uint32_t cookieIndex = 0; 1811 uint32_t index = 0; 1812 for (index = 0; index < fElementCount; index++) 1813 { 1814 if ( ((uint32_t) elementCookie >= fElements[index].cookieMin) && ((uint32_t) elementCookie <= fElements[index].cookieMax) ) 1815 { 1816 cookieIndex = 0; 1817 while ( (fElements[index].cookieMin != fElements[index].cookieMax) && ((fElements[index].cookieMin + cookieIndex) != (uint32_t)elementCookie) ) 1818 cookieIndex++; 1819 1820 if ( ppElementStruct ) 1821 *ppElementStruct = &fElements[index]; 1822 1823 if ( pIndex ) 1824 *pIndex = cookieIndex; 1825 1826 if ( pData ) 1827 *pData = fElementData; 1828 return true; 1829 } 1830 } 1831 cookieIndex = 0; 1832 for (index = 0; index < fReportHandlerElementCount; index++) 1833 { 1834 if ( ((uint32_t) elementCookie >= fReportHandlerElements[index].cookieMin) && ((uint32_t) elementCookie <= fReportHandlerElements[index].cookieMax) ) 1835 { 1836 if ( ppElementStruct ) 1837 *ppElementStruct = &fReportHandlerElements[index]; 1838 1839 if ( pIndex ) 1840 *pIndex = cookieIndex; 1841 1842 if ( pData ) 1843 *pData = fReportHandlerElementData; 1844 return true; 1845 } 1846 } 1847 return false; 1848} 1849 1850bool IOHIDDeviceClass::getElementStruct(IOHIDElementCookie elementCookie, IOHIDElementStruct * elementStruct) 1851{ 1852 IOHIDElementStruct * pElementStruct = 0; 1853 1854 if (getElementStructPtr(elementCookie, &pElementStruct)) 1855 { 1856 if (pElementStruct) 1857 { 1858 IOHIDElementStruct tempElement = *pElementStruct; 1859 1860 while ( tempElement.cookieMin != (uint32_t)elementCookie ) 1861 { 1862 tempElement.cookieMin++; 1863 1864 if (tempElement.duplicateValueSize) 1865 tempElement.valueLocation -= tempElement.duplicateValueSize; 1866 else 1867 tempElement.valueLocation -= tempElement.valueSize; 1868 } 1869 1870 // if a duplicate adjust the other stuff as well 1871 if ( tempElement.duplicateValueSize && (tempElement.cookieMin != pElementStruct->cookieMin)) 1872 { 1873 tempElement.size = tempElement.reportSize; 1874 tempElement.bytes = (tempElement.size + 7) / 8; 1875 } 1876 1877 if (elementStruct) 1878 *elementStruct = tempElement; 1879 } 1880 1881 return true; 1882 } 1883 1884 return false; 1885} 1886 1887//**************************************************************************************************** 1888// Class: IOHIDObsoleteDeviceClass 1889// Subclasses: IOHIDDeviceClass 1890//**************************************************************************************************** 1891IOCFPlugInInterface ** IOHIDObsoleteDeviceClass::alloc() 1892{ 1893 IOHIDObsoleteDeviceClass *me; 1894 1895 me = new IOHIDObsoleteDeviceClass; 1896 if (me) 1897 return (IOCFPlugInInterface **) &me->iunknown.pseudoVTable; 1898 else 1899 return 0; 1900} 1901 1902IOHIDObsoleteDeviceClass::IOHIDObsoleteDeviceClass() : IOHIDDeviceClass() 1903{ 1904 fHIDDevice.pseudoVTable = (IUnknownVTbl *) &sHIDDeviceInterfaceV122; 1905 fHIDDevice.obj = this; 1906 fInputReportContext = NULL; 1907} 1908 1909//==================================================================================================== 1910// IOHIDObsoleteDeviceClass::IOHIDDeviceInterfaceV1 Static Methods 1911//==================================================================================================== 1912 1913IOHIDDeviceInterface122 IOHIDObsoleteDeviceClass::sHIDDeviceInterfaceV122 = 1914{ 1915 0, 1916 &IOHIDIUnknown::genericQueryInterface, 1917 &IOHIDIUnknown::genericAddRef, 1918 &IOHIDIUnknown::genericRelease, 1919 &IOHIDObsoleteDeviceClass::_createAsyncEventSource, 1920 &IOHIDObsoleteDeviceClass::_getAsyncEventSource, 1921 &IOHIDDeviceClass::_getAsyncPort, 1922 &IOHIDObsoleteDeviceClass::_getAsyncPort, 1923 &IOHIDObsoleteDeviceClass::_open, 1924 &IOHIDObsoleteDeviceClass::_close, 1925 &IOHIDObsoleteDeviceClass::_setRemovalCallback, 1926 &IOHIDObsoleteDeviceClass::_getElementValue, 1927 &IOHIDObsoleteDeviceClass::_setElementValue, 1928 &IOHIDObsoleteDeviceClass::_queryElementValue, 1929 &IOHIDObsoleteDeviceClass::_startAllQueues, 1930 &IOHIDObsoleteDeviceClass::_stopAllQueues, 1931 &IOHIDObsoleteDeviceClass::_allocQueue, 1932 &IOHIDObsoleteDeviceClass::_allocOutputTransaction, 1933 &IOHIDObsoleteDeviceClass::_setReport, 1934 &IOHIDObsoleteDeviceClass::_getReport, 1935 &IOHIDObsoleteDeviceClass::_copyMatchingElements, 1936 &IOHIDObsoleteDeviceClass::_setInterruptReportHandlerCallback 1937}; 1938 1939//==================================================================================================== 1940// IOHIDObsoleteDeviceClass::IOHIDDeviceInterfaceV1 Static Methods 1941//==================================================================================================== 1942IOReturn IOHIDObsoleteDeviceClass::_createAsyncEventSource(void * self, CFRunLoopSourceRef * pSource) 1943{ 1944 return getThis(self)->createAsyncEventSource(pSource); 1945} 1946 1947CFRunLoopSourceRef IOHIDObsoleteDeviceClass::_getAsyncEventSource(void *self) 1948{ 1949 CFTypeRef source = NULL; 1950 getThis(self)->getAsyncEventSource(&source); 1951 return (CFRunLoopSourceRef)source; 1952} 1953 1954mach_port_t IOHIDObsoleteDeviceClass::_getAsyncPort(void *self) 1955{ 1956 mach_port_t port = MACH_PORT_NULL; 1957 getThis(self)->getAsyncPort(&port); 1958 return port; 1959} 1960 1961IOReturn IOHIDObsoleteDeviceClass::_close(void *self) 1962{ 1963 return getThis(self)->close(); 1964} 1965 1966IOReturn IOHIDObsoleteDeviceClass::_setRemovalCallback(void * self, IOHIDCallbackFunction callback, void * target, void * refcon) 1967{ 1968 return getThis(self)->setRemovalCallback (callback, target, refcon); 1969} 1970 1971IOReturn IOHIDObsoleteDeviceClass::_getElementValue(void * self, IOHIDElementCookie elementCookie, IOHIDEventStruct * valueEvent) 1972{ 1973 return getThis(self)->getElementValue (elementCookie, valueEvent); 1974} 1975 1976IOReturn IOHIDObsoleteDeviceClass::_setElementValue(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon) 1977{ 1978 return getThis(self)->setElementValue(cookie, pEvent, timeout, callback, target, refcon); 1979} 1980 1981IOReturn IOHIDObsoleteDeviceClass::_queryElementValue(void * self, IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon) 1982{ 1983 return getThis(self)->queryElementValue (cookie, pEvent, timeout, callback, target, refcon); 1984} 1985 1986IOReturn IOHIDObsoleteDeviceClass::_startAllQueues(void * self) 1987{ 1988 return getThis(self)->startAllQueues (); 1989} 1990 1991IOReturn IOHIDObsoleteDeviceClass::_stopAllQueues(void * self) 1992{ 1993 return getThis(self)->stopAllQueues (); 1994} 1995 1996IOHIDQueueInterface ** IOHIDObsoleteDeviceClass::_allocQueue(void *self) 1997{ 1998 return getThis(self)->allocQueue (); 1999} 2000 2001IOHIDOutputTransactionInterface ** IOHIDObsoleteDeviceClass::_allocOutputTransaction (void *self) 2002{ 2003 return getThis(self)->allocOutputTransaction(); 2004} 2005 2006IOReturn IOHIDObsoleteDeviceClass::_setReport (void * self, IOHIDReportType type, uint32_t id, void * report, uint32_t length, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon) 2007{ 2008 return getThis(self)->setReport(type, id, report, length, timeout, callback, target, refcon); 2009} 2010 2011IOReturn IOHIDObsoleteDeviceClass::_getReport (void * self, IOHIDReportType type, uint32_t id, void * report, uint32_t * pLength, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon) 2012{ 2013 return getThis(self)->getReport(type, id, report, pLength, timeout, callback, target, refcon); 2014} 2015 2016IOReturn IOHIDObsoleteDeviceClass::_copyMatchingElements(void * self, CFDictionaryRef matchingDict, CFArrayRef *elements) 2017{ 2018 IOReturn ret = kIOReturnNoMemory; 2019 CFMutableDictionaryRef cache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 2020 2021 if ( cache ) 2022 { 2023 ret = getThis(self)->copyMatchingElements(matchingDict, elements, 0, cache, kCreateMatchingHIDElementsWithDictionaries); 2024 CFRelease(cache); 2025 } 2026 2027 return ret; 2028} 2029 2030IOReturn IOHIDObsoleteDeviceClass::_setInterruptReportHandlerCallback(void * self, void * report, uint32_t length, IOHIDReportCallbackFunction callback, void * target, void * refcon) 2031{ 2032 return getThis(self)->setInterruptReportHandlerCallback(report, length, callback, target, refcon); 2033} 2034 2035IOHIDQueueClass * IOHIDObsoleteDeviceClass::createQueue(bool reportHandler) 2036{ 2037 IOHIDObsoleteQueueClass * newQueue = new IOHIDObsoleteQueueClass; 2038 2039 // attach the queue to us 2040 attachQueue (newQueue, reportHandler); 2041 2042 return newQueue; 2043} 2044 2045HRESULT IOHIDObsoleteDeviceClass::queryInterfaceTransaction (CFUUIDRef uuid __unused, void **ppv) 2046{ 2047 HRESULT res = S_OK; 2048 2049 IOHIDOutputTransactionClass * transaction = new IOHIDOutputTransactionClass; 2050 2051 transaction->setDirection(kIOHIDTransactionDirectionTypeOutput); 2052 2053 attachTransaction(transaction); 2054 2055 *ppv = transaction->getInterfaceMap(); 2056 2057 return res; 2058} 2059 2060 2061HRESULT IOHIDObsoleteDeviceClass::queryInterface(REFIID iid, void **ppv) 2062{ 2063 CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid); 2064 HRESULT res = S_OK; 2065 2066 if (CFEqual(uuid, kIOHIDQueueInterfaceID)) 2067 res = queryInterfaceQueue(uuid, ppv); 2068 else if (CFEqual(uuid, kIOHIDOutputTransactionInterfaceID)) 2069 res = queryInterfaceTransaction(uuid, ppv); 2070 else if (CFEqual(uuid, kIOHIDDeviceInterfaceID) || CFEqual(uuid, kIOHIDDeviceInterfaceID121) || CFEqual(uuid, kIOHIDDeviceInterfaceID122)) 2071 { 2072 *ppv = &fHIDDevice; 2073 addRef(); 2074 } 2075 else { 2076 res = IOHIDDeviceClass::queryInterface(iid, ppv); 2077 } 2078 2079 if (!*ppv) 2080 res = E_NOINTERFACE; 2081 2082 CFRelease(uuid); 2083 return res; 2084} 2085 2086IOReturn IOHIDObsoleteDeviceClass::createAsyncEventSource(CFRunLoopSourceRef * pSource) 2087{ 2088 IOReturn ret = IOHIDDeviceClass::getAsyncEventSource((CFTypeRef*)pSource); 2089 2090 if ( ret == kIOReturnSuccess && pSource && *pSource ) 2091 CFRetain(*pSource); 2092 2093 return ret; 2094} 2095 2096 2097IOReturn IOHIDObsoleteDeviceClass::setRemovalCallback(IOHIDCallbackFunction removalCallback, void * removalTarget, void * removalRefcon) 2098{ 2099 IOReturn ret = kIOReturnSuccess; 2100 2101 if (!fAsyncPrivateDataRef) 2102 { 2103 2104 fAsyncPrivateDataRef = (MyPrivateData *)malloc(sizeof(MyPrivateData)); 2105 bzero(fAsyncPrivateDataRef, sizeof(MyPrivateData)); 2106 2107 fAsyncPrivateDataRef->self = this; 2108 2109 if (!fAsyncPort) { 2110 ret = getAsyncPort(0); 2111 if (kIOReturnSuccess != ret) 2112 return ret; 2113 } 2114 2115 // Register for an interest notification of this device being removed. Use a reference to our 2116 // private data as the refCon which will be passed to the notification callback. 2117 ret = IOServiceAddInterestNotification( fAsyncPort, 2118 fService, 2119 kIOGeneralInterest, 2120 IOHIDDeviceClass::_deviceNotification, 2121 fAsyncPrivateDataRef, 2122 &(fAsyncPrivateDataRef->notification)); 2123 } 2124 2125 fRemovalCallback = removalCallback; 2126 fRemovalTarget = removalTarget; 2127 fRemovalRefcon = removalRefcon; 2128 2129 return ret; 2130} 2131 2132IOReturn 2133IOHIDObsoleteDeviceClass::setElementValue(IOHIDElementRef element, 2134 IOHIDValueRef event, 2135 uint32_t timeout, 2136 IOHIDValueCallback callback, 2137 void * refcon, 2138 IOOptionBits options) 2139{ 2140 return IOHIDDeviceClass::setElementValue(element, event, timeout, callback, refcon, options); 2141} 2142 2143IOReturn IOHIDObsoleteDeviceClass::setElementValue(IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon, IOOptionBits options) 2144{ 2145 IOHIDElementRef element = getElement(cookie); 2146 IOHIDValueRef event = _IOHIDValueCreateWithStruct(kCFAllocatorDefault, element, pEvent); 2147 IOReturn kr = kIOReturnNoMemory; 2148 2149 if ( event ) 2150 { 2151 IOHIDValueCallback valueCallback = NULL; 2152 IOHIDObsoleteCallbackArgs * valueArgs = NULL; 2153 2154 if ( callback ) { 2155 valueCallback = IOHIDObsoleteDeviceClass::_elementValueCallback; 2156 valueArgs = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs)); 2157 2158 if ( !valueArgs ) { 2159 CFRelease(event); 2160 return kIOReturnNoMemory; 2161 } 2162 2163 bzero(valueArgs, sizeof(IOHIDObsoleteCallbackArgs)); 2164 2165 valueArgs->self = this; 2166 valueArgs->callback = (void *)callback; 2167 valueArgs->target = target; 2168 valueArgs->refcon = refcon; 2169 } 2170 2171 kr = IOHIDDeviceClass::setElementValue(element, event, timeout, valueCallback, valueArgs, options); 2172 CFRelease(event); 2173 } 2174 2175 return kr; 2176} 2177 2178IOReturn IOHIDObsoleteDeviceClass::queryElementValue(IOHIDElementCookie cookie, IOHIDEventStruct * pEvent, uint32_t timeout, IOHIDElementCallbackFunction callback, void * target, void * refcon) 2179{ 2180 IOHIDValueRef event = 0; 2181 IOReturn kr = kIOReturnBadArgument; 2182 2183 if ( pEvent ) 2184 { 2185 IOHIDValueCallback valueCallback = NULL; 2186 IOHIDObsoleteCallbackArgs * valueArgs = NULL; 2187 2188 if ( callback ) { 2189 valueCallback = IOHIDObsoleteDeviceClass::_elementValueCallback; 2190 valueArgs = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs)); 2191 2192 if ( !valueArgs ) 2193 return kIOReturnNoMemory; 2194 2195 bzero(valueArgs, sizeof(IOHIDObsoleteCallbackArgs)); 2196 2197 valueArgs->self = this; 2198 valueArgs->callback = (void *)callback; 2199 valueArgs->target = target; 2200 valueArgs->refcon = refcon; 2201 } 2202 2203 kr = IOHIDDeviceClass::getElementValue(getElement(cookie), &event, timeout, valueCallback, valueArgs, kHIDGetElementValueForcePoll); 2204 2205 if ((kr==kIOReturnSuccess) && event) 2206 { 2207 uint32_t length = _IOHIDElementGetLength(IOHIDValueGetElement(event)); 2208 2209 pEvent->type = IOHIDElementGetType(IOHIDValueGetElement(event)); 2210 pEvent->elementCookie = IOHIDElementGetCookie(IOHIDValueGetElement(event)); 2211 *(UInt64 *)& pEvent->timestamp = IOHIDValueGetTimeStamp(event); 2212 2213 if ( length > sizeof(uint32_t) ) 2214 { 2215 pEvent->longValueSize = length; 2216 pEvent->longValue = malloc(length); 2217 bcopy(IOHIDValueGetBytePtr(event), pEvent->longValue, length); 2218 } 2219 else 2220 { 2221 pEvent->longValueSize = 0; 2222 pEvent->longValue = NULL; 2223 pEvent->value = IOHIDValueGetIntegerValue(event); 2224 } 2225 } 2226 } 2227 2228 return kr; 2229} 2230 2231IOReturn 2232IOHIDObsoleteDeviceClass::getElementValue(IOHIDElementRef element, 2233 IOHIDValueRef * pEvent, 2234 uint32_t timeout, 2235 IOHIDValueCallback callback, 2236 void * refcon, 2237 IOOptionBits options) 2238{ 2239 return IOHIDDeviceClass::getElementValue(element, pEvent, timeout, callback, refcon, options); 2240} 2241 2242IOReturn IOHIDObsoleteDeviceClass::getElementValue(IOHIDElementCookie cookie, IOHIDEventStruct * pEvent) 2243 2244{ 2245 IOHIDValueRef event = 0; 2246 IOReturn kr = kIOReturnBadArgument; 2247 2248 if ( pEvent ) 2249 { 2250 kr = IOHIDDeviceClass::getElementValue(getElement(cookie), &event); 2251 2252 if ((kr==kIOReturnSuccess) && event) 2253 { 2254 uint32_t length = _IOHIDElementGetLength(IOHIDValueGetElement(event)); 2255 2256 pEvent->type = IOHIDElementGetType(IOHIDValueGetElement(event)); 2257 pEvent->elementCookie = IOHIDElementGetCookie(IOHIDValueGetElement(event)); 2258 *(UInt64 *)& pEvent->timestamp = IOHIDValueGetTimeStamp(event); 2259 2260 if ( length > sizeof(uint32_t) ) 2261 { 2262 pEvent->longValueSize = length; 2263 pEvent->longValue = malloc(length); 2264 bcopy(IOHIDValueGetBytePtr(event), pEvent->longValue, length); 2265 } 2266 else 2267 { 2268 pEvent->longValueSize = 0; 2269 pEvent->longValue = NULL; 2270 pEvent->value = IOHIDValueGetIntegerValue(event); 2271 } 2272 } 2273 } 2274 2275 return kr; 2276} 2277 2278IOReturn 2279IOHIDObsoleteDeviceClass::setReport(IOHIDReportType reportType, 2280 uint32_t reportID, 2281 const uint8_t * report, 2282 CFIndex reportLength, 2283 uint32_t timeout, 2284 IOHIDReportCallback callback, 2285 void * refcon, 2286 IOOptionBits options) 2287{ 2288 return IOHIDDeviceClass::setReport(reportType, reportID, report, reportLength, timeout, callback, refcon, options); 2289} 2290 2291IOReturn IOHIDObsoleteDeviceClass::setReport(IOHIDReportType type, uint32_t id, void * report, uint32_t length, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon) 2292{ 2293 IOHIDReportCallback reportCallback = NULL; 2294 IOHIDObsoleteCallbackArgs * reportContext = NULL; 2295 2296 if ( callback ) { 2297 reportCallback = IOHIDObsoleteDeviceClass::_reportCallback; 2298 reportContext = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs)); 2299 2300 if ( !reportContext ) 2301 return kIOReturnNoMemory; 2302 2303 bzero(reportContext, sizeof(IOHIDObsoleteCallbackArgs)); 2304 2305 reportContext->self = this; 2306 reportContext->callback = (void *)callback; 2307 reportContext->target = target; 2308 reportContext->refcon = refcon; 2309 } 2310 2311 return IOHIDDeviceClass::setReport(type, id, (const uint8_t *)report, length, timeout, reportCallback, reportContext); 2312} 2313 2314IOReturn 2315IOHIDObsoleteDeviceClass::getReport(IOHIDReportType reportType, 2316 uint32_t reportID, 2317 uint8_t * report, 2318 CFIndex * pReportLength, 2319 uint32_t timeout, 2320 IOHIDReportCallback callback, 2321 void * refcon, 2322 IOOptionBits options) 2323{ 2324 return IOHIDDeviceClass::getReport(reportType, reportID, report, pReportLength, timeout, callback, refcon, options); 2325} 2326 2327IOReturn IOHIDObsoleteDeviceClass::getReport(IOHIDReportType type, uint32_t id, void * report, uint32_t * pLength, uint32_t timeout, IOHIDReportCallbackFunction callback, void * target, void * refcon) 2328{ 2329 IOHIDReportCallback reportCallback = NULL; 2330 IOHIDObsoleteCallbackArgs * reportContext = NULL; 2331 2332 if ( callback ) { 2333 reportCallback = IOHIDObsoleteDeviceClass::_reportCallback; 2334 reportContext = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs)); 2335 2336 if ( !reportContext ) 2337 return kIOReturnNoMemory; 2338 2339 bzero(reportContext, sizeof(IOHIDObsoleteCallbackArgs)); 2340 2341 reportContext->self = this; 2342 reportContext->callback = (void *)callback; 2343 reportContext->target = target; 2344 reportContext->refcon = refcon; 2345 reportContext->pLength = pLength; 2346 } 2347 2348 CFIndex pReportLength = pLength ? *pLength : 0; 2349 2350 IOReturn ret = IOHIDDeviceClass::getReport(type, id, (uint8_t *)report, &pReportLength, timeout, reportCallback, reportContext); 2351 2352 if ( pLength ) 2353 *pLength = pReportLength; 2354 2355 return ret; 2356} 2357 2358IOReturn IOHIDObsoleteDeviceClass::setInterruptReportHandlerCallback(void * report, uint32_t length, IOHIDReportCallbackFunction callback, void * target, void * refcon) 2359{ 2360 IOHIDObsoleteCallbackArgs * reportContext = (IOHIDObsoleteCallbackArgs *)fInputReportContext; 2361 2362 if ( !reportContext ) { 2363 reportContext = (IOHIDObsoleteCallbackArgs *)malloc(sizeof(IOHIDObsoleteCallbackArgs)); 2364 2365 if ( !reportContext ) 2366 return kIOReturnNoMemory; 2367 2368 fInputReportContext = reportContext; 2369 } 2370 2371 bzero(reportContext, sizeof(IOHIDObsoleteCallbackArgs)); 2372 2373 reportContext->self = this; 2374 reportContext->callback = (void *)callback; 2375 reportContext->target = target; 2376 reportContext->refcon = refcon; 2377 2378 return IOHIDDeviceClass::setInterruptReportCallback((uint8_t*)report, length, IOHIDObsoleteDeviceClass::_reportCallback, reportContext); 2379} 2380 2381void IOHIDObsoleteDeviceClass::_elementValueCallback(void * context, IOReturn result, void * sender, IOHIDValueRef value) 2382{ 2383 IOHIDObsoleteCallbackArgs * valueArgs = (IOHIDObsoleteCallbackArgs *)context; 2384 2385 (*(IOHIDElementCallbackFunction)valueArgs->callback)( 2386 valueArgs->target, 2387 result, 2388 valueArgs->refcon, 2389 sender, 2390 IOHIDElementGetCookie(IOHIDValueGetElement(value))); 2391 2392 free(context); 2393} 2394 2395void IOHIDObsoleteDeviceClass::_reportCallback( 2396 void * context, 2397 IOReturn result, 2398 void * sender, 2399 IOHIDReportType type __unused, 2400 uint32_t reportID __unused, 2401 uint8_t * report __unused, 2402 CFIndex reportLength) 2403{ 2404 IOHIDObsoleteCallbackArgs * args = (IOHIDObsoleteCallbackArgs*)context; 2405 2406 if ( args->pLength ) 2407 *(args->pLength) = reportLength; 2408 2409 (*(IOHIDReportCallbackFunction)args->callback)( 2410 args->target, 2411 result, 2412 args->refcon, 2413 sender, 2414 reportLength); 2415 2416 if ( args->self->fInputReportContext != context ) 2417 free(context); 2418} 2419 2420IOHIDQueueInterface ** IOHIDObsoleteDeviceClass::allocQueue() 2421{ 2422 IOHIDQueueInterface ** iohidqueue; 2423 HRESULT res; 2424 2425 res = this->queryInterface(CFUUIDGetUUIDBytes(kIOHIDQueueInterfaceID), (void **) &iohidqueue); 2426 2427 return iohidqueue; 2428} 2429 2430IOHIDOutputTransactionInterface ** IOHIDObsoleteDeviceClass::allocOutputTransaction() 2431{ 2432 IOHIDOutputTransactionInterface ** iohidoutputtransaction; 2433 HRESULT res; 2434 2435 res = this->queryInterface(CFUUIDGetUUIDBytes(kIOHIDOutputTransactionInterfaceID), (void **) &iohidoutputtransaction); 2436 2437 return iohidoutputtransaction; 2438} 2439