1/* 2 * @APPLE_LICENSE_HEADER_START@ 3 * 4 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. 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 "IOHIDEventServiceUserClient.h" 24#include "IOHIDEventServiceQueue.h" 25#include "IOHIDEventData.h" 26#include "IOHIDEvent.h" 27#include "IOHIDPrivateKeys.h" 28 29 30#define kQueueSizeMin 0 31#define kQueueSizeFake 128 32#define kQueueSizeMax 4096 33 34 35//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 36// __IOHIDEventServiceQueueFake 37//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 38class __IOHIDEventServiceQueueFake { 39public: 40 IOHIDEventServiceQueue * queue; 41 42 __IOHIDEventServiceQueueFake() { 43 queue = IOHIDEventServiceQueue::withCapacity(kQueueSizeFake); 44 }; 45 ~__IOHIDEventServiceQueueFake() { 46 queue->release(); 47 }; 48}; 49 50static __IOHIDEventServiceQueueFake __fakeQueue; 51 52 53//=========================================================================== 54// IOHIDEventServiceUserClient class 55 56#define super IOUserClient 57 58OSDefineMetaClassAndStructors( IOHIDEventServiceUserClient, IOUserClient ) 59 60//============================================================================== 61// IOHIDEventServiceUserClient::sMethods 62//============================================================================== 63const IOExternalMethodDispatch IOHIDEventServiceUserClient::sMethods[kIOHIDEventServiceUserClientNumCommands] = { 64 { // kIOHIDEventServiceUserClientOpen 65 (IOExternalMethodAction) &IOHIDEventServiceUserClient::_open, 66 1, 0, 67 0, 0 68 }, 69 { // kIOHIDEventServiceUserClientClose 70 (IOExternalMethodAction) &IOHIDEventServiceUserClient::_close, 71 1, 0, 72 0, 0 73 }, 74 { // kIOHIDEventServiceUserClientCopyEvent 75 (IOExternalMethodAction) &IOHIDEventServiceUserClient::_copyEvent, 76 2, -1, 77 0, -1 78 }, 79 { // kIOHIDEventServiceUserClientSetElementValue 80 (IOExternalMethodAction) &IOHIDEventServiceUserClient::_setElementValue, 81 3, 0, 82 0, 0 83 }, 84}; 85 86 87//============================================================================== 88// IOHIDEventServiceUserClient::getService 89//============================================================================== 90IOService * IOHIDEventServiceUserClient::getService( void ) 91{ 92 return _owner; 93} 94 95//============================================================================== 96// IOHIDEventServiceUserClient::clientClose 97//============================================================================== 98IOReturn IOHIDEventServiceUserClient::clientClose( void ) 99{ 100 if (_client) { 101 task_deallocate(_client); 102 _client = 0; 103 } 104 105 if (_owner) { 106 _owner->close(this, _options); 107 } 108 109 terminate(); 110 111 return kIOReturnSuccess; 112} 113 114//============================================================================== 115// IOHIDEventServiceUserClient::registerNotificationPort 116//============================================================================== 117IOReturn IOHIDEventServiceUserClient::registerNotificationPort( 118 mach_port_t port, 119 UInt32 type, 120 UInt32 refCon ) 121{ 122 _queue->setNotificationPort(port); 123 124 return kIOReturnSuccess; 125} 126 127//============================================================================== 128// IOHIDEventServiceUserClient::clientMemoryForType 129//============================================================================== 130IOReturn IOHIDEventServiceUserClient::clientMemoryForType( 131 UInt32 type, 132 IOOptionBits * options, 133 IOMemoryDescriptor ** memory ) 134{ 135 IOReturn ret = kIOReturnNoMemory; 136 137 if ( _queue ) { 138 IOMemoryDescriptor * memoryToShare = _queue->getMemoryDescriptor(); 139 140 // if we got some memory 141 if (memoryToShare) 142 { 143 // Memory will be released by user client 144 // when last map is destroyed. 145 146 memoryToShare->retain(); 147 148 ret = kIOReturnSuccess; 149 } 150 151 // set the result 152 *options = 0; 153 *memory = memoryToShare; 154 } 155 156 return ret; 157} 158 159//============================================================================== 160// IOHIDEventServiceUserClient::externalMethod 161//============================================================================== 162typedef struct HIDCommandGateArgs { 163 uint32_t selector; 164 IOExternalMethodArguments * arguments; 165 IOExternalMethodDispatch * dispatch; 166 OSObject * target; 167 void * reference; 168}HIDCommandGateArgs; 169 170IOReturn IOHIDEventServiceUserClient::externalMethod( 171 uint32_t selector, 172 IOExternalMethodArguments * arguments, 173 IOExternalMethodDispatch * dispatch, 174 OSObject * target, 175 void * reference) 176{ 177 if (selector < (uint32_t) kIOHIDEventServiceUserClientNumCommands) 178 { 179 dispatch = (IOExternalMethodDispatch *) &sMethods[selector]; 180 181 if (!target) 182 target = this; 183 } 184 185 return super::externalMethod(selector, arguments, dispatch, target, reference); 186} 187 188//============================================================================== 189// IOHIDEventServiceUserClient::initWithTask 190//============================================================================== 191bool IOHIDEventServiceUserClient::initWithTask(task_t owningTask, void * security_id, UInt32 type) 192{ 193 if (!super::init()) 194 return false; 195 196 _client = owningTask; 197 198 task_reference (_client); 199 200 return true; 201} 202 203//============================================================================== 204// IOHIDEventServiceUserClient::start 205//============================================================================== 206bool IOHIDEventServiceUserClient::start( IOService * provider ) 207{ 208 OSObject * object; 209 uint32_t queueSize = kQueueSizeMax; 210 211 if ( !super::start(provider) ) 212 return false; 213 214 _owner = OSDynamicCast(IOHIDEventService, provider); 215 if ( !_owner ) 216 return false; 217 218 object = provider->copyProperty(kIOHIDEventServiceQueueSize); 219 if ( OSDynamicCast(OSNumber, object) ) { 220 queueSize = ((OSNumber*)object)->unsigned32BitValue(); 221 queueSize = min(kQueueSizeMax, queueSize); 222 } 223 OSSafeReleaseNULL(object); 224 225 if ( queueSize ) { 226 _queue = IOHIDEventServiceQueue::withCapacity(queueSize); 227 } else { 228 _queue = __fakeQueue.queue; 229 if ( _queue ) 230 _queue->retain(); 231 } 232 233 if ( !_queue ) 234 return false; 235 236 return true; 237} 238 239//============================================================================== 240// IOHIDEventServiceUserClient::_open 241//============================================================================== 242IOReturn IOHIDEventServiceUserClient::_open( 243 IOHIDEventServiceUserClient * target, 244 void * reference, 245 IOExternalMethodArguments * arguments) 246{ 247 return target->open((IOOptionBits)arguments->scalarInput[0]); 248} 249 250//============================================================================== 251// IOHIDEventServiceUserClient::open 252//============================================================================== 253IOReturn IOHIDEventServiceUserClient::open(IOOptionBits options) 254{ 255 256 // get ready just in case events start coming our way 257 _queue->setState(true); 258 _options = options; 259 260 if (!_owner->open( this, 261 options, 262 NULL, 263 OSMemberFunctionCast(IOHIDEventService::Action, 264 this, &IOHIDEventServiceUserClient::eventServiceCallback)) ) { 265 _queue->setState(false); 266 return kIOReturnExclusiveAccess; 267 } 268 269 return kIOReturnSuccess; 270} 271 272//============================================================================== 273// IOHIDEventServiceUserClient::_close 274//============================================================================== 275IOReturn IOHIDEventServiceUserClient::_close( 276 IOHIDEventServiceUserClient * target, 277 void * reference, 278 IOExternalMethodArguments * arguments) 279{ 280 return target->close(); 281} 282 283//============================================================================== 284// IOHIDEventServiceUserClient::close 285//============================================================================== 286IOReturn IOHIDEventServiceUserClient::close() 287{ 288 _queue->setState(false); 289 _owner->close(this, _options); 290 291 return kIOReturnSuccess; 292} 293 294//============================================================================== 295// IOHIDEventServiceUserClient::_copyEvent 296//============================================================================== 297IOReturn IOHIDEventServiceUserClient::_copyEvent( 298 IOHIDEventServiceUserClient * target, 299 void * reference, 300 IOExternalMethodArguments * arguments) 301{ 302 IOHIDEvent * inEvent = NULL; 303 IOHIDEvent * outEvent = NULL; 304 IOReturn ret = kIOReturnError; 305 IOByteCount length = 0; 306 307 if ( arguments->structureInput && arguments->structureInputSize) 308 inEvent = IOHIDEvent::withBytes(arguments->structureInput, arguments->structureInputSize); 309 310 do { 311 outEvent = target->copyEvent(arguments->scalarInput[0], inEvent, arguments->scalarInput[1]); 312 313 if ( !outEvent ) 314 break; 315 316 length = outEvent->getLength(); 317 318 if ( length > arguments->structureOutputSize ) { 319 ret = kIOReturnBadArgument; 320 break; 321 } 322 323 outEvent->readBytes(arguments->structureOutput, length); 324 arguments->structureOutputSize = length; 325 326 ret = kIOReturnSuccess; 327 328 } while ( 0 ); 329 330 if ( inEvent ) 331 inEvent->release(); 332 333 if ( outEvent ) 334 outEvent->release(); 335 336 return ret; 337} 338 339//============================================================================== 340// IOHIDEventServiceUserClient::copyEvent 341//============================================================================== 342IOHIDEvent * IOHIDEventServiceUserClient::copyEvent(IOHIDEventType type, IOHIDEvent * matching, IOOptionBits options) 343{ 344 return _owner->copyEvent(type, matching, options); 345} 346 347//============================================================================== 348// IOHIDEventServiceUserClient::_setElementValue 349//============================================================================== 350IOReturn IOHIDEventServiceUserClient::_setElementValue( 351 IOHIDEventServiceUserClient * target, 352 void * reference, 353 IOExternalMethodArguments * arguments) 354{ 355 target->setElementValue(arguments->scalarInput[0], arguments->scalarInput[1], arguments->scalarInput[2]); 356 357 return kIOReturnSuccess; 358} 359 360//============================================================================== 361// IOHIDEventServiceUserClient::setElementValue 362//============================================================================== 363void IOHIDEventServiceUserClient::setElementValue(UInt32 usagePage, UInt32 usage, UInt32 value) 364{ 365 return _owner->setElementValue(usagePage, usage, value); 366} 367 368//============================================================================== 369// IOHIDEventServiceUserClient::didTerminate 370//============================================================================== 371bool IOHIDEventServiceUserClient::didTerminate(IOService *provider, IOOptionBits options, bool *defer) 372{ 373 _owner->close(this, _options); 374 375 return super::didTerminate(provider, options, defer); 376} 377 378//============================================================================== 379// IOHIDEventServiceUserClient::free 380//============================================================================== 381void IOHIDEventServiceUserClient::free() 382{ 383 if (_queue) { 384 _queue->release(); 385 _queue = 0; 386 } 387 388 if (_owner) { 389 _owner = 0; 390 } 391 392 super::free(); 393} 394 395//============================================================================== 396// IOHIDEventServiceUserClient::setProperties 397//============================================================================== 398IOReturn IOHIDEventServiceUserClient::setProperties( OSObject * properties ) 399{ 400 return _owner->setProperties(properties); 401} 402 403//============================================================================== 404// IOHIDEventServiceUserClient::eventServiceCallback 405//============================================================================== 406void IOHIDEventServiceUserClient::eventServiceCallback( 407 IOHIDEventService * sender, 408 void * context, 409 IOHIDEvent * event, 410 IOOptionBits options) 411{ 412 if (!_queue || !_queue->getState() || _queue == __fakeQueue.queue ) 413 return; 414 415 //enqueue the event 416 _queue->enqueueEvent(event); 417} 418