1/* 2 * 3 * @APPLE_LICENSE_HEADER_START@ 4 * 5 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. 6 * 7 * This file contains Original Code and/or Modifications of Original Code 8 * as defined in and that are subject to the Apple Public Source License 9 * Version 2.0 (the 'License'). You may not use this file except in 10 * compliance with the License. Please obtain a copy of the License at 11 * http://www.opensource.apple.com/apsl/ and read it before using this 12 * file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 * Please see the License for the specific language governing rights and 20 * limitations under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include "IOHIDEventServiceClass.h" 26#include "IOHIDEventServiceUserClient.h" 27#include "IOHIDEventData.h" 28#include <IOKit/hid/IOHIDUsageTables.h> 29#include <IOKit/hid/IOHIDServiceKeys.h> 30#include <IOKit/hid/IOHIDKeys.h> 31 32#if TARGET_OS_EMBEDDED // { 33#include <IOKit/hid/AppleEmbeddedHIDKeys.h> 34#endif // } TARGET_OS_EMBEDDED 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 <mach/mach_time.h> 43__END_DECLS 44 45#define QUEUE_LOCK(service) pthread_mutex_lock(&service->_queueLock) 46#define QUEUE_UNLOCK(service) pthread_mutex_unlock(&service->_queueLock) 47#define QUEUE_WAIT(service) while (service->_queueBusy) { pthread_cond_wait(&service->_queueCondition, &service->_queueLock); } 48#define QUEUE_SIGNAL(service) pthread_cond_signal(&service->_queueCondition) 49 50//=========================================================================== 51// Static Helper Declarations 52//=========================================================================== 53static IOReturn MergeDictionaries(CFDictionaryRef srcDict, CFMutableDictionaryRef * pDstDict); 54 55 56//=========================================================================== 57// CFPlugIn Static Assignments 58//=========================================================================== 59IOCFPlugInInterface IOHIDEventServiceClass::sIOCFPlugInInterfaceV1 = 60{ 61 0, 62 &IOHIDIUnknown::genericQueryInterface, 63 &IOHIDIUnknown::genericAddRef, 64 &IOHIDIUnknown::genericRelease, 65 1, 0, // version/revision 66 &IOHIDEventServiceClass::_probe, 67 &IOHIDEventServiceClass::_start, 68 &IOHIDEventServiceClass::_stop 69}; 70 71IOHIDServiceInterface2 IOHIDEventServiceClass::sIOHIDServiceInterface2 = 72{ 73 0, 74 &IOHIDIUnknown::genericQueryInterface, 75 &IOHIDIUnknown::genericAddRef, 76 &IOHIDIUnknown::genericRelease, 77 &IOHIDEventServiceClass::_open, 78 &IOHIDEventServiceClass::_close, 79 &IOHIDEventServiceClass::_copyProperty, 80 &IOHIDEventServiceClass::_setProperty, 81 &IOHIDEventServiceClass::_setEventCallback, 82 &IOHIDEventServiceClass::_scheduleWithRunLoop, 83 &IOHIDEventServiceClass::_unscheduleFromRunLoop, 84 &IOHIDEventServiceClass::_copyEvent, 85 &IOHIDEventServiceClass::_setElementValue 86}; 87 88//=========================================================================== 89// CONSTRUCTOR / DESTRUCTOR methods 90//=========================================================================== 91//--------------------------------------------------------------------------- 92// IOHIDEventServiceClass 93//--------------------------------------------------------------------------- 94IOHIDEventServiceClass::IOHIDEventServiceClass() : IOHIDIUnknown(&sIOCFPlugInInterfaceV1) 95{ 96 _hidService.pseudoVTable = NULL; 97 _hidService.obj = this; 98 99 _service = MACH_PORT_NULL; 100 _connect = MACH_PORT_NULL; 101 _isOpen = FALSE; 102 103 _asyncPort = MACH_PORT_NULL; 104 _asyncCFMachPort = NULL; 105 _asyncEventSource = NULL; 106 107 _serviceProperties = NULL; 108 _servicePreferences = NULL; 109 _eventCallback = NULL; 110 _eventTarget = NULL; 111 _eventRefcon = NULL; 112 113 _queueMappedMemory = NULL; 114 _queueMappedMemorySize = 0; 115 116 _queueBusy = FALSE; 117 118 pthread_mutex_init(&_queueLock, NULL); 119 pthread_cond_init(&_queueCondition, NULL); 120} 121 122//--------------------------------------------------------------------------- 123// ~IOHIDEventServiceClass 124//--------------------------------------------------------------------------- 125IOHIDEventServiceClass::~IOHIDEventServiceClass() 126{ 127 QUEUE_LOCK(this); 128 129 QUEUE_WAIT(this); 130 131 // finished with the shared memory 132 if (_queueMappedMemory) 133 { 134#if !__LP64__ 135 vm_address_t mappedMem = (vm_address_t)_queueMappedMemory; 136#else 137 mach_vm_address_t mappedMem = (mach_vm_address_t)_queueMappedMemory; 138#endif 139 IOConnectUnmapMemory ( _connect, 140 0, 141 mach_task_self(), 142 mappedMem); 143 _queueMappedMemory = NULL; 144 _queueMappedMemorySize = 0; 145 } 146 QUEUE_UNLOCK(this); 147 148 if (_connect) { 149 IOServiceClose(_connect); 150 _connect = MACH_PORT_NULL; 151 } 152 if (_service) { 153 IOObjectRelease(_service); 154 _service = MACH_PORT_NULL; 155 } 156 157 if (_serviceProperties) { 158 CFRelease(_serviceProperties); 159 _serviceProperties = NULL; 160 } 161 162 if (_servicePreferences) { 163 CFRelease(_servicePreferences); 164 _servicePreferences = NULL; 165 } 166 167 if (_asyncEventSource) { 168 CFRelease(_asyncEventSource); 169 _asyncEventSource = NULL; 170 } 171 172 if ( _asyncCFMachPort ) { 173 CFMachPortInvalidate(_asyncCFMachPort); 174 CFRelease(_asyncCFMachPort); 175 _asyncCFMachPort = NULL; 176 } 177 178 if ( _asyncPort ) { 179 mach_port_mod_refs(mach_task_self(), _asyncPort, MACH_PORT_RIGHT_RECEIVE, -1); 180 _asyncPort = MACH_PORT_NULL; 181 } 182 183 pthread_mutex_destroy(&_queueLock); 184 pthread_cond_destroy(&_queueCondition); 185} 186 187//=========================================================================== 188// IOCFPlugInInterface methods 189//=========================================================================== 190IOReturn IOHIDEventServiceClass::_probe(void *self, CFDictionaryRef propertyTable, io_service_t service, SInt32 *order) 191{ 192 return getThis(self)->probe(propertyTable, service, order); 193} 194 195IOReturn IOHIDEventServiceClass::_start(void *self, CFDictionaryRef propertyTable, io_service_t service) 196{ 197 return getThis(self)->start(propertyTable, service); 198} 199 200IOReturn IOHIDEventServiceClass::_stop(void *self) 201{ 202 return getThis(self)->stop(); 203} 204 205boolean_t IOHIDEventServiceClass::_open(void * self, IOOptionBits options) 206{ 207 return getThis(self)->open(options); 208} 209 210void IOHIDEventServiceClass::_close(void * self, IOOptionBits options) 211{ 212 getThis(self)->close(options); 213} 214 215CFTypeRef IOHIDEventServiceClass::_copyProperty(void * self, CFStringRef key) 216{ 217 return getThis(self)->copyProperty(key); 218} 219 220boolean_t IOHIDEventServiceClass::_setProperty(void * self, CFStringRef key, CFTypeRef property) 221{ 222 return getThis(self)->setProperty(key, property); 223} 224 225IOHIDEventRef IOHIDEventServiceClass::_copyEvent(void *self, IOHIDEventType type, IOHIDEventRef matching, IOOptionBits options) 226{ 227 return getThis(self)->copyEvent(type, matching, options); 228} 229 230IOReturn IOHIDEventServiceClass::_setElementValue(void *self, uint32_t usagePage, uint32_t usage, uint32_t value) 231{ 232 return getThis(self)->setElementValue(usagePage, usage, value); 233} 234 235void IOHIDEventServiceClass::_setEventCallback(void * self, IOHIDServiceEventCallback callback, void * target, void * refcon) 236{ 237 getThis(self)->setEventCallback(callback, target, refcon); 238} 239 240void IOHIDEventServiceClass::_scheduleWithRunLoop(void *self, CFRunLoopRef runLoop, CFStringRef runLoopMode) 241{ 242 return getThis(self)->scheduleWithRunLoop(runLoop, runLoopMode); 243} 244 245void IOHIDEventServiceClass::_unscheduleFromRunLoop(void *self, CFRunLoopRef runLoop, CFStringRef runLoopMode) 246{ 247 return getThis(self)->unscheduleFromRunLoop(runLoop, runLoopMode); 248} 249 250//------------------------------------------------------------------------------ 251// IOHIDEventServiceClass::_queueEventSourceCallback 252//------------------------------------------------------------------------------ 253void IOHIDEventServiceClass::_queueEventSourceCallback( 254 CFMachPortRef cfPort, 255 mach_msg_header_t * msg __unused, 256 CFIndex size __unused, 257 void * info) 258{ 259 IOHIDEventServiceClass *eventService = (IOHIDEventServiceClass *)info; 260 IOReturn ret = kIOReturnSuccess; 261 262 QUEUE_LOCK(eventService); 263 264 QUEUE_WAIT(eventService); 265 266 eventService->_queueBusy = TRUE; 267 268 do { 269 if ( !eventService->_queueMappedMemory ) 270 break; 271 272 // check entry size 273 IODataQueueEntry * nextEntry; 274 uint32_t dataSize; 275 276 // if queue empty, then stop 277 while ((nextEntry = IODataQueuePeek(eventService->_queueMappedMemory))) { 278 // RY: cfPort==NULL means we're draining 279 if ( cfPort ) { 280 IOHIDEventRef event = IOHIDEventCreateWithBytes(kCFAllocatorDefault, (const UInt8*)&(nextEntry->data), nextEntry->size); 281 282 if ( event ) { 283 QUEUE_UNLOCK(eventService); 284 eventService->dispatchHIDEvent(event); 285 QUEUE_LOCK(eventService); 286 CFRelease(event); 287 } 288 } 289 290 // dequeue the item 291 dataSize = 0; 292 IODataQueueDequeue(eventService->_queueMappedMemory, NULL, &dataSize); 293 } 294 } while ( 0 ); 295 296 eventService->_queueBusy = FALSE; 297 298 QUEUE_UNLOCK(eventService); 299 300 QUEUE_SIGNAL(eventService); 301} 302 303 304//------------------------------------------------------------------------------ 305// IOHIDEventServiceClass::dispatchHIDEvent 306//------------------------------------------------------------------------------ 307void IOHIDEventServiceClass::dispatchHIDEvent(IOHIDEventRef event, IOOptionBits options) 308{ 309 if ( !_eventCallback ) 310 return; 311 312 (*_eventCallback)(_eventTarget, _eventRefcon, (void *)&_hidService, event, options); 313} 314 315 316 317// Public Methods 318//--------------------------------------------------------------------------- 319// IOHIDEventServiceClass::alloc 320//--------------------------------------------------------------------------- 321IOCFPlugInInterface ** IOHIDEventServiceClass::alloc() 322{ 323 IOHIDEventServiceClass * self = new IOHIDEventServiceClass; 324 325 return self ? (IOCFPlugInInterface **) &self->iunknown.pseudoVTable : NULL; 326} 327 328//--------------------------------------------------------------------------- 329// IOHIDEventServiceClass::queryInterface 330//--------------------------------------------------------------------------- 331HRESULT IOHIDEventServiceClass::queryInterface(REFIID iid, void **ppv) 332{ 333 CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(NULL, iid); 334 HRESULT res = S_OK; 335 336 if (CFEqual(uuid, IUnknownUUID) || CFEqual(uuid, kIOCFPlugInInterfaceID)) 337 { 338 *ppv = &iunknown; 339 addRef(); 340 } 341 else if (CFEqual(uuid, kIOHIDServiceInterface2ID)) 342 { 343 _hidService.pseudoVTable = (IUnknownVTbl *) &sIOHIDServiceInterface2; 344 _hidService.obj = this; 345 *ppv = &_hidService; 346 addRef(); 347 } 348 else { 349 *ppv = 0; 350 } 351 352 if (!*ppv) 353 res = E_NOINTERFACE; 354 355 CFRelease(uuid); 356 return res; 357} 358 359//--------------------------------------------------------------------------- 360// IOHIDEventServiceClass::probe 361//--------------------------------------------------------------------------- 362IOReturn IOHIDEventServiceClass::probe(CFDictionaryRef propertyTable __unused, io_service_t service, SInt32 * order __unused) 363{ 364 if (!service || !IOObjectConformsTo(service, "IOHIDEventService")) 365 return kIOReturnBadArgument; 366 367 return kIOReturnSuccess; 368} 369 370#define GET_AND_SET_SERVICE_PROPERTY(reg,regKey,dict,propKey) \ 371{ \ 372 CFTypeRef typeRef = IORegistryEntryCreateCFProperty(reg,regKey, kCFAllocatorDefault, kNilOptions);\ 373 if (typeRef) \ 374 { \ 375 CFDictionarySetValue(dict,propKey,typeRef); \ 376 CFRelease(typeRef); \ 377 } \ 378} 379 380#define GET_AND_SET_PROPERTY(prop,regKey,dict,propKey) \ 381{ \ 382 CFTypeRef typeRef = CFDictionaryGetValue(prop,regKey); \ 383 if (typeRef) \ 384 CFDictionarySetValue(dict,propKey,typeRef); \ 385} 386 387 388//--------------------------------------------------------------------------- 389// IOHIDEventServiceClass::start 390//--------------------------------------------------------------------------- 391IOReturn IOHIDEventServiceClass::start(CFDictionaryRef propertyTable __unused, io_service_t service) 392{ 393 IOReturn ret = kIOReturnError; 394 HRESULT plugInResult = S_OK; 395 SInt32 score = 0; 396 CFMutableDictionaryRef serviceProps = NULL; 397 398 do { 399 _service = service; 400 IOObjectRetain(_service); 401 402 _serviceProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 403 404 if ( !_serviceProperties ) { 405 ret = kIOReturnNoMemory; 406 break; 407 } 408 409 IORegistryEntryCreateCFProperties(service, &serviceProps, kCFAllocatorDefault, 0); 410 411 if ( !serviceProps ) 412 break; 413 414 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDTransportKey), _serviceProperties, CFSTR(kIOHIDServiceTransportKey)); 415 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDVendorIDKey), _serviceProperties, CFSTR(kIOHIDServiceVendorIDKey)); 416 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDVendorIDSourceKey), _serviceProperties, CFSTR(kIOHIDServiceVendorIDSourceKey)); 417 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDProductIDKey), _serviceProperties, CFSTR(kIOHIDServiceProductIDKey)); 418 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDVersionNumberKey), _serviceProperties, CFSTR(kIOHIDServiceVersionNumberKey)); 419 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDManufacturerKey), _serviceProperties, CFSTR(kIOHIDServiceManufacturerKey)); 420 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDProductKey), _serviceProperties, CFSTR(kIOHIDServiceProductKey)); 421 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDSerialNumberKey), _serviceProperties, CFSTR(kIOHIDServiceSerialNumberKey)); 422 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDCountryCodeKey), _serviceProperties, CFSTR(kIOHIDServiceCountryCodeKey)); 423 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDLocationIDKey), _serviceProperties, CFSTR(kIOHIDServiceLocationIDKey)); 424 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDPrimaryUsagePageKey), _serviceProperties, CFSTR(kIOHIDServicePrimaryUsagePageKey)); 425 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDPrimaryUsageKey), _serviceProperties, CFSTR(kIOHIDServicePrimaryUsageKey)); 426 GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDDeviceUsagePairsKey), _serviceProperties, CFSTR(kIOHIDServiceDeviceUsagePairsKey)); 427// This should be considered a dymanic property 428// GET_AND_SET_PROPERTY(serviceProps, CFSTR(kIOHIDReportIntervalKey), _serviceProperties, CFSTR(kIOHIDServiceReportIntervalKey)); 429 430 CFRelease(serviceProps); 431 432 /* 433 // Get properties, but do so via IORegistryEntryCreateCFProperty instead 434 // of IORegistryEntryCreateCFProperties to avoid pulling in more that we 435 // need and increasing footprint 436 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDTransportKey), _serviceProperties, CFSTR(kIOHIDServiceTransportKey)); 437 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDVendorIDKey), _serviceProperties, CFSTR(kIOHIDServiceVendorIDKey)); 438 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDVendorIDSourceKey), _serviceProperties, CFSTR(kIOHIDServiceVendorIDSourceKey)); 439 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDProductIDKey), _serviceProperties, CFSTR(kIOHIDServiceProductIDKey)); 440 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDVersionNumberKey), _serviceProperties, CFSTR(kIOHIDServiceVersionNumberKey)); 441 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDManufacturerKey), _serviceProperties, CFSTR(kIOHIDServiceManufacturerKey)); 442 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDProductKey), _serviceProperties, CFSTR(kIOHIDServiceProductKey)); 443 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDSerialNumberKey), _serviceProperties, CFSTR(kIOHIDServiceSerialNumberKey)); 444 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDCountryCodeKey), _serviceProperties, CFSTR(kIOHIDServiceCountryCodeKey)); 445 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDLocationIDKey), _serviceProperties, CFSTR(kIOHIDServiceLocationIDKey)); 446 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDPrimaryUsagePageKey), _serviceProperties, CFSTR(kIOHIDServicePrimaryUsagePageKey)); 447 GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDPrimaryUsageKey), _serviceProperties, CFSTR(kIOHIDServicePrimaryUsageKey)); 448// This should be considered a dymanic property 449// GET_AND_SET_SERVICE_PROPERTY(service, CFSTR(kIOHIDReportIntervalKey), _serviceProperties, CFSTR(kIOHIDServiceReportIntervalKey)); 450 */ 451 452 // Establish connection with device 453 ret = IOServiceOpen(_service, mach_task_self(), 0, &_connect); 454 if (ret != kIOReturnSuccess || !_connect) 455 break; 456 457 // allocate the memory 458 QUEUE_LOCK(this); 459 460#if !__LP64__ 461 vm_address_t address = nil; 462 vm_size_t size = 0; 463#else 464 mach_vm_address_t address = nil; 465 mach_vm_size_t size = 0; 466#endif 467 ret = IOConnectMapMemory ( _connect, 468 0, 469 mach_task_self(), 470 &address, 471 &size, 472 kIOMapAnywhere ); 473 if (ret != kIOReturnSuccess) 474 return false; 475 476 _queueMappedMemory = (IODataQueueMemory *) address; 477 _queueMappedMemorySize = size; 478 479 if ( !_queueMappedMemory || !_queueMappedMemorySize ) 480 break; 481 482 _queueBusy = FALSE; 483 484 QUEUE_UNLOCK(this); 485 486 QUEUE_SIGNAL(this); 487 488 return kIOReturnSuccess; 489 490 } while (0); 491 492 if ( _service ) { 493 IOObjectRelease(_service); 494 _service = NULL; 495 } 496 497 return ret; 498} 499 500//--------------------------------------------------------------------------- 501// IOHIDEventServiceClass::stop 502//--------------------------------------------------------------------------- 503IOReturn IOHIDEventServiceClass::stop() 504{ 505 return kIOReturnSuccess; 506} 507 508//--------------------------------------------------------------------------- 509// IOHIDEventServiceClass::open 510//--------------------------------------------------------------------------- 511boolean_t IOHIDEventServiceClass::open(IOOptionBits options) 512{ 513 uint32_t len = 0; 514 uint64_t input = options; 515 IOReturn kr; 516 bool ret = true; 517 518 QUEUE_LOCK(this); 519 520 if ( !_isOpen ) { 521 522 do { 523 kr = IOConnectCallScalarMethod(_connect, kIOHIDEventServiceUserClientOpen, &input, 1, 0, &len);; 524 if ( kr != kIOReturnSuccess ) { 525 ret = false; 526 break; 527 } 528 529 _isOpen = true; 530 531 } while ( 0 ); 532 } 533 534 QUEUE_UNLOCK(this); 535 536 return ret; 537} 538 539//--------------------------------------------------------------------------- 540// IOHIDEventServiceClass::close 541//--------------------------------------------------------------------------- 542void IOHIDEventServiceClass::close(IOOptionBits options) 543{ 544 uint32_t len = 0; 545 uint64_t input = options; 546 547 QUEUE_LOCK(this); 548 549 if ( _isOpen ) { 550 (void) IOConnectCallScalarMethod(_connect, kIOHIDEventServiceUserClientClose, &input, 1, 0, &len); 551 552 // drain the queue just in case 553 QUEUE_UNLOCK(this); 554 555 if ( _eventCallback ) 556 _queueEventSourceCallback(NULL, NULL, 0, this); 557 558 QUEUE_LOCK(this); 559 560 _isOpen = false; 561 } 562 563 QUEUE_UNLOCK(this); 564} 565 566//--------------------------------------------------------------------------- 567// IOHIDEventServiceClass::copyProperty 568//--------------------------------------------------------------------------- 569CFTypeRef IOHIDEventServiceClass::copyProperty(CFStringRef key) 570{ 571 CFTypeRef value = CFDictionaryGetValue(_serviceProperties, key); 572 573 if ( value ) { 574 CFRetain(value); 575 } else { 576 value = IORegistryEntrySearchCFProperty(_service, kIOServicePlane, key, kCFAllocatorDefault, kIORegistryIterateRecursively| kIORegistryIterateParents); 577 } 578 579 return value; 580} 581 582//--------------------------------------------------------------------------- 583// IOHIDEventServiceClass::createFixedProperties 584//--------------------------------------------------------------------------- 585CFDictionaryRef IOHIDEventServiceClass::createFixedProperties(CFDictionaryRef floatProperties) 586{ 587 CFMutableDictionaryRef newProperties; 588 CFIndex count, index; 589 590 count = CFDictionaryGetCount(floatProperties); 591 if ( !count ) 592 return NULL; 593 594 newProperties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 595 if ( !newProperties ) 596 return NULL; 597 598 CFTypeRef values[count]; 599 CFTypeRef keys[count]; 600 601 CFDictionaryGetKeysAndValues(floatProperties, keys, values); 602 603 for ( index=0; index<count; index++) { 604 CFTypeRef value = values[index]; 605 CFTypeRef newValue = NULL; 606 607 if ( (CFNumberGetTypeID() == CFGetTypeID(value)) && CFNumberIsFloatType((CFNumberRef)value) ) { 608 double floatValue = 0.0; 609 IOFixed fixedValue = 0; 610 611 CFNumberGetValue((CFNumberRef)value, kCFNumberDoubleType, &floatValue); 612 613 fixedValue = floatValue * 65535; 614 615 value = newValue = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fixedValue); 616 } 617 618 CFDictionarySetValue(newProperties, keys[index], value); 619 620 if ( newValue ) 621 CFRelease(newValue); 622 } 623 624 return newProperties; 625} 626 627//--------------------------------------------------------------------------- 628// IOHIDEventServiceClass::setProperty 629//--------------------------------------------------------------------------- 630boolean_t IOHIDEventServiceClass::setProperty(CFStringRef key, CFTypeRef property) 631{ 632 CFDictionaryRef floatProperties = NULL; 633 boolean_t retVal; 634 635#if TARGET_OS_EMBEDDED // { 636 // RY: Convert these floating point properties to IOFixed. Limiting to accel shake but can get apply to others as well 637 if ( CFEqual(CFSTR(kIOHIDAccelerometerShakeKey), key) && (CFDictionaryGetTypeID() == CFGetTypeID(property)) ) { 638 property = floatProperties = createFixedProperties((CFDictionaryRef)property); 639 } 640#endif // } TARGET_OS_EMBEDDED 641 642 retVal = (IORegistryEntrySetCFProperty(_service, key, property) == kIOReturnSuccess); 643 644 if ( floatProperties ) 645 CFRelease(floatProperties); 646 647 return retVal; 648} 649 650//--------------------------------------------------------------------------- 651// IOHIDEventServiceClass::copyEvent 652//--------------------------------------------------------------------------- 653IOHIDEventRef IOHIDEventServiceClass::copyEvent(IOHIDEventType eventType, IOHIDEventRef matching, IOOptionBits options) 654{ 655 const UInt8 * inputData = NULL; 656 size_t inputDataSize = 0; 657 UInt8 * outputData = NULL; 658 size_t outputDataSize = 0; 659 size_t eventDataSize = 0; 660 CFDataRef fieldData = NULL; 661 CFMutableDataRef eventData = NULL; 662 IOHIDEventRef event = NULL; 663 IOReturn ret = kIOReturnSuccess; 664 665 if ( matching ) { 666 fieldData = IOHIDEventCreateData(kCFAllocatorDefault, matching); 667 668 if ( fieldData ) { 669 inputData = CFDataGetBytePtr(fieldData); 670 inputDataSize = CFDataGetLength(fieldData); 671 } 672 } 673 674 do { 675 // Grab the actual event from the user client 676 uint64_t input[2]; 677 678 input[0] = eventType; 679 input[1] = options; 680 681 IOHIDEventGetQueueElementSize(eventType, outputDataSize); 682 if ( !outputDataSize ) 683 break; 684 685 eventData = CFDataCreateMutable(kCFAllocatorDefault, outputDataSize); 686 if ( !eventData ) 687 break; 688 689 outputData = CFDataGetMutableBytePtr(eventData); 690 691 if ( !outputData ) 692 break; 693 694 CFDataSetLength(eventData, outputDataSize); 695 bzero(outputData, outputDataSize); 696 697 ret = IOConnectCallMethod(_connect, kIOHIDEventServiceUserClientCopyEvent, input, 2, inputData, inputDataSize, NULL, NULL, outputData, &outputDataSize); 698 if ( ret != kIOReturnSuccess || !outputDataSize) 699 break; 700 701 CFDataSetLength(eventData, outputDataSize); 702 703 event = IOHIDEventCreateWithData(kCFAllocatorDefault, eventData); 704 705 } while ( 0 ); 706 707 if ( fieldData ) 708 CFRelease(fieldData); 709 710 if ( eventData ) 711 CFRelease(eventData); 712 713 return event; 714} 715 716//--------------------------------------------------------------------------- 717// IOHIDEventServiceClass::setElementValue 718//--------------------------------------------------------------------------- 719IOReturn IOHIDEventServiceClass::setElementValue(uint32_t usagePage, uint32_t usage, uint32_t value) 720{ 721 uint64_t input[3] = {usagePage, usage, value}; 722 723 return IOConnectCallMethod(_connect, kIOHIDEventServiceUserClientSetElementValue, input, 3, NULL, 0, NULL, NULL, NULL, NULL); 724} 725 726 727//--------------------------------------------------------------------------- 728// IOHIDEventServiceClass::setEventCallback 729//--------------------------------------------------------------------------- 730void IOHIDEventServiceClass::setEventCallback(IOHIDServiceEventCallback callback, void * target, void * refcon) 731{ 732 _eventCallback = callback; 733 _eventTarget = target; 734 _eventRefcon = refcon; 735} 736 737//--------------------------------------------------------------------------- 738// IOHIDEventServiceClass::scheduleWithRunLoop 739//--------------------------------------------------------------------------- 740void IOHIDEventServiceClass::scheduleWithRunLoop(CFRunLoopRef runLoop, CFStringRef runLoopMode) 741{ 742 if ( !_asyncPort ) { 743 _asyncPort = IODataQueueAllocateNotificationPort(); 744 if (!_asyncPort) 745 return; 746 747 IOReturn ret = IOConnectSetNotificationPort(_connect, 0, _asyncPort, NULL); 748 if ( kIOReturnSuccess != ret ) 749 return; 750 } 751 752 if ( !_asyncCFMachPort ) { 753 CFMachPortContext context; 754 Boolean shouldFreeInfo = FALSE; 755 756 context.version = 1; 757 context.info = this; 758 context.retain = NULL; 759 context.release = NULL; 760 context.copyDescription = NULL; 761 762 _asyncCFMachPort = CFMachPortCreateWithPort(NULL, _asyncPort, 763 (CFMachPortCallBack) IOHIDEventServiceClass::_queueEventSourceCallback, 764 &context, &shouldFreeInfo); 765 766 if ( shouldFreeInfo ) { 767 // The CFMachPort we got might not work, but we'll proceed with it anyway. 768 asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s received an unexpected reused CFMachPort", __func__); 769 } 770 771 if (!_asyncCFMachPort) 772 return; 773 } 774 775 if ( !_asyncEventSource ) { 776 777 _asyncEventSource = CFMachPortCreateRunLoopSource(NULL, _asyncCFMachPort, 0); 778 779 if ( !_asyncEventSource ) 780 return; 781 } 782 CFRunLoopAddSource(runLoop, _asyncEventSource, runLoopMode); 783 784 // kick him for good measure 785 if ( _queueMappedMemory ) 786 CFRunLoopSourceSignal(_asyncEventSource); 787} 788 789//--------------------------------------------------------------------------- 790// IOHIDEventServiceClass::unscheduleFromRunLoop 791//--------------------------------------------------------------------------- 792void IOHIDEventServiceClass::unscheduleFromRunLoop(CFRunLoopRef runLoop, CFStringRef runLoopMode) 793{ 794 CFRunLoopRemoveSource(runLoop, _asyncEventSource, runLoopMode); 795} 796 797//=========================================================================== 798// Static Helper Definitions 799//=========================================================================== 800IOReturn MergeDictionaries(CFDictionaryRef srcDict, CFMutableDictionaryRef * pDstDict) 801{ 802 uint32_t count; 803 CFTypeRef * values; 804 CFStringRef * keys; 805 806 if ( !pDstDict || !srcDict || !(count = CFDictionaryGetCount(srcDict))) 807 return kIOReturnBadArgument; 808 809 if ( !*pDstDict || 810 !(*pDstDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) 811 return kIOReturnNoMemory; 812 813 values = (CFTypeRef *)malloc(sizeof(CFTypeRef) * count); 814 keys = (CFStringRef *)malloc(sizeof(CFStringRef) * count); 815 816 for ( uint32_t i=0; i<count; i++) 817 CFDictionarySetValue(*pDstDict, keys[i], values[i]); 818 819 free(values); 820 free(keys); 821 822 return kIOReturnSuccess; 823} 824