1/* 2 * @APPLE_LICENSE_HEADER_START@ 3 * 4 * Copyright (c) 1999-2009 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/* 24 * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. 25 * 26 * HISTORY 27 * 28 */ 29 30 31#include <IOKit/IOLib.h> 32#include <IOKit/hid/IOHIDEventTypes.h> 33#include <libkern/c++/OSContainers.h> 34#include <sys/proc.h> 35#include <AssertMacros.h> 36 37#include "IOHIDUserClient.h" 38#include "IOHIDParameter.h" 39#include "IOHIDFamilyPrivate.h" 40#include "IOHIDPrivate.h" 41#include "IOHIDSystem.h" 42#include "IOHIDEventSystemQueue.h" 43 44 45/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 46 47#undef super 48#define super IOUserClient 49 50OSDefineMetaClassAndStructors(IOHIDUserClient, IOUserClient) 51 52OSDefineMetaClassAndStructors(IOHIDParamUserClient, IOUserClient) 53 54OSDefineMetaClassAndStructors(IOHIDStackShotUserClient, IOUserClient) 55 56OSDefineMetaClassAndStructorsWithInit(IOHIDEventSystemUserClient, IOUserClient, IOHIDEventSystemUserClient::initialize()) 57 58/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 59 60bool IOHIDUserClient::start( IOService * _owner ) 61{ 62 if( !super::start( _owner )) 63 return( false); 64 65 owner = (IOHIDSystem *) _owner; 66 67 return( true ); 68} 69 70IOReturn IOHIDUserClient::clientClose( void ) 71{ 72 if (owner) { 73 owner->evClose(); 74 owner->serverConnect = 0; 75 detach(owner); 76 owner = NULL; 77 } 78 79 return( kIOReturnSuccess); 80} 81 82IOService * IOHIDUserClient::getService( void ) 83{ 84 return( owner ); 85} 86 87IOReturn IOHIDUserClient::registerNotificationPort( 88 mach_port_t port, 89 UInt32 type, 90 UInt32 refCon __unused ) 91{ 92 if( type != kIOHIDEventNotification) 93 return kIOReturnUnsupported; 94 if (!owner) 95 return kIOReturnOffline; 96 97 owner->setEventPort(port); 98 return kIOReturnSuccess; 99} 100 101IOReturn IOHIDUserClient::connectClient( IOUserClient * client ) 102{ 103 IOGBounds * bounds; 104 IOService * provider; 105 IOGraphicsDevice * graphicsDevice; 106 107 provider = client->getProvider(); 108 109 // avoiding OSDynamicCast & dependency on graphics family 110 if( !provider || !provider->metaCast("IOGraphicsDevice")) 111 return( kIOReturnBadArgument ); 112 113 graphicsDevice = (IOGraphicsDevice *) provider; 114 graphicsDevice->getBoundingRect(&bounds); 115 116 if (owner) 117 owner->registerScreen(graphicsDevice, bounds, bounds+1); 118 119 return( kIOReturnSuccess); 120} 121 122IOReturn IOHIDUserClient::clientMemoryForType( UInt32 type, 123 UInt32 * flags, IOMemoryDescriptor ** memory ) 124{ 125 if( type == kIOHIDGlobalMemory) { 126 *flags = 0; 127 128 if (owner && owner->globalMemory) { 129 owner->globalMemory->retain(); 130 *memory = owner->globalMemory; 131 } 132 else { 133 *memory = NULL; 134 } 135 } else { 136 return kIOReturnBadArgument; 137 } 138 139 return kIOReturnSuccess; 140} 141 142IOExternalMethod * IOHIDUserClient::getTargetAndMethodForIndex( 143 IOService ** targetP, UInt32 index ) 144{ 145 static const IOExternalMethod methodTemplate[] = { 146/* 0 */ { NULL, (IOMethod) &IOHIDSystem::createShmem, 147 kIOUCScalarIScalarO, 1, 0 }, 148/* 1 */ { NULL, (IOMethod) &IOHIDSystem::setEventsEnable, 149 kIOUCScalarIScalarO, 1, 0 }, 150/* 2 */ { NULL, (IOMethod) &IOHIDSystem::setCursorEnable, 151 kIOUCScalarIScalarO, 1, 0 }, 152/* 3 */ { NULL, (IOMethod) &IOHIDSystem::extPostEvent, 153 kIOUCStructIStructO, kIOUCVariableStructureSize, 0 }, 154/* 4 */ { NULL, (IOMethod) &IOHIDSystem::extSetMouseLocation, 155 kIOUCStructIStructO, kIOUCVariableStructureSize, 0 }, 156/* 5 */ { NULL, (IOMethod) &IOHIDSystem::extGetButtonEventNum, 157 kIOUCScalarIScalarO, 1, 1 }, 158/* 6 */ { NULL, (IOMethod) &IOHIDSystem::extSetBounds, 159 kIOUCStructIStructO, sizeof( IOGBounds), 0 }, 160/* 7 */ { NULL, (IOMethod) &IOHIDSystem::extRegisterVirtualDisplay, 161 kIOUCScalarIScalarO, 0, 1 }, 162/* 8 */ { NULL, (IOMethod) &IOHIDSystem::extUnregisterVirtualDisplay, 163 kIOUCScalarIScalarO, 1, 0 }, 164/* 9 */ { NULL, (IOMethod) &IOHIDSystem::extSetVirtualDisplayBounds, 165 kIOUCScalarIScalarO, 5, 0 }, 166/* 10 */ { NULL, (IOMethod) &IOHIDSystem::extGetUserHidActivityState, 167 kIOUCScalarIScalarO, 0, 1 }, 168/* 11 */ { NULL, (IOMethod) &IOHIDSystem::setContinuousCursorEnable, 169 kIOUCScalarIScalarO, 1, 0 }, 170}; 171 172 if( index >= (sizeof(methodTemplate) / sizeof(methodTemplate[0]))) 173 return( NULL ); 174 175 *targetP = owner; 176 177 return( (IOExternalMethod *)(methodTemplate + index) ); 178} 179 180IOReturn IOHIDUserClient::setProperties( OSObject * properties ) 181{ 182 OSDictionary * dict = OSDynamicCast(OSDictionary, properties); 183 if (dict && dict->getObject(kIOHIDUseKeyswitchKey) && 184 ( clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator) != kIOReturnSuccess)) 185 { 186 dict->removeObject(kIOHIDUseKeyswitchKey); 187 } 188 189 return( owner ? owner->setProperties( properties ) : kIOReturnOffline ); 190} 191 192IOReturn IOHIDUserClient::extGetUserHidActivityState(void* value,void*,void*,void*,void*,void*) 193{ 194 IOReturn result = owner ? owner->extSetVirtualDisplayBounds(value, 0,0,0,0,0) : kIOReturnOffline; 195 196 return result; 197} 198 199/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 200bool IOHIDParamUserClient::start( IOService * _owner ) 201{ 202 if( !super::start( _owner )) 203 return( false); 204 205 owner = (IOHIDSystem *) _owner; 206 207 return( true ); 208} 209 210IOService * IOHIDParamUserClient::getService( void ) 211{ 212 return( owner ); 213} 214 215IOExternalMethod * IOHIDParamUserClient::getTargetAndMethodForIndex( 216 IOService ** targetP, UInt32 index ) 217{ 218 // get the same library function to work for param & server connects 219 static const IOExternalMethod methodTemplate[] = { 220 /* 0 */ { NULL, NULL, kIOUCScalarIScalarO, 1, 0 }, 221 /* 1 */ { NULL, NULL, kIOUCScalarIScalarO, 1, 0 }, 222 /* 2 */ { NULL, NULL, kIOUCScalarIScalarO, 1, 0 }, 223 /* 3 */ { NULL, (IOMethod) &IOHIDParamUserClient::extPostEvent, kIOUCStructIStructO, 0xffffffff, 0 }, 224 /* 4 */ { NULL, (IOMethod) &IOHIDSystem::extSetMouseLocation, kIOUCStructIStructO, 0xffffffff, 0 }, 225 /* 5 */ { NULL, (IOMethod) &IOHIDSystem::extGetStateForSelector, kIOUCScalarIScalarO, 1, 1 }, 226 /* 6 */ { NULL, (IOMethod) &IOHIDSystem::extSetStateForSelector, kIOUCScalarIScalarO, 2, 0 }, 227 /* 7 */ { NULL, (IOMethod) &IOHIDSystem::extRegisterVirtualDisplay, kIOUCScalarIScalarO, 0, 1 }, 228 /* 8 */ { NULL, (IOMethod) &IOHIDSystem::extUnregisterVirtualDisplay, kIOUCScalarIScalarO, 1, 0 }, 229 /* 9 */ { NULL, (IOMethod) &IOHIDSystem::extSetVirtualDisplayBounds, kIOUCScalarIScalarO, 5, 0 }, 230 /* 10 */ { NULL, (IOMethod) &IOHIDParamUserClient::extGetUserHidActivityState, kIOUCScalarIScalarO, 0, 1 }, 231 /* 11 */ { NULL, (IOMethod) &IOHIDSystem::setContinuousCursorEnable, kIOUCScalarIScalarO, 1, 0 }, 232 }; 233 IOExternalMethod *result = NULL; 234 235 if ((index < 3) || (index >= (sizeof(methodTemplate) / sizeof(methodTemplate[0])))) { 236 *targetP = NULL; 237 result = NULL; 238 } 239 else { 240 result = (IOExternalMethod *) (methodTemplate + index); 241 if ((index == 10) || (index == 3)) { 242 *targetP = this; 243 } 244 else { 245 *targetP = owner; 246 } 247 } 248 249 return result; 250} 251 252IOReturn IOHIDParamUserClient::extPostEvent(void*p1,void*p2,void*,void*,void*,void*) 253{ 254 IOReturn result = clientHasPrivilege(current_task(), kIOClientPrivilegeLocalUser); 255 if ( result == kIOReturnSuccess ) { 256 result = owner ? owner->extPostEvent(p1, p2, NULL, NULL, NULL, NULL) : kIOReturnOffline; 257 } 258 return result; 259} 260 261IOReturn IOHIDParamUserClient::setProperties( OSObject * properties ) 262{ 263 OSDictionary * dict = OSDynamicCast(OSDictionary, properties); 264 if (dict && dict->getObject(kIOHIDUseKeyswitchKey) && 265 ( clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator) != kIOReturnSuccess)) 266 { 267 dict->removeObject(kIOHIDUseKeyswitchKey); 268 } 269 270 return( owner ? owner->setProperties( properties ) : kIOReturnOffline ); 271} 272 273IOReturn IOHIDParamUserClient::extGetUserHidActivityState(void* value,void*,void*,void*,void*,void*) 274{ 275 IOReturn result = owner ? owner->extGetUserHidActivityState(value, 0,0,0,0,0) : kIOReturnOffline; 276 277 return result; 278} 279 280/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 281bool IOHIDStackShotUserClient:: 282initWithTask(task_t owningTask, void * /* security_id */, UInt32 /* type */) 283{ 284 if (!super::init()) 285 return false; 286 IOReturn priv = IOUserClient::clientHasPrivilege(owningTask, kIOClientPrivilegeAdministrator); 287 if (priv != kIOReturnSuccess) { 288 IOLog("%s call failed %08x\n", __PRETTY_FUNCTION__, priv); 289 return false; 290 } 291 292 client = owningTask; 293 task_reference (client); 294 295 return true; 296} 297 298bool IOHIDStackShotUserClient::start( IOService * _owner ) 299{ 300 if( !super::start( _owner )) 301 return( false); 302 303 owner = (IOHIDSystem *) _owner; 304 305 return( true ); 306} 307 308IOReturn IOHIDStackShotUserClient::clientClose( void ) 309{ 310 if (client) { 311 task_deallocate(client); 312 client = 0; 313 } 314 315 if (owner) 316 detach(owner); 317 owner = NULL; 318 319 return( kIOReturnSuccess); 320} 321 322IOService * IOHIDStackShotUserClient::getService( void ) 323{ 324 return(owner); 325} 326 327 328IOReturn IOHIDStackShotUserClient::registerNotificationPort( 329 mach_port_t port, 330 UInt32 type, 331 UInt32 refCon __unused ) 332{ 333 if( type != kIOHIDStackShotNotification) 334 return( kIOReturnUnsupported); 335 if (!owner) 336 return kIOReturnOffline; 337 owner->setStackShotPort(port); 338 return( kIOReturnSuccess); 339} 340 341/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 342 343enum { kIOHIDEventSystemKernelQueueID = 100, kIOHIDEventSystemUserQueueID = 200 }; 344 345static OSArray * gAllUserQueues; 346static IOLock * gAllUserQueuesLock; 347 348void 349IOHIDEventSystemUserClient::initialize(void) 350{ 351 gAllUserQueuesLock = IOLockAlloc(); 352 gAllUserQueues = OSArray::withCapacity(4); 353} 354 355UInt32 356IOHIDEventSystemUserClient::createIDForDataQueue(IODataQueue * eventQueue) 357{ 358 UInt32 queueIdx; 359 360 if (!eventQueue) 361 return (0); 362 363 IOLockLock(gAllUserQueuesLock); 364 for (queueIdx = 0; 365 OSDynamicCast(IODataQueue, gAllUserQueues->getObject(queueIdx)); 366 queueIdx++) {} 367 gAllUserQueues->setObject(queueIdx, eventQueue); 368 IOLockUnlock(gAllUserQueuesLock); 369 370 return (queueIdx + kIOHIDEventSystemUserQueueID); 371} 372 373void 374IOHIDEventSystemUserClient::removeIDForDataQueue(IODataQueue * eventQueue) 375{ 376 UInt32 queueIdx; 377 OSObject * obj; 378 379 if (!eventQueue) 380 return; 381 382 IOLockLock(gAllUserQueuesLock); 383 for (queueIdx = 0; 384 (obj = gAllUserQueues->getObject(queueIdx)); 385 queueIdx++) { 386 if (obj == eventQueue) 387 gAllUserQueues->replaceObject(queueIdx, kOSBooleanFalse); 388 } 389 IOLockUnlock(gAllUserQueuesLock); 390} 391 392IODataQueue * 393IOHIDEventSystemUserClient::copyDataQueueWithID(UInt32 queueID) 394{ 395 IODataQueue * eventQueue; 396 397 IOLockLock(gAllUserQueuesLock); 398 eventQueue = OSDynamicCast(IODataQueue, gAllUserQueues->getObject(queueID - kIOHIDEventSystemUserQueueID)); 399 if (eventQueue) 400 eventQueue->retain(); 401 IOLockUnlock(gAllUserQueuesLock); 402 403 return (eventQueue); 404} 405 406bool IOHIDEventSystemUserClient:: 407initWithTask(task_t owningTask, void * /* security_id */, UInt32 /* type */) 408{ 409 if ( !super::init() ) { 410 return false; 411 } 412 413 IOReturn priv = IOUserClient::clientHasPrivilege(owningTask, kIOClientPrivilegeAdministrator); 414 if (priv != kIOReturnSuccess) { 415 IOLog("%s: Client task not privileged to open IOHIDSystem for mapping memory (%08x)\n", __PRETTY_FUNCTION__, priv); 416 return false; 417 } 418 419 420 client = owningTask; 421 task_reference (client); 422 423 return true; 424} 425 426bool IOHIDEventSystemUserClient::start( IOService * _owner ) 427{ 428 if( !super::start( _owner )) 429 return( false); 430 431 owner = (IOHIDSystem *) _owner; 432 433 return( true ); 434} 435 436IOReturn IOHIDEventSystemUserClient::clientClose( void ) 437{ 438 if (client) { 439 task_deallocate(client); 440 client = 0; 441 } 442 443 if (owner) 444 detach(owner); 445 owner = NULL; 446 447 return( kIOReturnSuccess); 448} 449 450IOService * IOHIDEventSystemUserClient::getService( void ) 451{ 452 return( owner ); 453} 454 455IOReturn IOHIDEventSystemUserClient::clientMemoryForType( UInt32 type, 456 UInt32 * flags, IOMemoryDescriptor ** memory ) 457{ 458 IODataQueue * eventQueue = NULL; 459 IOReturn ret = kIOReturnNoMemory; 460 461 if (type == kIOHIDEventSystemKernelQueueID) 462 eventQueue = kernelQueue; 463 else 464 eventQueue = copyDataQueueWithID(type); 465 466 if ( eventQueue ) { 467 IOMemoryDescriptor * desc = NULL; 468 *flags = 0; 469 470 desc = eventQueue->getMemoryDescriptor(); 471 472 if ( desc ) { 473 desc->retain(); 474 ret = kIOReturnSuccess; 475 } 476 477 *memory = desc; 478 if (type != kIOHIDEventSystemKernelQueueID) 479 eventQueue->release(); 480 481 } else { 482 ret = kIOReturnBadArgument; 483 } 484 485 return ret; 486} 487 488IOExternalMethod * IOHIDEventSystemUserClient::getTargetAndMethodForIndex( 489 IOService ** targetP, UInt32 index ) 490{ 491 static const IOExternalMethod methodTemplate[] = { 492/* 0 */ { NULL, (IOMethod) &IOHIDEventSystemUserClient::createEventQueue, 493 kIOUCScalarIScalarO, 2, 1 }, 494/* 1 */ { NULL, (IOMethod) &IOHIDEventSystemUserClient::destroyEventQueue, 495 kIOUCScalarIScalarO, 2, 0 }, 496/* 2 */ { NULL, (IOMethod) &IOHIDEventSystemUserClient::tickle, 497 kIOUCScalarIScalarO, 1, 0 } 498 }; 499 500 if( index > (sizeof(methodTemplate) / sizeof(methodTemplate[0]))) 501 return( NULL ); 502 503 *targetP = this; 504 return( (IOExternalMethod *)(methodTemplate + index) ); 505} 506 507IOReturn IOHIDEventSystemUserClient::createEventQueue(void*p1,void*p2,void*p3,void*,void*,void*) 508{ 509 UInt32 type = (uintptr_t)p1; 510 IOByteCount size = (uintptr_t)p2; 511 UInt32 * pToken = (UInt32 *)p3; 512 UInt32 token = 0; 513 IODataQueue * eventQueue = NULL; 514 515 if( !size ) 516 return kIOReturnBadArgument; 517 518 switch ( type ) { 519 case kIOHIDEventQueueTypeKernel: 520 if (!owner) 521 return kIOReturnOffline; 522 if ( !kernelQueue ) { 523 kernelQueue = IOHIDEventServiceQueue::withCapacity(size); 524 if ( kernelQueue ) { 525 kernelQueue->setState(true); 526 owner->registerEventQueue(kernelQueue); 527 } 528 } 529 eventQueue = kernelQueue; 530 token = kIOHIDEventSystemKernelQueueID; 531 if ( pToken ) { 532 *pToken = kIOHIDEventSystemKernelQueueID; 533 } 534 break; 535 case kIOHIDEventQueueTypeUser: 536 if (!userQueues) 537 userQueues = OSSet::withCapacity(4); 538 539 eventQueue = IOHIDEventSystemQueue::withCapacity(size); 540 token = createIDForDataQueue(eventQueue); 541 if (eventQueue && userQueues) { 542 userQueues->setObject(eventQueue); 543 eventQueue->release(); 544 } 545 break; 546 } 547 548 if( !eventQueue ) 549 return kIOReturnNoMemory; 550 551 if ( pToken ) { 552 *pToken = token; 553 } 554 555 return kIOReturnSuccess; 556} 557 558IOReturn IOHIDEventSystemUserClient::destroyEventQueue(void*p1,void*p2,void*,void*,void*,void*) 559{ 560 UInt32 type = (uintptr_t) p1; 561 UInt32 queueID = (uintptr_t) p2; 562 IODataQueue * eventQueue = NULL; 563 564 if (queueID == kIOHIDEventSystemKernelQueueID) { 565 eventQueue = kernelQueue; 566 type = kIOHIDEventQueueTypeKernel; 567 } else { 568 eventQueue = copyDataQueueWithID(queueID); 569 type = kIOHIDEventQueueTypeUser; 570 } 571 572 if ( !eventQueue ) 573 return kIOReturnBadArgument; 574 575 switch ( type ) { 576 case kIOHIDEventQueueTypeKernel: 577 kernelQueue->setState(false); 578 if (owner) owner->unregisterEventQueue(kernelQueue); 579 kernelQueue->release(); 580 kernelQueue = NULL; 581 break; 582 case kIOHIDEventQueueTypeUser: 583 if (userQueues) 584 userQueues->removeObject(eventQueue); 585 removeIDForDataQueue(eventQueue); 586 eventQueue->release(); 587 break; 588 } 589 590 return kIOReturnSuccess; 591} 592 593IOReturn IOHIDEventSystemUserClient::tickle(void*p1,void*,void*,void*,void*,void*) 594{ 595 IOHIDEventType eventType = (uintptr_t) p1; 596 597 /* Tickles coming from userspace must follow the same policy as IOHIDSystem.cpp: 598 * If the display is on, send tickles as usual 599 * If the display is off, only tickle on key presses and button clicks. 600 */ 601 intptr_t otherType = NX_NULLEVENT; 602 if (eventType == kIOHIDEventTypeButton) 603 otherType = NX_LMOUSEDOWN; 604 else if (eventType == kIOHIDEventTypeKeyboard) 605 otherType = NX_KEYDOWN; 606 607 if (otherType) 608 { 609 IOHIDSystemActivityTickle(otherType, this); 610 } 611 612 return kIOReturnSuccess; 613} 614 615void IOHIDEventSystemUserClient::free() 616{ 617 if ( kernelQueue ) { 618 kernelQueue->setState(false); 619 if ( owner ) 620 owner->unregisterEventQueue(kernelQueue); 621 622 kernelQueue->release(); 623 } 624 625 if ( userQueues ) { 626 OSObject * obj; 627 while ((obj = userQueues->getAnyObject())) 628 { 629 removeIDForDataQueue(OSDynamicCast(IODataQueue, obj)); 630 userQueues->removeObject(obj); 631 } 632 userQueues->release(); 633 } 634 635 super::free(); 636} 637 638IOReturn IOHIDEventSystemUserClient::registerNotificationPort( 639 mach_port_t port, 640 UInt32 type, 641 UInt32 refCon __unused ) 642{ 643 IODataQueue * eventQueue = NULL; 644 645 if (type == kIOHIDEventSystemKernelQueueID) 646 eventQueue = kernelQueue; 647 else 648 eventQueue = copyDataQueueWithID(type); 649 650 if ( !eventQueue ) 651 return kIOReturnBadArgument; 652 653 eventQueue->setNotificationPort(port); 654 655 if (type != kIOHIDEventSystemKernelQueueID) 656 eventQueue->release(); 657 658 return (kIOReturnSuccess); 659} 660 661