1/* 2 * Copyright (c) 1999-2008 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23#include <pthread.h> 24#include <CoreFoundation/CFRuntime.h> 25#include "IOHIDManager.h" 26#include <IOKit/IOKitLib.h> 27#include "IOHIDLibPrivate.h" 28#include "IOHIDDevice.h" 29#include "IOHIDLib.h" 30#include "IOHIDManagerPersistentProperties.h" 31 32static IOHIDManagerRef __IOHIDManagerCreate( 33 CFAllocatorRef allocator, 34 CFAllocatorContext * context __unused); 35static void __IOHIDManagerRelease( CFTypeRef object ); 36static void __IOHIDManagerSetDeviceMatching( 37 IOHIDManagerRef manager, 38 CFDictionaryRef matching); 39static void __IOHIDManagerDeviceAdded( 40 void * context, 41 io_iterator_t iterator); 42static void __IOHIDManagerDeviceRemoved( 43 void * context, 44 IOReturn result, 45 void * sender); 46static void __IOHIDManagerDeviceApplier( 47 const void * value, 48 void * context); 49static void __IOHIDManagerInitialEnumCallback( 50 void * info); 51static void __IOHIDManagerMergeDictionaries( 52 CFDictionaryRef srcDict, 53 CFMutableDictionaryRef dstDict); 54 55enum { 56 kDeviceApplierOpen = 1 << 0, 57 kDeviceApplierClose = 1 << 1, 58 kDeviceApplierInitEnumCallback = 1 << 2, 59 kDeviceApplierSetInputMatching = 1 << 3, 60 kDeviceApplierSetInputCallback = 1 << 4, 61 kDeviceApplierSetInputReportCallback = 1 << 5, 62 kDeviceApplierScheduleRunLoop = 1 << 6, 63 kDeviceApplierUnscheduleRunLoop = 1 << 7 64}; 65 66typedef struct __DeviceApplierArgs { 67 IOHIDManagerRef manager; 68 IOOptionBits options; 69 IOReturn retVal; 70} DeviceApplierArgs; 71 72typedef struct __IOHIDManager 73{ 74 CFRuntimeBase cfBase; // base CFType information 75 76 CFMutableSetRef devices; 77 CFMutableSetRef iterators; 78 CFMutableDictionaryRef properties; 79 CFMutableDictionaryRef deviceInputBuffers; 80 81 IONotificationPortRef notifyPort; 82 CFRunLoopRef runLoop; 83 CFStringRef runLoopMode; 84 85 CFRunLoopSourceRef initEnumRunLoopSource; 86 CFMutableDictionaryRef initRetVals; 87 88 Boolean isOpen; 89 IOOptionBits openOptions; 90 IOOptionBits createOptions; 91 92 void * inputContext; 93 IOHIDValueCallback inputCallback; 94 95 void * reportContext; 96 IOHIDReportCallback reportCallback; 97 98 void * matchContext; 99 IOHIDDeviceCallback matchCallback; 100 101 void * removalContext; 102 IOHIDDeviceCallback removalCallback; 103 104 CFArrayRef inputMatchingMultiple; 105 Boolean isDirty; 106 107} __IOHIDManager, *__IOHIDManagerRef; 108 109static const CFRuntimeClass __IOHIDManagerClass = { 110 0, // version 111 "IOHIDManager", // className 112 NULL, // init 113 NULL, // copy 114 __IOHIDManagerRelease, // finalize 115 NULL, // equal 116 NULL, // hash 117 NULL, // copyFormattingDesc 118 NULL, 119 NULL, 120 NULL 121}; 122 123static pthread_once_t __sessionTypeInit = PTHREAD_ONCE_INIT; 124static CFTypeID __kIOHIDManagerTypeID = _kCFRuntimeNotATypeID; 125 126//------------------------------------------------------------------------------ 127// __IOHIDManagerRegister 128//------------------------------------------------------------------------------ 129void __IOHIDManagerRegister(void) 130{ 131 __kIOHIDManagerTypeID = _CFRuntimeRegisterClass(&__IOHIDManagerClass); 132} 133 134//------------------------------------------------------------------------------ 135// __IOHIDManagerCreate 136//------------------------------------------------------------------------------ 137IOHIDManagerRef __IOHIDManagerCreate( 138 CFAllocatorRef allocator, 139 CFAllocatorContext * context __unused) 140{ 141 IOHIDManagerRef manager = NULL; 142 void * offset = NULL; 143 uint32_t size; 144 145 /* allocate service */ 146 size = sizeof(__IOHIDManager) - sizeof(CFRuntimeBase); 147 manager = (IOHIDManagerRef)_CFRuntimeCreateInstance( 148 allocator, 149 IOHIDManagerGetTypeID(), 150 size, 151 NULL); 152 153 if (!manager) 154 return NULL; 155 156 offset = manager; 157 bzero(offset + sizeof(CFRuntimeBase), size); 158 159 return manager; 160} 161 162//------------------------------------------------------------------------------ 163// __IOHIDManagerRelease 164//------------------------------------------------------------------------------ 165void __IOHIDManagerRelease( CFTypeRef object ) 166{ 167 IOHIDManagerRef manager = (IOHIDManagerRef)object; 168 169 if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) && 170 !(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) { 171 __IOHIDManagerSaveProperties(manager, NULL); 172 } 173 174 if ( manager->isOpen ) { 175 // This will unschedule the manager if it was opened 176 IOHIDManagerClose(manager, manager->openOptions); 177 } 178 179 if ( manager->runLoop ) { 180 // This will unschedule the manager if it wasn't 181 IOHIDManagerUnscheduleFromRunLoop(manager, manager->runLoop, manager->runLoopMode); 182 } 183 184 // Destroy the notification 185 if (manager->notifyPort) { 186 CFRunLoopSourceInvalidate(IONotificationPortGetRunLoopSource(manager->notifyPort)); 187 if (manager->runLoop) 188 CFRunLoopRemoveSource(manager->runLoop, 189 IONotificationPortGetRunLoopSource(manager->notifyPort), 190 manager->runLoopMode); 191 IONotificationPortDestroy(manager->notifyPort); 192 manager->notifyPort = NULL; 193 } 194 195 if ( manager->devices ) { 196 CFRelease(manager->devices); 197 manager->devices = NULL; 198 } 199 200 if ( manager->deviceInputBuffers ) { 201 CFRelease(manager->deviceInputBuffers); 202 manager->deviceInputBuffers = NULL; 203 } 204 205 if ( manager->iterators ) { 206 CFRelease(manager->iterators); 207 manager->iterators = NULL; 208 } 209 210 if ( manager->properties ) { 211 CFRelease(manager->properties); 212 manager->properties = NULL; 213 } 214 215 if ( manager->initRetVals ) { 216 CFRelease(manager->initRetVals); 217 manager->initRetVals = NULL; 218 } 219 220 if ( manager->inputMatchingMultiple ) { 221 CFRelease(manager->inputMatchingMultiple); 222 manager->inputMatchingMultiple = NULL; 223 } 224} 225 226//------------------------------------------------------------------------------ 227// __IOHIDManagerSetDeviceMatching 228//------------------------------------------------------------------------------ 229void __IOHIDManagerSetDeviceMatching( 230 IOHIDManagerRef manager, 231 CFDictionaryRef matching) 232{ 233 CFMutableDictionaryRef matchingDict = NULL; 234 io_iterator_t iterator; 235 IOReturn kr; 236 237 if (!manager->notifyPort) { 238 manager->notifyPort = IONotificationPortCreate(kIOMasterPortDefault); 239 240 if (manager->runLoop) 241 CFRunLoopAddSource( 242 manager->runLoop, 243 IONotificationPortGetRunLoopSource(manager->notifyPort), 244 manager->runLoopMode); 245 } 246 247 matchingDict = IOServiceMatching(kIOHIDDeviceKey); 248 249 if ( !matchingDict ) 250 return; 251 252 __IOHIDManagerMergeDictionaries(matching, matchingDict); 253 254 // Now set up a notification to be called when a device is first 255 // matched by I/O Kit. Note that this will not catch any devices that were 256 // already plugged in so we take care of those later. 257 kr = IOServiceAddMatchingNotification(manager->notifyPort, 258 kIOFirstMatchNotification, 259 matchingDict, 260 __IOHIDManagerDeviceAdded, 261 manager, 262 &iterator 263 ); 264 265 if ( kr != kIOReturnSuccess ) 266 return; 267 268 // Add iterator to set for later destruction 269 if ( !manager->iterators ) { 270 CFSetCallBacks callbacks; 271 272 bzero(&callbacks, sizeof(CFSetCallBacks)); 273 274 callbacks.retain = _IOObjectCFRetain; 275 callbacks.release = _IOObjectCFRelease; 276 277 manager->iterators = CFSetCreateMutable( 278 CFGetAllocator(manager), 279 0, 280 &callbacks); 281 if ( !manager->iterators ) 282 return; 283 } 284 285 intptr_t temp = iterator; 286 CFSetAddValue(manager->iterators, (void *)temp); 287 IOObjectRelease(iterator); 288 289 __IOHIDManagerDeviceAdded(manager, iterator); 290} 291 292//------------------------------------------------------------------------------ 293// __IOHIDManagerDeviceAdded 294//------------------------------------------------------------------------------ 295void __IOHIDManagerDeviceAdded( void * refcon, 296 io_iterator_t iterator) 297{ 298 IOHIDManagerRef manager = (IOHIDManagerRef)refcon; 299 IOHIDDeviceRef device; 300 IOReturn retVal; 301 io_service_t service; 302 Boolean initial = FALSE; 303 304 while (( service = IOIteratorNext(iterator) )) { 305 306 device = IOHIDDeviceCreate(CFGetAllocator(manager), service); 307 308 if ( device ) { 309 if ( !manager->devices ) { 310 manager->devices = CFSetCreateMutable( 311 CFGetAllocator(manager), 312 0, 313 &kCFTypeSetCallBacks); 314 initial = TRUE; 315 316 if ( manager->isOpen ) 317 manager->initRetVals = CFDictionaryCreateMutable( 318 CFGetAllocator(manager), 319 0, 320 &kCFTypeDictionaryKeyCallBacks, 321 NULL); 322 } 323 324 if ( manager->devices ) { 325 CFSetAddValue(manager->devices, device); 326 } 327 328 CFRelease(device); 329 330 DeviceApplierArgs args; 331 332 args.manager = manager; 333 args.options = 0; 334 335 IOHIDDeviceRegisterRemovalCallback( 336 device, 337 __IOHIDManagerDeviceRemoved, 338 manager); 339 340 retVal = kIOReturnSuccess; 341 342 if ( manager->isOpen ) 343 args.options |= kDeviceApplierOpen; 344 345 if ( manager->inputMatchingMultiple ) 346 args.options |= kDeviceApplierSetInputMatching; 347 348 if ( manager->inputCallback ) 349 args.options |= kDeviceApplierSetInputCallback; 350 351 if ( manager->reportCallback ) 352 args.options |= kDeviceApplierSetInputReportCallback; 353 354 if ( manager->runLoop ) { 355 args.options |= kDeviceApplierScheduleRunLoop; 356 357 // If this this is called using the iterator returned in 358 // IOServiceAddMatchingNotification, pend performing the 359 // callback on the runLoop 360 if ( !initial && manager->matchCallback ) 361 args.options |= kDeviceApplierInitEnumCallback; 362 } 363 364 __IOHIDManagerDeviceApplier((const void *)device, &args); 365 366 if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) && 367 !(manager->createOptions & kIOHIDManagerOptionDoNotLoadProperties)) { 368 __IOHIDDeviceLoadProperties(device); 369 } 370 if (manager->properties) { 371 CFDictionaryApplyFunction(manager->properties, 372 __IOHIDApplyPropertiesToDeviceFromDictionary, 373 device); 374 } 375 } 376 377 IOObjectRelease(service); 378 } 379 380 // Dispatch initial enumeration callback on runLoop 381 if ( initial ) { 382 383 CFRunLoopSourceContext context; 384 385 bzero(&context, sizeof(CFRunLoopSourceContext)); 386 387 context.info = manager; 388 context.perform = __IOHIDManagerInitialEnumCallback; 389 390 manager->initEnumRunLoopSource = CFRunLoopSourceCreate( 391 CFGetAllocator(manager), 392 0, 393 &context); 394 395 if ( manager->runLoop && manager->initEnumRunLoopSource ) { 396 CFRunLoopAddSource( 397 manager->runLoop, 398 manager->initEnumRunLoopSource, 399 manager->runLoopMode); 400 401 CFRunLoopSourceSignal(manager->initEnumRunLoopSource); 402 } 403 } 404} 405 406//------------------------------------------------------------------------------ 407// __IOHIDManagerDeviceRemoved 408//------------------------------------------------------------------------------ 409void __IOHIDManagerDeviceRemoved( void * context, 410 IOReturn result __unused, 411 void * sender) 412{ 413 IOHIDManagerRef manager = (IOHIDManagerRef)context; 414 415 if ( manager->deviceInputBuffers ) 416 CFDictionaryRemoveValue(manager->deviceInputBuffers, sender); 417 418 if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) && 419 !(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) { 420 if (CFSetContainsValue(manager->devices, sender)) 421 __IOHIDDeviceSaveProperties((IOHIDDeviceRef)sender, NULL); 422 } 423 424 CFSetRemoveValue(manager->devices, sender); 425 426 if ( manager->removalCallback ) 427 (*manager->removalCallback)(manager->removalContext, 428 kIOReturnSuccess, 429 manager, 430 sender); 431} 432 433//------------------------------------------------------------------------------ 434// __IOHIDManagerInitialEnumCallback 435//------------------------------------------------------------------------------ 436void __IOHIDManagerInitialEnumCallback(void * info) 437{ 438 IOHIDManagerRef manager = (IOHIDManagerRef)info; 439 440 if ( manager->matchCallback && manager->devices ) { 441 DeviceApplierArgs args; 442 443 args.manager = manager; 444 args.options = kDeviceApplierInitEnumCallback; 445 446 CFSetApplyFunction( manager->devices, 447 __IOHIDManagerDeviceApplier, 448 &args); 449 } 450 451 // After we have dispatched all of the enum callbacks, kill the source 452 if (manager->runLoop) 453 CFRunLoopRemoveSource(manager->runLoop, 454 manager->initEnumRunLoopSource, 455 manager->runLoopMode); 456 457 CFRelease(manager->initEnumRunLoopSource); 458 manager->initEnumRunLoopSource = NULL; 459 460 if ( manager->initRetVals ) { 461 CFRelease(manager->initRetVals); 462 manager->initRetVals = NULL; 463 } 464} 465 466//------------------------------------------------------------------------------ 467// __IOHIDManagerDeviceApplier 468//------------------------------------------------------------------------------ 469void __IOHIDManagerDeviceApplier( 470 const void * value, 471 void * context) 472{ 473 DeviceApplierArgs * args = (DeviceApplierArgs*)context; 474 IOHIDDeviceRef device = (IOHIDDeviceRef)value; 475 intptr_t retVal = kIOReturnSuccess; 476 477 if ( args->options & kDeviceApplierOpen ) { 478 retVal = IOHIDDeviceOpen( device, 479 args->manager->openOptions); 480 if ( args->manager->initRetVals ) 481 CFDictionarySetValue(args->manager->initRetVals, device, (void*)retVal); 482 } 483 484 if ( args->options & kDeviceApplierClose ) 485 retVal = IOHIDDeviceClose( device, 486 args->manager->openOptions); 487 488 if ( args->options & kDeviceApplierInitEnumCallback ) { 489 if ( args->manager->initRetVals ) 490 retVal = (intptr_t)CFDictionaryGetValue( 491 args->manager->initRetVals, 492 device); 493 494 (*args->manager->matchCallback)( args->manager->matchContext, 495 retVal, 496 args->manager, 497 device); 498 } 499 500 if ( args->options & kDeviceApplierSetInputMatching ) 501 IOHIDDeviceSetInputValueMatchingMultiple( 502 device, 503 args->manager->inputMatchingMultiple); 504 505 if ( args->options & kDeviceApplierSetInputCallback ) 506 IOHIDDeviceRegisterInputValueCallback( 507 device, 508 args->manager->inputCallback, 509 args->manager->inputContext); 510 511 if ( args->options & kDeviceApplierSetInputReportCallback ) { 512 CFMutableDataRef dataRef = NULL; 513 if ( !args->manager->deviceInputBuffers ) { 514 args->manager->deviceInputBuffers = CFDictionaryCreateMutable(CFGetAllocator(args->manager), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 515 } 516 517 dataRef = (CFMutableDataRef)CFDictionaryGetValue(args->manager->deviceInputBuffers, device); 518 if ( !dataRef ) { 519 CFNumberRef number = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDMaxInputReportSizeKey)); 520 CFIndex length = 64; 521 522 if ( number ) { 523 CFNumberGetValue(number, kCFNumberCFIndexType, &length); 524 } 525 526 dataRef = CFDataCreateMutable(CFGetAllocator(args->manager), length); 527 if ( dataRef ) { 528 CFDataSetLength(dataRef, length); 529 CFDictionarySetValue(args->manager->deviceInputBuffers, device, dataRef); 530 CFRelease(dataRef); 531 } 532 } 533 534 IOHIDDeviceRegisterInputReportCallback( 535 device, 536 (uint8_t *)CFDataGetMutableBytePtr(dataRef), 537 CFDataGetLength(dataRef), 538 args->manager->reportCallback, 539 args->manager->reportContext); 540 } 541 542 if ( args->options & kDeviceApplierScheduleRunLoop ) 543 IOHIDDeviceScheduleWithRunLoop( device, 544 args->manager->runLoop, 545 args->manager->runLoopMode); 546 547 if ( args->options & kDeviceApplierUnscheduleRunLoop ) 548 IOHIDDeviceUnscheduleFromRunLoop( device, 549 args->manager->runLoop, 550 args->manager->runLoopMode); 551 552 if ( args->retVal == kIOReturnSuccess && retVal != kIOReturnSuccess ) 553 args->retVal = retVal; 554} 555 556//------------------------------------------------------------------------------ 557// IOHIDManagerGetTypeID 558//------------------------------------------------------------------------------ 559CFTypeID IOHIDManagerGetTypeID(void) 560{ 561 if ( _kCFRuntimeNotATypeID == __kIOHIDManagerTypeID ) 562 pthread_once(&__sessionTypeInit, __IOHIDManagerRegister); 563 564 return __kIOHIDManagerTypeID; 565} 566 567//------------------------------------------------------------------------------ 568// IOHIDManagerCreate 569//------------------------------------------------------------------------------ 570IOHIDManagerRef IOHIDManagerCreate( 571 CFAllocatorRef allocator, 572 IOOptionBits options) 573{ 574 IOHIDManagerRef manager; 575 576 manager = __IOHIDManagerCreate(allocator, NULL); 577 578 if (!manager) 579 return NULL; 580 581 manager->createOptions = options; 582 583 if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) && 584 !(manager->createOptions & kIOHIDManagerOptionDoNotLoadProperties)) 585 { 586 __IOHIDManagerLoadProperties(manager); 587 } 588 589 return manager; 590} 591 592//------------------------------------------------------------------------------ 593// IOHIDManagerOpen 594//------------------------------------------------------------------------------ 595IOReturn IOHIDManagerOpen( 596 IOHIDManagerRef manager, 597 IOOptionBits options) 598{ 599 IOReturn retVal = kIOReturnSuccess; 600 601 if ( !manager->isOpen ) { 602 manager->isOpen = TRUE; 603 manager->openOptions = options; 604 605 if ( manager->devices ) { 606 DeviceApplierArgs args; 607 608 args.manager = manager; 609 args.options = kDeviceApplierOpen; 610 args.retVal = kIOReturnSuccess; 611 612 if ( manager->inputMatchingMultiple ) 613 args.options |= kDeviceApplierSetInputMatching; 614 615 if ( manager->inputCallback ) 616 args.options |= kDeviceApplierSetInputCallback; 617 618 if ( manager->reportCallback ) 619 args.options |= kDeviceApplierSetInputReportCallback; 620 621 CFSetApplyFunction( manager->devices, 622 __IOHIDManagerDeviceApplier, 623 &args); 624 625 retVal = args.retVal; 626 } 627 } 628 629 return retVal; 630} 631 632//------------------------------------------------------------------------------ 633// IOHIDManagerClose 634//------------------------------------------------------------------------------ 635IOReturn IOHIDManagerClose( 636 IOHIDManagerRef manager, 637 IOOptionBits options) 638{ 639 IOReturn retVal = kIOReturnSuccess; 640 641 if (manager->runLoop) { 642 IOHIDManagerUnscheduleFromRunLoop(manager, manager->runLoop, manager->runLoopMode); 643 } 644 645 if ( manager->isOpen ) { 646 manager->isOpen = FALSE; 647 manager->openOptions = options; 648 649 if ( manager->devices ) { 650 DeviceApplierArgs args; 651 652 args.manager = manager; 653 args.options = kDeviceApplierClose; 654 args.retVal = kIOReturnSuccess; 655 656 CFSetApplyFunction( manager->devices, 657 __IOHIDManagerDeviceApplier, 658 &args); 659 660 retVal = args.retVal; 661 } 662 } 663 664 if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) && 665 !(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) { 666 __IOHIDManagerSaveProperties(manager, NULL); 667 } 668 669 return retVal; 670} 671 672//------------------------------------------------------------------------------ 673// IOHIDManagerGetProperty 674//------------------------------------------------------------------------------ 675CFTypeRef IOHIDManagerGetProperty( 676 IOHIDManagerRef manager, 677 CFStringRef key) 678{ 679 if ( !manager->properties ) 680 return NULL; 681 682 return CFDictionaryGetValue(manager->properties, key); 683} 684 685//------------------------------------------------------------------------------ 686// IOHIDManagerSetProperty 687//------------------------------------------------------------------------------ 688Boolean IOHIDManagerSetProperty( 689 IOHIDManagerRef manager, 690 CFStringRef key, 691 CFTypeRef value) 692{ 693 __IOHIDApplyPropertyToSetContext context = { 694 key, value 695 }; 696 697 if (!manager->properties) { 698 manager->properties = CFDictionaryCreateMutable(CFGetAllocator(manager), 699 0, 700 &kCFTypeDictionaryKeyCallBacks, 701 &kCFTypeDictionaryValueCallBacks); 702 if (!manager->properties) 703 return FALSE; 704 } 705 706 manager->isDirty = TRUE; 707 CFDictionarySetValue(manager->properties, key, value); 708 if (manager->devices) 709 CFSetApplyFunction(manager->devices, __IOHIDApplyPropertyToDeviceSet, &context); 710 711 return TRUE; 712} 713 714//------------------------------------------------------------------------------ 715// IOHIDManagerSetDeviceMatching 716//------------------------------------------------------------------------------ 717void IOHIDManagerSetDeviceMatching( 718 IOHIDManagerRef manager, 719 CFDictionaryRef matching) 720{ 721 CFArrayRef multiple = NULL; 722 723 if ( matching ) 724 multiple = CFArrayCreate(CFGetAllocator(manager), 725 (const void **)&matching, 726 1, 727 &kCFTypeArrayCallBacks); 728 729 IOHIDManagerSetDeviceMatchingMultiple(manager, multiple); 730 731 if ( multiple ) 732 CFRelease(multiple); 733} 734 735//------------------------------------------------------------------------------ 736// IOHIDManagerSetDeviceMatchingMultiple 737//------------------------------------------------------------------------------ 738void IOHIDManagerSetDeviceMatchingMultiple( 739 IOHIDManagerRef manager, 740 CFArrayRef multiple) 741{ 742 CFIndex i, count; 743 CFTypeRef value; 744 745 if ( manager->devices ) { 746 if ( (manager->createOptions & kIOHIDManagerOptionUsePersistentProperties) && 747 !(manager->createOptions & kIOHIDManagerOptionDoNotSaveProperties)) { 748 __IOHIDManagerSaveProperties(manager, NULL); 749 } 750 CFSetRemoveAllValues(manager->devices); 751 } 752 753 if ( manager->iterators ) 754 CFSetRemoveAllValues(manager->iterators); 755 756 if ( manager->deviceInputBuffers ) 757 CFDictionaryRemoveAllValues(manager->deviceInputBuffers); 758 759 if ( multiple ) { 760 count = CFArrayGetCount(multiple); 761 for ( i=0; i<count; i++ ) { 762 value = CFArrayGetValueAtIndex(multiple, i); 763 if (CFDictionaryGetTypeID() == CFGetTypeID(value)) 764 __IOHIDManagerSetDeviceMatching(manager, (CFDictionaryRef)value); 765 } 766 } 767 else 768 __IOHIDManagerSetDeviceMatching(manager, NULL); 769 770} 771 772//------------------------------------------------------------------------------ 773// IOHIDManagerCopyDevices 774//------------------------------------------------------------------------------ 775CFSetRef IOHIDManagerCopyDevices( 776 IOHIDManagerRef manager) 777{ 778 return manager->devices ? 779 CFSetCreateCopy(CFGetAllocator(manager), manager->devices) : NULL; 780} 781 782//------------------------------------------------------------------------------ 783// IOHIDManagerRegisterDeviceMatchingCallback 784//------------------------------------------------------------------------------ 785void IOHIDManagerRegisterDeviceMatchingCallback( 786 IOHIDManagerRef manager, 787 IOHIDDeviceCallback callback, 788 void * context) 789{ 790 manager->matchCallback = callback; 791 manager->matchContext = context; 792} 793 794//------------------------------------------------------------------------------ 795// IOHIDManagerRegisterDeviceRemovalCallback 796//------------------------------------------------------------------------------ 797void IOHIDManagerRegisterDeviceRemovalCallback( 798 IOHIDManagerRef manager, 799 IOHIDDeviceCallback callback, 800 void * context) 801{ 802 manager->removalCallback = callback; 803 manager->removalContext = context; 804 805} 806 807//------------------------------------------------------------------------------ 808// IOHIDManagerRegisterInputReportCallback 809//------------------------------------------------------------------------------ 810void IOHIDManagerRegisterInputReportCallback( 811 IOHIDManagerRef manager, 812 IOHIDReportCallback callback, 813 void * context) 814{ 815 manager->reportCallback = callback; 816 manager->reportContext = context; 817 818 if ( manager->isOpen && manager->devices ) { 819 DeviceApplierArgs args; 820 821 args.manager = manager; 822 args.options = kDeviceApplierSetInputReportCallback; 823 824 CFSetApplyFunction( manager->devices, 825 __IOHIDManagerDeviceApplier, 826 &args); 827 } 828} 829 830//------------------------------------------------------------------------------ 831// IOHIDManagerRegisterInputValueCallback 832//------------------------------------------------------------------------------ 833void IOHIDManagerRegisterInputValueCallback( 834 IOHIDManagerRef manager, 835 IOHIDValueCallback callback, 836 void * context) 837{ 838 manager->inputCallback = callback; 839 manager->inputContext = context; 840 841 if ( manager->isOpen && manager->devices ) { 842 DeviceApplierArgs args; 843 844 args.manager = manager; 845 args.options = kDeviceApplierSetInputCallback; 846 847 CFSetApplyFunction( manager->devices, 848 __IOHIDManagerDeviceApplier, 849 &args); 850 } 851} 852 853//------------------------------------------------------------------------------ 854// IOHIDManagerSetInputValueMatching 855//------------------------------------------------------------------------------ 856void IOHIDManagerSetInputValueMatching( 857 IOHIDManagerRef manager, 858 CFDictionaryRef matching) 859{ 860 if ( matching ) { 861 CFArrayRef multiple = CFArrayCreate(CFGetAllocator(manager), (const void **)&matching, 1, &kCFTypeArrayCallBacks); 862 863 IOHIDManagerSetInputValueMatchingMultiple(manager, multiple); 864 865 CFRelease(multiple); 866 } else { 867 IOHIDManagerSetInputValueMatchingMultiple(manager, NULL); 868 } 869} 870 871//------------------------------------------------------------------------------ 872// IOHIDManagerSetInputValueMatchingMultiple 873//------------------------------------------------------------------------------ 874void IOHIDManagerSetInputValueMatchingMultiple( 875 IOHIDManagerRef manager, 876 CFArrayRef multiple) 877{ 878 if ( manager->inputMatchingMultiple ) 879 CFRelease(manager->inputMatchingMultiple); 880 881 if ( multiple ) 882 CFRetain(multiple); 883 884 manager->inputMatchingMultiple = multiple; 885 886 if ( manager->isOpen && manager->devices ) { 887 DeviceApplierArgs args; 888 889 args.manager = manager; 890 args.options = kDeviceApplierSetInputMatching; 891 892 CFSetApplyFunction( manager->devices, 893 __IOHIDManagerDeviceApplier, 894 &args); 895 } 896} 897 898//------------------------------------------------------------------------------ 899// IOHIDManagerScheduleWithRunLoop 900//------------------------------------------------------------------------------ 901void IOHIDManagerScheduleWithRunLoop( 902 IOHIDManagerRef manager, 903 CFRunLoopRef runLoop, 904 CFStringRef runLoopMode) 905{ 906 manager->runLoop = runLoop; 907 manager->runLoopMode = runLoopMode; 908 909 if ( manager->runLoop ) { 910 // Schedule the notifyPort 911 if (manager->notifyPort) 912 CFRunLoopAddSource( 913 manager->runLoop, 914 IONotificationPortGetRunLoopSource(manager->notifyPort), 915 manager->runLoopMode); 916 917 // schedule the initial enumeration routine 918 if ( manager->initEnumRunLoopSource ) { 919 CFRunLoopAddSource( 920 manager->runLoop, 921 manager->initEnumRunLoopSource, 922 manager->runLoopMode); 923 924 CFRunLoopSourceSignal(manager->initEnumRunLoopSource); 925 } 926 927 // Schedule the devices 928 if ( manager->devices ) { 929 DeviceApplierArgs args; 930 931 args.manager = manager; 932 args.options = kDeviceApplierScheduleRunLoop; 933 934 CFSetApplyFunction( manager->devices, 935 __IOHIDManagerDeviceApplier, 936 &args); 937 } 938 } 939} 940 941//------------------------------------------------------------------------------ 942// IOHIDManagerUnscheduleFromRunLoop 943//------------------------------------------------------------------------------ 944void IOHIDManagerUnscheduleFromRunLoop( 945 IOHIDManagerRef manager, 946 CFRunLoopRef runLoop, 947 CFStringRef runLoopMode) 948{ 949 if (!manager->runLoop) 950 return; 951 952 if (!CFEqual(manager->runLoop, runLoop) || 953 !CFEqual(manager->runLoopMode, runLoopMode)) 954 return; 955 956 if ( manager->devices ) { 957 // Unschedule the devices 958 DeviceApplierArgs args; 959 960 args.manager = manager; 961 args.options = kDeviceApplierUnscheduleRunLoop; 962 963 CFSetApplyFunction( manager->devices, 964 __IOHIDManagerDeviceApplier, 965 &args); 966 967 // Unschedule the initial enumeration routine 968 if (manager->initEnumRunLoopSource) { 969 CFRunLoopSourceInvalidate(manager->initEnumRunLoopSource); 970 CFRunLoopRemoveSource(manager->runLoop, 971 manager->initEnumRunLoopSource, 972 manager->runLoopMode); 973 CFRelease(manager->initEnumRunLoopSource); 974 manager->initEnumRunLoopSource = NULL; 975 } 976 } 977 978 manager->runLoop = NULL; 979 manager->runLoopMode = NULL; 980} 981 982//------------------------------------------------------------------------------ 983// IOHIDManagerSaveToPropertyDomain 984//------------------------------------------------------------------------------ 985void IOHIDManagerSaveToPropertyDomain(IOHIDManagerRef manager, 986 CFStringRef applicationID, 987 CFStringRef userName, 988 CFStringRef hostName, 989 IOOptionBits options) 990{ 991 __IOHIDPropertyContext context = { 992 applicationID, userName, hostName, options 993 }; 994 995 if (manager && applicationID && userName && hostName) { 996 __IOHIDManagerSaveProperties(manager, &context); 997 } 998 else { 999 // LOG AN ERROR? 1000 } 1001} 1002 1003//------------------------------------------------------------------------------ 1004CFStringRef __IOHIDManagerGetRootKey() 1005{ 1006 return CFSTR(kIOHIDManagerKey); 1007} 1008 1009//------------------------------------------------------------------------------ 1010void __IOHIDManagerSaveProperties(IOHIDManagerRef manager, __IOHIDPropertyContext *context) 1011{ 1012 if (manager->isDirty && manager->properties) { 1013 __IOHIDPropertySaveToKeyWithSpecialKeys(manager->properties, 1014 __IOHIDManagerGetRootKey(), 1015 NULL, 1016 context); 1017 manager->isDirty = FALSE; 1018 } 1019 1020 if (manager->devices) 1021 CFSetApplyFunction(manager->devices, __IOHIDSaveDeviceSet, context); 1022} 1023 1024//------------------------------------------------------------------------------ 1025void __IOHIDManagerLoadProperties(IOHIDManagerRef manager) 1026{ 1027 // Convert to __IOHIDPropertyLoadFromKeyWithSpecialKeys if we identify special keys 1028 CFMutableDictionaryRef properties = __IOHIDPropertyLoadDictionaryFromKey(__IOHIDManagerGetRootKey()); 1029 1030 if (properties) { 1031 CFRELEASE_IF_NOT_NULL(manager->properties); 1032 manager->properties = properties; 1033 manager->isDirty = FALSE; 1034 } 1035 1036 // We do not load device properties here, since the devices are not present when this is called. 1037} 1038 1039//------------------------------------------------------------------------------ 1040void __IOHIDPropertySaveWithContext(CFStringRef key, CFPropertyListRef value, __IOHIDPropertyContext *context) 1041{ 1042 if (key && value) { 1043 if (context && context->applicationID && context->userName && context->hostName) { 1044 CFPreferencesSetValue(key, value, context->applicationID, context->userName, context->hostName); 1045 } 1046 else { 1047 CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication); 1048 } 1049 } 1050} 1051 1052//------------------------------------------------------------------------------ 1053void __IOHIDPropertySaveToKeyWithSpecialKeys(CFDictionaryRef dictionary, CFStringRef key, CFStringRef *specialKeys, __IOHIDPropertyContext *context) 1054{ 1055 CFMutableDictionaryRef temp = CFDictionaryCreateMutableCopy(NULL, 0, dictionary); 1056 1057 if (specialKeys) { 1058 while (*specialKeys) { 1059 CFTypeRef value = CFDictionaryGetValue(temp, *specialKeys); 1060 if (value) { 1061 CFStringRef subKey = CFStringCreateWithFormat(NULL, NULL, 1062 CFSTR("%@#%@"), 1063 key, 1064 *specialKeys); 1065 __IOHIDPropertySaveWithContext(subKey, value, context); 1066 CFDictionaryRemoveValue(temp, *specialKeys); 1067 CFRelease(subKey); 1068 } 1069 specialKeys++; 1070 } 1071 } 1072 1073 CFAbsoluteTime time = CFAbsoluteTimeGetCurrent(); 1074 CFNumberRef timeNum = CFNumberCreate(NULL, kCFNumberDoubleType, &time); 1075 CFDictionaryAddValue(temp, CFSTR("time of last save"), timeNum); 1076 CFRelease(timeNum); 1077 __IOHIDPropertySaveWithContext(key, temp, context); 1078 CFRelease(temp); 1079} 1080 1081//------------------------------------------------------------------------------ 1082CFMutableDictionaryRef __IOHIDPropertyLoadDictionaryFromKey(CFStringRef key) 1083{ 1084 CFMutableDictionaryRef result = NULL; 1085 CFDictionaryRef baseProperties = CFPreferencesCopyAppValue(key, kCFPreferencesCurrentApplication); 1086 if (baseProperties && (CFGetTypeID(baseProperties) == CFDictionaryGetTypeID())) { 1087 result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1088 1089 CFDictionaryRef properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost); 1090 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1091 __IOHIDManagerMergeDictionaries(properties, result); 1092 if (properties) 1093 CFRelease(properties); 1094 1095 properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); 1096 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1097 __IOHIDManagerMergeDictionaries(properties, result); 1098 if (properties) 1099 CFRelease(properties); 1100 1101 properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 1102 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1103 __IOHIDManagerMergeDictionaries(properties, result); 1104 if (properties) 1105 CFRelease(properties); 1106 1107 properties = CFPreferencesCopyValue(key, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); 1108 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1109 __IOHIDManagerMergeDictionaries(properties, result); 1110 if (properties) 1111 CFRelease(properties); 1112 1113 properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost); 1114 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1115 __IOHIDManagerMergeDictionaries(properties, result); 1116 if (properties) 1117 CFRelease(properties); 1118 1119 properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); 1120 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1121 __IOHIDManagerMergeDictionaries(properties, result); 1122 if (properties) 1123 CFRelease(properties); 1124 1125 properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 1126 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1127 __IOHIDManagerMergeDictionaries(properties, result); 1128 if (properties) 1129 CFRelease(properties); 1130 1131 properties = CFPreferencesCopyValue(key, kCFPreferencesCurrentApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); 1132 if (properties && (CFGetTypeID(properties) == CFDictionaryGetTypeID())) 1133 __IOHIDManagerMergeDictionaries(properties, result); 1134 if (properties) 1135 CFRelease(properties); 1136 1137 __IOHIDManagerMergeDictionaries(baseProperties, result); 1138 } 1139 if (baseProperties) 1140 CFRelease(baseProperties); 1141 return result; 1142} 1143 1144//------------------------------------------------------------------------------ 1145CFMutableDictionaryRef __IOHIDPropertyLoadFromKeyWithSpecialKeys(CFStringRef key, CFStringRef *specialKeys) 1146{ 1147 CFMutableDictionaryRef result = __IOHIDPropertyLoadDictionaryFromKey(key); 1148 1149 if (!result) 1150 result = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1151 1152 while (*specialKeys) { 1153 CFStringRef subKey = CFStringCreateWithFormat(NULL, NULL, 1154 CFSTR("%@#%@"), 1155 key, 1156 *specialKeys); 1157 CFPropertyListRef value = CFPreferencesCopyAppValue(subKey, kCFPreferencesCurrentApplication); 1158 if (value) { 1159 CFDictionarySetValue(result, *specialKeys, value); 1160 CFRelease(value); 1161 } 1162 1163 CFRelease(subKey); 1164 specialKeys++; 1165 } 1166 1167 return result; 1168} 1169 1170//=========================================================================== 1171// Static Helper Definitions 1172//=========================================================================== 1173//------------------------------------------------------------------------------ 1174// __IOHIDManagerMergeDictionaries 1175//------------------------------------------------------------------------------ 1176void __IOHIDManagerMergeDictionaries(CFDictionaryRef srcDict, 1177 CFMutableDictionaryRef dstDict) 1178{ 1179 uint32_t count; 1180 CFTypeRef * values; 1181 CFStringRef * keys; 1182 1183 if ( !dstDict || !srcDict || !(count = CFDictionaryGetCount(srcDict))) 1184 return; 1185 1186 values = (CFTypeRef *)malloc(sizeof(CFTypeRef) * count); 1187 keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count); 1188 1189 if ( values && keys ) { 1190 CFDictionaryGetKeysAndValues(srcDict, (const void **)keys, (const void **)values); 1191 1192 for ( uint32_t i=0; i<count; i++) 1193 CFDictionarySetValue(dstDict, keys[i], values[i]); 1194 } 1195 1196 if ( values ) 1197 free(values); 1198 1199 if ( keys ) 1200 free(keys); 1201} 1202 1203