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 239void IOHIDEventServiceUserClient::stop( IOService * provider ) 240{ 241 _owner = NULL; 242 super::stop(provider); 243} 244 245//============================================================================== 246// IOHIDEventServiceUserClient::_open 247//============================================================================== 248IOReturn IOHIDEventServiceUserClient::_open( 249 IOHIDEventServiceUserClient * target, 250 void * reference, 251 IOExternalMethodArguments * arguments) 252{ 253 return target->open((IOOptionBits)arguments->scalarInput[0]); 254} 255 256//============================================================================== 257// IOHIDEventServiceUserClient::open 258//============================================================================== 259IOReturn IOHIDEventServiceUserClient::open(IOOptionBits options) 260{ 261 if (!_owner) { 262 _queue->setState(false); 263 return kIOReturnOffline; 264 } 265 266 // get ready just in case events start coming our way 267 _queue->setState(true); 268 _options = options; 269 270 if (!_owner->open( this, 271 options, 272 NULL, 273 OSMemberFunctionCast(IOHIDEventService::Action, 274 this, &IOHIDEventServiceUserClient::eventServiceCallback)) ) { 275 _queue->setState(false); 276 return kIOReturnExclusiveAccess; 277 } 278 279 return kIOReturnSuccess; 280} 281 282//============================================================================== 283// IOHIDEventServiceUserClient::_close 284//============================================================================== 285IOReturn IOHIDEventServiceUserClient::_close( 286 IOHIDEventServiceUserClient * target, 287 void * reference, 288 IOExternalMethodArguments * arguments) 289{ 290 return target->close(); 291} 292 293//============================================================================== 294// IOHIDEventServiceUserClient::close 295//============================================================================== 296IOReturn IOHIDEventServiceUserClient::close() 297{ 298 _queue->setState(false); 299 if (_owner) 300 _owner->close(this, _options); 301 302 return kIOReturnSuccess; 303} 304 305//============================================================================== 306// IOHIDEventServiceUserClient::_copyEvent 307//============================================================================== 308IOReturn IOHIDEventServiceUserClient::_copyEvent( 309 IOHIDEventServiceUserClient * target, 310 void * reference, 311 IOExternalMethodArguments * arguments) 312{ 313 IOHIDEvent * inEvent = NULL; 314 IOHIDEvent * outEvent = NULL; 315 IOReturn ret = kIOReturnError; 316 IOByteCount length = 0; 317 318 if ( arguments->structureInput && arguments->structureInputSize) 319 inEvent = IOHIDEvent::withBytes(arguments->structureInput, arguments->structureInputSize); 320 321 do { 322 outEvent = target->copyEvent(arguments->scalarInput[0], inEvent, arguments->scalarInput[1]); 323 324 if ( !outEvent ) 325 break; 326 327 length = outEvent->getLength(); 328 329 if ( length > arguments->structureOutputSize ) { 330 ret = kIOReturnBadArgument; 331 break; 332 } 333 334 outEvent->readBytes(arguments->structureOutput, length); 335 arguments->structureOutputSize = length; 336 337 ret = kIOReturnSuccess; 338 339 } while ( 0 ); 340 341 if ( inEvent ) 342 inEvent->release(); 343 344 if ( outEvent ) 345 outEvent->release(); 346 347 return ret; 348} 349 350//============================================================================== 351// IOHIDEventServiceUserClient::copyEvent 352//============================================================================== 353IOHIDEvent * IOHIDEventServiceUserClient::copyEvent(IOHIDEventType type, IOHIDEvent * matching, IOOptionBits options) 354{ 355 return _owner ? _owner->copyEvent(type, matching, options) : NULL; 356} 357 358//============================================================================== 359// IOHIDEventServiceUserClient::_setElementValue 360//============================================================================== 361IOReturn IOHIDEventServiceUserClient::_setElementValue( 362 IOHIDEventServiceUserClient * target, 363 void * reference, 364 IOExternalMethodArguments * arguments) 365{ 366 target->setElementValue(arguments->scalarInput[0], arguments->scalarInput[1], arguments->scalarInput[2]); 367 368 return kIOReturnSuccess; 369} 370 371//============================================================================== 372// IOHIDEventServiceUserClient::setElementValue 373//============================================================================== 374void IOHIDEventServiceUserClient::setElementValue(UInt32 usagePage, UInt32 usage, UInt32 value) 375{ 376 if (_owner) 377 _owner->setElementValue(usagePage, usage, value); 378} 379 380//============================================================================== 381// IOHIDEventServiceUserClient::didTerminate 382//============================================================================== 383bool IOHIDEventServiceUserClient::didTerminate(IOService *provider, IOOptionBits options, bool *defer) 384{ 385 if (_owner) 386 _owner->close(this, _options); 387 388 return super::didTerminate(provider, options, defer); 389} 390 391//============================================================================== 392// IOHIDEventServiceUserClient::free 393//============================================================================== 394void IOHIDEventServiceUserClient::free() 395{ 396 if (_queue) { 397 _queue->release(); 398 _queue = NULL; 399 } 400 401 if (_owner) { 402 _owner = NULL; 403 } 404 405 super::free(); 406} 407 408//============================================================================== 409// IOHIDEventServiceUserClient::setProperties 410//============================================================================== 411IOReturn IOHIDEventServiceUserClient::setProperties( OSObject * properties ) 412{ 413 return _owner ? _owner->setProperties(properties) : kIOReturnOffline; 414} 415 416//============================================================================== 417// IOHIDEventServiceUserClient::eventServiceCallback 418//============================================================================== 419void IOHIDEventServiceUserClient::eventServiceCallback( 420 IOHIDEventService * sender, 421 void * context, 422 IOHIDEvent * event, 423 IOOptionBits options) 424{ 425 if (!_queue || !_queue->getState() || _queue == __fakeQueue.queue ) 426 return; 427 428 //enqueue the event 429 _queue->enqueueEvent(event); 430} 431