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 "IOHIDLibPrivate.h" 28#include "IOHIDDevice.h" 29#include "IOHIDTransaction.h" 30 31static IOHIDTransactionRef __IOHIDTransactionCreate( 32 CFAllocatorRef allocator, 33 CFAllocatorContext * context __unused); 34static void __IOHIDTransactionRelease( CFTypeRef object ); 35static void __IOHIDTransactionCommitCallback( 36 void * context, 37 IOReturn result, 38 void * sender); 39 40 41typedef struct __IOHIDTransaction 42{ 43 CFRuntimeBase cfBase; // base CFType information 44 45 IOHIDDeviceTransactionInterface** transactionInterface; 46 47 CFTypeRef asyncEventSource; 48 CFRunLoopRef runLoop; 49 CFStringRef runLoopMode; 50 51 IOHIDDeviceRef device; 52 void * context; 53 IOHIDCallback callback; 54} __IOHIDTransaction, *__IOHIDTransactionRef; 55 56static const CFRuntimeClass __IOHIDTransactionClass = { 57 0, // version 58 "IOHIDTransaction", // className 59 NULL, // init 60 NULL, // copy 61 __IOHIDTransactionRelease, // finalize 62 NULL, // equal 63 NULL, // hash 64 NULL, // copyFormattingDesc 65 NULL, 66 NULL, 67 NULL 68}; 69 70static pthread_once_t __transactionTypeInit = PTHREAD_ONCE_INIT; 71static CFTypeID __kIOHIDTransactionTypeID = _kCFRuntimeNotATypeID; 72 73//------------------------------------------------------------------------------ 74// __IOHIDTransactionRegister 75//------------------------------------------------------------------------------ 76void __IOHIDTransactionRegister(void) 77{ 78 __kIOHIDTransactionTypeID = 79 _CFRuntimeRegisterClass(&__IOHIDTransactionClass); 80} 81 82//------------------------------------------------------------------------------ 83// __IOHIDTransactionCreate 84//------------------------------------------------------------------------------ 85IOHIDTransactionRef __IOHIDTransactionCreate( 86 CFAllocatorRef allocator, 87 CFAllocatorContext * context __unused) 88{ 89 IOHIDTransactionRef transaction = NULL; 90 void * offset = NULL; 91 uint32_t size; 92 93 /* allocate service */ 94 size = sizeof(__IOHIDTransaction) - sizeof(CFRuntimeBase); 95 transaction = (IOHIDTransactionRef)_CFRuntimeCreateInstance( 96 allocator, 97 IOHIDTransactionGetTypeID(), 98 size, 99 NULL); 100 101 if (!transaction) 102 return NULL; 103 104 offset = transaction; 105 bzero(offset + sizeof(CFRuntimeBase), size); 106 107 return transaction; 108} 109 110//------------------------------------------------------------------------------ 111// __IOHIDTransactionRelease 112//------------------------------------------------------------------------------ 113void __IOHIDTransactionRelease( CFTypeRef object ) 114{ 115 IOHIDTransactionRef transaction = (IOHIDTransactionRef)object; 116 117 if ( transaction->transactionInterface ) { 118 (*transaction->transactionInterface)->Release( 119 transaction->transactionInterface); 120 transaction->transactionInterface = NULL; 121 } 122 123 if ( transaction->device ) { 124 CFRelease(transaction->device); 125 transaction->device = NULL; 126 } 127} 128 129//------------------------------------------------------------------------------ 130// __IOHIDTransactionCommitCallback 131//------------------------------------------------------------------------------ 132void __IOHIDTransactionCommitCallback( 133 void * context, 134 IOReturn result, 135 void * sender) 136{ 137 IOHIDTransactionRef transaction = (IOHIDTransactionRef)context; 138 139 if ((transaction->transactionInterface == sender) && transaction->callback) 140 (*transaction->callback)( transaction->context, 141 result, 142 transaction); 143} 144 145//------------------------------------------------------------------------------ 146// IOHIDTransactionGetTypeID 147//------------------------------------------------------------------------------ 148CFTypeID IOHIDTransactionGetTypeID(void) 149{ 150 if ( _kCFRuntimeNotATypeID == __kIOHIDTransactionTypeID ) 151 pthread_once(&__transactionTypeInit, __IOHIDTransactionRegister); 152 153 return __kIOHIDTransactionTypeID; 154} 155 156//------------------------------------------------------------------------------ 157// IOHIDTransactionCreate 158//------------------------------------------------------------------------------ 159IOHIDTransactionRef IOHIDTransactionCreate( 160 CFAllocatorRef allocator, 161 IOHIDDeviceRef device, 162 IOHIDTransactionDirectionType direction, 163 IOOptionBits options) 164{ 165 IOCFPlugInInterface ** deviceInterface = NULL; 166 IOHIDDeviceTransactionInterface ** transactionInterface = NULL; 167 IOHIDTransactionRef transaction = NULL; 168 IOReturn ret; 169 170 if ( !device ) 171 return NULL; 172 173 deviceInterface = _IOHIDDeviceGetIOCFPlugInInterface(device); 174 175 if ( !deviceInterface ) 176 return NULL; 177 178 ret = (*deviceInterface)->QueryInterface( 179 deviceInterface, 180 CFUUIDGetUUIDBytes(kIOHIDDeviceTransactionInterfaceID), 181 (LPVOID)&transactionInterface); 182 183 if ( ret != kIOReturnSuccess || !transactionInterface ) 184 return NULL; 185 186 transaction = __IOHIDTransactionCreate(allocator, NULL); 187 188 if ( !transaction ) { 189 (*transactionInterface)->Release(transactionInterface); 190 return NULL; 191 } 192 193 transaction->transactionInterface = transactionInterface; 194 transaction->device = (IOHIDDeviceRef)CFRetain(device); 195 196 (*transaction->transactionInterface)->setDirection( 197 transaction->transactionInterface, 198 direction, 199 options); 200 201 return transaction; 202} 203 204//------------------------------------------------------------------------------ 205// IOHIDTransactionGetDirection 206//------------------------------------------------------------------------------ 207IOHIDDeviceRef IOHIDTransactionGetDevice( 208 IOHIDTransactionRef transaction) 209{ 210 return transaction->device; 211} 212 213//------------------------------------------------------------------------------ 214// IOHIDTransactionGetDirection 215//------------------------------------------------------------------------------ 216IOHIDTransactionDirectionType IOHIDTransactionGetDirection( 217 IOHIDTransactionRef transaction) 218{ 219 IOHIDTransactionDirectionType direction = 0; 220 (*transaction->transactionInterface)->getDirection( 221 transaction->transactionInterface, 222 &direction); 223 224 return direction; 225} 226 227//------------------------------------------------------------------------------ 228// IOHIDTransactionSetDirection 229//------------------------------------------------------------------------------ 230void IOHIDTransactionSetDirection( 231 IOHIDTransactionRef transaction, 232 IOHIDTransactionDirectionType direction) 233{ 234 (*transaction->transactionInterface)->setDirection( 235 transaction->transactionInterface, 236 direction, 237 0); 238} 239 240//------------------------------------------------------------------------------ 241// IOHIDTransactionAddElement 242//------------------------------------------------------------------------------ 243void IOHIDTransactionAddElement( 244 IOHIDTransactionRef transaction, 245 IOHIDElementRef element) 246{ 247 (*transaction->transactionInterface)->addElement( 248 transaction->transactionInterface, 249 element, 250 0); 251} 252 253//------------------------------------------------------------------------------ 254// IOHIDTransactionRemoveElement 255//------------------------------------------------------------------------------ 256void IOHIDTransactionRemoveElement( 257 IOHIDTransactionRef transaction, 258 IOHIDElementRef element) 259{ 260 (*transaction->transactionInterface)->removeElement( 261 transaction->transactionInterface, 262 element, 263 0); 264} 265 266//------------------------------------------------------------------------------ 267// IOHIDTransactionContainsElement 268//------------------------------------------------------------------------------ 269Boolean IOHIDTransactionContainsElement( 270 IOHIDTransactionRef transaction, 271 IOHIDElementRef element) 272{ 273 Boolean hasElement = FALSE; 274 275 (*transaction->transactionInterface)->containsElement( 276 transaction->transactionInterface, 277 element, 278 &hasElement, 279 0); 280 281 return hasElement; 282} 283 284//------------------------------------------------------------------------------ 285// IOHIDTransactionScheduleWithRunLoop 286//------------------------------------------------------------------------------ 287void IOHIDTransactionScheduleWithRunLoop( 288 IOHIDTransactionRef transaction, 289 CFRunLoopRef runLoop, 290 CFStringRef runLoopMode) 291{ 292 if ( !transaction->asyncEventSource) { 293 IOReturn ret; 294 295 ret = (*transaction->transactionInterface)->getAsyncEventSource( 296 transaction->transactionInterface, 297 &transaction->asyncEventSource); 298 299 if (ret != kIOReturnSuccess || !transaction->asyncEventSource) 300 return; 301 } 302 303 transaction->runLoop = runLoop; 304 transaction->runLoopMode = runLoopMode; 305 306 if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopSourceGetTypeID()) 307 CFRunLoopAddSource( transaction->runLoop, 308 (CFRunLoopSourceRef)transaction->asyncEventSource, 309 transaction->runLoopMode); 310 else if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopTimerGetTypeID()) 311 CFRunLoopAddTimer( transaction->runLoop, 312 (CFRunLoopTimerRef)transaction->asyncEventSource, 313 transaction->runLoopMode); 314 315} 316 317//------------------------------------------------------------------------------ 318// IOHIDTransactionUnscheduleFromRunLoop 319//------------------------------------------------------------------------------ 320void IOHIDTransactionUnscheduleFromRunLoop( 321 IOHIDTransactionRef transaction, 322 CFRunLoopRef runLoop, 323 CFStringRef runLoopMode) 324{ 325 if ( !transaction->asyncEventSource ) 326 return; 327 328 if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopSourceGetTypeID()) 329 CFRunLoopRemoveSource( runLoop, 330 (CFRunLoopSourceRef)transaction->asyncEventSource, 331 runLoopMode); 332 else if (CFGetTypeID(transaction->asyncEventSource) == CFRunLoopTimerGetTypeID()) 333 CFRunLoopRemoveTimer( runLoop, 334 (CFRunLoopTimerRef)transaction->asyncEventSource, 335 runLoopMode); 336 337 transaction->runLoop = NULL; 338 transaction->runLoopMode = NULL; 339} 340 341//------------------------------------------------------------------------------ 342// IOHIDTransactionSetValue 343//------------------------------------------------------------------------------ 344void IOHIDTransactionSetValue( 345 IOHIDTransactionRef transaction, 346 IOHIDElementRef element, 347 IOHIDValueRef value, 348 IOOptionBits options) 349{ 350 (*transaction->transactionInterface)->setValue( 351 transaction->transactionInterface, 352 element, 353 value, 354 options); 355} 356 357//------------------------------------------------------------------------------ 358// IOHIDTransactionGetValue 359//------------------------------------------------------------------------------ 360IOHIDValueRef IOHIDTransactionGetValue( 361 IOHIDTransactionRef transaction, 362 IOHIDElementRef element, 363 IOOptionBits options) 364{ 365 IOHIDValueRef value = NULL; 366 IOReturn ret; 367 368 ret = (*transaction->transactionInterface)->getValue( 369 transaction->transactionInterface, 370 element, 371 &value, 372 options); 373 374 return (ret == kIOReturnSuccess) ? value : NULL; 375} 376 377//------------------------------------------------------------------------------ 378// IOHIDTransactionCommit 379//------------------------------------------------------------------------------ 380IOReturn IOHIDTransactionCommit( 381 IOHIDTransactionRef transaction) 382{ 383 return IOHIDTransactionCommitWithCallback(transaction, 0, NULL, NULL); 384} 385 386//------------------------------------------------------------------------------ 387// IOHIDTransactionCommitWithCallback 388//------------------------------------------------------------------------------ 389IOReturn IOHIDTransactionCommitWithCallback( 390 IOHIDTransactionRef transaction, 391 CFTimeInterval timeout, 392 IOHIDCallback callback, 393 void * context) 394{ 395 uint32_t timeoutMS = timeout / 1000; 396 397 transaction->callback = callback; 398 transaction->context = context; 399 400 return (*transaction->transactionInterface)->commit( 401 transaction->transactionInterface, 402 timeoutMS, 403 __IOHIDTransactionCommitCallback, 404 transaction, 405 0); 406} 407 408//------------------------------------------------------------------------------ 409// IOHIDTransactionUnscheduleFromRunLoop 410//------------------------------------------------------------------------------ 411void IOHIDTransactionClear( 412 IOHIDTransactionRef transaction) 413{ 414 (*transaction->transactionInterface)->clear( 415 transaction->transactionInterface, 416 0); 417} 418