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