1/* 2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23#include <IOKit/system.h> 24 25#include <IOKit/IOService.h> 26#include <libkern/c++/OSContainers.h> 27#include <libkern/c++/OSUnserialize.h> 28#include <IOKit/IOCatalogue.h> 29#include <IOKit/IOCommand.h> 30#include <IOKit/IODeviceMemory.h> 31#include <IOKit/IOInterrupts.h> 32#include <IOKit/IOInterruptController.h> 33#include <IOKit/IOPlatformExpert.h> 34#include <IOKit/IOMessage.h> 35#include <IOKit/IOLib.h> 36#include <IOKit/IOKitKeysPrivate.h> 37#include <IOKit/IOBSD.h> 38#include <IOKit/IOUserClient.h> 39#include <IOKit/IOWorkLoop.h> 40#include <mach/sync_policy.h> 41#include <IOKit/assert.h> 42#include <sys/errno.h> 43 44//#define LOG kprintf 45#define LOG IOLog 46 47#include "IOServicePrivate.h" 48 49// take lockForArbitration before LOCKNOTIFY 50 51/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 52 53#define super IORegistryEntry 54 55OSDefineMetaClassAndStructors(IOService, IORegistryEntry) 56 57OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier) 58 59OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier) 60 61OSDefineMetaClassAndStructors(_IOConfigThread, OSObject) 62 63OSDefineMetaClassAndStructors(_IOServiceJob, OSObject) 64 65OSDefineMetaClassAndStructors(IOResources, IOService) 66 67OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator) 68 69OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject) 70 71/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 72 73static IOPlatformExpert * gIOPlatform; 74static class IOPMrootDomain * gIOPMRootDomain; 75const IORegistryPlane * gIOServicePlane; 76const IORegistryPlane * gIOPowerPlane; 77const OSSymbol * gIODeviceMemoryKey; 78const OSSymbol * gIOInterruptControllersKey; 79const OSSymbol * gIOInterruptSpecifiersKey; 80 81const OSSymbol * gIOResourcesKey; 82const OSSymbol * gIOResourceMatchKey; 83const OSSymbol * gIOProviderClassKey; 84const OSSymbol * gIONameMatchKey; 85const OSSymbol * gIONameMatchedKey; 86const OSSymbol * gIOPropertyMatchKey; 87const OSSymbol * gIOLocationMatchKey; 88const OSSymbol * gIOParentMatchKey; 89const OSSymbol * gIOPathMatchKey; 90const OSSymbol * gIOMatchCategoryKey; 91const OSSymbol * gIODefaultMatchCategoryKey; 92const OSSymbol * gIOMatchedServiceCountKey; 93 94const OSSymbol * gIOUserClientClassKey; 95const OSSymbol * gIOKitDebugKey; 96 97const OSSymbol * gIOCommandPoolSizeKey; 98 99const OSSymbol * gIOConsoleUsersKey; 100const OSSymbol * gIOConsoleSessionUIDKey; 101const OSSymbol * gIOConsoleUsersSeedKey; 102 103static int gIOResourceGenerationCount; 104 105const OSSymbol * gIOServiceKey; 106const OSSymbol * gIOPublishNotification; 107const OSSymbol * gIOFirstPublishNotification; 108const OSSymbol * gIOMatchedNotification; 109const OSSymbol * gIOFirstMatchNotification; 110const OSSymbol * gIOTerminatedNotification; 111 112const OSSymbol * gIOGeneralInterest; 113const OSSymbol * gIOBusyInterest; 114const OSSymbol * gIOAppPowerStateInterest; 115const OSSymbol * gIOPriorityPowerStateInterest; 116 117static OSDictionary * gNotifications; 118static IORecursiveLock * gNotificationLock; 119 120static IOService * gIOResources; 121static IOService * gIOServiceRoot; 122 123static OSOrderedSet * gJobs; 124static semaphore_port_t gJobsSemaphore; 125static IOLock * gJobsLock; 126static int gOutstandingJobs; 127static int gNumConfigThreads; 128static int gNumWaitingThreads; 129static IOLock * gIOServiceBusyLock; 130 131static thread_t gIOTerminateThread; 132static UInt32 gIOTerminateWork; 133static OSArray * gIOTerminatePhase2List; 134static OSArray * gIOStopList; 135static OSArray * gIOStopProviderList; 136static OSArray * gIOFinalizeList; 137 138static SInt32 gIOConsoleUsersSeed; 139static OSData * gIOConsoleUsersSeedValue; 140 141/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 142 143#define LOCKREADNOTIFY() \ 144 IORecursiveLockLock( gNotificationLock ) 145#define LOCKWRITENOTIFY() \ 146 IORecursiveLockLock( gNotificationLock ) 147#define LOCKWRITE2READNOTIFY() 148#define UNLOCKNOTIFY() \ 149 IORecursiveLockUnlock( gNotificationLock ) 150#define SLEEPNOTIFY(event) \ 151 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT ) 152#define WAKEUPNOTIFY(event) \ 153 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false ) 154 155#define randomDelay() \ 156 int del = read_processor_clock(); \ 157 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \ 158 IOSleep( del ); 159 160/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 161 162#define queue_element(entry, element, type, field) do { \ 163 vm_address_t __ele = (vm_address_t) (entry); \ 164 __ele -= -4 + ((size_t)(&((type) 4)->field)); \ 165 (element) = (type) __ele; \ 166 } while(0) 167 168#define iterqueue(que, elt) \ 169 for (queue_entry_t elt = queue_first(que); \ 170 !queue_end(que, elt); \ 171 elt = queue_next(elt)) 172 173/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 174 175struct ArbitrationLockQueueElement { 176 queue_chain_t link; 177 IOThread thread; 178 IOService * service; 179 unsigned count; 180 bool required; 181 bool aborted; 182}; 183 184static queue_head_t gArbitrationLockQueueActive; 185static queue_head_t gArbitrationLockQueueWaiting; 186static queue_head_t gArbitrationLockQueueFree; 187static IOLock * gArbitrationLockQueueLock; 188 189bool IOService::isInactive( void ) const 190 { return( 0 != (kIOServiceInactiveState & getState())); } 191 192/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 193 194void IOService::initialize( void ) 195{ 196 kern_return_t err; 197 198 gIOServicePlane = IORegistryEntry::makePlane( kIOServicePlane ); 199 gIOPowerPlane = IORegistryEntry::makePlane( kIOPowerPlane ); 200 201 gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey ); 202 gIONameMatchKey = OSSymbol::withCStringNoCopy( kIONameMatchKey ); 203 gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); 204 gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); 205 gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); 206 gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); 207 gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); 208 209 gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); 210 gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( 211 kIODefaultMatchCategoryKey ); 212 gIOMatchedServiceCountKey = OSSymbol::withCStringNoCopy( 213 kIOMatchedServiceCountKey ); 214 215 gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey ); 216 217 gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass ); 218 gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey ); 219 220 gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" ); 221 gIOInterruptControllersKey 222 = OSSymbol::withCStringNoCopy("IOInterruptControllers"); 223 gIOInterruptSpecifiersKey 224 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers"); 225 226 gIOKitDebugKey = OSSymbol::withCStringNoCopy( kIOKitDebugKey ); 227 228 gIOCommandPoolSizeKey = OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey ); 229 230 gIOGeneralInterest = OSSymbol::withCStringNoCopy( kIOGeneralInterest ); 231 gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest ); 232 gIOAppPowerStateInterest = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest ); 233 gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest ); 234 235 gNotifications = OSDictionary::withCapacity( 1 ); 236 gIOPublishNotification = OSSymbol::withCStringNoCopy( 237 kIOPublishNotification ); 238 gIOFirstPublishNotification = OSSymbol::withCStringNoCopy( 239 kIOFirstPublishNotification ); 240 gIOMatchedNotification = OSSymbol::withCStringNoCopy( 241 kIOMatchedNotification ); 242 gIOFirstMatchNotification = OSSymbol::withCStringNoCopy( 243 kIOFirstMatchNotification ); 244 gIOTerminatedNotification = OSSymbol::withCStringNoCopy( 245 kIOTerminatedNotification ); 246 gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); 247 248 gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey); 249 gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey); 250 gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey); 251 gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); 252 253 gNotificationLock = IORecursiveLockAlloc(); 254 255 assert( gIOServicePlane && gIODeviceMemoryKey 256 && gIOInterruptControllersKey && gIOInterruptSpecifiersKey 257 && gIOResourcesKey && gNotifications && gNotificationLock 258 && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey 259 && gIOMatchCategoryKey && gIODefaultMatchCategoryKey 260 && gIOPublishNotification && gIOMatchedNotification 261 && gIOTerminatedNotification && gIOServiceKey 262 && gIOConsoleUsersKey && gIOConsoleSessionUIDKey 263 && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue); 264 265 gJobsLock = IOLockAlloc(); 266 gJobs = OSOrderedSet::withCapacity( 10 ); 267 268 gIOServiceBusyLock = IOLockAlloc(); 269 270 err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0); 271 272 assert( gIOServiceBusyLock && gJobs && gJobsLock && (err == KERN_SUCCESS) ); 273 274 gIOResources = IOResources::resources(); 275 assert( gIOResources ); 276 277 gArbitrationLockQueueLock = IOLockAlloc(); 278 queue_init(&gArbitrationLockQueueActive); 279 queue_init(&gArbitrationLockQueueWaiting); 280 queue_init(&gArbitrationLockQueueFree); 281 282 assert( gArbitrationLockQueueLock ); 283 284 gIOTerminatePhase2List = OSArray::withCapacity( 2 ); 285 gIOStopList = OSArray::withCapacity( 16 ); 286 gIOStopProviderList = OSArray::withCapacity( 16 ); 287 gIOFinalizeList = OSArray::withCapacity( 16 ); 288 assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList ); 289} 290 291/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 292 293#if IOMATCHDEBUG 294static UInt64 getDebugFlags( OSDictionary * props ) 295{ 296 OSNumber * debugProp; 297 UInt64 debugFlags; 298 299 debugProp = OSDynamicCast( OSNumber, 300 props->getObject( gIOKitDebugKey )); 301 if( debugProp) 302 debugFlags = debugProp->unsigned64BitValue(); 303 else 304 debugFlags = gIOKitDebug; 305 306 return( debugFlags ); 307} 308#endif 309 310/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 311 312// Probe a matched service and return an instance to be started. 313// The default score is from the property table, & may be altered 314// during probe to change the start order. 315 316IOService * IOService::probe( IOService * provider, 317 SInt32 * score ) 318{ 319 return( this ); 320} 321 322bool IOService::start( IOService * provider ) 323{ 324 return( true ); 325} 326 327void IOService::stop( IOService * provider ) 328{ 329} 330 331void IOService::free( void ) 332{ 333 if( getPropertyTable()) 334 unregisterAllInterest(); 335 PMfree(); 336 super::free(); 337} 338 339/* 340 * Attach in service plane 341 */ 342bool IOService::attach( IOService * provider ) 343{ 344 bool ok; 345 346 if( provider) { 347 348 if( gIOKitDebug & kIOLogAttach) 349 LOG( "%s::attach(%s)\n", getName(), 350 provider->getName()); 351 352 provider->lockForArbitration(); 353 if( provider->__state[0] & kIOServiceInactiveState) 354 ok = false; 355 else 356 ok = attachToParent( provider, gIOServicePlane); 357 provider->unlockForArbitration(); 358 359 } else { 360 gIOServiceRoot = this; 361 ok = attachToParent( getRegistryRoot(), gIOServicePlane); 362 } 363 364 return( ok ); 365} 366 367IOService * IOService::getServiceRoot( void ) 368{ 369 return( gIOServiceRoot ); 370} 371 372void IOService::detach( IOService * provider ) 373{ 374 IOService * newProvider = 0; 375 SInt32 busy; 376 bool adjParent; 377 378 if( gIOKitDebug & kIOLogAttach) 379 LOG("%s::detach(%s)\n", getName(), provider->getName()); 380 381 lockForArbitration(); 382 383 adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask)) 384 && (provider == getProvider())); 385 386 detachFromParent( provider, gIOServicePlane ); 387 388 if( busy) { 389 newProvider = getProvider(); 390 if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider)) 391 _adjustBusy( -busy ); 392 } 393 394 unlockForArbitration(); 395 396 if( newProvider) { 397 newProvider->lockForArbitration(); 398 newProvider->_adjustBusy(1); 399 newProvider->unlockForArbitration(); 400 } 401 402 // check for last client detach from a terminated service 403 if( provider->lockForArbitration( true )) { 404 if( adjParent) 405 provider->_adjustBusy( -1 ); 406 if( (provider->__state[1] & kIOServiceTermPhase3State) 407 && (0 == provider->getClient())) { 408 provider->scheduleFinalize(); 409 } 410 provider->unlockForArbitration(); 411 } 412} 413 414/* 415 * Register instance - publish it for matching 416 */ 417 418void IOService::registerService( IOOptionBits options ) 419{ 420 char * pathBuf; 421 const char * path; 422 char * skip; 423 int len; 424 enum { kMaxPathLen = 256 }; 425 enum { kMaxChars = 63 }; 426 427 IORegistryEntry * parent = this; 428 IORegistryEntry * root = getRegistryRoot(); 429 while( parent && (parent != root)) 430 parent = parent->getParentEntry( gIOServicePlane); 431 432 if( parent != root) { 433 IOLog("%s: not registry member at registerService()\n", getName()); 434 return; 435 } 436 437 // Allow the Platform Expert to adjust this node. 438 if( gIOPlatform && (!gIOPlatform->platformAdjustService(this))) 439 return; 440 441 if( (this != gIOResources) 442 && (kIOLogRegister & gIOKitDebug)) { 443 444 pathBuf = (char *) IOMalloc( kMaxPathLen ); 445 446 IOLog( "Registering: " ); 447 448 len = kMaxPathLen; 449 if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) { 450 451 path = pathBuf; 452 if( len > kMaxChars) { 453 IOLog(".."); 454 len -= kMaxChars; 455 path += len; 456 if( (skip = strchr( path, '/'))) 457 path = skip; 458 } 459 } else 460 path = getName(); 461 462 IOLog( "%s\n", path ); 463 464 if( pathBuf) 465 IOFree( pathBuf, kMaxPathLen ); 466 } 467 468 startMatching( options ); 469} 470 471void IOService::startMatching( IOOptionBits options ) 472{ 473 IOService * provider; 474 UInt32 prevBusy = 0; 475 bool needConfig; 476 bool needWake = false; 477 bool ok; 478 bool sync; 479 bool waitAgain; 480 481 lockForArbitration(); 482 483 sync = (options & kIOServiceSynchronous) 484 || ((provider = getProvider()) 485 && (provider->__state[1] & kIOServiceSynchronousState)); 486 487 488 needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState))) 489 && (0 == (__state[0] & kIOServiceInactiveState)); 490 491 __state[1] |= kIOServiceNeedConfigState; 492 493// __state[0] &= ~kIOServiceInactiveState; 494 495// if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n", 496// OSKernelStackRemaining(), getName()); 497 498 if( needConfig) { 499 prevBusy = _adjustBusy( 1 ); 500 needWake = (0 != (kIOServiceSyncPubState & __state[1])); 501 } 502 503 if( sync) 504 __state[1] |= kIOServiceSynchronousState; 505 else 506 __state[1] &= ~kIOServiceSynchronousState; 507 508 unlockForArbitration(); 509 510 if( needConfig) { 511 512 if( needWake) { 513 IOLockLock( gIOServiceBusyLock ); 514 thread_wakeup( (event_t) this/*&__state[1]*/ ); 515 IOLockUnlock( gIOServiceBusyLock ); 516 517 } else if( !sync || (kIOServiceAsynchronous & options)) { 518 519 ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options )); 520 521 } else do { 522 523 if( (__state[1] & kIOServiceNeedConfigState)) 524 doServiceMatch( options ); 525 526 lockForArbitration(); 527 IOLockLock( gIOServiceBusyLock ); 528 529 waitAgain = (prevBusy < (__state[1] & kIOServiceBusyStateMask)); 530 if( waitAgain) 531 __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState; 532 else 533 __state[1] &= ~kIOServiceSyncPubState; 534 535 unlockForArbitration(); 536 537 if( waitAgain) 538 assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT); 539 540 IOLockUnlock( gIOServiceBusyLock ); 541 if( waitAgain) 542 thread_block(THREAD_CONTINUE_NULL); 543 544 } while( waitAgain ); 545 } 546} 547 548IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) 549{ 550 OSDictionary * table; 551 OSSet * set; 552 OSSet * allSet = 0; 553 IOService * service; 554#if IOMATCHDEBUG 555 SInt32 count = 0; 556#endif 557 558 newTables->retain(); 559 560 while( (table = (OSDictionary *) newTables->getFirstObject())) { 561 562 LOCKWRITENOTIFY(); 563 set = (OSSet *) getExistingServices( table, 564 kIOServiceRegisteredState, 565 kIOServiceExistingSet); 566 UNLOCKNOTIFY(); 567 if( set) { 568 569#if IOMATCHDEBUG 570 count += set->getCount(); 571#endif 572 if (allSet) { 573 allSet->merge((const OSSet *) set); 574 set->release(); 575 } 576 else 577 allSet = set; 578 } 579 580#if IOMATCHDEBUG 581 if( getDebugFlags( table ) & kIOLogMatch) 582 LOG("Matching service count = %ld\n", count); 583#endif 584 newTables->removeObject(table); 585 } 586 587 if (allSet) { 588 while( (service = (IOService *) allSet->getAnyObject())) { 589 service->startMatching(kIOServiceAsynchronous); 590 allSet->removeObject(service); 591 } 592 allSet->release(); 593 } 594 595 newTables->release(); 596 597 return( kIOReturnSuccess ); 598} 599 600 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type, 601 IOOptionBits options ) 602{ 603 _IOServiceJob * job; 604 605 job = new _IOServiceJob; 606 if( job && !job->init()) { 607 job->release(); 608 job = 0; 609 } 610 611 if( job) { 612 job->type = type; 613 job->nub = nub; 614 job->options = options; 615 nub->retain(); // thread will release() 616 pingConfig( job ); 617 } 618 619 return( job ); 620} 621 622/* 623 * Called on a registered service to see if it matches 624 * a property table. 625 */ 626 627bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score ) 628{ 629 return( matchPropertyTable(table) ); 630} 631 632bool IOService::matchPropertyTable( OSDictionary * table ) 633{ 634 return( true ); 635} 636 637/* 638 * Called on a matched service to allocate resources 639 * before first driver is attached. 640 */ 641 642IOReturn IOService::getResources( void ) 643{ 644 return( kIOReturnSuccess); 645} 646 647/* 648 * Client/provider accessors 649 */ 650 651IOService * IOService::getProvider( void ) const 652{ 653 IOService * self = (IOService *) this; 654 IOService * parent; 655 SInt32 generation; 656 657 parent = __provider; 658 generation = getGenerationCount(); 659 if( __providerGeneration == generation) 660 return( parent ); 661 662 parent = (IOService *) getParentEntry( gIOServicePlane); 663 if( parent == IORegistryEntry::getRegistryRoot()) 664 /* root is not an IOService */ 665 parent = 0; 666 667 self->__provider = parent; 668 // save the count before getParentEntry() 669 self->__providerGeneration = generation; 670 671 return( parent ); 672} 673 674IOWorkLoop * IOService::getWorkLoop() const 675{ 676 IOService *provider = getProvider(); 677 678 if (provider) 679 return provider->getWorkLoop(); 680 else 681 return 0; 682} 683 684OSIterator * IOService::getProviderIterator( void ) const 685{ 686 return( getParentIterator( gIOServicePlane)); 687} 688 689IOService * IOService::getClient( void ) const 690{ 691 return( (IOService *) getChildEntry( gIOServicePlane)); 692} 693 694OSIterator * IOService::getClientIterator( void ) const 695{ 696 return( getChildIterator( gIOServicePlane)); 697} 698 699OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter, 700 const IOService * client, 701 const IOService * provider ) 702{ 703 _IOOpenServiceIterator * inst; 704 705 if( !_iter) 706 return( 0 ); 707 708 inst = new _IOOpenServiceIterator; 709 710 if( inst && !inst->init()) { 711 inst->release(); 712 inst = 0; 713 } 714 if( inst) { 715 inst->iter = _iter; 716 inst->client = client; 717 inst->provider = provider; 718 } 719 720 return( inst ); 721} 722 723void _IOOpenServiceIterator::free() 724{ 725 iter->release(); 726 if( last) 727 last->unlockForArbitration(); 728 OSIterator::free(); 729} 730 731OSObject * _IOOpenServiceIterator::getNextObject() 732{ 733 IOService * next; 734 735 if( last) 736 last->unlockForArbitration(); 737 738 while( (next = (IOService *) iter->getNextObject())) { 739 740 next->lockForArbitration(); 741 if( (client && (next->isOpen( client ))) 742 || (provider && (provider->isOpen( next ))) ) 743 break; 744 next->unlockForArbitration(); 745 } 746 747 last = next; 748 749 return( next ); 750} 751 752bool _IOOpenServiceIterator::isValid() 753{ 754 return( iter->isValid() ); 755} 756 757void _IOOpenServiceIterator::reset() 758{ 759 if( last) { 760 last->unlockForArbitration(); 761 last = 0; 762 } 763 iter->reset(); 764} 765 766OSIterator * IOService::getOpenProviderIterator( void ) const 767{ 768 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 )); 769} 770 771OSIterator * IOService::getOpenClientIterator( void ) const 772{ 773 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this )); 774} 775 776 777IOReturn IOService::callPlatformFunction( const OSSymbol * functionName, 778 bool waitForFunction, 779 void *param1, void *param2, 780 void *param3, void *param4 ) 781{ 782 IOReturn result = kIOReturnUnsupported; 783 IOService *provider = getProvider(); 784 785 if (provider != 0) { 786 result = provider->callPlatformFunction(functionName, waitForFunction, 787 param1, param2, param3, param4); 788 } 789 790 return result; 791} 792 793IOReturn IOService::callPlatformFunction( const char * functionName, 794 bool waitForFunction, 795 void *param1, void *param2, 796 void *param3, void *param4 ) 797{ 798 IOReturn result = kIOReturnNoMemory; 799 const OSSymbol *functionSymbol = OSSymbol::withCString(functionName); 800 801 if (functionSymbol != 0) { 802 result = callPlatformFunction(functionSymbol, waitForFunction, 803 param1, param2, param3, param4); 804 functionSymbol->release(); 805 } 806 807 return result; 808} 809 810 811/* 812 * Accessors for global services 813 */ 814 815IOPlatformExpert * IOService::getPlatform( void ) 816{ 817 return( gIOPlatform); 818} 819 820class IOPMrootDomain * IOService::getPMRootDomain( void ) 821{ 822 return( gIOPMRootDomain); 823} 824 825IOService * IOService::getResourceService( void ) 826{ 827 return( gIOResources ); 828} 829 830void IOService::setPlatform( IOPlatformExpert * platform) 831{ 832 gIOPlatform = platform; 833 gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane ); 834} 835 836void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain) 837{ 838 gIOPMRootDomain = rootDomain; 839 publishResource("IOKit"); 840} 841 842/* 843 * Stacking change 844 */ 845 846bool IOService::lockForArbitration( bool isSuccessRequired ) 847{ 848 bool found; 849 bool success; 850 ArbitrationLockQueueElement * element; 851 ArbitrationLockQueueElement * active; 852 ArbitrationLockQueueElement * waiting; 853 854 enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action; 855 856 // lock global access 857 IOTakeLock( gArbitrationLockQueueLock ); 858 859 // obtain an unused queue element 860 if( !queue_empty( &gArbitrationLockQueueFree )) { 861 queue_remove_first( &gArbitrationLockQueueFree, 862 element, 863 ArbitrationLockQueueElement *, 864 link ); 865 } else { 866 element = IONew( ArbitrationLockQueueElement, 1 ); 867 assert( element ); 868 } 869 870 // prepare the queue element 871 element->thread = IOThreadSelf(); 872 element->service = this; 873 element->count = 1; 874 element->required = isSuccessRequired; 875 element->aborted = false; 876 877 // determine whether this object is already locked (ie. on active queue) 878 found = false; 879 queue_iterate( &gArbitrationLockQueueActive, 880 active, 881 ArbitrationLockQueueElement *, 882 link ) 883 { 884 if( active->service == element->service ) { 885 found = true; 886 break; 887 } 888 } 889 890 if( found ) { // this object is already locked 891 892 // determine whether it is the same or a different thread trying to lock 893 if( active->thread != element->thread ) { // it is a different thread 894 895 ArbitrationLockQueueElement * victim = 0; 896 897 // before placing this new thread on the waiting queue, we look for 898 // a deadlock cycle... 899 900 while( 1 ) { 901 // determine whether the active thread holding the object we 902 // want is waiting for another object to be unlocked 903 found = false; 904 queue_iterate( &gArbitrationLockQueueWaiting, 905 waiting, 906 ArbitrationLockQueueElement *, 907 link ) 908 { 909 if( waiting->thread == active->thread ) { 910 assert( false == waiting->aborted ); 911 found = true; 912 break; 913 } 914 } 915 916 if( found ) { // yes, active thread waiting for another object 917 918 // this may be a candidate for rejection if the required 919 // flag is not set, should we detect a deadlock later on 920 if( false == waiting->required ) 921 victim = waiting; 922 923 // find the thread that is holding this other object, that 924 // is blocking the active thread from proceeding (fun :-) 925 found = false; 926 queue_iterate( &gArbitrationLockQueueActive, 927 active, // (reuse active queue element) 928 ArbitrationLockQueueElement *, 929 link ) 930 { 931 if( active->service == waiting->service ) { 932 found = true; 933 break; 934 } 935 } 936 937 // someone must be holding it or it wouldn't be waiting 938 assert( found ); 939 940 if( active->thread == element->thread ) { 941 942 // doh, it's waiting for the thread that originated 943 // this whole lock (ie. current thread) -> deadlock 944 if( false == element->required ) { // willing to fail? 945 946 // the originating thread doesn't have the required 947 // flag, so it can fail 948 success = false; // (fail originating lock request) 949 break; // (out of while) 950 951 } else { // originating thread is not willing to fail 952 953 // see if we came across a waiting thread that did 954 // not have the 'required' flag set: we'll fail it 955 if( victim ) { 956 957 // we do have a willing victim, fail it's lock 958 victim->aborted = true; 959 960 // take the victim off the waiting queue 961 queue_remove( &gArbitrationLockQueueWaiting, 962 victim, 963 ArbitrationLockQueueElement *, 964 link ); 965 966 // wake the victim 967 IOLockWakeup( gArbitrationLockQueueLock, 968 victim, 969 /* one thread */ true ); 970 971 // allow this thread to proceed (ie. wait) 972 success = true; // (put request on wait queue) 973 break; // (out of while) 974 } else { 975 976 // all the waiting threads we came across in 977 // finding this loop had the 'required' flag 978 // set, so we've got a deadlock we can't avoid 979 panic("I/O Kit: Unrecoverable deadlock."); 980 } 981 } 982 } else { 983 // repeat while loop, redefining active thread to be the 984 // thread holding "this other object" (see above), and 985 // looking for threads waiting on it; note the active 986 // variable points to "this other object" already... so 987 // there nothing to do in this else clause. 988 } 989 } else { // no, active thread is not waiting for another object 990 991 success = true; // (put request on wait queue) 992 break; // (out of while) 993 } 994 } // while forever 995 996 if( success ) { // put the request on the waiting queue? 997 kern_return_t wait_result; 998 999 // place this thread on the waiting queue and put it to sleep; 1000 // we place it at the tail of the queue...
1001 queue_enter( &gArbitrationLockQueueWaiting, 1002 element, 1003 ArbitrationLockQueueElement *, 1004 link ); 1005 1006 // declare that this thread will wait for a given event 1007restart_sleep: wait_result = assert_wait( element, 1008 element->required ? THREAD_UNINT 1009 : THREAD_INTERRUPTIBLE ); 1010 1011 // unlock global access 1012 IOUnlock( gArbitrationLockQueueLock ); 1013 1014 // put thread to sleep, waiting for our event to fire... 1015 if (wait_result == THREAD_WAITING) 1016 wait_result = thread_block(THREAD_CONTINUE_NULL); 1017 1018 1019 // ...and we've been woken up; we might be in one of two states: 1020 // (a) we've been aborted and our queue element is not on 1021 // any of the three queues, but is floating around 1022 // (b) we're allowed to proceed with the lock and we have 1023 // already been moved from the waiting queue to the 1024 // active queue. 1025 // ...plus a 3rd state, should the thread have been interrupted: 1026 // (c) we're still on the waiting queue 1027 1028 // determine whether we were interrupted out of our sleep 1029 if( THREAD_INTERRUPTED == wait_result ) { 1030 1031 // re-lock global access 1032 IOTakeLock( gArbitrationLockQueueLock ); 1033 1034 // determine whether we're still on the waiting queue 1035 found = false; 1036 queue_iterate( &gArbitrationLockQueueWaiting, 1037 waiting, // (reuse waiting queue element) 1038 ArbitrationLockQueueElement *, 1039 link ) 1040 { 1041 if( waiting == element ) { 1042 found = true; 1043 break; 1044 } 1045 } 1046 1047 if( found ) { // yes, we're still on the waiting queue 1048 1049 // determine whether we're willing to fail 1050 if( false == element->required ) { 1051 1052 // mark us as aborted 1053 element->aborted = true; 1054 1055 // take us off the waiting queue 1056 queue_remove( &gArbitrationLockQueueWaiting, 1057 element, 1058 ArbitrationLockQueueElement *, 1059 link ); 1060 } else { // we are not willing to fail 1061 1062 // ignore interruption, go back to sleep 1063 goto restart_sleep; 1064 } 1065 } 1066 1067 // unlock global access 1068 IOUnlock( gArbitrationLockQueueLock ); 1069 1070 // proceed as though this were a normal wake up 1071 wait_result = THREAD_AWAKENED; 1072 } 1073 1074 assert( THREAD_AWAKENED == wait_result ); 1075 1076 // determine whether we've been aborted while we were asleep 1077 if( element->aborted ) { 1078 assert( false == element->required ); 1079 1080 // re-lock global access 1081 IOTakeLock( gArbitrationLockQueueLock ); 1082 1083 action = kPutOnFreeQueue; 1084 success = false; 1085 } else { // we weren't aborted, so we must be ready to go :-) 1086 1087 // we've already been moved from waiting to active queue 1088 return true; 1089 } 1090 1091 } else { // the lock request is to be failed 1092 1093 // return unused queue element to queue 1094 action = kPutOnFreeQueue; 1095 } 1096 } else { // it is the same thread, recursive access is allowed 1097 1098 // add one level of recursion 1099 active->count++; 1100 1101 // return unused queue element to queue 1102 action = kPutOnFreeQueue; 1103 success = true; 1104 } 1105 } else { // this object is not already locked, so let this thread through 1106 action = kPutOnActiveQueue; 1107 success = true; 1108 } 1109 1110 // put the new element on a queue 1111 if( kPutOnActiveQueue == action ) { 1112 queue_enter( &gArbitrationLockQueueActive, 1113 element, 1114 ArbitrationLockQueueElement *, 1115 link ); 1116 } else if( kPutOnFreeQueue == action ) { 1117 queue_enter( &gArbitrationLockQueueFree, 1118 element, 1119 ArbitrationLockQueueElement *, 1120 link ); 1121 } else { 1122 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above 1123 } 1124 1125 // unlock global access 1126 IOUnlock( gArbitrationLockQueueLock ); 1127 1128 return( success ); 1129} 1130 1131void IOService::unlockForArbitration( void ) 1132{ 1133 bool found; 1134 ArbitrationLockQueueElement * element; 1135 1136 // lock global access 1137 IOTakeLock( gArbitrationLockQueueLock ); 1138 1139 // find the lock element for this object (ie. on active queue) 1140 found = false; 1141 queue_iterate( &gArbitrationLockQueueActive, 1142 element, 1143 ArbitrationLockQueueElement *, 1144 link ) 1145 { 1146 if( element->service == this ) { 1147 found = true; 1148 break; 1149 } 1150 } 1151 1152 assert( found ); 1153 1154 // determine whether the lock has been taken recursively 1155 if( element->count > 1 ) { 1156 // undo one level of recursion 1157 element->count--; 1158 1159 } else { 1160 1161 // remove it from the active queue 1162 queue_remove( &gArbitrationLockQueueActive, 1163 element, 1164 ArbitrationLockQueueElement *, 1165 link ); 1166 1167 // put it on the free queue 1168 queue_enter( &gArbitrationLockQueueFree, 1169 element, 1170 ArbitrationLockQueueElement *, 1171 link ); 1172 1173 // determine whether a thread is waiting for object (head to tail scan) 1174 found = false; 1175 queue_iterate( &gArbitrationLockQueueWaiting, 1176 element, 1177 ArbitrationLockQueueElement *, 1178 link ) 1179 { 1180 if( element->service == this ) { 1181 found = true; 1182 break; 1183 } 1184 } 1185 1186 if ( found ) { // we found an interested thread on waiting queue 1187 1188 // remove it from the waiting queue 1189 queue_remove( &gArbitrationLockQueueWaiting, 1190 element, 1191 ArbitrationLockQueueElement *, 1192 link ); 1193 1194 // put it on the active queue 1195 queue_enter( &gArbitrationLockQueueActive, 1196 element, 1197 ArbitrationLockQueueElement *, 1198 link ); 1199 1200 // wake the waiting thread 1201 IOLockWakeup( gArbitrationLockQueueLock, 1202 element, 1203 /* one thread */ true ); 1204 } 1205 } 1206 1207 // unlock global access 1208 IOUnlock( gArbitrationLockQueueLock ); 1209} 1210 1211void IOService::applyToProviders( IOServiceApplierFunction applier, 1212 void * context ) 1213{ 1214 applyToParents( (IORegistryEntryApplierFunction) applier, 1215 context, gIOServicePlane ); 1216} 1217 1218void IOService::applyToClients( IOServiceApplierFunction applier, 1219 void * context ) 1220{ 1221 applyToChildren( (IORegistryEntryApplierFunction) applier, 1222 context, gIOServicePlane ); 1223} 1224 1225 1226/* 1227 * Client messages 1228 */ 1229 1230 1231// send a message to a client or interested party of this service 1232IOReturn IOService::messageClient( UInt32 type, OSObject * client, 1233 void * argument, vm_size_t argSize ) 1234{ 1235 IOReturn ret; 1236 IOService * service; 1237 _IOServiceInterestNotifier * notify; 1238 1239 if( (service = OSDynamicCast( IOService, client))) 1240 ret = service->message( type, this, argument ); 1241 1242 else if( (notify = OSDynamicCast( _IOServiceInterestNotifier, client))) { 1243 1244 _IOServiceNotifierInvocation invocation; 1245 bool willNotify; 1246 1247 invocation.thread = current_thread(); 1248 1249 LOCKWRITENOTIFY(); 1250 willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); 1251 1252 if( willNotify) { 1253 queue_enter( ¬ify->handlerInvocations, &invocation, 1254 _IOServiceNotifierInvocation *, link ); 1255 } 1256 UNLOCKNOTIFY(); 1257 1258 if( willNotify) { 1259 1260 ret = (*notify->handler)( notify->target, notify->ref, 1261 type, this, argument, argSize ); 1262 1263 LOCKWRITENOTIFY(); 1264 queue_remove( ¬ify->handlerInvocations, &invocation, 1265 _IOServiceNotifierInvocation *, link ); 1266 if( kIOServiceNotifyWaiter & notify->state) { 1267 notify->state &= ~kIOServiceNotifyWaiter; 1268 WAKEUPNOTIFY( notify ); 1269 } 1270 UNLOCKNOTIFY(); 1271 1272 } else 1273 ret = kIOReturnSuccess; 1274 1275 } else 1276 ret = kIOReturnBadArgument; 1277 1278 return( ret ); 1279} 1280 1281void IOService::applyToInterested( const OSSymbol * typeOfInterest, 1282 OSObjectApplierFunction applier, 1283 void * context ) 1284{ 1285 OSArray * copyArray = 0; 1286 1287 applyToClients( (IOServiceApplierFunction) applier, context ); 1288 1289 LOCKREADNOTIFY(); 1290 1291 IOCommand *notifyList = 1292 OSDynamicCast( IOCommand, getProperty( typeOfInterest )); 1293 1294 if( notifyList) { 1295 copyArray = OSArray::withCapacity(1); 1296 1297 // iterate over queue, entry is set to each element in the list 1298 iterqueue(¬ifyList->fCommandChain, entry) { 1299 _IOServiceInterestNotifier * notify; 1300 1301 queue_element(entry, notify, _IOServiceInterestNotifier *, chain); 1302 copyArray->setObject(notify); 1303 } 1304 } 1305 UNLOCKNOTIFY(); 1306 1307 if( copyArray) { 1308 unsigned int index; 1309 OSObject * next; 1310 1311 for( index = 0; (next = copyArray->getObject( index )); index++) 1312 (*applier)(next, context); 1313 copyArray->release(); 1314 } 1315} 1316 1317struct MessageClientsContext { 1318 IOService * service; 1319 UInt32 type; 1320 void * argument; 1321 vm_size_t argSize; 1322 IOReturn ret; 1323}; 1324 1325static void messageClientsApplier( OSObject * object, void * ctx ) 1326{ 1327 IOReturn ret; 1328 MessageClientsContext * context = (MessageClientsContext *) ctx; 1329 1330 ret = context->service->messageClient( context->type, 1331 object, context->argument, context->argSize ); 1332 if( kIOReturnSuccess != ret) 1333 context->ret = ret; 1334} 1335 1336// send a message to all clients 1337IOReturn IOService::messageClients( UInt32 type, 1338 void * argument, vm_size_t argSize ) 1339{ 1340 MessageClientsContext context; 1341 1342 context.service = this; 1343 context.type = type; 1344 context.argument = argument; 1345 context.argSize = argSize; 1346 context.ret = kIOReturnSuccess; 1347 1348 applyToInterested( gIOGeneralInterest, 1349 &messageClientsApplier, &context ); 1350 1351 return( context.ret ); 1352} 1353 1354IOReturn IOService::acknowledgeNotification( IONotificationRef notification, 1355 IOOptionBits response ) 1356{ 1357 return( kIOReturnUnsupported ); 1358} 1359 1360IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, 1361 IOServiceInterestHandler handler, void * target, void * ref ) 1362{ 1363 _IOServiceInterestNotifier * notify = 0; 1364 1365 if( (typeOfInterest != gIOGeneralInterest) 1366 && (typeOfInterest != gIOBusyInterest) 1367 && (typeOfInterest != gIOAppPowerStateInterest) 1368 && (typeOfInterest != gIOPriorityPowerStateInterest)) 1369 return( 0 ); 1370 1371 lockForArbitration(); 1372 if( 0 == (__state[0] & kIOServiceInactiveState)) { 1373 1374 notify = new _IOServiceInterestNotifier; 1375 if( notify && !notify->init()) { 1376 notify->release(); 1377 notify = 0; 1378 } 1379 1380 if( notify) { 1381 notify->handler = handler; 1382 notify->target = target; 1383 notify->ref = ref; 1384 notify->state = kIOServiceNotifyEnable; 1385 queue_init( ¬ify->handlerInvocations ); 1386 1387 ////// queue 1388 1389 LOCKWRITENOTIFY(); 1390 1391 // Get the head of the notifier linked list 1392 IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest ); 1393 if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) { 1394 notifyList = OSTypeAlloc(IOCommand); 1395 if (notifyList) { 1396 notifyList->init(); 1397 setProperty( typeOfInterest, notifyList); 1398 notifyList->release(); 1399 } 1400 } 1401 1402 if (notifyList) { 1403 enqueue(¬ifyList->fCommandChain, ¬ify->chain); 1404 notify->retain(); // ref'ed while in list 1405 } 1406 1407 UNLOCKNOTIFY(); 1408 } 1409 } 1410 unlockForArbitration(); 1411 1412 return( notify ); 1413} 1414 1415static void cleanInterestList( OSObject * head ) 1416{ 1417 IOCommand *notifyHead = OSDynamicCast(IOCommand, head); 1418 if (!notifyHead) 1419 return; 1420 1421 LOCKWRITENOTIFY(); 1422 while ( queue_entry_t entry = dequeue(¬ifyHead->fCommandChain) ) { 1423 queue_next(entry) = queue_prev(entry) = 0; 1424 1425 _IOServiceInterestNotifier * notify; 1426 1427 queue_element(entry, notify, _IOServiceInterestNotifier *, chain); 1428 notify->release(); 1429 } 1430 UNLOCKNOTIFY(); 1431} 1432 1433void IOService::unregisterAllInterest( void ) 1434{ 1435 cleanInterestList( getProperty( gIOGeneralInterest )); 1436 cleanInterestList( getProperty( gIOBusyInterest )); 1437 cleanInterestList( getProperty( gIOAppPowerStateInterest )); 1438 cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); 1439} 1440 1441/* 1442 * _IOServiceInterestNotifier 1443 */ 1444 1445// wait for all threads, other than the current one, 1446// to exit the handler 1447 1448void _IOServiceInterestNotifier::wait() 1449{ 1450 _IOServiceNotifierInvocation * next; 1451 bool doWait; 1452 1453 do { 1454 doWait = false; 1455 queue_iterate( &handlerInvocations, next, 1456 _IOServiceNotifierInvocation *, link) { 1457 if( next->thread != current_thread() ) { 1458 doWait = true; 1459 break; 1460 } 1461 } 1462 if( doWait) { 1463 state |= kIOServiceNotifyWaiter; 1464 SLEEPNOTIFY(this); 1465 } 1466 1467 } while( doWait ); 1468} 1469 1470void _IOServiceInterestNotifier::free() 1471{ 1472 assert( queue_empty( &handlerInvocations )); 1473 OSObject::free(); 1474} 1475 1476void _IOServiceInterestNotifier::remove() 1477{ 1478 LOCKWRITENOTIFY(); 1479 1480 if( queue_next( &chain )) { 1481 remqueue( 0, &chain); 1482 queue_next( &chain) = queue_prev( &chain) = 0; 1483 release(); 1484 } 1485 1486 state &= ~kIOServiceNotifyEnable; 1487 1488 wait(); 1489 1490 UNLOCKNOTIFY(); 1491 1492 release(); 1493} 1494 1495bool _IOServiceInterestNotifier::disable() 1496{ 1497 bool ret; 1498 1499 LOCKWRITENOTIFY(); 1500 1501 ret = (0 != (kIOServiceNotifyEnable & state)); 1502 state &= ~kIOServiceNotifyEnable; 1503 if( ret) 1504 wait(); 1505 1506 UNLOCKNOTIFY(); 1507 1508 return( ret ); 1509} 1510 1511void _IOServiceInterestNotifier::enable( bool was ) 1512{ 1513 LOCKWRITENOTIFY(); 1514 if( was) 1515 state |= kIOServiceNotifyEnable; 1516 else 1517 state &= ~kIOServiceNotifyEnable; 1518 UNLOCKNOTIFY(); 1519} 1520 1521/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1522 1523/* 1524 * Termination 1525 */ 1526 1527#define tailQ(o) setObject(o) 1528#define headQ(o) setObject(0, o) 1529#define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); } 1530 1531inline void _workLoopAction( IOWorkLoop::Action action, 1532 IOService * service, 1533 void * p0 = 0, void * p1 = 0, 1534 void * p2 = 0, void * p3 = 0 ) 1535{ 1536 IOWorkLoop * wl; 1537 1538 if( (wl = service->getWorkLoop())) { 1539 wl->retain(); 1540 wl->runAction( action, service, p0, p1, p2, p3 ); 1541 wl->release(); 1542 } else 1543 (*action)( service, p0, p1, p2, p3 ); 1544} 1545 1546bool IOService::requestTerminate( IOService * provider, IOOptionBits options ) 1547{ 1548 bool ok; 1549 1550 // if its our only provider 1551 ok = isParent( provider, gIOServicePlane, true); 1552 1553 // -- compat 1554 if( ok) { 1555 provider->terminateClient( this, options | kIOServiceRecursing ); 1556 ok = (0 != (__state[1] & kIOServiceRecursing)); 1557 } 1558 // -- 1559 1560 return( ok ); 1561} 1562 1563bool IOService::terminatePhase1( IOOptionBits options ) 1564{ 1565 IOService * victim; 1566 IOService * client; 1567 OSIterator * iter; 1568 OSArray * makeInactive; 1569 bool ok; 1570 bool didInactive; 1571 bool startPhase2 = false; 1572 1573 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options); 1574 1575 // -- compat 1576 if( options & kIOServiceRecursing) { 1577 __state[1] |= kIOServiceRecursing; 1578 return( true ); 1579 } 1580 // -- 1581 1582 makeInactive = OSArray::withCapacity( 16 ); 1583 if( !makeInactive) 1584 return( false ); 1585 1586 victim = this; 1587 victim->retain(); 1588 1589 while( victim ) { 1590 1591 didInactive = victim->lockForArbitration( true ); 1592 if( didInactive) { 1593 didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState)); 1594 if( didInactive) { 1595 victim->__state[0] |= kIOServiceInactiveState; 1596 victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState 1597 | kIOServiceFirstPublishState | kIOServiceFirstMatchState); 1598 victim->_adjustBusy( 1 ); 1599 } 1600 victim->unlockForArbitration(); 1601 } 1602 if( victim == this) 1603 startPhase2 = didInactive; 1604 if( didInactive) { 1605 1606 victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); 1607 IOUserClient::destroyUserReferences( victim ); 1608 1609 iter = victim->getClientIterator(); 1610 if( iter) { 1611 while( (client = (IOService *) iter->getNextObject())) { 1612 TLOG("%s::requestTerminate(%s, %08lx)\n", 1613 client->getName(), victim->getName(), options); 1614 ok = client->requestTerminate( victim, options ); 1615 TLOG("%s::requestTerminate(%s, ok = %d)\n", 1616 client->getName(), victim->getName(), ok); 1617 if( ok) 1618 makeInactive->setObject( client ); 1619 } 1620 iter->release(); 1621 } 1622 } 1623 victim->release(); 1624 victim = (IOService *) makeInactive->getObject(0); 1625 if( victim) { 1626 victim->retain(); 1627 makeInactive->removeObject(0); 1628 } 1629 } 1630 1631 makeInactive->release(); 1632 1633 if( startPhase2) 1634 scheduleTerminatePhase2( options ); 1635 1636 return( true ); 1637} 1638 1639void IOService::scheduleTerminatePhase2( IOOptionBits options ) 1640{ 1641 AbsoluteTime deadline; 1642 int waitResult = THREAD_AWAKENED; 1643 bool wait, haveDeadline = false; 1644 1645 options |= kIOServiceRequired; 1646 1647 retain(); 1648 1649 IOLockLock( gJobsLock ); 1650 1651 if( (options & kIOServiceSynchronous) 1652 && (current_thread() != gIOTerminateThread)) { 1653 1654 do { 1655 wait = (gIOTerminateThread != 0); 1656 if( wait) { 1657 // wait to become the terminate thread 1658 IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT); 1659 } 1660 } while( wait ); 1661 1662 gIOTerminateThread = current_thread(); 1663 gIOTerminatePhase2List->setObject( this ); 1664 gIOTerminateWork++; 1665 1666 do { 1667 while( gIOTerminateWork ) 1668 terminateWorker( options ); 1669 wait = (0 != (__state[1] & kIOServiceBusyStateMask)); 1670 if( wait) { 1671 // wait for the victim to go non-busy 1672 if( !haveDeadline) { 1673 clock_interval_to_deadline( 15, kSecondScale, &deadline ); 1674 haveDeadline = true; 1675 } 1676 waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork, 1677 deadline, THREAD_UNINT ); 1678 if( waitResult == THREAD_TIMED_OUT) { 1679 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName()); 1680 } 1681 } 1682 } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT))); 1683 1684 gIOTerminateThread = 0; 1685 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); 1686 1687 } else { 1688 // ! kIOServiceSynchronous 1689 1690 gIOTerminatePhase2List->setObject( this ); 1691 if( 0 == gIOTerminateWork++) { 1692 if( !gIOTerminateThread) 1693 gIOTerminateThread = IOCreateThread( &terminateThread, (void *) options ); 1694 else 1695 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 1696 } 1697 } 1698 1699 IOLockUnlock( gJobsLock ); 1700 1701 release(); 1702} 1703 1704void IOService::terminateThread( void * arg ) 1705{ 1706 IOLockLock( gJobsLock ); 1707 1708 while (gIOTerminateWork) 1709 terminateWorker( (IOOptionBits) arg ); 1710 1711 gIOTerminateThread = 0; 1712 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); 1713 1714 IOLockUnlock( gJobsLock ); 1715} 1716 1717void IOService::scheduleStop( IOService * provider ) 1718{ 1719 TLOG("%s::scheduleStop(%s)\n", getName(), provider->getName()); 1720 1721 IOLockLock( gJobsLock ); 1722 gIOStopList->tailQ( this ); 1723 gIOStopProviderList->tailQ( provider ); 1724 1725 if( 0 == gIOTerminateWork++) { 1726 if( !gIOTerminateThread) 1727 gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); 1728 else 1729 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 1730 } 1731 1732 IOLockUnlock( gJobsLock ); 1733} 1734 1735void IOService::scheduleFinalize( void ) 1736{ 1737 TLOG("%s::scheduleFinalize\n", getName()); 1738 1739 IOLockLock( gJobsLock ); 1740 gIOFinalizeList->tailQ( this ); 1741 1742 if( 0 == gIOTerminateWork++) { 1743 if( !gIOTerminateThread) 1744 gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); 1745 else 1746 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 1747 } 1748 1749 IOLockUnlock( gJobsLock ); 1750} 1751 1752bool IOService::willTerminate( IOService * provider, IOOptionBits options ) 1753{ 1754 return( true ); 1755} 1756 1757bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer ) 1758{ 1759 if( false == *defer) { 1760 1761 if( lockForArbitration( true )) { 1762 if( false == provider->handleIsOpen( this )) 1763 scheduleStop( provider ); 1764 // -- compat 1765 else { 1766 message( kIOMessageServiceIsRequestingClose, provider, (void *) options ); 1767 if( false == provider->handleIsOpen( this )) 1768 scheduleStop( provider ); 1769 } 1770 // -- 1771 unlockForArbitration(); 1772 } 1773 } 1774 1775 return( true ); 1776} 1777 1778void IOService::actionWillTerminate( IOService * victim, IOOptionBits options, 1779 OSArray * doPhase2List ) 1780{ 1781 OSIterator * iter; 1782 IOService * client; 1783 bool ok; 1784 1785 iter = victim->getClientIterator(); 1786 if( iter) { 1787 while( (client = (IOService *) iter->getNextObject())) { 1788 TLOG("%s::willTerminate(%s, %08lx)\n", 1789 client->getName(), victim->getName(), options); 1790 ok = client->willTerminate( victim, options ); 1791 doPhase2List->tailQ( client ); 1792 } 1793 iter->release(); 1794 } 1795} 1796 1797void IOService::actionDidTerminate( IOService * victim, IOOptionBits options ) 1798{ 1799 OSIterator * iter; 1800 IOService * client; 1801 bool defer = false; 1802 1803 victim->messageClients( kIOMessageServiceIsTerminated, (void *) options ); 1804 1805 iter = victim->getClientIterator(); 1806 if( iter) { 1807 while( (client = (IOService *) iter->getNextObject())) { 1808 TLOG("%s::didTerminate(%s, %08lx)\n", 1809 client->getName(), victim->getName(), options); 1810 client->didTerminate( victim, options, &defer ); 1811 TLOG("%s::didTerminate(%s, defer %d)\n", 1812 client->getName(), victim->getName(), defer); 1813 } 1814 iter->release(); 1815 } 1816} 1817 1818void IOService::actionFinalize( IOService * victim, IOOptionBits options ) 1819{ 1820 TLOG("%s::finalize(%08lx)\n", victim->getName(), options); 1821 victim->finalize( options ); 1822} 1823 1824void IOService::actionStop( IOService * provider, IOService * client ) 1825{ 1826 TLOG("%s::stop(%s)\n", client->getName(), provider->getName()); 1827 client->stop( provider ); 1828 if( provider->isOpen( client )) 1829 provider->close( client ); 1830 TLOG("%s::detach(%s)\n", client->getName(), provider->getName()); 1831 client->detach( provider ); 1832} 1833 1834void IOService::terminateWorker( IOOptionBits options ) 1835{ 1836 OSArray * doPhase2List; 1837 OSArray * didPhase2List; 1838 OSSet * freeList; 1839 UInt32 workDone; 1840 IOService * victim; 1841 IOService * client; 1842 IOService * provider; 1843 unsigned int idx; 1844 bool moreToDo; 1845 bool doPhase2; 1846 bool doPhase3; 1847 1848 options |= kIOServiceRequired; 1849 1850 doPhase2List = OSArray::withCapacity( 16 ); 1851 didPhase2List = OSArray::withCapacity( 16 ); 1852 freeList = OSSet::withCapacity( 16 ); 1853 if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList)) 1854 return; 1855 1856 do { 1857 workDone = gIOTerminateWork; 1858 1859 while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) { 1860 1861 victim->retain(); 1862 gIOTerminatePhase2List->removeObject(0); 1863 IOLockUnlock( gJobsLock ); 1864 1865 while( victim ) { 1866 1867 doPhase2 = victim->lockForArbitration( true ); 1868 if( doPhase2) { 1869 doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0])); 1870 if( doPhase2) { 1871 doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State)) 1872 && (0 == (victim->__state[1] & kIOServiceConfigState)); 1873 if( doPhase2) 1874 victim->__state[1] |= kIOServiceTermPhase2State; 1875 } 1876 victim->unlockForArbitration(); 1877 } 1878 if( doPhase2) { 1879 if( 0 == victim->getClient()) { 1880 // no clients - will go to finalize 1881 IOLockLock( gJobsLock ); 1882 gIOFinalizeList->tailQ( victim ); 1883 IOLockUnlock( gJobsLock ); 1884 } else { 1885 _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate, 1886 victim, (void *) options, (void *) doPhase2List ); 1887 } 1888 didPhase2List->headQ( victim ); 1889 } 1890 victim->release(); 1891 victim = (IOService *) doPhase2List->getObject(0); 1892 if( victim) { 1893 victim->retain(); 1894 doPhase2List->removeObject(0); 1895 } 1896 } 1897 1898 while( (victim = (IOService *) didPhase2List->getObject(0)) ) { 1899 1900 if( victim->lockForArbitration( true )) { 1901 victim->__state[1] |= kIOServiceTermPhase3State; 1902 victim->unlockForArbitration(); 1903 } 1904 _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate, 1905 victim, (void *) options ); 1906 didPhase2List->removeObject(0); 1907 } 1908 IOLockLock( gJobsLock ); 1909 } 1910 1911 // phase 3 1912 do { 1913 doPhase3 = false; 1914 // finalize leaves 1915 while( (victim = (IOService *) gIOFinalizeList->getObject(0))) { 1916 1917 IOLockUnlock( gJobsLock ); 1918 _workLoopAction( (IOWorkLoop::Action) &actionFinalize, 1919 victim, (void *) options ); 1920 IOLockLock( gJobsLock ); 1921 // hold off free 1922 freeList->setObject( victim ); 1923 // safe if finalize list is append only 1924 gIOFinalizeList->removeObject(0); 1925 } 1926 1927 for( idx = 0; 1928 (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) { 1929 1930 provider = (IOService *) gIOStopProviderList->getObject(idx); 1931 assert( provider ); 1932 1933 if( !provider->isChild( client, gIOServicePlane )) { 1934 // may be multiply queued - nop it 1935 TLOG("%s::nop stop(%s)\n", client->getName(), provider->getName()); 1936 } else { 1937 // not ready for stop if it has clients, skip it 1938 if( (client->__state[1] & kIOServiceTermPhase3State) && client->getClient()) { 1939 TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName()); 1940 idx++; 1941 continue; 1942 } 1943 1944 IOLockUnlock( gJobsLock ); 1945 _workLoopAction( (IOWorkLoop::Action) &actionStop, 1946 provider, (void *) client ); 1947 IOLockLock( gJobsLock ); 1948 // check the finalize list now 1949 doPhase3 = true; 1950 } 1951 // hold off free 1952 freeList->setObject( client ); 1953 freeList->setObject( provider ); 1954 1955 // safe if stop list is append only 1956 gIOStopList->removeObject( idx ); 1957 gIOStopProviderList->removeObject( idx ); 1958 idx = 0; 1959 } 1960 1961 } while( doPhase3 ); 1962 1963 gIOTerminateWork -= workDone; 1964 moreToDo = (gIOTerminateWork != 0); 1965 1966 if( !moreToDo) { 1967 TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount()); 1968 } 1969 1970 } while( moreToDo ); 1971 1972 IOLockUnlock( gJobsLock ); 1973 1974 freeList->release(); 1975 doPhase2List->release(); 1976 didPhase2List->release(); 1977 1978 IOLockLock( gJobsLock ); 1979} 1980 1981bool IOService::finalize( IOOptionBits options ) 1982{ 1983 OSIterator * iter; 1984 IOService * provider; 1985 1986 iter = getProviderIterator(); 1987 assert( iter ); 1988 1989 if( iter) { 1990 while( (provider = (IOService *) iter->getNextObject())) { 1991 1992 // -- compat 1993 if( 0 == (__state[1] & kIOServiceTermPhase3State)) { 1994 /* we come down here on programmatic terminate */ 1995 stop( provider ); 1996 if( provider->isOpen( this )) 1997 provider->close( this ); 1998 detach( provider ); 1999 } else { 2000 //--
2001 if( provider->lockForArbitration( true )) { 2002 if( 0 == (provider->__state[1] & kIOServiceTermPhase3State)) 2003 scheduleStop( provider ); 2004 provider->unlockForArbitration(); 2005 } 2006 } 2007 } 2008 iter->release(); 2009 } 2010 2011 return( true ); 2012} 2013 2014#undef tailQ 2015#undef headQ 2016 2017/* 2018 * Terminate 2019 */ 2020 2021void IOService::doServiceTerminate( IOOptionBits options ) 2022{ 2023} 2024 2025// a method in case someone needs to override it 2026bool IOService::terminateClient( IOService * client, IOOptionBits options ) 2027{ 2028 bool ok; 2029 2030 if( client->isParent( this, gIOServicePlane, true)) 2031 // we are the clients only provider 2032 ok = client->terminate( options ); 2033 else 2034 ok = true; 2035 2036 return( ok ); 2037} 2038 2039bool IOService::terminate( IOOptionBits options ) 2040{ 2041 options |= kIOServiceTerminate; 2042 2043 return( terminatePhase1( options )); 2044} 2045 2046/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2047 2048/* 2049 * Open & close 2050 */ 2051 2052struct ServiceOpenMessageContext 2053{ 2054 IOService * service; 2055 UInt32 type; 2056 IOService * excludeClient; 2057 IOOptionBits options; 2058}; 2059 2060static void serviceOpenMessageApplier( OSObject * object, void * ctx ) 2061{ 2062 ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx; 2063 2064 if( object != context->excludeClient) 2065 context->service->messageClient( context->type, object, (void *) context->options ); 2066} 2067 2068bool IOService::open( IOService * forClient, 2069 IOOptionBits options, 2070 void * arg ) 2071{ 2072 bool ok; 2073 ServiceOpenMessageContext context; 2074 2075 context.service = this; 2076 context.type = kIOMessageServiceIsAttemptingOpen; 2077 context.excludeClient = forClient; 2078 context.options = options; 2079 2080 applyToInterested( gIOGeneralInterest, 2081 &serviceOpenMessageApplier, &context ); 2082 2083 if( false == lockForArbitration(false) ) 2084 return false; 2085 2086 ok = (0 == (__state[0] & kIOServiceInactiveState)); 2087 if( ok) 2088 ok = handleOpen( forClient, options, arg ); 2089 2090 unlockForArbitration(); 2091 2092 return( ok ); 2093} 2094 2095void IOService::close( IOService * forClient, 2096 IOOptionBits options ) 2097{ 2098 bool wasClosed; 2099 bool last = false; 2100 2101 lockForArbitration(); 2102 2103 wasClosed = handleIsOpen( forClient ); 2104 if( wasClosed) { 2105 handleClose( forClient, options ); 2106 last = (__state[1] & kIOServiceTermPhase3State); 2107 } 2108 2109 unlockForArbitration(); 2110 2111 if( last) 2112 forClient->scheduleStop( this ); 2113 2114 else if( wasClosed) { 2115 2116 ServiceOpenMessageContext context; 2117 2118 context.service = this; 2119 context.type = kIOMessageServiceWasClosed; 2120 context.excludeClient = forClient; 2121 context.options = options; 2122 2123 applyToInterested( gIOGeneralInterest, 2124 &serviceOpenMessageApplier, &context ); 2125 } 2126} 2127 2128bool IOService::isOpen( const IOService * forClient ) const 2129{ 2130 IOService * self = (IOService *) this; 2131 bool ok; 2132 2133 self->lockForArbitration(); 2134 2135 ok = handleIsOpen( forClient ); 2136 2137 self->unlockForArbitration(); 2138 2139 return( ok ); 2140} 2141 2142bool IOService::handleOpen( IOService * forClient, 2143 IOOptionBits options, 2144 void * arg ) 2145{ 2146 bool ok; 2147 2148 ok = (0 == __owner); 2149 if( ok ) 2150 __owner = forClient; 2151 2152 else if( options & kIOServiceSeize ) { 2153 ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose, 2154 __owner, (void *) options )); 2155 if( ok && (0 == __owner )) 2156 __owner = forClient; 2157 else 2158 ok = false; 2159 } 2160 return( ok ); 2161} 2162 2163void IOService::handleClose( IOService * forClient, 2164 IOOptionBits options ) 2165{ 2166 if( __owner == forClient) 2167 __owner = 0; 2168} 2169 2170bool IOService::handleIsOpen( const IOService * forClient ) const 2171{ 2172 if( forClient) 2173 return( __owner == forClient ); 2174 else 2175 return( __owner != forClient ); 2176} 2177 2178/* 2179 * Probing & starting 2180 */ 2181static SInt32 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) 2182{ 2183 const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1; 2184 const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2; 2185 SInt32 val1; 2186 SInt32 val2; 2187 2188 val1 = 0; 2189 val2 = 0; 2190 2191 if ( obj1 ) 2192 val1 = obj1->priority; 2193 2194 if ( obj2 ) 2195 val2 = obj2->priority; 2196 2197 return ( val1 - val2 ); 2198} 2199 2200static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref) 2201{ 2202 OSDictionary * dict; 2203 IOService * service; 2204 _IOServiceNotifier * notify; 2205 OSSymbol * key = (OSSymbol *) ref; 2206 OSNumber * offset; 2207 2208 if( (notify = OSDynamicCast( _IOServiceNotifier, entry))) 2209 return( notify->priority ); 2210 2211 else if( (service = OSDynamicCast( IOService, entry))) 2212 offset = OSDynamicCast(OSNumber, service->getProperty( key )); 2213 else if( (dict = OSDynamicCast( OSDictionary, entry))) 2214 offset = OSDynamicCast(OSNumber, dict->getObject( key )); 2215 else { 2216 assert( false ); 2217 offset = 0; 2218 } 2219 2220 if( offset) 2221 return( (SInt32) offset->unsigned32BitValue()); 2222 else 2223 return( kIODefaultProbeScore ); 2224} 2225 2226SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) 2227{ 2228 const OSObject * obj1 = (const OSObject *) inObj1; 2229 const OSObject * obj2 = (const OSObject *) inObj2; 2230 SInt32 val1; 2231 SInt32 val2; 2232 2233 val1 = 0; 2234 val2 = 0; 2235 2236 if ( obj1 ) 2237 val1 = IOServiceObjectOrder( obj1, ref ); 2238 2239 if ( obj2 ) 2240 val2 = IOServiceObjectOrder( obj2, ref ); 2241 2242 return ( val1 - val2 ); 2243} 2244 2245IOService * IOService::getClientWithCategory( const OSSymbol * category ) 2246{ 2247 IOService * service = 0; 2248 OSIterator * iter; 2249 const OSSymbol * nextCat; 2250 2251 iter = getClientIterator(); 2252 if( iter) { 2253 while( (service = (IOService *) iter->getNextObject())) { 2254 if( kIOServiceInactiveState & service->__state[0]) 2255 continue; 2256 nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol, 2257 service->getProperty( gIOMatchCategoryKey )); 2258 if( category == nextCat) 2259 break; 2260 } 2261 iter->release(); 2262 } 2263 return( service ); 2264} 2265 2266bool IOService::invokeNotifer( _IOServiceNotifier * notify ) 2267{ 2268 _IOServiceNotifierInvocation invocation; 2269 bool willNotify; 2270 bool ret = true; 2271 2272 invocation.thread = current_thread(); 2273 2274 LOCKWRITENOTIFY(); 2275 willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); 2276 2277 if( willNotify) { 2278 queue_enter( ¬ify->handlerInvocations, &invocation, 2279 _IOServiceNotifierInvocation *, link ); 2280 } 2281 UNLOCKNOTIFY(); 2282 2283 if( willNotify) { 2284 2285 ret = (*notify->handler)( notify->target, notify->ref, this ); 2286 2287 LOCKWRITENOTIFY(); 2288 queue_remove( ¬ify->handlerInvocations, &invocation, 2289 _IOServiceNotifierInvocation *, link ); 2290 if( kIOServiceNotifyWaiter & notify->state) { 2291 notify->state &= ~kIOServiceNotifyWaiter; 2292 WAKEUPNOTIFY( notify ); 2293 } 2294 UNLOCKNOTIFY(); 2295 } 2296 2297 return( ret ); 2298} 2299 2300/* 2301 * Alloc and probe matching classes, 2302 * called on the provider instance 2303 */ 2304 2305void IOService::probeCandidates( OSOrderedSet * matches ) 2306{ 2307 OSDictionary * match = 0; 2308 OSSymbol * symbol; 2309 IOService * inst; 2310 IOService * newInst; 2311 OSDictionary * props; 2312 SInt32 score; 2313 OSNumber * newPri; 2314 OSOrderedSet * familyMatches = 0; 2315 OSOrderedSet * startList; 2316 OSDictionary * startDict = 0; 2317 const OSSymbol * category; 2318 OSIterator * iter; 2319 _IOServiceNotifier * notify; 2320 OSObject * nextMatch = 0; 2321 bool started; 2322 bool needReloc = false; 2323#if IOMATCHDEBUG 2324 SInt64 debugFlags; 2325#endif 2326 2327 assert( matches ); 2328 while( !needReloc && (nextMatch = matches->getFirstObject())) { 2329 2330 nextMatch->retain(); 2331 matches->removeObject(nextMatch); 2332 2333 if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) { 2334 2335 lockForArbitration(); 2336 if( 0 == (__state[0] & kIOServiceInactiveState)) 2337 invokeNotifer( notify ); 2338 unlockForArbitration(); 2339 nextMatch->release(); 2340 nextMatch = 0; 2341 continue; 2342 2343 } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) { 2344 nextMatch->release(); 2345 nextMatch = 0; 2346 continue; 2347 } 2348 2349 props = 0; 2350#if IOMATCHDEBUG 2351 debugFlags = getDebugFlags( match ); 2352#endif 2353 2354 do { 2355 category = OSDynamicCast( OSSymbol, 2356 match->getObject( gIOMatchCategoryKey )); 2357 if( 0 == category) 2358 category = gIODefaultMatchCategoryKey; 2359 2360 if( getClientWithCategory( category )) { 2361#if IOMATCHDEBUG 2362 if( debugFlags & kIOLogMatch) 2363 LOG("%s: match category %s exists\n", getName(), 2364 category->getCStringNoCopy()); 2365#endif 2366 nextMatch->release(); 2367 nextMatch = 0; 2368 continue; 2369 } 2370 2371 // create a copy now in case its modified during matching 2372 props = OSDictionary::withDictionary( match, match->getCount()); 2373 if( 0 == props) 2374 continue; 2375 props->setCapacityIncrement(1); 2376 2377 // check the nub matches 2378 if( false == passiveMatch( props, true )) 2379 continue; 2380 2381 // Check to see if driver reloc has been loaded. 2382 needReloc = (false == gIOCatalogue->isModuleLoaded( match )); 2383 if( needReloc) { 2384#if IOMATCHDEBUG 2385 if( debugFlags & kIOLogCatalogue) 2386 LOG("%s: stalling for module\n", getName()); 2387#endif 2388 // If reloc hasn't been loaded, exit; 2389 // reprobing will occur after reloc has been loaded. 2390 continue; 2391 } 2392 2393 // reorder on family matchPropertyTable score. 2394 if( 0 == familyMatches) 2395 familyMatches = OSOrderedSet::withCapacity( 1, 2396 IOServiceOrdering, (void *) gIOProbeScoreKey ); 2397 if( familyMatches) 2398 familyMatches->setObject( props ); 2399 2400 } while( false ); 2401 2402 if (nextMatch) { 2403 nextMatch->release(); 2404 nextMatch = 0; 2405 } 2406 if( props) 2407 props->release(); 2408 } 2409 matches->release(); 2410 matches = 0; 2411 2412 if( familyMatches) { 2413 2414 while( !needReloc 2415 && (props = (OSDictionary *) familyMatches->getFirstObject())) { 2416 2417 props->retain(); 2418 familyMatches->removeObject( props ); 2419 2420 inst = 0; 2421 newInst = 0; 2422#if IOMATCHDEBUG 2423 debugFlags = getDebugFlags( props ); 2424#endif 2425 do { 2426 symbol = OSDynamicCast( OSSymbol, 2427 props->getObject( gIOClassKey)); 2428 if( !symbol) 2429 continue; 2430 2431 // alloc the driver instance 2432 inst = (IOService *) OSMetaClass::allocClassWithName( symbol); 2433 2434 if( !inst) { 2435 IOLog("Couldn't alloc class \"%s\"\n", 2436 symbol->getCStringNoCopy()); 2437 continue; 2438 } 2439 2440 // init driver instance 2441 if( !(inst->init( props ))) { 2442#if IOMATCHDEBUG 2443 if( debugFlags & kIOLogStart) 2444 IOLog("%s::init fails\n", symbol->getCStringNoCopy()); 2445#endif 2446 continue; 2447 } 2448 if( __state[1] & kIOServiceSynchronousState) 2449 inst->__state[1] |= kIOServiceSynchronousState; 2450 2451 // give the driver the default match category if not specified 2452 category = OSDynamicCast( OSSymbol, 2453 props->getObject( gIOMatchCategoryKey )); 2454 if( 0 == category) 2455 category = gIODefaultMatchCategoryKey; 2456 inst->setProperty( gIOMatchCategoryKey, (OSObject *) category ); 2457 2458 // attach driver instance 2459 if( !(inst->attach( this ))) 2460 continue; 2461 2462 // pass in score from property table 2463 score = familyMatches->orderObject( props ); 2464 2465 // & probe the new driver instance 2466#if IOMATCHDEBUG 2467 if( debugFlags & kIOLogProbe) 2468 LOG("%s::probe(%s)\n", 2469 inst->getMetaClass()->getClassName(), getName()); 2470#endif 2471 2472 newInst = inst->probe( this, &score ); 2473 inst->detach( this ); 2474 if( 0 == newInst) { 2475#if IOMATCHDEBUG 2476 if( debugFlags & kIOLogProbe) 2477 IOLog("%s::probe fails\n", symbol->getCStringNoCopy()); 2478#endif 2479 continue; 2480 } 2481 2482 // save the score 2483 newPri = OSNumber::withNumber( score, 32 ); 2484 if( newPri) { 2485 newInst->setProperty( gIOProbeScoreKey, newPri ); 2486 newPri->release(); 2487 } 2488 2489 // add to start list for the match category 2490 if( 0 == startDict) 2491 startDict = OSDictionary::withCapacity( 1 ); 2492 assert( startDict ); 2493 startList = (OSOrderedSet *) 2494 startDict->getObject( category ); 2495 if( 0 == startList) { 2496 startList = OSOrderedSet::withCapacity( 1, 2497 IOServiceOrdering, (void *) gIOProbeScoreKey ); 2498 if( startDict && startList) { 2499 startDict->setObject( category, startList ); 2500 startList->release(); 2501 } 2502 } 2503 assert( startList ); 2504 if( startList) 2505 startList->setObject( newInst ); 2506 2507 } while( false ); 2508 2509 props->release(); 2510 if( inst) 2511 inst->release(); 2512 } 2513 familyMatches->release(); 2514 familyMatches = 0; 2515 } 2516 2517 // start the best (until success) of each category 2518 2519 iter = OSCollectionIterator::withCollection( startDict ); 2520 if( iter) { 2521 while( (category = (const OSSymbol *) iter->getNextObject())) { 2522 2523 startList = (OSOrderedSet *) startDict->getObject( category ); 2524 assert( startList ); 2525 if( !startList) 2526 continue; 2527 2528 started = false; 2529 while( true // (!started) 2530 && (inst = (IOService *)startList->getFirstObject())) { 2531 2532 inst->retain(); 2533 startList->removeObject(inst); 2534 2535#if IOMATCHDEBUG 2536 debugFlags = getDebugFlags( inst->getPropertyTable() ); 2537 2538 if( debugFlags & kIOLogStart) { 2539 if( started) 2540 LOG( "match category exists, skipping " ); 2541 LOG( "%s::start(%s) <%d>\n", inst->getName(), 2542 getName(), inst->getRetainCount()); 2543 } 2544#endif 2545 if( false == started) 2546 started = startCandidate( inst ); 2547#if IOMATCHDEBUG 2548 if( (debugFlags & kIOLogStart) && (false == started)) 2549 LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(), 2550 inst->getRetainCount()); 2551#endif 2552 inst->release(); 2553 } 2554 } 2555 iter->release(); 2556 } 2557 2558 2559 // adjust the busy count by -1 if matching is stalled for a module, 2560 // or +1 if a previously stalled matching is complete. 2561 lockForArbitration(); 2562 SInt32 adjBusy = 0; 2563 if( needReloc) { 2564 adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1; 2565 if( adjBusy) 2566 __state[1] |= kIOServiceModuleStallState; 2567 2568 } else if( __state[1] & kIOServiceModuleStallState) { 2569 __state[1] &= ~kIOServiceModuleStallState; 2570 adjBusy = -1; 2571 } 2572 if( adjBusy) 2573 _adjustBusy( adjBusy ); 2574 unlockForArbitration(); 2575 2576 if( startDict) 2577 startDict->release(); 2578} 2579 2580/* 2581 * Start a previously attached & probed instance, 2582 * called on exporting object instance 2583 */ 2584 2585bool IOService::startCandidate( IOService * service ) 2586{ 2587 bool ok; 2588 2589 ok = service->attach( this ); 2590 2591 if( ok) 2592 { 2593 if (this != gIOResources) 2594 { 2595 // stall for any nub resources 2596 checkResources(); 2597 // stall for any driver resources 2598 service->checkResources(); 2599 } 2600 2601 AbsoluteTime startTime; 2602 AbsoluteTime endTime; 2603 UInt64 nano; 2604 2605 if (kIOLogStart & gIOKitDebug) 2606 clock_get_uptime(&startTime); 2607 2608 ok = service->start(this); 2609 2610 if (kIOLogStart & gIOKitDebug) 2611 { 2612 clock_get_uptime(&endTime); 2613 2614 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) 2615 { 2616 SUB_ABSOLUTETIME(&endTime, &startTime); 2617 absolutetime_to_nanoseconds(endTime, &nano); 2618 if (nano > 500000000ULL) 2619 IOLog("%s::start took %ld ms\n", service->getName(), (UInt32)(nano / 1000000ULL)); 2620 } 2621 } 2622 if( !ok) 2623 service->detach( this ); 2624 } 2625 return( ok ); 2626} 2627 2628IOService * IOService::resources( void ) 2629{ 2630 return( gIOResources ); 2631} 2632 2633void IOService::publishResource( const char * key, OSObject * value ) 2634{ 2635 const OSSymbol * sym; 2636 2637 if( (sym = OSSymbol::withCString( key))) { 2638 publishResource( sym, value); 2639 sym->release(); 2640 } 2641} 2642 2643void IOService::publishResource( const OSSymbol * key, OSObject * value ) 2644{ 2645 if( 0 == value) 2646 value = (OSObject *) gIOServiceKey; 2647 2648 gIOResources->setProperty( key, value); 2649 2650 if( IORecursiveLockHaveLock( gNotificationLock)) 2651 return; 2652 2653 gIOResourceGenerationCount++; 2654 gIOResources->registerService(); 2655} 2656 2657bool IOService::addNeededResource( const char * key ) 2658{ 2659 OSObject * resourcesProp; 2660 OSSet * set; 2661 OSString * newKey; 2662 bool ret; 2663 2664 resourcesProp = getProperty( gIOResourceMatchKey ); 2665 2666 newKey = OSString::withCString( key ); 2667 if( (0 == resourcesProp) || (0 == newKey)) 2668 return( false); 2669 2670 set = OSDynamicCast( OSSet, resourcesProp ); 2671 if( !set) { 2672 set = OSSet::withCapacity( 1 ); 2673 if( set) 2674 set->setObject( resourcesProp ); 2675 } 2676 else 2677 set->retain(); 2678 2679 set->setObject( newKey ); 2680 newKey->release(); 2681 ret = setProperty( gIOResourceMatchKey, set ); 2682 set->release(); 2683 2684 return( ret ); 2685} 2686 2687bool IOService::checkResource( OSObject * matching ) 2688{ 2689 OSString * str; 2690 OSDictionary * table; 2691 2692 if( (str = OSDynamicCast( OSString, matching ))) { 2693 if( gIOResources->getProperty( str )) 2694 return( true ); 2695 } 2696 2697 if( str) 2698 table = resourceMatching( str ); 2699 else if( (table = OSDynamicCast( OSDictionary, matching ))) 2700 table->retain(); 2701 else { 2702 IOLog("%s: Can't match using: %s\n", getName(), 2703 matching->getMetaClass()->getClassName()); 2704 /* false would stall forever */ 2705 return( true ); 2706 } 2707 2708 if( gIOKitDebug & kIOLogConfig) 2709 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName()); 2710 2711 waitForService( table ); 2712 2713 if( gIOKitDebug & kIOLogConfig) 2714 LOG("config(%x): waking\n", (int) IOThreadSelf() ); 2715 2716 return( true ); 2717} 2718 2719bool IOService::checkResources( void ) 2720{ 2721 OSObject * resourcesProp; 2722 OSSet * set; 2723 OSIterator * iter; 2724 bool ok; 2725 2726 resourcesProp = getProperty( gIOResourceMatchKey ); 2727 if( 0 == resourcesProp) 2728 return( true ); 2729 2730 if( (set = OSDynamicCast( OSSet, resourcesProp ))) { 2731 2732 iter = OSCollectionIterator::withCollection( set ); 2733 ok = (0 != iter); 2734 while( ok && (resourcesProp = iter->getNextObject()) ) 2735 ok = checkResource( resourcesProp ); 2736 if( iter) 2737 iter->release(); 2738 2739 } else 2740 ok = checkResource( resourcesProp ); 2741 2742 return( ok ); 2743} 2744 2745 2746void _IOConfigThread::configThread( void ) 2747{ 2748 _IOConfigThread * inst; 2749 2750 do { 2751 if( !(inst = new _IOConfigThread)) 2752 continue; 2753 if( !inst->init()) 2754 continue; 2755 if( !(IOCreateThread((IOThreadFunc) &_IOConfigThread::main, inst ))) 2756 continue; 2757 2758 return; 2759 2760 } while( false); 2761 2762 if( inst) 2763 inst->release(); 2764 2765 return; 2766} 2767 2768void _IOConfigThread::free( void ) 2769{ 2770 OSObject::free(); 2771} 2772 2773void IOService::doServiceMatch( IOOptionBits options ) 2774{ 2775 _IOServiceNotifier * notify; 2776 OSIterator * iter; 2777 OSOrderedSet * matches; 2778 SInt32 catalogGeneration; 2779 bool keepGuessing = true; 2780 bool reRegistered = true; 2781 2782// job->nub->deliverNotification( gIOPublishNotification, 2783// kIOServiceRegisteredState, 0xffffffff ); 2784 2785 while( keepGuessing ) { 2786 2787 matches = gIOCatalogue->findDrivers( this, &catalogGeneration ); 2788 // the matches list should always be created by findDrivers() 2789 if( matches) { 2790 2791 lockForArbitration(); 2792 if( 0 == (__state[0] & kIOServiceFirstPublishState)) 2793 deliverNotification( gIOFirstPublishNotification, 2794 kIOServiceFirstPublishState, 0xffffffff ); 2795 LOCKREADNOTIFY(); 2796 __state[1] &= ~kIOServiceNeedConfigState; 2797 __state[1] |= kIOServiceConfigState; 2798 __state[0] |= kIOServiceRegisteredState; 2799 2800 if( reRegistered && (0 == (__state[0] & kIOServiceInactiveState))) { 2801 2802 iter = OSCollectionIterator::withCollection( (OSOrderedSet *) 2803 gNotifications->getObject( gIOPublishNotification ) ); 2804 if( iter) { 2805 while((notify = (_IOServiceNotifier *) 2806 iter->getNextObject())) { 2807 2808 if( passiveMatch( notify->matching ) 2809 && (kIOServiceNotifyEnable & notify->state)) 2810 matches->setObject( notify ); 2811 } 2812 iter->release(); 2813 } 2814 } 2815 2816 UNLOCKNOTIFY(); 2817 unlockForArbitration(); 2818 2819 if( matches->getCount() && (kIOReturnSuccess == getResources())) 2820 probeCandidates( matches ); 2821 else 2822 matches->release(); 2823 } 2824 2825 lockForArbitration(); 2826 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState)); 2827 keepGuessing = 2828 (reRegistered || (catalogGeneration != 2829 gIOCatalogue->getGenerationCount())) 2830 && (0 == (__state[0] & kIOServiceInactiveState)); 2831 2832 if( keepGuessing) 2833 unlockForArbitration(); 2834 } 2835 2836 if( (0 == (__state[0] & kIOServiceInactiveState)) 2837 && (0 == (__state[1] & kIOServiceModuleStallState)) ) { 2838 deliverNotification( gIOMatchedNotification, 2839 kIOServiceMatchedState, 0xffffffff ); 2840 if( 0 == (__state[0] & kIOServiceFirstMatchState)) 2841 deliverNotification( gIOFirstMatchNotification, 2842 kIOServiceFirstMatchState, 0xffffffff ); 2843 } 2844 2845 __state[1] &= ~kIOServiceConfigState; 2846 if( __state[0] & kIOServiceInactiveState) 2847 scheduleTerminatePhase2(); 2848 2849 _adjustBusy( -1 ); 2850 unlockForArbitration(); 2851} 2852 2853UInt32 IOService::_adjustBusy( SInt32 delta ) 2854{ 2855 IOService * next; 2856 UInt32 count; 2857 UInt32 result; 2858 bool wasQuiet, nowQuiet, needWake; 2859 2860 next = this; 2861 result = __state[1] & kIOServiceBusyStateMask; 2862 2863 if( delta) do { 2864 if( next != this) 2865 next->lockForArbitration(); 2866 count = next->__state[1] & kIOServiceBusyStateMask; 2867 assert( count < kIOServiceBusyMax); 2868 wasQuiet = (0 == count); 2869 assert( (!wasQuiet) || (delta > 0)); 2870 next->__state[1] += delta; 2871 nowQuiet = (0 == (next->__state[1] & kIOServiceBusyStateMask)); 2872 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1])); 2873 2874 if( needWake) { 2875 next->__state[1] &= ~kIOServiceBusyWaiterState; 2876 IOLockLock( gIOServiceBusyLock ); 2877 thread_wakeup( (event_t) next); 2878 IOLockUnlock( gIOServiceBusyLock ); 2879 } 2880 if( next != this) 2881 next->unlockForArbitration(); 2882 2883 if( (wasQuiet || nowQuiet) ) { 2884 OSArray * array; 2885 unsigned int index; 2886 OSObject * interested; 2887 2888 array = OSDynamicCast( OSArray, next->getProperty( gIOBusyInterest )); 2889 if( array) { 2890 LOCKREADNOTIFY(); 2891 for( index = 0; 2892 (interested = array->getObject( index )); 2893 index++) { 2894 next->messageClient(kIOMessageServiceBusyStateChange, 2895 interested, (void *) wasQuiet /* busy now */); 2896 } 2897 UNLOCKNOTIFY(); 2898 } 2899 2900 if( nowQuiet && (next == gIOServiceRoot)) 2901 OSMetaClass::considerUnloads(); 2902 } 2903 2904 delta = nowQuiet ? -1 : +1; 2905 2906 } while( (wasQuiet || nowQuiet) && (next = next->getProvider())); 2907 2908 return( result ); 2909} 2910 2911void IOService::adjustBusy( SInt32 delta ) 2912{ 2913 lockForArbitration(); 2914 _adjustBusy( delta ); 2915 unlockForArbitration(); 2916} 2917 2918UInt32 IOService::getBusyState( void ) 2919{ 2920 return( __state[1] & kIOServiceBusyStateMask ); 2921} 2922 2923IOReturn IOService::waitForState( UInt32 mask, UInt32 value, 2924 mach_timespec_t * timeout ) 2925{ 2926 bool wait; 2927 int waitResult = THREAD_AWAKENED; 2928 bool computeDeadline = true; 2929 AbsoluteTime abstime; 2930 2931 do { 2932 lockForArbitration(); 2933 IOLockLock( gIOServiceBusyLock ); 2934 wait = (value != (__state[1] & mask)); 2935 if( wait) { 2936 __state[1] |= kIOServiceBusyWaiterState; 2937 unlockForArbitration(); 2938 if( timeout ) { 2939 if( computeDeadline ) { 2940 AbsoluteTime nsinterval; 2941 clock_interval_to_absolutetime_interval( 2942 timeout->tv_sec, kSecondScale, &abstime ); 2943 clock_interval_to_absolutetime_interval( 2944 timeout->tv_nsec, kNanosecondScale, &nsinterval ); 2945 ADD_ABSOLUTETIME( &abstime, &nsinterval ); 2946 clock_absolutetime_interval_to_deadline( 2947 abstime, &abstime ); 2948 computeDeadline = false; 2949 } 2950 2951 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime)); 2952 } 2953 else 2954 assert_wait((event_t)this, THREAD_UNINT ); 2955 } else 2956 unlockForArbitration(); 2957 IOLockUnlock( gIOServiceBusyLock ); 2958 if( wait) 2959 waitResult = thread_block(THREAD_CONTINUE_NULL); 2960 2961 } while( wait && (waitResult != THREAD_TIMED_OUT)); 2962 2963 if( waitResult == THREAD_TIMED_OUT) 2964 return( kIOReturnTimeout ); 2965 else 2966 return( kIOReturnSuccess ); 2967} 2968 2969IOReturn IOService::waitQuiet( mach_timespec_t * timeout ) 2970{ 2971 return( waitForState( kIOServiceBusyStateMask, 0, timeout )); 2972} 2973 2974bool IOService::serializeProperties( OSSerialize * s ) const 2975{ 2976#if 0 2977 ((IOService *)this)->setProperty( ((IOService *)this)->__state, 2978 sizeof( __state), "__state"); 2979#endif 2980 return( super::serializeProperties(s) ); 2981} 2982 2983 2984void _IOConfigThread::main( _IOConfigThread * self ) 2985{ 2986 _IOServiceJob * job; 2987 IOService * nub; 2988 bool alive = true; 2989 2990 do { 2991 2992// randomDelay(); 2993 2994 semaphore_wait( gJobsSemaphore ); 2995 2996 IOTakeLock( gJobsLock ); 2997 job = (_IOServiceJob *) gJobs->getFirstObject(); 2998 job->retain(); 2999 gJobs->removeObject(job); 3000 if( job) {
3001 gOutstandingJobs--; 3002// gNumConfigThreads--; // we're out of service 3003 gNumWaitingThreads--; // we're out of service 3004 } 3005 IOUnlock( gJobsLock ); 3006 3007 if( job) { 3008 3009 nub = job->nub; 3010 3011 if( gIOKitDebug & kIOLogConfig) 3012 LOG("config(%x): starting on %s, %d\n", 3013 (int) IOThreadSelf(), job->nub->getName(), job->type); 3014 3015 switch( job->type) { 3016 3017 case kMatchNubJob: 3018 nub->doServiceMatch( job->options ); 3019 break; 3020 3021 default: 3022 LOG("config(%x): strange type (%d)\n", 3023 (int) IOThreadSelf(), job->type ); 3024 break; 3025 } 3026 3027 nub->release(); 3028 job->release(); 3029 3030 IOTakeLock( gJobsLock ); 3031 alive = (gOutstandingJobs > gNumWaitingThreads); 3032 if( alive) 3033 gNumWaitingThreads++; // back in service 3034// gNumConfigThreads++; 3035 else { 3036 if( 0 == --gNumConfigThreads) { 3037// IOLog("MATCH IDLE\n"); 3038 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false ); 3039 } 3040 } 3041 IOUnlock( gJobsLock ); 3042 } 3043 3044 } while( alive ); 3045 3046 if( gIOKitDebug & kIOLogConfig) 3047 LOG("config(%x): terminating\n", (int) IOThreadSelf() ); 3048 3049 self->release(); 3050} 3051 3052IOReturn IOService::waitMatchIdle( UInt32 msToWait ) 3053{ 3054 bool wait; 3055 int waitResult = THREAD_AWAKENED; 3056 bool computeDeadline = true; 3057 AbsoluteTime abstime; 3058 3059 IOLockLock( gJobsLock ); 3060 do { 3061 wait = (0 != gNumConfigThreads); 3062 if( wait) { 3063 if( msToWait) { 3064 if( computeDeadline ) { 3065 clock_interval_to_absolutetime_interval( 3066 msToWait, kMillisecondScale, &abstime ); 3067 clock_absolutetime_interval_to_deadline( 3068 abstime, &abstime ); 3069 computeDeadline = false; 3070 } 3071 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads, 3072 abstime, THREAD_UNINT ); 3073 } else { 3074 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads, 3075 THREAD_UNINT ); 3076 } 3077 } 3078 } while( wait && (waitResult != THREAD_TIMED_OUT)); 3079 IOLockUnlock( gJobsLock ); 3080 3081 if( waitResult == THREAD_TIMED_OUT) 3082 return( kIOReturnTimeout ); 3083 else 3084 return( kIOReturnSuccess ); 3085} 3086 3087void _IOServiceJob::pingConfig( _IOServiceJob * job ) 3088{ 3089 int count; 3090 bool create; 3091 3092 assert( job ); 3093 3094 IOTakeLock( gJobsLock ); 3095 3096 gOutstandingJobs++; 3097 gJobs->setLastObject( job ); 3098 3099 count = gNumWaitingThreads; 3100// if( gNumConfigThreads) count++;// assume we're called from a config thread 3101 3102 create = ( (gOutstandingJobs > count) 3103 && (gNumConfigThreads < kMaxConfigThreads) ); 3104 if( create) { 3105 gNumConfigThreads++; 3106 gNumWaitingThreads++; 3107 } 3108 3109 IOUnlock( gJobsLock ); 3110 3111 job->release(); 3112 3113 if( create) { 3114 if( gIOKitDebug & kIOLogConfig) 3115 LOG("config(%d): creating\n", gNumConfigThreads - 1); 3116 _IOConfigThread::configThread(); 3117 } 3118 3119 semaphore_signal( gJobsSemaphore ); 3120} 3121 3122// internal - call with gNotificationLock 3123OSObject * IOService::getExistingServices( OSDictionary * matching, 3124 IOOptionBits inState, IOOptionBits options ) 3125{ 3126 OSObject * current = 0; 3127 OSIterator * iter; 3128 IOService * service; 3129 OSObject * obj; 3130 3131 if( !matching) 3132 return( 0 ); 3133 3134 if(true 3135 && (obj = matching->getObject(gIOProviderClassKey)) 3136 && gIOResourcesKey 3137 && gIOResourcesKey->isEqualTo(obj) 3138 && (service = gIOResources)) 3139 { 3140 if( (inState == (service->__state[0] & inState)) 3141 && (0 == (service->__state[0] & kIOServiceInactiveState)) 3142 && service->passiveMatch( matching )) 3143 { 3144 if( options & kIONotifyOnce) 3145 current = service; 3146 else 3147 current = OSSet::withObjects( 3148 (const OSObject **) &service, 1, 1 ); 3149 } 3150 } 3151 else 3152 { 3153 iter = IORegistryIterator::iterateOver( gIOServicePlane, 3154 kIORegistryIterateRecursively ); 3155 if( iter) { 3156 do { 3157 iter->reset(); 3158 while( (service = (IOService *) iter->getNextObject())) { 3159 if( (inState == (service->__state[0] & inState)) 3160 && (0 == (service->__state[0] & kIOServiceInactiveState)) 3161 && service->passiveMatch( matching )) { 3162 3163 if( options & kIONotifyOnce) { 3164 current = service; 3165 break; 3166 } 3167 if( current) 3168 ((OSSet *)current)->setObject( service ); 3169 else 3170 current = OSSet::withObjects( 3171 (const OSObject **) &service, 1, 1 ); 3172 } 3173 } 3174 } while( !service && !iter->isValid()); 3175 iter->release(); 3176 } 3177 } 3178 3179 if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) { 3180 iter = OSCollectionIterator::withCollection( (OSSet *)current ); 3181 current->release(); 3182 current = iter; 3183 } 3184 3185 return( current ); 3186} 3187 3188// public version 3189OSIterator * IOService::getMatchingServices( OSDictionary * matching ) 3190{ 3191 OSIterator * iter; 3192 3193 // is a lock even needed? 3194 LOCKWRITENOTIFY(); 3195 3196 iter = (OSIterator *) getExistingServices( matching, 3197 kIOServiceMatchedState ); 3198 3199 UNLOCKNOTIFY(); 3200 3201 return( iter ); 3202} 3203 3204 3205// internal - call with gNotificationLock 3206IONotifier * IOService::setNotification( 3207 const OSSymbol * type, OSDictionary * matching, 3208 IOServiceNotificationHandler handler, void * target, void * ref, 3209 SInt32 priority ) 3210{ 3211 _IOServiceNotifier * notify = 0; 3212 OSOrderedSet * set; 3213 3214 if( !matching) 3215 return( 0 ); 3216 3217 notify = new _IOServiceNotifier; 3218 if( notify && !notify->init()) { 3219 notify->release(); 3220 notify = 0; 3221 } 3222 3223 if( notify) { 3224 notify->matching = matching; 3225 notify->handler = handler; 3226 notify->target = target; 3227 notify->ref = ref; 3228 notify->priority = priority; 3229 notify->state = kIOServiceNotifyEnable; 3230 queue_init( ¬ify->handlerInvocations ); 3231 3232 ////// queue 3233 3234 if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) { 3235 set = OSOrderedSet::withCapacity( 1, 3236 IONotifyOrdering, 0 ); 3237 if( set) { 3238 gNotifications->setObject( type, set ); 3239 set->release(); 3240 } 3241 } 3242 notify->whence = set; 3243 if( set) 3244 set->setObject( notify ); 3245 } 3246 3247 return( notify ); 3248} 3249 3250// internal - call with gNotificationLock 3251IONotifier * IOService::doInstallNotification( 3252 const OSSymbol * type, OSDictionary * matching, 3253 IOServiceNotificationHandler handler, 3254 void * target, void * ref, 3255 SInt32 priority, OSIterator ** existing ) 3256{ 3257 OSIterator * exist; 3258 IONotifier * notify; 3259 IOOptionBits inState; 3260 3261 if( !matching) 3262 return( 0 ); 3263 3264 if( type == gIOPublishNotification) 3265 inState = kIOServiceRegisteredState; 3266 3267 else if( type == gIOFirstPublishNotification) 3268 inState = kIOServiceFirstPublishState; 3269 3270 else if( (type == gIOMatchedNotification) 3271 || (type == gIOFirstMatchNotification)) 3272 inState = kIOServiceMatchedState; 3273 else if( type == gIOTerminatedNotification) 3274 inState = 0; 3275 else 3276 return( 0 ); 3277 3278 notify = setNotification( type, matching, handler, target, ref, priority ); 3279 3280 if( inState) 3281 // get the current set 3282 exist = (OSIterator *) getExistingServices( matching, inState ); 3283 else 3284 exist = 0; 3285 3286 *existing = exist; 3287 3288 return( notify ); 3289} 3290 3291 3292IONotifier * IOService::installNotification( 3293 const OSSymbol * type, OSDictionary * matching, 3294 IOServiceNotificationHandler handler, 3295 void * target, void * ref, 3296 SInt32 priority, OSIterator ** existing ) 3297{ 3298 IONotifier * notify; 3299 3300 LOCKWRITENOTIFY(); 3301 3302 notify = doInstallNotification( type, matching, handler, target, ref, 3303 priority, existing ); 3304 3305 UNLOCKNOTIFY(); 3306 3307 return( notify ); 3308} 3309 3310IONotifier * IOService::addNotification( 3311 const OSSymbol * type, OSDictionary * matching, 3312 IOServiceNotificationHandler handler, 3313 void * target, void * ref, 3314 SInt32 priority ) 3315{ 3316 OSIterator * existing; 3317 _IOServiceNotifier * notify; 3318 IOService * next; 3319 3320 notify = (_IOServiceNotifier *) installNotification( type, matching, 3321 handler, target, ref, priority, &existing ); 3322 3323 // send notifications for existing set 3324 if( existing) { 3325 3326 notify->retain(); // in case handler remove()s 3327 while( (next = (IOService *) existing->getNextObject())) { 3328 3329 next->lockForArbitration(); 3330 if( 0 == (next->__state[0] & kIOServiceInactiveState)) 3331 next->invokeNotifer( notify ); 3332 next->unlockForArbitration(); 3333 } 3334 notify->release(); 3335 existing->release(); 3336 } 3337 3338 return( notify ); 3339} 3340 3341struct SyncNotifyVars { 3342 semaphore_port_t waitHere; 3343 IOService * result; 3344}; 3345 3346bool IOService::syncNotificationHandler( 3347 void * /* target */, void * ref, 3348 IOService * newService ) 3349{ 3350 3351 // result may get written more than once before the 3352 // notification is removed! 3353 ((SyncNotifyVars *) ref)->result = newService; 3354 semaphore_signal( ((SyncNotifyVars *) ref)->waitHere ); 3355 3356 return( false ); 3357} 3358 3359IOService * IOService::waitForService( OSDictionary * matching, 3360 mach_timespec_t * timeout ) 3361{ 3362 IONotifier * notify = 0; 3363 // priority doesn't help us much since we need a thread wakeup 3364 SInt32 priority = 0; 3365 SyncNotifyVars state; 3366 kern_return_t err = kIOReturnBadArgument; 3367 3368 if( !matching) 3369 return( 0 ); 3370 3371 state.waitHere = 0; 3372 state.result = 0; 3373 3374 LOCKWRITENOTIFY(); 3375 3376 do { 3377 3378 state.result = (IOService *) getExistingServices( matching, 3379 kIOServiceMatchedState, kIONotifyOnce ); 3380 if( state.result) 3381 continue; 3382 3383 err = semaphore_create( kernel_task, &state.waitHere, 3384 SYNC_POLICY_FIFO, 0 ); 3385 if( KERN_SUCCESS != err) 3386 continue; 3387 3388 notify = IOService::setNotification( gIOMatchedNotification, matching, 3389 &IOService::syncNotificationHandler, (void *) 0, 3390 (void *) &state, priority ); 3391 3392 } while( false ); 3393 3394 UNLOCKNOTIFY(); 3395 3396 if( notify) { 3397 if( timeout) 3398 err = semaphore_timedwait( state.waitHere, *timeout ); 3399 else 3400 err = semaphore_wait( state.waitHere ); 3401 } 3402 3403 if( notify) 3404 notify->remove(); // dequeues 3405 else 3406 matching->release(); 3407 if( state.waitHere) 3408 semaphore_destroy( kernel_task, state.waitHere ); 3409 3410 return( state.result ); 3411} 3412 3413void IOService::deliverNotification( const OSSymbol * type, 3414 IOOptionBits orNewState, IOOptionBits andNewState ) 3415{ 3416 _IOServiceNotifier * notify; 3417 OSIterator * iter; 3418 OSArray * willSend = 0; 3419 3420 lockForArbitration(); 3421 3422 if( (0 == (__state[0] & kIOServiceInactiveState)) 3423 || (type == gIOTerminatedNotification)) { 3424 3425 LOCKREADNOTIFY(); 3426 3427 iter = OSCollectionIterator::withCollection( (OSOrderedSet *) 3428 gNotifications->getObject( type ) ); 3429 3430 if( iter) { 3431 while( (notify = (_IOServiceNotifier *) iter->getNextObject())) { 3432 3433 if( passiveMatch( notify->matching) 3434 && (kIOServiceNotifyEnable & notify->state)) { 3435 if( 0 == willSend) 3436 willSend = OSArray::withCapacity(8); 3437 if( willSend) 3438 willSend->setObject( notify ); 3439 } 3440 } 3441 iter->release(); 3442 } 3443 3444 __state[0] = (__state[0] | orNewState) & andNewState; 3445 3446 UNLOCKNOTIFY(); 3447 } 3448 3449 if( willSend) { 3450 for( unsigned int idx = 0; 3451 (notify = (_IOServiceNotifier *) willSend->getObject(idx)); 3452 idx++) { 3453 invokeNotifer( notify ); 3454 } 3455 willSend->release(); 3456 } 3457 unlockForArbitration(); 3458} 3459 3460IOOptionBits IOService::getState( void ) const 3461{ 3462 return( __state[0] ); 3463} 3464 3465/* 3466 * Helpers to make matching objects for simple cases 3467 */ 3468 3469OSDictionary * IOService::serviceMatching( const OSString * name, 3470 OSDictionary * table ) 3471{ 3472 if( !table) 3473 table = OSDictionary::withCapacity( 2 ); 3474 if( table) 3475 table->setObject(gIOProviderClassKey, (OSObject *)name ); 3476 3477 return( table ); 3478} 3479 3480OSDictionary * IOService::serviceMatching( const char * name, 3481 OSDictionary * table ) 3482{ 3483 const OSString * str; 3484 3485 str = OSSymbol::withCString( name ); 3486 if( !str) 3487 return( 0 ); 3488 3489 table = serviceMatching( str, table ); 3490 str->release(); 3491 return( table ); 3492} 3493 3494OSDictionary * IOService::nameMatching( const OSString * name, 3495 OSDictionary * table ) 3496{ 3497 if( !table) 3498 table = OSDictionary::withCapacity( 2 ); 3499 if( table) 3500 table->setObject( gIONameMatchKey, (OSObject *)name ); 3501 3502 return( table ); 3503} 3504 3505OSDictionary * IOService::nameMatching( const char * name, 3506 OSDictionary * table ) 3507{ 3508 const OSString * str; 3509 3510 str = OSSymbol::withCString( name ); 3511 if( !str) 3512 return( 0 ); 3513 3514 table = nameMatching( str, table ); 3515 str->release(); 3516 return( table ); 3517} 3518 3519OSDictionary * IOService::resourceMatching( const OSString * str, 3520 OSDictionary * table ) 3521{ 3522 table = serviceMatching( gIOResourcesKey, table ); 3523 if( table) 3524 table->setObject( gIOResourceMatchKey, (OSObject *) str ); 3525 3526 return( table ); 3527} 3528 3529OSDictionary * IOService::resourceMatching( const char * name, 3530 OSDictionary * table ) 3531{ 3532 const OSSymbol * str; 3533 3534 str = OSSymbol::withCString( name ); 3535 if( !str) 3536 return( 0 ); 3537 3538 table = resourceMatching( str, table ); 3539 str->release(); 3540 3541 return( table ); 3542} 3543 3544/* 3545 * _IOServiceNotifier 3546 */ 3547 3548// wait for all threads, other than the current one, 3549// to exit the handler 3550 3551void _IOServiceNotifier::wait() 3552{ 3553 _IOServiceNotifierInvocation * next; 3554 bool doWait; 3555 3556 do { 3557 doWait = false; 3558 queue_iterate( &handlerInvocations, next, 3559 _IOServiceNotifierInvocation *, link) { 3560 if( next->thread != current_thread() ) { 3561 doWait = true; 3562 break; 3563 } 3564 } 3565 if( doWait) { 3566 state |= kIOServiceNotifyWaiter; 3567 SLEEPNOTIFY(this); 3568 } 3569 3570 } while( doWait ); 3571} 3572 3573void _IOServiceNotifier::free() 3574{ 3575 assert( queue_empty( &handlerInvocations )); 3576 OSObject::free(); 3577} 3578 3579void _IOServiceNotifier::remove() 3580{ 3581 LOCKWRITENOTIFY(); 3582 3583 if( whence) { 3584 whence->removeObject( (OSObject *) this ); 3585 whence = 0; 3586 } 3587 if( matching) { 3588 matching->release(); 3589 matching = 0; 3590 } 3591 3592 state &= ~kIOServiceNotifyEnable; 3593 3594 wait(); 3595 3596 UNLOCKNOTIFY(); 3597 3598 release(); 3599} 3600 3601bool _IOServiceNotifier::disable() 3602{ 3603 bool ret; 3604 3605 LOCKWRITENOTIFY(); 3606 3607 ret = (0 != (kIOServiceNotifyEnable & state)); 3608 state &= ~kIOServiceNotifyEnable; 3609 if( ret) 3610 wait(); 3611 3612 UNLOCKNOTIFY(); 3613 3614 return( ret ); 3615} 3616 3617void _IOServiceNotifier::enable( bool was ) 3618{ 3619 LOCKWRITENOTIFY(); 3620 if( was) 3621 state |= kIOServiceNotifyEnable; 3622 else 3623 state &= ~kIOServiceNotifyEnable; 3624 UNLOCKNOTIFY(); 3625} 3626 3627/* 3628 * IOResources 3629 */ 3630 3631IOService * IOResources::resources( void ) 3632{ 3633 IOResources * inst; 3634 3635 inst = new IOResources; 3636 if( inst && !inst->init()) { 3637 inst->release(); 3638 inst = 0; 3639 } 3640 3641 return( inst ); 3642} 3643 3644IOWorkLoop * IOResources::getWorkLoop() const 3645{ 3646 // If we are the resource root then bringe over to the 3647 // platform to get its workloop 3648 if (this == (IOResources *) gIOResources) 3649 return getPlatform()->getWorkLoop(); 3650 else 3651 return IOService::getWorkLoop(); 3652} 3653 3654bool IOResources::matchPropertyTable( OSDictionary * table ) 3655{ 3656 OSObject * prop; 3657 OSString * str; 3658 OSSet * set; 3659 OSIterator * iter; 3660 bool ok = false; 3661 3662 prop = table->getObject( gIOResourceMatchKey ); 3663 str = OSDynamicCast( OSString, prop ); 3664 if( str) 3665 ok = (0 != getProperty( str )); 3666 3667 else if( (set = OSDynamicCast( OSSet, prop))) { 3668 3669 iter = OSCollectionIterator::withCollection( set ); 3670 ok = (iter != 0); 3671 while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) )) 3672 ok = (0 != getProperty( str )); 3673 3674 if( iter) 3675 iter->release(); 3676 } 3677 3678 return( ok ); 3679} 3680 3681IOReturn IOResources::setProperties( OSObject * properties ) 3682{ 3683 IOReturn err; 3684 const OSSymbol * key; 3685 OSDictionary * dict; 3686 OSCollectionIterator * iter; 3687 3688 err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); 3689 if ( kIOReturnSuccess != err) 3690 return( err ); 3691 3692 dict = OSDynamicCast(OSDictionary, properties); 3693 if( 0 == dict) 3694 return( kIOReturnBadArgument); 3695 3696 iter = OSCollectionIterator::withCollection( dict); 3697 if( 0 == iter) 3698 return( kIOReturnBadArgument); 3699 3700 while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 3701 3702 if (gIOConsoleUsersKey == key) 3703 { 3704 IORegistryEntry::getRegistryRoot()->setProperty(key, dict->getObject(key)); 3705 OSIncrementAtomic( &gIOConsoleUsersSeed ); 3706 publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue ); 3707 continue; 3708 } 3709 3710 publishResource( key, dict->getObject(key) ); 3711 } 3712 3713 iter->release(); 3714 3715 return( kIOReturnSuccess ); 3716} 3717 3718/* 3719 * Helpers for matching dictionaries. 3720 * Keys existing in matching are checked in properties. 3721 * Keys may be a string or OSCollection of IOStrings 3722 */ 3723 3724bool IOService::compareProperty( OSDictionary * matching, 3725 const char * key ) 3726{ 3727 OSObject * value; 3728 bool ok; 3729 3730 value = matching->getObject( key ); 3731 if( value) 3732 ok = value->isEqualTo( getProperty( key )); 3733 else 3734 ok = true; 3735 3736 return( ok ); 3737} 3738 3739 3740bool IOService::compareProperty( OSDictionary * matching, 3741 const OSString * key ) 3742{ 3743 OSObject * value; 3744 bool ok; 3745 3746 value = matching->getObject( key ); 3747 if( value) 3748 ok = value->isEqualTo( getProperty( key )); 3749 else 3750 ok = true; 3751 3752 return( ok ); 3753} 3754 3755bool IOService::compareProperties( OSDictionary * matching, 3756 OSCollection * keys ) 3757{ 3758 OSCollectionIterator * iter; 3759 const OSString * key; 3760 bool ok = true; 3761 3762 if( !matching || !keys) 3763 return( false ); 3764 3765 iter = OSCollectionIterator::withCollection( keys ); 3766 3767 if( iter) { 3768 while( ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) 3769 ok = compareProperty( matching, key ); 3770 3771 iter->release(); 3772 } 3773 keys->release(); // !! consume a ref !! 3774 3775 return( ok ); 3776} 3777 3778/* Helper to add a location matching dict to the table */ 3779 3780OSDictionary * IOService::addLocation( OSDictionary * table ) 3781{ 3782 OSDictionary * dict; 3783 3784 if( !table) 3785 return( 0 ); 3786 3787 dict = OSDictionary::withCapacity( 1 ); 3788 if( dict) { 3789 table->setObject( gIOLocationMatchKey, dict ); 3790 dict->release(); 3791 } 3792 3793 return( dict ); 3794} 3795 3796/* 3797 * Go looking for a provider to match a location dict. 3798 */ 3799 3800IOService * IOService::matchLocation( IOService * /* client */ ) 3801{ 3802 IOService * parent; 3803 3804 parent = getProvider(); 3805 3806 if( parent) 3807 parent = parent->matchLocation( this ); 3808 3809 return( parent ); 3810} 3811 3812bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) 3813{ 3814 IOService * where; 3815 OSString * matched; 3816 OSObject * obj; 3817 OSString * str; 3818 IORegistryEntry * entry; 3819 OSNumber * num; 3820 SInt32 score; 3821 OSNumber * newPri; 3822 bool match = true; 3823 bool matchParent = false; 3824 UInt32 done; 3825 3826 assert( table ); 3827 3828 where = this; 3829 3830 do { 3831 do { 3832 done = 0; 3833 3834 str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); 3835 if( str) { 3836 done++; 3837 match = (0 != where->metaCast( str )); 3838 if( !match) 3839 break; 3840 } 3841 3842 obj = table->getObject( gIONameMatchKey ); 3843 if( obj) { 3844 done++; 3845 match = where->compareNames( obj, changesOK ? &matched : 0 ); 3846 if( !match) 3847 break; 3848 if( changesOK && matched) { 3849 // leave a hint as to which name matched 3850 table->setObject( gIONameMatchedKey, matched ); 3851 matched->release(); 3852 } 3853 } 3854 3855 str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey )); 3856 if( str) { 3857 3858 const OSSymbol * sym; 3859 3860 done++; 3861 match = false; 3862 sym = where->copyLocation(); 3863 if( sym) { 3864 match = sym->isEqualTo( str ); 3865 sym->release(); 3866 } 3867 if( !match) 3868 break; 3869 } 3870 3871 obj = table->getObject( gIOPropertyMatchKey ); 3872 if( obj) { 3873 3874 OSDictionary * dict; 3875 OSDictionary * nextDict; 3876 OSIterator * iter; 3877 3878 done++; 3879 match = false; 3880 dict = where->dictionaryWithProperties(); 3881 if( dict) { 3882 nextDict = OSDynamicCast( OSDictionary, obj); 3883 if( nextDict) 3884 iter = 0; 3885 else 3886 iter = OSCollectionIterator::withCollection( 3887 OSDynamicCast(OSCollection, obj)); 3888 3889 while( nextDict 3890 || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, 3891 iter->getNextObject()))))) { 3892 match = dict->isEqualTo( nextDict, nextDict); 3893 if( match) 3894 break; 3895 nextDict = 0; 3896 } 3897 dict->release(); 3898 if( iter) 3899 iter->release(); 3900 } 3901 if( !match) 3902 break; 3903 } 3904 3905 str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); 3906 if( str) { 3907 done++; 3908 entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); 3909 match = (where == entry); 3910 if( entry) 3911 entry->release(); 3912 if( !match) 3913 break; 3914 } 3915 3916 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); 3917 if( num) { 3918 3919 OSIterator * iter; 3920 IOService * service = 0; 3921 UInt32 serviceCount = 0; 3922 3923 done++; 3924 iter = where->getClientIterator(); 3925 if( iter) { 3926 while( (service = (IOService *) iter->getNextObject())) { 3927 if( kIOServiceInactiveState & service->__state[0]) 3928 continue; 3929 if( 0 == service->getProperty( gIOMatchCategoryKey )) 3930 continue; 3931 ++serviceCount; 3932 } 3933 iter->release(); 3934 } 3935 match = (serviceCount == num->unsigned32BitValue()); 3936 if( !match) 3937 break; 3938 } 3939 3940 if( done == table->getCount()) { 3941 // don't call family if we've done all the entries in the table 3942 matchParent = false; 3943 break; 3944 } 3945 3946 // pass in score from property table 3947 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); 3948 3949 // do family specific matching 3950 match = where->matchPropertyTable( table, &score ); 3951 3952 if( !match) { 3953#if IOMATCHDEBUG 3954 if( kIOLogMatch & getDebugFlags( table )) 3955 LOG("%s: family specific matching fails\n", where->getName()); 3956#endif 3957 break; 3958 } 3959 3960 if( changesOK) { 3961 // save the score 3962 newPri = OSNumber::withNumber( score, 32 ); 3963 if( newPri) { 3964 table->setObject( gIOProbeScoreKey, newPri ); 3965 newPri->release(); 3966 } 3967 } 3968 3969 if( !(match = where->compareProperty( table, kIOBSDNameKey ))) 3970 break; 3971 3972 matchParent = false; 3973 3974 obj = OSDynamicCast( OSDictionary, 3975 table->getObject( gIOParentMatchKey )); 3976 if( obj) { 3977 match = false; 3978 matchParent = true; 3979 table = (OSDictionary *) obj; 3980 break; 3981 } 3982 3983 table = OSDynamicCast( OSDictionary, 3984 table->getObject( gIOLocationMatchKey )); 3985 if( table) { 3986 match = false; 3987 where = where->getProvider(); 3988 if( where) 3989 where = where->matchLocation( where ); 3990 } 3991 3992 } while( table && where ); 3993 3994 } while( matchParent && (where = where->getProvider()) ); 3995 3996 if( kIOLogMatch & gIOKitDebug) 3997 if( where != this) 3998 LOG("match parent @ %s = %d\n", 3999 where->getName(), match ); 4000
4001 return( match ); 4002} 4003 4004 4005IOReturn IOService::newUserClient( task_t owningTask, void * securityID, 4006 UInt32 type, OSDictionary * properties, 4007 IOUserClient ** handler ) 4008{ 4009 const OSSymbol *userClientClass = 0; 4010 IOUserClient *client; 4011 OSObject *temp; 4012 4013 // First try my own properties for a user client class name 4014 temp = getProperty(gIOUserClientClassKey); 4015 if (temp) { 4016 if (OSDynamicCast(OSSymbol, temp)) 4017 userClientClass = (const OSSymbol *) temp; 4018 else if (OSDynamicCast(OSString, temp)) { 4019 userClientClass = OSSymbol::withString((OSString *) temp); 4020 if (userClientClass) 4021 setProperty(kIOUserClientClassKey, 4022 (OSObject *) userClientClass); 4023 } 4024 } 4025 4026 // Didn't find one so lets just bomb out now without further ado. 4027 if (!userClientClass) 4028 return kIOReturnUnsupported; 4029 4030 temp = OSMetaClass::allocClassWithName(userClientClass); 4031 if (!temp) 4032 return kIOReturnNoMemory; 4033 4034 if (OSDynamicCast(IOUserClient, temp)) 4035 client = (IOUserClient *) temp; 4036 else { 4037 temp->release(); 4038 return kIOReturnUnsupported; 4039 } 4040 4041 if ( !client->initWithTask(owningTask, securityID, type, properties) ) { 4042 client->release(); 4043 return kIOReturnBadArgument; 4044 } 4045 4046 if ( !client->attach(this) ) { 4047 client->release(); 4048 return kIOReturnUnsupported; 4049 } 4050 4051 if ( !client->start(this) ) { 4052 client->detach(this); 4053 client->release(); 4054 return kIOReturnUnsupported; 4055 } 4056 4057 *handler = client; 4058 return kIOReturnSuccess; 4059} 4060 4061IOReturn IOService::newUserClient( task_t owningTask, void * securityID, 4062 UInt32 type, IOUserClient ** handler ) 4063{ 4064 return( newUserClient( owningTask, securityID, type, 0, handler )); 4065} 4066 4067IOReturn IOService::requestProbe( IOOptionBits options ) 4068{ 4069 return( kIOReturnUnsupported); 4070} 4071 4072/* 4073 * Convert an IOReturn to text. Subclasses which add additional 4074 * IOReturn's should override this method and call 4075 * super::stringFromReturn if the desired value is not found. 4076 */ 4077 4078const char * IOService::stringFromReturn( IOReturn rtn ) 4079{ 4080 static const IONamedValue IOReturn_values[] = { 4081 {kIOReturnSuccess, "success" }, 4082 {kIOReturnError, "general error" }, 4083 {kIOReturnNoMemory, "memory allocation error" }, 4084 {kIOReturnNoResources, "resource shortage" }, 4085 {kIOReturnIPCError, "Mach IPC failure" }, 4086 {kIOReturnNoDevice, "no such device" }, 4087 {kIOReturnNotPrivileged, "privilege violation" }, 4088 {kIOReturnBadArgument, "invalid argument" }, 4089 {kIOReturnLockedRead, "device is read locked" }, 4090 {kIOReturnLockedWrite, "device is write locked" }, 4091 {kIOReturnExclusiveAccess, "device is exclusive access" }, 4092 {kIOReturnBadMessageID, "bad IPC message ID" }, 4093 {kIOReturnUnsupported, "unsupported function" }, 4094 {kIOReturnVMError, "virtual memory error" }, 4095 {kIOReturnInternalError, "internal driver error" }, 4096 {kIOReturnIOError, "I/O error" }, 4097 {kIOReturnCannotLock, "cannot acquire lock" }, 4098 {kIOReturnNotOpen, "device is not open" }, 4099 {kIOReturnNotReadable, "device is not readable" }, 4100 {kIOReturnNotWritable, "device is not writeable" }, 4101 {kIOReturnNotAligned, "alignment error" }, 4102 {kIOReturnBadMedia, "media error" }, 4103 {kIOReturnStillOpen, "device is still open" }, 4104 {kIOReturnRLDError, "rld failure" }, 4105 {kIOReturnDMAError, "DMA failure" }, 4106 {kIOReturnBusy, "device is busy" }, 4107 {kIOReturnTimeout, "I/O timeout" }, 4108 {kIOReturnOffline, "device is offline" }, 4109 {kIOReturnNotReady, "device is not ready" }, 4110 {kIOReturnNotAttached, "device/channel is not attached" }, 4111 {kIOReturnNoChannels, "no DMA channels available" }, 4112 {kIOReturnNoSpace, "no space for data" }, 4113 {kIOReturnPortExists, "device port already exists" }, 4114 {kIOReturnCannotWire, "cannot wire physical memory" }, 4115 {kIOReturnNoInterrupt, "no interrupt attached" }, 4116 {kIOReturnNoFrames, "no DMA frames enqueued" }, 4117 {kIOReturnMessageTooLarge, "message is too large" }, 4118 {kIOReturnNotPermitted, "operation is not permitted" }, 4119 {kIOReturnNoPower, "device is without power" }, 4120 {kIOReturnNoMedia, "media is not present" }, 4121 {kIOReturnUnformattedMedia, "media is not formatted" }, 4122 {kIOReturnUnsupportedMode, "unsupported mode" }, 4123 {kIOReturnUnderrun, "data underrun" }, 4124 {kIOReturnOverrun, "data overrun" }, 4125 {kIOReturnDeviceError, "device error" }, 4126 {kIOReturnNoCompletion, "no completion routine" }, 4127 {kIOReturnAborted, "operation was aborted" }, 4128 {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" }, 4129 {kIOReturnNotResponding, "device is not responding" }, 4130 {kIOReturnInvalid, "unanticipated driver error" }, 4131 {0, NULL } 4132 }; 4133 4134 return IOFindNameForValue(rtn, IOReturn_values); 4135} 4136 4137/* 4138 * Convert an IOReturn to an errno. 4139 */ 4140int IOService::errnoFromReturn( IOReturn rtn ) 4141{ 4142 switch(rtn) { 4143 // (obvious match) 4144 case kIOReturnSuccess: 4145 return(0); 4146 case kIOReturnNoMemory: 4147 return(ENOMEM); 4148 case kIOReturnNoDevice: 4149 return(ENXIO); 4150 case kIOReturnVMError: 4151 return(EFAULT); 4152 case kIOReturnNotPermitted: 4153 return(EPERM); 4154 case kIOReturnNotPrivileged: 4155 return(EACCES); 4156 case kIOReturnIOError: 4157 return(EIO); 4158 case kIOReturnNotWritable: 4159 return(EROFS); 4160 case kIOReturnBadArgument: 4161 return(EINVAL); 4162 case kIOReturnUnsupported: 4163 return(ENOTSUP); 4164 case kIOReturnBusy: 4165 return(EBUSY); 4166 case kIOReturnNoPower: 4167 return(EPWROFF); 4168 case kIOReturnDeviceError: 4169 return(EDEVERR); 4170 case kIOReturnTimeout: 4171 return(ETIMEDOUT); 4172 case kIOReturnMessageTooLarge: 4173 return(EMSGSIZE); 4174 case kIOReturnNoSpace: 4175 return(ENOSPC); 4176 case kIOReturnCannotLock: 4177 return(ENOLCK); 4178 4179 // (best match) 4180 case kIOReturnBadMessageID: 4181 case kIOReturnNoCompletion: 4182 case kIOReturnNotAligned: 4183 return(EINVAL); 4184 case kIOReturnNotReady: 4185 return(EBUSY); 4186 case kIOReturnRLDError: 4187 return(EBADMACHO); 4188 case kIOReturnPortExists: 4189 case kIOReturnStillOpen: 4190 return(EEXIST); 4191 case kIOReturnExclusiveAccess: 4192 case kIOReturnLockedRead: 4193 case kIOReturnLockedWrite: 4194 case kIOReturnNotAttached: 4195 case kIOReturnNotOpen: 4196 case kIOReturnNotReadable: 4197 return(EACCES); 4198 case kIOReturnCannotWire: 4199 case kIOReturnNoResources: 4200 return(ENOMEM); 4201 case kIOReturnAborted: 4202 case kIOReturnOffline: 4203 case kIOReturnNotResponding: 4204 return(EBUSY); 4205 case kIOReturnBadMedia: 4206 case kIOReturnNoMedia: 4207 case kIOReturnUnformattedMedia: 4208 return(ENXIO); // (media error) 4209 case kIOReturnDMAError: 4210 case kIOReturnOverrun: 4211 case kIOReturnUnderrun: 4212 return(EIO); // (transfer error) 4213 case kIOReturnNoBandwidth: 4214 case kIOReturnNoChannels: 4215 case kIOReturnNoFrames: 4216 case kIOReturnNoInterrupt: 4217 return(EIO); // (hardware error) 4218 case kIOReturnError: 4219 case kIOReturnInternalError: 4220 case kIOReturnInvalid: 4221 return(EIO); // (generic error) 4222 case kIOReturnIPCError: 4223 return(EIO); // (ipc error) 4224 default: 4225 return(EIO); // (all other errors) 4226 } 4227} 4228 4229IOReturn IOService::message( UInt32 type, IOService * provider, 4230 void * argument ) 4231{ 4232 /* 4233 * Generic entry point for calls from the provider. A return value of 4234 * kIOReturnSuccess indicates that the message was received, and where 4235 * applicable, that it was successful. 4236 */ 4237 4238 return kIOReturnUnsupported; 4239} 4240 4241/* 4242 * Device memory 4243 */ 4244 4245IOItemCount IOService::getDeviceMemoryCount( void ) 4246{ 4247 OSArray * array; 4248 IOItemCount count; 4249 4250 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); 4251 if( array) 4252 count = array->getCount(); 4253 else 4254 count = 0; 4255 4256 return( count); 4257} 4258 4259IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index ) 4260{ 4261 OSArray * array; 4262 IODeviceMemory * range; 4263 4264 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); 4265 if( array) 4266 range = (IODeviceMemory *) array->getObject( index ); 4267 else 4268 range = 0; 4269 4270 return( range); 4271} 4272 4273IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index, 4274 IOOptionBits options ) 4275{ 4276 IODeviceMemory * range; 4277 IOMemoryMap * map; 4278 4279 range = getDeviceMemoryWithIndex( index ); 4280 if( range) 4281 map = range->map( options ); 4282 else 4283 map = 0; 4284 4285 return( map ); 4286} 4287 4288OSArray * IOService::getDeviceMemory( void ) 4289{ 4290 return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey))); 4291} 4292 4293 4294void IOService::setDeviceMemory( OSArray * array ) 4295{ 4296 setProperty( gIODeviceMemoryKey, array); 4297} 4298 4299/* 4300 * Device interrupts 4301 */ 4302 4303IOReturn IOService::resolveInterrupt(IOService *nub, int source) 4304{ 4305 IOInterruptController *interruptController; 4306 OSArray *array; 4307 OSData *data; 4308 OSSymbol *interruptControllerName; 4309 long numSources; 4310 IOInterruptSource *interruptSources; 4311 4312 // Get the parents list from the nub. 4313 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey)); 4314 if (array == 0) return kIOReturnNoResources; 4315 4316 // Allocate space for the IOInterruptSources if needed... then return early. 4317 if (nub->_interruptSources == 0) { 4318 numSources = array->getCount(); 4319 interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource)); 4320 if (interruptSources == 0) return kIOReturnNoMemory; 4321 4322 bzero(interruptSources, numSources * sizeof(IOInterruptSource)); 4323 4324 nub->_numInterruptSources = numSources; 4325 nub->_interruptSources = interruptSources; 4326 return kIOReturnSuccess; 4327 } 4328 4329 interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source)); 4330 if (interruptControllerName == 0) return kIOReturnNoResources; 4331 4332 interruptController = getPlatform()->lookUpInterruptController(interruptControllerName); 4333 if (interruptController == 0) return kIOReturnNoResources; 4334 4335 // Get the interrupt numbers from the nub. 4336 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey)); 4337 if (array == 0) return kIOReturnNoResources; 4338 data = OSDynamicCast(OSData, array->getObject(source)); 4339 if (data == 0) return kIOReturnNoResources; 4340 4341 // Set the interruptController and interruptSource in the nub's table. 4342 interruptSources = nub->_interruptSources; 4343 interruptSources[source].interruptController = interruptController; 4344 interruptSources[source].vectorData = data; 4345 4346 return kIOReturnSuccess; 4347} 4348 4349IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController) 4350{ 4351 IOReturn ret; 4352 4353 /* Make sure the _interruptSources are set */ 4354 if (_interruptSources == 0) { 4355 ret = resolveInterrupt(this, source); 4356 if (ret != kIOReturnSuccess) return ret; 4357 } 4358 4359 /* Make sure the local source number is valid */ 4360 if ((source < 0) || (source >= _numInterruptSources)) 4361 return kIOReturnNoInterrupt; 4362 4363 /* Look up the contoller for the local source */ 4364 *interruptController = _interruptSources[source].interruptController; 4365 4366 if (*interruptController == NULL) { 4367 if (!resolve) return kIOReturnNoInterrupt; 4368 4369 /* Try to reslove the interrupt */ 4370 ret = resolveInterrupt(this, source); 4371 if (ret != kIOReturnSuccess) return ret; 4372 4373 *interruptController = _interruptSources[source].interruptController; 4374 } 4375 4376 return kIOReturnSuccess; 4377} 4378 4379IOReturn IOService::registerInterrupt(int source, OSObject *target, 4380 IOInterruptAction handler, 4381 void *refCon) 4382{ 4383 IOInterruptController *interruptController; 4384 IOReturn ret; 4385 4386 ret = lookupInterrupt(source, true, &interruptController); 4387 if (ret != kIOReturnSuccess) return ret; 4388 4389 /* Register the source */ 4390 return interruptController->registerInterrupt(this, source, target, 4391 (IOInterruptHandler)handler, 4392 refCon); 4393} 4394 4395IOReturn IOService::unregisterInterrupt(int source) 4396{ 4397 IOInterruptController *interruptController; 4398 IOReturn ret; 4399 4400 ret = lookupInterrupt(source, false, &interruptController); 4401 if (ret != kIOReturnSuccess) return ret; 4402 4403 /* Unregister the source */ 4404 return interruptController->unregisterInterrupt(this, source); 4405} 4406 4407IOReturn IOService::getInterruptType(int source, int *interruptType) 4408{ 4409 IOInterruptController *interruptController; 4410 IOReturn ret; 4411 4412 ret = lookupInterrupt(source, true, &interruptController); 4413 if (ret != kIOReturnSuccess) return ret; 4414 4415 /* Return the type */ 4416 return interruptController->getInterruptType(this, source, interruptType); 4417} 4418 4419IOReturn IOService::enableInterrupt(int source) 4420{ 4421 IOInterruptController *interruptController; 4422 IOReturn ret; 4423 4424 ret = lookupInterrupt(source, false, &interruptController); 4425 if (ret != kIOReturnSuccess) return ret; 4426 4427 /* Enable the source */ 4428 return interruptController->enableInterrupt(this, source); 4429} 4430 4431IOReturn IOService::disableInterrupt(int source) 4432{ 4433 IOInterruptController *interruptController; 4434 IOReturn ret; 4435 4436 ret = lookupInterrupt(source, false, &interruptController); 4437 if (ret != kIOReturnSuccess) return ret; 4438 4439 /* Disable the source */ 4440 return interruptController->disableInterrupt(this, source); 4441} 4442 4443IOReturn IOService::causeInterrupt(int source) 4444{ 4445 IOInterruptController *interruptController; 4446 IOReturn ret; 4447 4448 ret = lookupInterrupt(source, false, &interruptController); 4449 if (ret != kIOReturnSuccess) return ret; 4450 4451 /* Cause an interrupt for the source */ 4452 return interruptController->causeInterrupt(this, source); 4453} 4454 4455OSMetaClassDefineReservedUsed(IOService, 0); 4456OSMetaClassDefineReservedUsed(IOService, 1); 4457OSMetaClassDefineReservedUsed(IOService, 2); 4458OSMetaClassDefineReservedUsed(IOService, 3); 4459 4460OSMetaClassDefineReservedUnused(IOService, 4); 4461OSMetaClassDefineReservedUnused(IOService, 5); 4462OSMetaClassDefineReservedUnused(IOService, 6); 4463OSMetaClassDefineReservedUnused(IOService, 7); 4464OSMetaClassDefineReservedUnused(IOService, 8); 4465OSMetaClassDefineReservedUnused(IOService, 9); 4466OSMetaClassDefineReservedUnused(IOService, 10); 4467OSMetaClassDefineReservedUnused(IOService, 11); 4468OSMetaClassDefineReservedUnused(IOService, 12); 4469OSMetaClassDefineReservedUnused(IOService, 13); 4470OSMetaClassDefineReservedUnused(IOService, 14); 4471OSMetaClassDefineReservedUnused(IOService, 15); 4472OSMetaClassDefineReservedUnused(IOService, 16); 4473OSMetaClassDefineReservedUnused(IOService, 17); 4474OSMetaClassDefineReservedUnused(IOService, 18); 4475OSMetaClassDefineReservedUnused(IOService, 19); 4476OSMetaClassDefineReservedUnused(IOService, 20); 4477OSMetaClassDefineReservedUnused(IOService, 21); 4478OSMetaClassDefineReservedUnused(IOService, 22); 4479OSMetaClassDefineReservedUnused(IOService, 23); 4480OSMetaClassDefineReservedUnused(IOService, 24); 4481OSMetaClassDefineReservedUnused(IOService, 25); 4482OSMetaClassDefineReservedUnused(IOService, 26); 4483OSMetaClassDefineReservedUnused(IOService, 27); 4484OSMetaClassDefineReservedUnused(IOService, 28); 4485OSMetaClassDefineReservedUnused(IOService, 29); 4486OSMetaClassDefineReservedUnused(IOService, 30); 4487OSMetaClassDefineReservedUnused(IOService, 31); 4488OSMetaClassDefineReservedUnused(IOService, 32); 4489OSMetaClassDefineReservedUnused(IOService, 33); 4490OSMetaClassDefineReservedUnused(IOService, 34); 4491OSMetaClassDefineReservedUnused(IOService, 35); 4492OSMetaClassDefineReservedUnused(IOService, 36); 4493OSMetaClassDefineReservedUnused(IOService, 37); 4494OSMetaClassDefineReservedUnused(IOService, 38); 4495OSMetaClassDefineReservedUnused(IOService, 39); 4496OSMetaClassDefineReservedUnused(IOService, 40); 4497OSMetaClassDefineReservedUnused(IOService, 41); 4498OSMetaClassDefineReservedUnused(IOService, 42); 4499OSMetaClassDefineReservedUnused(IOService, 43); 4500OSMetaClassDefineReservedUnused(IOService, 44); 4501OSMetaClassDefineReservedUnused(IOService, 45); 4502OSMetaClassDefineReservedUnused(IOService, 46); 4503OSMetaClassDefineReservedUnused(IOService, 47); 4504OSMetaClassDefineReservedUnused(IOService, 48); 4505OSMetaClassDefineReservedUnused(IOService, 49); 4506OSMetaClassDefineReservedUnused(IOService, 50); 4507OSMetaClassDefineReservedUnused(IOService, 51); 4508OSMetaClassDefineReservedUnused(IOService, 52); 4509OSMetaClassDefineReservedUnused(IOService, 53); 4510OSMetaClassDefineReservedUnused(IOService, 54); 4511OSMetaClassDefineReservedUnused(IOService, 55); 4512OSMetaClassDefineReservedUnused(IOService, 56); 4513OSMetaClassDefineReservedUnused(IOService, 57); 4514OSMetaClassDefineReservedUnused(IOService, 58); 4515OSMetaClassDefineReservedUnused(IOService, 59); 4516OSMetaClassDefineReservedUnused(IOService, 60); 4517OSMetaClassDefineReservedUnused(IOService, 61); 4518OSMetaClassDefineReservedUnused(IOService, 62); 4519OSMetaClassDefineReservedUnused(IOService, 63); 4520

