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 24#include <pthread.h> 25#include <CoreFoundation/CFRuntime.h> 26#include <IOKit/hid/IOHIDDevicePlugIn.h> 27#include <asl.h> 28#include "IOHIDLibPrivate.h" 29#include "IOHIDDevice.h" 30#include "IOHIDQueue.h" 31 32static IOHIDQueueRef __IOHIDQueueCreate( 33 CFAllocatorRef allocator, 34 CFAllocatorContext * context __unused); 35static void __IOHIDQueueRelease( CFTypeRef object ); 36static void __IOHIDQueueValueAvailableCallback( 37 void * context, 38 IOReturn result, 39 void * sender); 40 41 42typedef struct __IOHIDQueue 43{ 44 CFRuntimeBase cfBase; // base CFType information 45 46 IOHIDDeviceQueueInterface** queueInterface; 47 48 CFTypeRef asyncEventSource; 49 CFRunLoopRef asyncRunLoop; 50 CFStringRef asyncRunLoopMode; 51 52 IOHIDDeviceRef device; 53 CFMutableDictionaryRef callbackDictionary; 54 55 CFMutableSetRef elements; 56} __IOHIDQueue, *__IOHIDQueueRef; 57 58static const CFRuntimeClass __IOHIDQueueClass = { 59 0, // version 60 "IOHIDQueue", // className 61 NULL, // init 62 NULL, // copy 63 __IOHIDQueueRelease, // finalize 64 NULL, // equal 65 NULL, // hash 66 NULL, // copyFormattingDesc 67 NULL, 68 NULL, 69 NULL 70}; 71 72static pthread_once_t __queueTypeInit = PTHREAD_ONCE_INIT; 73static CFTypeID __kIOHIDQueueTypeID = _kCFRuntimeNotATypeID; 74 75//------------------------------------------------------------------------------ 76// __IOHIDQueueRegister 77//------------------------------------------------------------------------------ 78void __IOHIDQueueRegister(void) 79{ 80 __kIOHIDQueueTypeID = _CFRuntimeRegisterClass(&__IOHIDQueueClass); 81} 82 83//------------------------------------------------------------------------------ 84// __IOHIDQueueCreate 85//------------------------------------------------------------------------------ 86IOHIDQueueRef __IOHIDQueueCreate( 87 CFAllocatorRef allocator, 88 CFAllocatorContext * context __unused) 89{ 90 IOHIDQueueRef queue = NULL; 91 void * offset = NULL; 92 uint32_t size; 93 94 /* allocate service */ 95 size = sizeof(__IOHIDQueue) - sizeof(CFRuntimeBase); 96 queue = (IOHIDQueueRef)_CFRuntimeCreateInstance(allocator, IOHIDQueueGetTypeID(), size, NULL); 97 98 if (!queue) 99 return NULL; 100 101 offset = queue; 102 bzero(offset + sizeof(CFRuntimeBase), size); 103 104 return queue; 105} 106 107//------------------------------------------------------------------------------ 108// __IOHIDQueueRelease 109//------------------------------------------------------------------------------ 110void __IOHIDQueueRelease( CFTypeRef object ) 111{ 112 IOHIDQueueRef queue = (IOHIDQueueRef)object; 113 114 if ( queue->elements ) { 115 CFRelease(queue->elements); 116 queue->elements = NULL; 117 } 118 119 if ( queue->queueInterface ) { 120 (*queue->queueInterface)->Release(queue->queueInterface); 121 queue->queueInterface = NULL; 122 } 123 124 if ( queue->device ) { 125 queue->device = NULL; 126 } 127 128 if ( queue->callbackDictionary ) { 129 CFRelease(queue->callbackDictionary); 130 queue->callbackDictionary = NULL; 131 } 132 133} 134 135//------------------------------------------------------------------------------ 136// __IOHIDQueueValueAvailableCallback 137//------------------------------------------------------------------------------ 138void __IOHIDQueueValueAvailableCallback( 139 void * context, 140 IOReturn result, 141 void * sender __unused) 142{ 143 IOHIDQueueRef queue = (IOHIDQueueRef)context; 144 145 if ( !queue || !queue->callbackDictionary) 146 return; 147 148 IOHIDCallbackApplierContext applierContext = { 149 result, queue 150 }; 151 152 CFRetain(queue); 153 CFDictionaryApplyFunction(queue->callbackDictionary, _IOHIDCallbackApplier, (void*)&applierContext); 154 CFRelease(queue); 155} 156 157//------------------------------------------------------------------------------ 158// IOHIDQueueGetTypeID 159//------------------------------------------------------------------------------ 160CFTypeID IOHIDQueueGetTypeID(void) 161{ 162 if ( _kCFRuntimeNotATypeID == __kIOHIDQueueTypeID ) 163 pthread_once(&__queueTypeInit, __IOHIDQueueRegister); 164 165 return __kIOHIDQueueTypeID; 166} 167 168//------------------------------------------------------------------------------ 169// IOHIDQueueCreate 170//------------------------------------------------------------------------------ 171IOHIDQueueRef IOHIDQueueCreate( 172 CFAllocatorRef allocator, 173 IOHIDDeviceRef device, 174 CFIndex depth, 175 IOOptionBits options) 176{ 177 IOCFPlugInInterface ** deviceInterface = NULL; 178 IOHIDDeviceQueueInterface ** queueInterface = NULL; 179 IOHIDQueueRef queue = NULL; 180 IOReturn ret; 181 182 if ( !device ) 183 return NULL; 184 185 deviceInterface = _IOHIDDeviceGetIOCFPlugInInterface(device); 186 187 if ( !deviceInterface ) 188 return NULL; 189 190 ret = (*deviceInterface)->QueryInterface( 191 deviceInterface, 192 CFUUIDGetUUIDBytes(kIOHIDDeviceQueueInterfaceID), 193 (LPVOID)&queueInterface); 194 195 if ( ret != kIOReturnSuccess || !queueInterface ) 196 return NULL; 197 198 queue = __IOHIDQueueCreate(allocator, NULL); 199 200 if ( !queue ) { 201 (*queueInterface)->Release(queueInterface); 202 return NULL; 203 } 204 205 queue->queueInterface = queueInterface; 206 /* 9254987 - device is retained by our caller */ 207 queue->device = device; 208 209 (*queue->queueInterface)->setDepth(queue->queueInterface, depth, options); 210 211 return queue; 212} 213 214//------------------------------------------------------------------------------ 215// IOHIDQueueGetDevice 216//------------------------------------------------------------------------------ 217IOHIDDeviceRef IOHIDQueueGetDevice( 218 IOHIDQueueRef queue) 219{ 220 /* caller should retain */ 221 return queue->device; 222} 223 224//------------------------------------------------------------------------------ 225// IOHIDQueueGetDepth 226//------------------------------------------------------------------------------ 227CFIndex IOHIDQueueGetDepth( 228 IOHIDQueueRef queue) 229{ 230 uint32_t depth = 0; 231 (*queue->queueInterface)->getDepth(queue->queueInterface, &depth); 232 233 return depth; 234} 235 236//------------------------------------------------------------------------------ 237// IOHIDQueueSetDepth 238//------------------------------------------------------------------------------ 239void IOHIDQueueSetDepth( 240 IOHIDQueueRef queue, 241 CFIndex depth) 242{ 243 (*queue->queueInterface)->setDepth(queue->queueInterface, depth, 0); 244} 245 246//------------------------------------------------------------------------------ 247// IOHIDQueueAddElement 248//------------------------------------------------------------------------------ 249void IOHIDQueueAddElement( 250 IOHIDQueueRef queue, 251 IOHIDElementRef element) 252{ 253 (*queue->queueInterface)->addElement(queue->queueInterface, element, 0); 254 255 if ( !queue->elements ) 256 queue->elements = CFSetCreateMutable(CFGetAllocator(queue), 0, &kCFTypeSetCallBacks); 257 258 if ( queue->elements ) 259 CFSetAddValue(queue->elements, element); 260} 261 262//------------------------------------------------------------------------------ 263// IOHIDQueueRemoveElement 264//------------------------------------------------------------------------------ 265void IOHIDQueueRemoveElement( 266 IOHIDQueueRef queue, 267 IOHIDElementRef element) 268{ 269 (*queue->queueInterface)->removeElement(queue->queueInterface, element, 0); 270 271 if ( queue->elements ) 272 CFSetRemoveValue(queue->elements, element); 273} 274 275//------------------------------------------------------------------------------ 276// IOHIDQueueContainsElement 277//------------------------------------------------------------------------------ 278Boolean IOHIDQueueContainsElement( 279 IOHIDQueueRef queue, 280 IOHIDElementRef element) 281{ 282 Boolean hasElement = FALSE; 283 284 (*queue->queueInterface)->containsElement( 285 queue->queueInterface, 286 element, 287 &hasElement, 288 0); 289 290 return hasElement; 291} 292 293//------------------------------------------------------------------------------ 294// IOHIDQueueStart 295//------------------------------------------------------------------------------ 296void IOHIDQueueStart( IOHIDQueueRef queue) 297{ 298 (*queue->queueInterface)->start(queue->queueInterface, 0); 299} 300 301//------------------------------------------------------------------------------ 302// IOHIDQueueStop 303//------------------------------------------------------------------------------ 304void IOHIDQueueStop( IOHIDQueueRef queue) 305{ 306 (*queue->queueInterface)->stop(queue->queueInterface, 0); 307} 308 309//------------------------------------------------------------------------------ 310// IOHIDQueueScheduleWithRunLoop 311//------------------------------------------------------------------------------ 312void IOHIDQueueScheduleWithRunLoop( 313 IOHIDQueueRef queue, 314 CFRunLoopRef runLoop, 315 CFStringRef runLoopMode) 316{ 317 if ( !queue->asyncEventSource) { 318 IOReturn ret; 319 320 ret = (*queue->queueInterface)->getAsyncEventSource( 321 queue->queueInterface, 322 &queue->asyncEventSource); 323 324 if (ret != kIOReturnSuccess || !queue->asyncEventSource) 325 return; 326 } 327 328 queue->asyncRunLoop = runLoop; 329 queue->asyncRunLoopMode = runLoopMode; 330 331 if (CFGetTypeID(queue->asyncEventSource) == CFRunLoopSourceGetTypeID()) 332 CFRunLoopAddSource( queue->asyncRunLoop, 333 (CFRunLoopSourceRef)queue->asyncEventSource, 334 queue->asyncRunLoopMode); 335 else if (CFGetTypeID(queue->asyncEventSource) == CFRunLoopTimerGetTypeID()) 336 CFRunLoopAddTimer( queue->asyncRunLoop, 337 (CFRunLoopTimerRef)queue->asyncEventSource, 338 queue->asyncRunLoopMode); 339 340} 341 342//------------------------------------------------------------------------------ 343// IOHIDQueueUnscheduleFromRunLoop 344//------------------------------------------------------------------------------ 345void IOHIDQueueUnscheduleFromRunLoop( 346 IOHIDQueueRef queue, 347 CFRunLoopRef runLoop, 348 CFStringRef runLoopMode) 349{ 350 if ( !queue->asyncEventSource ) 351 return; 352 353 if (CFGetTypeID(queue->asyncEventSource) == CFRunLoopSourceGetTypeID()) 354 CFRunLoopRemoveSource( runLoop, 355 (CFRunLoopSourceRef)queue->asyncEventSource, 356 runLoopMode); 357 else if (CFGetTypeID(queue->asyncEventSource) == CFRunLoopTimerGetTypeID()) 358 CFRunLoopRemoveTimer( runLoop, 359 (CFRunLoopTimerRef)queue->asyncEventSource, 360 runLoopMode); 361 362 queue->asyncRunLoop = NULL; 363 queue->asyncRunLoopMode = NULL; 364} 365 366//------------------------------------------------------------------------------ 367// IOHIDQueueRegisterValueAvailableCallback 368//------------------------------------------------------------------------------ 369void IOHIDQueueRegisterValueAvailableCallback( 370 IOHIDQueueRef queue, 371 IOHIDCallback callback, 372 void * context) 373{ 374 if (!callback) { 375 _IOHIDLog(ASL_LEVEL_ERR, "%s called with a NULL callback\n", __func__); 376 return; 377 } 378 if (!queue->callbackDictionary) { 379 queue->callbackDictionary = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); 380 } 381 if (!queue->callbackDictionary) { 382 _IOHIDLog(ASL_LEVEL_ERR, "%s unable to create dictionary\n", __func__); 383 return; 384 } 385 CFDictionarySetValue(queue->callbackDictionary, (void*)callback, context); 386 387 (*queue->queueInterface)->setValueAvailableCallback( 388 queue->queueInterface, 389 __IOHIDQueueValueAvailableCallback, 390 queue); 391} 392 393//------------------------------------------------------------------------------ 394// IOHIDQueueCopyNextValue 395//------------------------------------------------------------------------------ 396IOHIDValueRef IOHIDQueueCopyNextValue( 397 IOHIDQueueRef queue) 398{ 399 return IOHIDQueueCopyNextValueWithTimeout(queue, 0); 400} 401 402//------------------------------------------------------------------------------ 403// IOHIDQueueCopyNextValueWithTimeout 404//------------------------------------------------------------------------------ 405IOHIDValueRef IOHIDQueueCopyNextValueWithTimeout( 406 IOHIDQueueRef queue, 407 CFTimeInterval timeout) 408{ 409 IOHIDValueRef value = NULL; 410 uint32_t timeoutMS = timeout * 1000; 411 412 (*queue->queueInterface)->copyNextValue(queue->queueInterface, 413 &value, 414 timeoutMS, 415 0); 416 417 return value; 418} 419 420//------------------------------------------------------------------------------ 421// _IOHIDQueueCopyElements 422//------------------------------------------------------------------------------ 423CFArrayRef _IOHIDQueueCopyElements(IOHIDQueueRef queue) 424{ 425 if ( !queue->elements ) 426 return NULL; 427 428 CFIndex count = CFSetGetCount( queue->elements ); 429 430 if ( !count ) 431 return NULL; 432 433 IOHIDElementRef * elements = malloc(sizeof(IOHIDElementRef) * count); 434 CFArrayRef ret = NULL; 435 436 bzero(elements, sizeof(IOHIDElementRef) * count); 437 438 CFSetGetValues(queue->elements, (const void **)elements); 439 440 ret = CFArrayCreate(CFGetAllocator(queue), (const void **)elements, count, &kCFTypeArrayCallBacks); 441 442 free(elements); 443 444 return ret; 445} 446 447