|
|
1.1 ! root 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: * Copyright (c) 1991-1999 Apple Computer, Inc. All rights reserved. ! 24: * ! 25: * HISTORY ! 26: * ! 27: * 29-Jan-91 Portions from IODevice.m, Doug Mitchell at NeXT, Created. ! 28: * 18-Jun-98 start IOKit objc ! 29: * 10-Nov-98 start iokit cpp ! 30: * 25-Feb-99 sdouglas, add threads and locks to ensure deadlock ! 31: * ! 32: */ ! 33: ! 34: #include <IOKit/system.h> ! 35: ! 36: #include <IOKit/IOService.h> ! 37: #include <libkern/c++/OSContainers.h> ! 38: #include <libkern/c++/OSUnserialize.h> ! 39: #include <IOKit/IOCatalogue.h> ! 40: #include <IOKit/IODeviceMemory.h> ! 41: #include <IOKit/IOInterrupts.h> ! 42: #include <IOKit/IOInterruptController.h> ! 43: #include <IOKit/IOPlatformExpert.h> ! 44: #include <IOKit/IOMessage.h> ! 45: #include <IOKit/IOLib.h> ! 46: #include <IOKit/IOKitKeys.h> ! 47: #include <IOKit/IOBSD.h> ! 48: #include <IOKit/IOUserClient.h> ! 49: ! 50: //#define LESS_THREAD_CREATE ! 51: //#define LOG kprintf ! 52: #define LOG IOLog ! 53: ! 54: #include "IOServicePrivate.h" ! 55: #include <mach/sync_policy.h> ! 56: ! 57: #include <IOKit/assert.h> ! 58: ! 59: #include <sys/errno.h> ! 60: ! 61: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 62: ! 63: #define super IORegistryEntry ! 64: ! 65: OSDefineMetaClassAndStructors(IOService, IORegistryEntry) ! 66: ! 67: OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier) ! 68: ! 69: OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier) ! 70: ! 71: OSDefineMetaClassAndStructors(_IOConfigThread, OSObject) ! 72: ! 73: OSDefineMetaClassAndStructors(_IOServiceJob, OSObject) ! 74: ! 75: OSDefineMetaClassAndStructors(IOResources, IOService) ! 76: ! 77: OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator) ! 78: ! 79: OSDefineMetaClass(IONotifier, OSObject) ! 80: OSDefineAbstractStructors(IONotifier, OSObject) ! 81: ! 82: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 83: ! 84: static IOPlatformExpert * gIOPlatform; ! 85: const IORegistryPlane * gIOServicePlane; ! 86: const IORegistryPlane * gIOPowerPlane; ! 87: const OSSymbol * gIODeviceMemoryKey; ! 88: const OSSymbol * gIOInterruptControllersKey; ! 89: const OSSymbol * gIOInterruptSpecifiersKey; ! 90: ! 91: const OSSymbol * gIOResourcesKey; ! 92: const OSSymbol * gIOResourceMatchKey; ! 93: const OSSymbol * gIOProviderClassKey; ! 94: const OSSymbol * gIONameMatchKey; ! 95: const OSSymbol * gIONameMatchedKey; ! 96: const OSSymbol * gIOLocationMatchKey; ! 97: const OSSymbol * gIOPathMatchKey; ! 98: const OSSymbol * gIOMatchCategoryKey; ! 99: const OSSymbol * gIODefaultMatchCategoryKey; ! 100: const OSSymbol * gIOKitDebugKey; ! 101: ! 102: static int gIOResourceGenerationCount; ! 103: ! 104: const OSSymbol * gIOServiceKey; ! 105: const OSSymbol * gIOPublishNotification; ! 106: const OSSymbol * gIOFirstPublishNotification; ! 107: const OSSymbol * gIOMatchedNotification; ! 108: const OSSymbol * gIOFirstMatchNotification; ! 109: const OSSymbol * gIOTerminatedNotification; ! 110: ! 111: const OSSymbol * gIOGeneralInterest; ! 112: const OSSymbol * gIOBusyInterest; ! 113: ! 114: static OSDictionary * gNotifications; ! 115: static IORecursiveLock * gNotificationLock; ! 116: ! 117: static IOService * gIOResources; ! 118: static IOService * gIOServiceRoot; ! 119: ! 120: static OSOrderedSet * gJobs; ! 121: static semaphore_port_t gJobsSemaphore; ! 122: static IOLock * gJobsLock; ! 123: static int gOutstandingJobs; ! 124: static int gNumConfigThreads; ! 125: static int gNumWaitingThreads; ! 126: static IOLock * gIOServiceBusyLock; ! 127: ! 128: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 129: ! 130: #define LOCKREADNOTIFY() \ ! 131: IORecursiveLockLock( gNotificationLock ) ! 132: #define LOCKWRITENOTIFY() \ ! 133: IORecursiveLockLock( gNotificationLock ) ! 134: #define LOCKWRITE2READNOTIFY() ! 135: #define UNLOCKNOTIFY() \ ! 136: IORecursiveLockUnlock( gNotificationLock ) ! 137: ! 138: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 139: ! 140: struct ArbitrationLockQueueElement { ! 141: queue_chain_t link; ! 142: IOThread thread; ! 143: IOService * service; ! 144: unsigned count; ! 145: bool required; ! 146: bool aborted; ! 147: }; ! 148: ! 149: static queue_head_t gArbitrationLockQueueActive; ! 150: static queue_head_t gArbitrationLockQueueWaiting; ! 151: static queue_head_t gArbitrationLockQueueFree; ! 152: static IOLock * gArbitrationLockQueueLock; ! 153: ! 154: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 155: ! 156: void IOService::initialize( void ) ! 157: { ! 158: kern_return_t err; ! 159: ! 160: gIOServicePlane = IORegistryEntry::makePlane( kIOServicePlane ); ! 161: gIOPowerPlane = IORegistryEntry::makePlane( kIOPowerPlane ); ! 162: ! 163: gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey ); ! 164: gIONameMatchKey = OSSymbol::withCStringNoCopy( kIONameMatchKey ); ! 165: gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); ! 166: gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); ! 167: gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); ! 168: ! 169: gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); ! 170: gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( ! 171: kIODefaultMatchCategoryKey ); ! 172: ! 173: gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass ); ! 174: gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey ); ! 175: ! 176: gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" ); ! 177: gIOInterruptControllersKey ! 178: = OSSymbol::withCStringNoCopy("IOInterruptControllers"); ! 179: gIOInterruptSpecifiersKey ! 180: = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers"); ! 181: ! 182: gIOKitDebugKey = OSSymbol::withCStringNoCopy( kIOKitDebugKey ); ! 183: ! 184: gIOGeneralInterest = OSSymbol::withCStringNoCopy( kIOGeneralInterest ); ! 185: gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest ); ! 186: ! 187: gNotifications = OSDictionary::withCapacity( 1 ); ! 188: gIOPublishNotification = OSSymbol::withCStringNoCopy( ! 189: kIOPublishNotification ); ! 190: gIOFirstPublishNotification = OSSymbol::withCStringNoCopy( ! 191: kIOFirstPublishNotification ); ! 192: gIOMatchedNotification = OSSymbol::withCStringNoCopy( ! 193: kIOMatchedNotification ); ! 194: gIOFirstMatchNotification = OSSymbol::withCStringNoCopy( ! 195: kIOFirstMatchNotification ); ! 196: gIOTerminatedNotification = OSSymbol::withCStringNoCopy( ! 197: kIOTerminatedNotification ); ! 198: gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); ! 199: ! 200: gNotificationLock = IORecursiveLockAlloc(); ! 201: ! 202: assert( gIOServicePlane && gIODeviceMemoryKey ! 203: && gIOInterruptControllersKey && gIOInterruptSpecifiersKey ! 204: && gIOResourcesKey && gNotifications && gNotificationLock ! 205: && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey ! 206: && gIOMatchCategoryKey && gIODefaultMatchCategoryKey ! 207: && gIOPublishNotification && gIOMatchedNotification ! 208: && gIOTerminatedNotification && gIOServiceKey ); ! 209: ! 210: gJobsLock = IOLockAlloc(); ! 211: gJobs = OSOrderedSet::withCapacity( 10 ); ! 212: ! 213: gIOServiceBusyLock = IOLockAlloc(); ! 214: ! 215: err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0); ! 216: ! 217: assert( gIOServiceBusyLock && gJobs && gJobsLock && (err == KERN_SUCCESS) ); ! 218: ! 219: gIOResources = IOResources::resources(); ! 220: assert( gIOResources ); ! 221: ! 222: gArbitrationLockQueueLock = IOLockAlloc(); ! 223: queue_init(&gArbitrationLockQueueActive); ! 224: queue_init(&gArbitrationLockQueueWaiting); ! 225: queue_init(&gArbitrationLockQueueFree); ! 226: ! 227: assert( gArbitrationLockQueueLock ); ! 228: ! 229: #ifdef LESS_THREAD_CREATE ! 230: for( int i = 0; i < kMaxConfigThreads; i++) ! 231: _IOConfigThread::configThread(); ! 232: #endif ! 233: ! 234: } ! 235: ! 236: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 237: ! 238: #ifdef DEBUG ! 239: static UInt64 getDebugFlags( OSDictionary * props ) ! 240: { ! 241: OSNumber * debugProp; ! 242: UInt64 debugFlags; ! 243: ! 244: debugProp = OSDynamicCast( OSNumber, ! 245: props->getObject( gIOKitDebugKey )); ! 246: if( debugProp) ! 247: debugFlags = debugProp->unsigned64BitValue(); ! 248: else ! 249: debugFlags = gIOKitDebug; ! 250: ! 251: return( debugFlags ); ! 252: } ! 253: #endif ! 254: ! 255: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ! 256: ! 257: // Probe a matched service and return an instance to be started. ! 258: // The default score is from the property table, & may be altered ! 259: // during probe to change the start order. ! 260: ! 261: IOService * IOService::probe( IOService * /* provider */, ! 262: SInt32 * /* score */) ! 263: { ! 264: return( this ); ! 265: } ! 266: ! 267: bool IOService::start( IOService * provider ) ! 268: { ! 269: return( true ); ! 270: } ! 271: ! 272: void IOService::stop( IOService * /* provider */ ) ! 273: { ! 274: } ! 275: ! 276: /* ! 277: * Attach in service plane ! 278: */ ! 279: bool IOService::attach( IOService * provider ) ! 280: { ! 281: bool ok; ! 282: ! 283: if( provider) { ! 284: ! 285: if( gIOKitDebug & kIOLogAttach) ! 286: LOG( "%s::attach(%s)\n", getName(), ! 287: provider->getName()); ! 288: ! 289: provider->lockForArbitration(); ! 290: if( provider->__state[0] & kIOServiceInactiveState) ! 291: ok = false; ! 292: else ! 293: ok = attachToParent( provider, gIOServicePlane); ! 294: provider->unlockForArbitration(); ! 295: ! 296: } else { ! 297: ! 298: gIOServiceRoot = this; ! 299: ok = attachToParent( getRegistryRoot(), gIOServicePlane); ! 300: gIOResources->attachToParent( getRegistryRoot(), ! 301: gIOServicePlane ); ! 302: publishResource("IOKit"); ! 303: } ! 304: ! 305: return( ok ); ! 306: } ! 307: ! 308: IOService * IOService::getServiceRoot( void ) ! 309: { ! 310: return( gIOServiceRoot ); ! 311: } ! 312: ! 313: void IOService::detach( IOService * provider ) ! 314: { ! 315: if( gIOKitDebug & kIOLogAttach) ! 316: LOG("%s::detach(%s)\n", getName(), provider->getName()); ! 317: ! 318: detachFromParent( provider, gIOServicePlane ); ! 319: } ! 320: ! 321: /* ! 322: * Register instance - publish it for matching ! 323: */ ! 324: ! 325: void IOService::registerService( IOOptionBits options = 0 ) ! 326: { ! 327: char * pathBuf; ! 328: const char * path; ! 329: char * skip; ! 330: int len; ! 331: enum { kMaxPathLen = 256 }; ! 332: enum { kMaxChars = 63 }; ! 333: ! 334: // Allow the Platform Expert to adjust this node. ! 335: if (gIOPlatform) ! 336: if (!gIOPlatform->platformAdjustService(this)) ! 337: return; ! 338: ! 339: if( (this != gIOResources) ! 340: && (kIOLogRegister & gIOKitDebug)) { ! 341: ! 342: pathBuf = (char *) IOMalloc( kMaxPathLen ); ! 343: ! 344: IOLog( "Registering: " ); ! 345: ! 346: len = kMaxPathLen; ! 347: if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) { ! 348: ! 349: path = pathBuf; ! 350: if( len > kMaxChars) { ! 351: IOLog(".."); ! 352: len -= kMaxChars; ! 353: path += len; ! 354: if( (skip = strchr( path, '/'))) ! 355: path = skip; ! 356: } ! 357: } else ! 358: path = getName(); ! 359: ! 360: IOLog( "%s\n", path ); ! 361: ! 362: if( pathBuf) ! 363: IOFree( pathBuf, kMaxPathLen ); ! 364: } ! 365: ! 366: startMatching( options ); ! 367: } ! 368: ! 369: void IOService::startMatching( IOOptionBits options = 0 ) ! 370: { ! 371: IOService * provider; ! 372: bool needConfig; ! 373: bool ok; ! 374: bool sync; ! 375: ! 376: lockForArbitration(); ! 377: ! 378: sync = (options & kIOServiceSynchronous) ! 379: || ((provider = getProvider()) ! 380: && (provider->__state[1] & kIOServiceSynchronousState)); ! 381: if( sync) ! 382: __state[1] |= kIOServiceSynchronousState; ! 383: else ! 384: __state[1] &= ~kIOServiceSynchronousState; ! 385: ! 386: needConfig = (0 == (__state[1] & kIOServiceConfigState)) ! 387: && (0 == (__state[0] & kIOServiceInactiveState)) ! 388: && (kIOServiceRegisteredState != ! 389: (__state[0] & (kIOServiceRegisteredState ! 390: | kIOServiceMatchedState))); ! 391: __state[1] |= kIOServiceConfigState; ! 392: // __state[0] &= ~kIOServiceInactiveState; ! 393: ! 394: // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n", ! 395: // OSKernelStackRemaining(), getName()); ! 396: ! 397: unlockForArbitration(); ! 398: ! 399: if( needConfig) { ! 400: adjustBusy( 1 ); ! 401: if( sync) { ! 402: doServiceMatch(); ! 403: waitQuiet(); ! 404: } else ! 405: ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob )); ! 406: } ! 407: } ! 408: ! 409: IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) ! 410: { ! 411: OSDictionary * table; ! 412: OSIterator * iter; ! 413: IOService * service; ! 414: #ifdef DEBUG ! 415: SInt32 count = 0; ! 416: #endif ! 417: ! 418: newTables->retain(); ! 419: ! 420: while( (table = (OSDictionary *) newTables->getFirstObject())) { ! 421: ! 422: LOCKWRITENOTIFY(); ! 423: iter = (OSIterator *) getExistingServices( table, ! 424: kIOServiceMatchedState ); ! 425: UNLOCKNOTIFY(); ! 426: if( iter) { ! 427: while( (service = (IOService *) iter->getNextObject())) { ! 428: service->startMatching(); ! 429: #ifdef DEBUG ! 430: count++; ! 431: #endif ! 432: } ! 433: iter->release(); ! 434: } ! 435: #ifdef DEBUG ! 436: if( getDebugFlags( table ) & kIOLogMatch) ! 437: LOG("Matching service count = %ld\n", count); ! 438: #endif ! 439: newTables->removeObject(table); ! 440: } ! 441: ! 442: newTables->release(); ! 443: ! 444: return( kIOReturnSuccess ); ! 445: } ! 446: ! 447: _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type, ! 448: IOOptionBits options = 0 ) ! 449: { ! 450: _IOServiceJob * job; ! 451: ! 452: job = new _IOServiceJob; ! 453: if( job && !job->init()) { ! 454: job->release(); ! 455: job = 0; ! 456: } ! 457: ! 458: if( job) { ! 459: job->type = type; ! 460: job->nub = nub; ! 461: job->options = options; ! 462: nub->retain(); // thread will release() ! 463: pingConfig( job ); ! 464: } ! 465: ! 466: return( job ); ! 467: } ! 468: ! 469: /* ! 470: * Called on a registered service to see if it matches ! 471: * a property table. ! 472: */ ! 473: ! 474: bool IOService::matchPropertyTable( OSDictionary * table ) ! 475: { ! 476: return( true ); ! 477: } ! 478: ! 479: /* ! 480: * Called on a matched service to allocate resources ! 481: * before first driver is attached. ! 482: */ ! 483: ! 484: IOReturn IOService::getResources( void ) ! 485: { ! 486: return( kIOReturnSuccess); ! 487: } ! 488: ! 489: /* ! 490: * Client/provider accessors ! 491: */ ! 492: ! 493: IOService * IOService::getProvider( void ) const ! 494: { ! 495: IOService * self = (IOService *) this; ! 496: IOService * parent; ! 497: SInt32 generation; ! 498: ! 499: parent = __provider; ! 500: generation = getGenerationCount(); ! 501: if( __providerGeneration == generation) ! 502: return( parent ); ! 503: ! 504: parent = (IOService *) getParentEntry( gIOServicePlane); ! 505: if( parent == IORegistryEntry::getRegistryRoot()) ! 506: /* root is not an IOService */ ! 507: parent = 0; ! 508: ! 509: self->__provider = parent; ! 510: // save the count before getParentEntry() ! 511: self->__providerGeneration = generation; ! 512: ! 513: return( parent ); ! 514: } ! 515: ! 516: IOWorkLoop * IOService::getWorkLoop() const ! 517: { ! 518: return getProvider()->getWorkLoop(); ! 519: } ! 520: ! 521: OSIterator * IOService::getProviderIterator( void ) const ! 522: { ! 523: return( getParentIterator( gIOServicePlane)); ! 524: } ! 525: ! 526: IOService * IOService::getClient( void ) const ! 527: { ! 528: return( (IOService *) getChildEntry( gIOServicePlane)); ! 529: } ! 530: ! 531: OSIterator * IOService::getClientIterator( void ) const ! 532: { ! 533: return( getChildIterator( gIOServicePlane)); ! 534: } ! 535: ! 536: OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter, ! 537: const IOService * client, ! 538: const IOService * provider ) ! 539: { ! 540: _IOOpenServiceIterator * inst; ! 541: ! 542: if( !_iter) ! 543: return( 0 ); ! 544: ! 545: inst = new _IOOpenServiceIterator; ! 546: ! 547: if( inst && !inst->init()) { ! 548: inst->release(); ! 549: inst = 0; ! 550: } ! 551: if( inst) { ! 552: inst->iter = _iter; ! 553: inst->client = client; ! 554: inst->provider = provider; ! 555: } ! 556: ! 557: return( inst ); ! 558: } ! 559: ! 560: void _IOOpenServiceIterator::free() ! 561: { ! 562: iter->release(); ! 563: if( last) ! 564: last->unlockForArbitration(); ! 565: OSIterator::free(); ! 566: } ! 567: ! 568: OSObject * _IOOpenServiceIterator::getNextObject() ! 569: { ! 570: IOService * next; ! 571: ! 572: if( last) ! 573: last->unlockForArbitration(); ! 574: ! 575: while( (next = (IOService *) iter->getNextObject())) { ! 576: ! 577: next->lockForArbitration(); ! 578: if( (client && (next->isOpen( client ))) ! 579: || (provider && (provider->isOpen( next ))) ) ! 580: break; ! 581: next->unlockForArbitration(); ! 582: } ! 583: ! 584: last = next; ! 585: ! 586: return( next ); ! 587: } ! 588: ! 589: bool _IOOpenServiceIterator::isValid() ! 590: { ! 591: return( iter->isValid() ); ! 592: } ! 593: ! 594: void _IOOpenServiceIterator::reset() ! 595: { ! 596: if( last) { ! 597: last->unlockForArbitration(); ! 598: last = 0; ! 599: } ! 600: iter->reset(); ! 601: } ! 602: ! 603: OSIterator * IOService::getOpenProviderIterator( void ) const ! 604: { ! 605: return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 )); ! 606: } ! 607: ! 608: OSIterator * IOService::getOpenClientIterator( void ) const ! 609: { ! 610: return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this )); ! 611: } ! 612: ! 613: ! 614: /* ! 615: * Platform expert accessors ! 616: */ ! 617: ! 618: IOPlatformExpert * IOService::getPlatform( void ) ! 619: { ! 620: return( gIOPlatform); ! 621: } ! 622: ! 623: void IOService::setPlatform( IOPlatformExpert * platform) ! 624: { ! 625: gIOPlatform = platform; ! 626: } ! 627: ! 628: /* ! 629: * Stacking change ! 630: */ ! 631: ! 632: bool IOService::lockForArbitration( bool isSuccessRequired = true ) ! 633: { ! 634: bool found; ! 635: bool success; ! 636: ArbitrationLockQueueElement * element; ! 637: ArbitrationLockQueueElement * active; ! 638: ArbitrationLockQueueElement * waiting; ! 639: ! 640: enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action; ! 641: ! 642: // lock global access ! 643: IOTakeLock( gArbitrationLockQueueLock ); ! 644: ! 645: // obtain an unused queue element ! 646: if( !queue_empty( &gArbitrationLockQueueFree )) { ! 647: queue_remove_first( &gArbitrationLockQueueFree, ! 648: element, ! 649: ArbitrationLockQueueElement *, ! 650: link ); ! 651: } else { ! 652: element = IONew( ArbitrationLockQueueElement, 1 ); ! 653: assert( element ); ! 654: } ! 655: ! 656: // prepare the queue element ! 657: element->thread = IOThreadSelf(); ! 658: element->service = this; ! 659: element->count = 1; ! 660: element->required = isSuccessRequired; ! 661: element->aborted = false; ! 662: ! 663: // determine whether this object is already locked (ie. on active queue) ! 664: found = false; ! 665: queue_iterate( &gArbitrationLockQueueActive, ! 666: active, ! 667: ArbitrationLockQueueElement *, ! 668: link ) ! 669: { ! 670: if( active->service == element->service ) { ! 671: found = true; ! 672: break; ! 673: } ! 674: } ! 675: ! 676: if( found ) { // this object is already locked ! 677: ! 678: // determine whether it is the same or a different thread trying to lock ! 679: if( active->thread != element->thread ) { // it is a different thread ! 680: ! 681: ArbitrationLockQueueElement * victim = 0; ! 682: ! 683: // before placing this new thread on the waiting queue, we look for ! 684: // a deadlock cycle... ! 685: ! 686: while( 1 ) { ! 687: // determine whether the active thread holding the object we ! 688: // want is waiting for another object to be unlocked ! 689: found = false; ! 690: queue_iterate( &gArbitrationLockQueueWaiting, ! 691: waiting, ! 692: ArbitrationLockQueueElement *, ! 693: link ) ! 694: { ! 695: if( waiting->thread == active->thread ) { ! 696: assert( false == waiting->aborted ); ! 697: found = true; ! 698: break; ! 699: } ! 700: } ! 701: ! 702: if( found ) { // yes, active thread waiting for another object ! 703: ! 704: // this may be a candidate for rejection if the required ! 705: // flag is not set, should we detect a deadlock later on ! 706: if( false == waiting->required ) ! 707: victim = waiting; ! 708: ! 709: // find the thread that is holding this other object, that ! 710: // is blocking the active thread from proceeding (fun :-) ! 711: found = false; ! 712: queue_iterate( &gArbitrationLockQueueActive, ! 713: active, // (reuse active queue element) ! 714: ArbitrationLockQueueElement *, ! 715: link ) ! 716: { ! 717: if( active->service == waiting->service ) { ! 718: found = true; ! 719: break; ! 720: } ! 721: } ! 722: ! 723: // someone must be holding it or it wouldn't be waiting ! 724: assert( found ); ! 725: ! 726: if( active->service == element->service ) { ! 727: ! 728: // doh, it's waiting for the thread that originated ! 729: // this whole lock (ie. current thread) -> deadlock ! 730: if( false == element->required ) { // willing to fail? ! 731: ! 732: // the originating thread doesn't have the required ! 733: // flag, so it can fail ! 734: success = false; // (fail originating lock request) ! 735: break; // (out of while) ! 736: ! 737: } else { // originating thread is not willing to fail ! 738: ! 739: // see if we came across a waiting thread that did ! 740: // not have the 'required' flag set: we'll fail it ! 741: if( victim ) { ! 742: ! 743: // we do have a willing victim, fail it's lock ! 744: victim->aborted = true; ! 745: ! 746: // take the victim off the waiting queue ! 747: queue_remove( &gArbitrationLockQueueWaiting, ! 748: victim, ! 749: ArbitrationLockQueueElement *, ! 750: link ); ! 751: ! 752: // wake the victim ! 753: thread_wakeup_one(victim); ! 754: ! 755: // allow this thread to proceed (ie. wait) ! 756: success = true; // (put request on wait queue) ! 757: break; // (out of while) ! 758: } else { ! 759: ! 760: // all the waiting threads we came across in ! 761: // finding this loop had the 'required' flag ! 762: // set, so we've got a deadlock we can't avoid ! 763: panic("I/O Kit: Unrecoverable deadlock."); ! 764: } ! 765: } ! 766: } else { ! 767: // repeat while loop, redefining active thread to be the ! 768: // thread holding "this other object" (see above), and ! 769: // looking for threads waiting on it; note the active ! 770: // variable points to "this other object" already... so ! 771: // there nothing to do in this else clause. ! 772: } ! 773: } else { // no, active thread is not waiting for another object ! 774: ! 775: success = true; // (put request on wait queue) ! 776: break; // (out of while) ! 777: } ! 778: } // while forever ! 779: ! 780: if( success ) { // put the request on the waiting queue? ! 781: ! 782: // place this thread on the waiting queue and put it to sleep; ! 783: // we place it at the tail of the queue... ! 784: queue_enter( &gArbitrationLockQueueWaiting, ! 785: element, ! 786: ArbitrationLockQueueElement *, ! 787: link ); ! 788: ! 789: // declare that this thread will wait for an given event ! 790: assert_wait(element, THREAD_UNINT); ! 791: ! 792: // unlock global access ! 793: IOUnlock( gArbitrationLockQueueLock ); ! 794: ! 795: // put thread to sleep, waiting for the our event to fire... ! 796: thread_block((void (*)(void)) 0); ! 797: ! 798: assert( THREAD_AWAKENED == thread_wait_result() ); ! 799: ! 800: // ...and we've been woken up; we might be one of two states: ! 801: // (a) we've been aborted and our queue element is not on ! 802: // any of the three queues, but is floating around ! 803: // (b) we're allowed to proceed with the lock and we have ! 804: // already been moved from the waiting queue to the ! 805: // active queue. ! 806: ! 807: // determine whether we've been aborted while we were asleep ! 808: if( element->aborted ) { ! 809: assert( false == element->required ); ! 810: ! 811: // re-lock global access ! 812: IOTakeLock( gArbitrationLockQueueLock ); ! 813: ! 814: action = kPutOnFreeQueue; ! 815: success = false; ! 816: } else { // we weren't aborted, so we must be ready to go :-) ! 817: ! 818: // we've already been moved from waiting to active queue ! 819: return true; ! 820: } ! 821: ! 822: } else { // the lock request is to be failed ! 823: ! 824: // return unused queue element to queue ! 825: action = kPutOnFreeQueue; ! 826: } ! 827: } else { // it is the same thread, recursive access is allowed ! 828: ! 829: // add one level of recursion ! 830: active->count++; ! 831: ! 832: // return unused queue element to queue ! 833: action = kPutOnFreeQueue; ! 834: success = true; ! 835: } ! 836: } else { // this object is not already locked, so let this thread through ! 837: action = kPutOnActiveQueue; ! 838: success = true; ! 839: } ! 840: ! 841: // put the new element on a queue ! 842: if( kPutOnActiveQueue == action ) { ! 843: queue_enter( &gArbitrationLockQueueActive, ! 844: element, ! 845: ArbitrationLockQueueElement *, ! 846: link ); ! 847: } else if( kPutOnFreeQueue == action ) { ! 848: queue_enter( &gArbitrationLockQueueFree, ! 849: element, ! 850: ArbitrationLockQueueElement *, ! 851: link ); ! 852: } else { ! 853: assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above ! 854: } ! 855: ! 856: // unlock global access ! 857: IOUnlock( gArbitrationLockQueueLock ); ! 858: ! 859: return( success ); ! 860: } ! 861: ! 862: void IOService::unlockForArbitration( void ) ! 863: { ! 864: bool found; ! 865: ArbitrationLockQueueElement * element; ! 866: ! 867: // lock global access ! 868: IOTakeLock( gArbitrationLockQueueLock ); ! 869: ! 870: // find the lock element for this object (ie. on active queue) ! 871: found = false; ! 872: queue_iterate( &gArbitrationLockQueueActive, ! 873: element, ! 874: ArbitrationLockQueueElement *, ! 875: link ) ! 876: { ! 877: if( element->service == this ) { ! 878: found = true; ! 879: break; ! 880: } ! 881: } ! 882: ! 883: assert( found ); ! 884: ! 885: // determine whether the lock has been taken recursively ! 886: if( element->count > 1 ) { ! 887: // undo one level of recursion ! 888: element->count--; ! 889: ! 890: } else { ! 891: ! 892: // remove it from the active queue ! 893: queue_remove( &gArbitrationLockQueueActive, ! 894: element, ! 895: ArbitrationLockQueueElement *, ! 896: link ); ! 897: ! 898: // put it on the free queue ! 899: queue_enter( &gArbitrationLockQueueFree, ! 900: element, ! 901: ArbitrationLockQueueElement *, ! 902: link ); ! 903: ! 904: // determine whether a thread is waiting for object (head to tail scan) ! 905: found = false; ! 906: queue_iterate( &gArbitrationLockQueueWaiting, ! 907: element, ! 908: ArbitrationLockQueueElement *, ! 909: link ) ! 910: { ! 911: if( element->service == this ) { ! 912: found = true; ! 913: break; ! 914: } ! 915: } ! 916: ! 917: if ( found ) { // we found an interested thread on waiting queue ! 918: ! 919: // remove it from the waiting queue ! 920: queue_remove( &gArbitrationLockQueueWaiting, ! 921: element, ! 922: ArbitrationLockQueueElement *, ! 923: link ); ! 924: ! 925: // put it on the active queue ! 926: queue_enter( &gArbitrationLockQueueActive, ! 927: element, ! 928: ArbitrationLockQueueElement *, ! 929: link ); ! 930: ! 931: // wake the waiting thread ! 932: thread_wakeup_one(element); ! 933: } ! 934: } ! 935: ! 936: // unlock global access ! 937: IOUnlock( gArbitrationLockQueueLock ); ! 938: } ! 939: ! 940: void IOService::applyToProviders( IOServiceApplierFunction applier, ! 941: void * context ) ! 942: { ! 943: applyToParents( (IORegistryEntryApplierFunction) applier, ! 944: context, gIOServicePlane ); ! 945: } ! 946: ! 947: void IOService::applyToClients( IOServiceApplierFunction applier, ! 948: void * context ) ! 949: { ! 950: applyToChildren( (IORegistryEntryApplierFunction) applier, ! 951: context, gIOServicePlane ); ! 952: } ! 953: ! 954: ! 955: /* ! 956: * Client messages ! 957: */ ! 958: ! 959: ! 960: // send a message to a client or interested party of this service ! 961: IOReturn IOService::messageClient( UInt32 type, OSObject * client, ! 962: void * argument = 0, vm_size_t argSize = 0 ) ! 963: { ! 964: IOReturn ret; ! 965: IOService * service; ! 966: _IOServiceInterestNotifier * interested; ! 967: ! 968: if( (service = OSDynamicCast( IOService, client))) ! 969: ret = service->message( type, this, argument ); ! 970: ! 971: else if( (interested = OSDynamicCast( _IOServiceInterestNotifier, client))) { ! 972: if( interested->fEnable) ! 973: ret = (*interested->handler)( interested->target, interested->ref, ! 974: type, this, argument, argSize ); ! 975: else ! 976: ret = kIOReturnSuccess; ! 977: ! 978: } else ! 979: ret = kIOReturnBadArgument; ! 980: ! 981: return( ret ); ! 982: } ! 983: ! 984: void IOService::applyToInterested( const OSSymbol * typeOfInterest, ! 985: OSObjectApplierFunction applier, ! 986: void * context ) ! 987: { ! 988: OSArray * array; ! 989: unsigned int index; ! 990: OSObject * next; ! 991: ! 992: applyToClients( (IOServiceApplierFunction) applier, context ); ! 993: ! 994: array = OSDynamicCast( OSArray, getProperty( typeOfInterest )); ! 995: if( array) { ! 996: LOCKREADNOTIFY(); ! 997: for( index = 0; ! 998: (next = array->getObject( index )); ! 999: index++) { ! 1000: (*applier)(next, context); ! 1001: } ! 1002: UNLOCKNOTIFY(); ! 1003: } ! 1004: } ! 1005: ! 1006: struct MessageClientsContext { ! 1007: IOService * service; ! 1008: UInt32 type; ! 1009: void * argument; ! 1010: vm_size_t argSize; ! 1011: IOReturn ret; ! 1012: }; ! 1013: ! 1014: static void messageClientsApplier( OSObject * object, void * ctx ) ! 1015: { ! 1016: IOReturn ret; ! 1017: MessageClientsContext * context = (MessageClientsContext *) ctx; ! 1018: ! 1019: ret = context->service->messageClient( context->type, ! 1020: object, context->argument, context->argSize ); ! 1021: if( kIOReturnSuccess != ret) ! 1022: context->ret = ret; ! 1023: } ! 1024: ! 1025: // send a message to all clients ! 1026: IOReturn IOService::messageClients( UInt32 type, ! 1027: void * argument = 0, vm_size_t argSize = 0 ) ! 1028: { ! 1029: MessageClientsContext context; ! 1030: ! 1031: context.service = this; ! 1032: context.type = type; ! 1033: context.argument = argument; ! 1034: context.argSize = argSize; ! 1035: context.ret = kIOReturnSuccess; ! 1036: ! 1037: applyToInterested( gIOGeneralInterest, ! 1038: &messageClientsApplier, &context ); ! 1039: ! 1040: return( context.ret ); ! 1041: } ! 1042: ! 1043: IOReturn IOService::acknowledgeNotification( IONotificationRef notification, ! 1044: IOOptionBits response ) ! 1045: { ! 1046: return( kIOReturnUnsupported ); ! 1047: } ! 1048: ! 1049: IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, ! 1050: IOServiceInterestHandler handler, void * target, void * ref ) ! 1051: { ! 1052: _IOServiceInterestNotifier * notify = 0; ! 1053: OSArray * set; ! 1054: ! 1055: if( (typeOfInterest != gIOGeneralInterest) ! 1056: && (typeOfInterest != gIOBusyInterest)) ! 1057: return( 0 ); ! 1058: ! 1059: lockForArbitration(); ! 1060: if( 0 == (__state[0] & kIOServiceInactiveState)) { ! 1061: ! 1062: notify = new _IOServiceInterestNotifier; ! 1063: if( notify && !notify->init()) { ! 1064: notify->release(); ! 1065: notify = 0; ! 1066: } ! 1067: ! 1068: if( notify) { ! 1069: notify->handler = handler; ! 1070: notify->target = target; ! 1071: notify->ref = ref; ! 1072: notify->fEnable = true; ! 1073: ! 1074: ////// queue ! 1075: ! 1076: LOCKWRITENOTIFY(); ! 1077: if( 0 == (set = (OSArray *) getProperty( typeOfInterest ))) { ! 1078: set = OSArray::withCapacity( 1 ); ! 1079: if( set) { ! 1080: setProperty( typeOfInterest, set ); ! 1081: set->release(); ! 1082: } ! 1083: } ! 1084: notify->whence = set; ! 1085: if( set) ! 1086: set->setObject( notify ); ! 1087: UNLOCKNOTIFY(); ! 1088: } ! 1089: } ! 1090: unlockForArbitration(); ! 1091: ! 1092: return( notify ); ! 1093: } ! 1094: ! 1095: static void cleanInterestArray( OSObject * object ) ! 1096: { ! 1097: OSArray * array; ! 1098: unsigned int index; ! 1099: _IOServiceInterestNotifier * next; ! 1100: ! 1101: if( (array = OSDynamicCast( OSArray, object))) { ! 1102: LOCKWRITENOTIFY(); ! 1103: for( index = 0; ! 1104: (next = (_IOServiceInterestNotifier *) ! 1105: array->getObject( index )); ! 1106: index++) { ! 1107: next->whence = 0; ! 1108: } ! 1109: UNLOCKNOTIFY(); ! 1110: } ! 1111: } ! 1112: ! 1113: void IOService::unregisterAllInterest( void ) ! 1114: { ! 1115: cleanInterestArray( getProperty( gIOGeneralInterest )); ! 1116: cleanInterestArray( getProperty( gIOBusyInterest )); ! 1117: } ! 1118: ! 1119: /* ! 1120: * _IOServiceInterestNotifier ! 1121: */ ! 1122: ! 1123: void _IOServiceInterestNotifier::remove() ! 1124: { ! 1125: LOCKWRITENOTIFY(); ! 1126: ! 1127: if( whence) { ! 1128: whence->removeObject(whence->getNextIndexOfObject( ! 1129: (OSObject *) this, 0 )); ! 1130: whence = 0; ! 1131: } ! 1132: ! 1133: fEnable = false; ! 1134: ! 1135: UNLOCKNOTIFY(); ! 1136: ! 1137: release(); ! 1138: } ! 1139: ! 1140: bool _IOServiceInterestNotifier::disable() ! 1141: { ! 1142: bool ret; ! 1143: ! 1144: LOCKWRITENOTIFY(); ! 1145: ret = fEnable; ! 1146: fEnable = false; ! 1147: UNLOCKNOTIFY(); ! 1148: ! 1149: return( ret ); ! 1150: } ! 1151: ! 1152: void _IOServiceInterestNotifier::enable( bool was ) ! 1153: { ! 1154: LOCKWRITENOTIFY(); ! 1155: fEnable = was; ! 1156: UNLOCKNOTIFY(); ! 1157: } ! 1158: ! 1159: /* ! 1160: * Terminate ! 1161: */ ! 1162: ! 1163: // a method in case someone needs to override it ! 1164: bool IOService::terminateClient( IOService * client, IOOptionBits options ) ! 1165: { ! 1166: bool ok; ! 1167: ! 1168: if( client->isParent( this, gIOServicePlane, true)) ! 1169: // we are the clients only provider ! 1170: ok = client->terminate( options ); ! 1171: else ! 1172: ok = true; ! 1173: ! 1174: return( ok ); ! 1175: } ! 1176: ! 1177: struct TerminateClientsContext { ! 1178: IOService * provider; ! 1179: IOOptionBits options; ! 1180: }; ! 1181: ! 1182: static void terminateClientsApplier( OSObject * object, void * ctx ) ! 1183: { ! 1184: TerminateClientsContext * context = (TerminateClientsContext *) ctx; ! 1185: IOService * client; ! 1186: ! 1187: context->provider->messageClient( kIOMessageServiceIsTerminated, ! 1188: object, (void *) context->options ); ! 1189: ! 1190: if( (client = OSDynamicCast( IOService, object))){ ! 1191: if( gIOKitDebug & kIOLogYield) ! 1192: LOG("%s::terminateClient(%s,%08lx)\n", ! 1193: context->provider->getName(), ! 1194: client->getName(), context->options); ! 1195: ! 1196: context->provider->terminateClient( ! 1197: client, ((context->options) | kIOServiceRecursing) ! 1198: & ~kIOServiceSynchronous ); ! 1199: } ! 1200: } ! 1201: ! 1202: bool IOService::terminate( IOOptionBits options = 0 ) ! 1203: { ! 1204: bool ok; ! 1205: bool wasClosed; ! 1206: bool madeInactive; ! 1207: TerminateClientsContext context; ! 1208: ! 1209: if( false == lockForArbitration( (options & kIOServiceRequired) )) ! 1210: return false; ! 1211: ! 1212: retain(); ! 1213: ! 1214: ok = (options & kIOServiceRequired); ! 1215: wasClosed = (false == handleIsOpen( 0 )); ! 1216: if( !ok) ! 1217: ok = wasClosed; ! 1218: ! 1219: if( ok) { ! 1220: madeInactive = (0 == (__state[0] & kIOServiceInactiveState)); ! 1221: if( madeInactive) { ! 1222: __state[0] |= kIOServiceInactiveState; ! 1223: __state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState); ! 1224: if( 0 == (options & kIOServiceRecursing)) ! 1225: __state[1] |= kIOServiceTerminatedState; ! 1226: } ! 1227: } else ! 1228: madeInactive = false; ! 1229: ! 1230: unlockForArbitration(); ! 1231: ! 1232: if( madeInactive) { ! 1233: ! 1234: adjustBusy( 1 ); ! 1235: context.provider = this; ! 1236: context.options = options; ! 1237: applyToInterested( gIOGeneralInterest, ! 1238: &terminateClientsApplier, (void *) &context ); ! 1239: ! 1240: if( wasClosed && (0 == (options & kIOServiceRecursing))) { ! 1241: if( options & kIOServiceSynchronous) ! 1242: doServiceTerminate( 0 ); ! 1243: else ! 1244: ok = (0 != _IOServiceJob::startJob( this, kTerminateNubJob, 0 )); ! 1245: } ! 1246: if( options & kIOServiceSynchronous) ! 1247: waitQuiet(); ! 1248: } ! 1249: ! 1250: release(); ! 1251: ! 1252: return( ok ); ! 1253: } ! 1254: ! 1255: void IOService::doServiceTerminate( IOOptionBits options ) ! 1256: { ! 1257: IOService * next; ! 1258: OSIterator * iter; ! 1259: IOService * client; ! 1260: OSArray * deathList = 0; ! 1261: unsigned int index; ! 1262: bool finalize; ! 1263: bool ok = true; ! 1264: ! 1265: next = this; ! 1266: deathList = OSArray::withObjects( (OSObject **)&next, 1, 1 ); ! 1267: assert( deathList ); ! 1268: if( !deathList) ! 1269: return; ! 1270: ! 1271: index = 0; ! 1272: do { ! 1273: iter = next->getClientIterator(); ! 1274: assert( iter ); ! 1275: if( iter) { ! 1276: ! 1277: while( (client = (IOService *) iter->getNextObject())) { ! 1278: ! 1279: if( gIOKitDebug & kIOLogYield) ! 1280: LOG("%s::actionClients(%s)\n", ! 1281: next->getName(), client->getName()); ! 1282: ! 1283: client->stop( next ); ! 1284: ! 1285: if( next->isOpen( client )) ! 1286: next->close( client ); ! 1287: ! 1288: client->detach( next ); ! 1289: ! 1290: client->lockForArbitration(); ! 1291: if( (client->__state[0] & kIOServiceInactiveState) ! 1292: && (0 == (client->__state[1] & kIOServiceTerminatedState)) ! 1293: && (0 == client->getProvider()) ) { ! 1294: client->__state[1] |= kIOServiceTerminatedState; ! 1295: finalize = (false == client->handleIsOpen( 0 )); ! 1296: } else ! 1297: finalize = false; ! 1298: client->unlockForArbitration(); ! 1299: ! 1300: if( finalize) { ! 1301: next->adjustBusy( -1 ); // because the client is detached now ! 1302: // and won't adjust its provider busy count ! 1303: deathList->setObject( client ); ! 1304: } ! 1305: } ! 1306: iter->release(); ! 1307: } ! 1308: ! 1309: } while( (next = (IOService *) deathList->getObject( ++index )) ); ! 1310: ! 1311: while( index--) { ! 1312: ! 1313: next = (IOService *) deathList->getObject( index ); ! 1314: assert( next ); ! 1315: next->retain(); ! 1316: deathList->removeObject( index ); ! 1317: ! 1318: next->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); ! 1319: ! 1320: IOUserClient::destroyUserReferences( next ); ! 1321: ! 1322: next->unregisterAllInterest(); ! 1323: ! 1324: ok = next->finalize( options ); ! 1325: assert( ok ); ! 1326: ! 1327: if( gIOKitDebug & kIOLogYield) ! 1328: LOG("%s __state = %08lx:%08lx\n", next->getName(), ! 1329: next->__state[0], next->__state[1]); ! 1330: next->adjustBusy( -1 ); ! 1331: ! 1332: next->release(); ! 1333: } ! 1334: ! 1335: deathList->release(); ! 1336: } ! 1337: ! 1338: bool IOService::finalize( IOOptionBits options ) ! 1339: { ! 1340: OSIterator * iter; ! 1341: IOService * provider; ! 1342: ! 1343: iter = getProviderIterator(); ! 1344: assert( iter ); ! 1345: ! 1346: if( iter) { ! 1347: while( (provider = (IOService *) iter->getNextObject())) { ! 1348: stop( provider ); ! 1349: if( provider->isOpen( this )) ! 1350: provider->close( this ); ! 1351: detach( provider ); ! 1352: provider->adjustBusy( -1 ); ! 1353: } ! 1354: iter->release(); ! 1355: } ! 1356: ! 1357: return( true ); ! 1358: } ! 1359: ! 1360: /* ! 1361: * Open & close ! 1362: */ ! 1363: ! 1364: bool IOService::open( IOService * forClient, ! 1365: IOOptionBits options = 0, ! 1366: void * arg = 0 ) ! 1367: { ! 1368: bool ok; ! 1369: ! 1370: if( false == lockForArbitration(false) ) ! 1371: return false; ! 1372: ! 1373: ok = (0 == (__state[0] & kIOServiceInactiveState)); ! 1374: if( ok) ! 1375: ok = handleOpen( forClient, options, arg ); ! 1376: ! 1377: unlockForArbitration(); ! 1378: ! 1379: return( ok ); ! 1380: } ! 1381: ! 1382: void IOService::close( IOService * forClient, ! 1383: IOOptionBits options = 0 ) ! 1384: { ! 1385: bool ok; ! 1386: bool wasClosed; ! 1387: bool last = false; ! 1388: OSIterator * iter; ! 1389: IOService * client; ! 1390: ! 1391: lockForArbitration(); ! 1392: ! 1393: wasClosed = handleIsOpen( forClient ); ! 1394: if( wasClosed) { ! 1395: handleClose( forClient, options ); ! 1396: ! 1397: last = ( (__state[1] & kIOServiceTerminatedState) ! 1398: && (false == handleIsOpen( 0 )) ); ! 1399: } ! 1400: ! 1401: unlockForArbitration(); ! 1402: ! 1403: if( last) { ! 1404: ok = (0 != _IOServiceJob::startJob( this, kTerminateNubJob, 0 )); ! 1405: assert( ok ); ! 1406: ! 1407: } else if( wasClosed) { ! 1408: ! 1409: iter = getClientIterator(); ! 1410: assert( iter ); ! 1411: ! 1412: if( iter) { ! 1413: while( (client = (IOService *) iter->getNextObject())) { ! 1414: if( client != forClient) ! 1415: messageClient( kIOMessageServiceWasClosed, client, 0 ); ! 1416: } ! 1417: iter->release(); ! 1418: } ! 1419: } ! 1420: } ! 1421: ! 1422: bool IOService::isOpen( const IOService * forClient = 0 ) const ! 1423: { ! 1424: IOService * self = (IOService *) this; ! 1425: bool ok; ! 1426: ! 1427: self->lockForArbitration(); ! 1428: ! 1429: ok = handleIsOpen( forClient ); ! 1430: ! 1431: self->unlockForArbitration(); ! 1432: ! 1433: return( ok ); ! 1434: } ! 1435: ! 1436: bool IOService::handleOpen( IOService * forClient, ! 1437: IOOptionBits options, ! 1438: void * arg ) ! 1439: { ! 1440: bool ok; ! 1441: ! 1442: ok = (0 == __owner); ! 1443: if( ok ) ! 1444: __owner = forClient; ! 1445: ! 1446: else if( options & kIOServiceSeize ) { ! 1447: ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose, ! 1448: __owner, (void *) options )); ! 1449: if( ok && (0 == __owner )) ! 1450: __owner = forClient; ! 1451: } ! 1452: ! 1453: return( ok ); ! 1454: } ! 1455: ! 1456: void IOService::handleClose( IOService * forClient, ! 1457: IOOptionBits options ) ! 1458: { ! 1459: if( __owner == forClient) ! 1460: __owner = 0; ! 1461: } ! 1462: ! 1463: bool IOService::handleIsOpen( const IOService * forClient ) const ! 1464: { ! 1465: if( forClient) ! 1466: return( __owner == forClient ); ! 1467: else ! 1468: return( __owner != forClient ); ! 1469: } ! 1470: ! 1471: /* ! 1472: * Probing & starting ! 1473: */ ! 1474: ! 1475: SInt32 IONotifyOrdering( OSObject * obj1, OSObject * obj2, void * ref) ! 1476: { ! 1477: SInt32 val1; ! 1478: SInt32 val2; ! 1479: ! 1480: val1 = 0; ! 1481: val2 = 0; ! 1482: ! 1483: if ( obj1 ) ! 1484: val1 = ((_IOServiceNotifier *)obj1)->priority; ! 1485: ! 1486: if ( obj2 ) ! 1487: val2 = ((_IOServiceNotifier *)obj2)->priority; ! 1488: ! 1489: return ( val1 - val2 ); ! 1490: } ! 1491: ! 1492: static SInt32 IOServiceObjectOrder( OSObject * entry, void * ref) ! 1493: { ! 1494: OSDictionary * dict; ! 1495: IOService * service; ! 1496: _IOServiceNotifier * notify; ! 1497: OSSymbol * key = (OSSymbol *) ref; ! 1498: OSNumber * offset; ! 1499: ! 1500: if( (notify = OSDynamicCast( _IOServiceNotifier, entry))) ! 1501: return( notify->priority ); ! 1502: ! 1503: else if( (service = OSDynamicCast( IOService, entry))) ! 1504: offset = OSDynamicCast(OSNumber, service->getProperty( key )); ! 1505: else if( (dict = OSDynamicCast( OSDictionary, entry))) ! 1506: offset = OSDynamicCast(OSNumber, dict->getObject( key )); ! 1507: else { ! 1508: assert( false ); ! 1509: offset = 0; ! 1510: } ! 1511: ! 1512: if( offset) ! 1513: return( (SInt32) offset->unsigned32BitValue()); ! 1514: else ! 1515: return( kIODefaultProbeScore ); ! 1516: } ! 1517: ! 1518: SInt32 IOServiceOrdering( OSObject * obj1, OSObject * obj2, void * ref ) ! 1519: { ! 1520: SInt32 val1; ! 1521: SInt32 val2; ! 1522: ! 1523: val1 = 0; ! 1524: val2 = 0; ! 1525: ! 1526: if ( obj1 ) ! 1527: val1 = IOServiceObjectOrder( obj1, ref ); ! 1528: ! 1529: if ( obj2 ) ! 1530: val2 = IOServiceObjectOrder( obj2, ref ); ! 1531: ! 1532: return ( val1 - val2 ); ! 1533: } ! 1534: ! 1535: IOService * IOService::getClientWithCategory( const OSSymbol * category ) ! 1536: { ! 1537: IOService * service = 0; ! 1538: OSIterator * iter; ! 1539: const OSSymbol * nextCat; ! 1540: ! 1541: iter = getClientIterator(); ! 1542: if( iter) { ! 1543: while( (service = (IOService *) iter->getNextObject())) { ! 1544: if( kIOServiceInactiveState & service->__state[0]) ! 1545: continue; ! 1546: nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol, ! 1547: service->getProperty( gIOMatchCategoryKey )); ! 1548: if( category == nextCat) ! 1549: break; ! 1550: } ! 1551: iter->release(); ! 1552: } ! 1553: return( service ); ! 1554: } ! 1555: ! 1556: /* ! 1557: * Alloc and probe matching classes, ! 1558: * called on the provider instance ! 1559: */ ! 1560: ! 1561: void IOService::probeCandidates( OSOrderedSet * matches ) ! 1562: { ! 1563: OSDictionary * match; ! 1564: OSSymbol * symbol; ! 1565: IOService * inst; ! 1566: IOService * newInst; ! 1567: OSDictionary * props; ! 1568: SInt32 score; ! 1569: OSNumber * newPri; ! 1570: OSOrderedSet * startList; ! 1571: OSDictionary * startDict = 0; ! 1572: const OSSymbol * category; ! 1573: OSIterator * iter; ! 1574: _IOServiceNotifier * notify; ! 1575: OSObject * nextMatch; ! 1576: bool started; ! 1577: bool needReloc = false; ! 1578: bool needsCat; ! 1579: #ifdef DEBUG ! 1580: SInt64 debugFlags; ! 1581: #endif ! 1582: ! 1583: assert( matches ); ! 1584: while( (nextMatch = matches->getFirstObject())) { ! 1585: ! 1586: nextMatch->retain(); ! 1587: matches->removeObject(nextMatch); ! 1588: ! 1589: if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) { ! 1590: ! 1591: lockForArbitration(); ! 1592: LOCKREADNOTIFY(); ! 1593: if( notify->fEnable ! 1594: && (0 == (__state[0] & kIOServiceInactiveState))) ! 1595: (*notify->handler)( notify->target, notify->ref, this ); ! 1596: UNLOCKNOTIFY(); ! 1597: unlockForArbitration(); ! 1598: nextMatch->release(); ! 1599: continue; ! 1600: ! 1601: } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) { ! 1602: nextMatch->release(); ! 1603: continue; ! 1604: } ! 1605: ! 1606: props = 0; ! 1607: inst = 0; ! 1608: newInst = 0; ! 1609: #ifdef DEBUG ! 1610: debugFlags = getDebugFlags( match ); ! 1611: #endif ! 1612: ! 1613: do { ! 1614: category = OSDynamicCast( OSSymbol, ! 1615: match->getObject( gIOMatchCategoryKey )); ! 1616: needsCat = (0 == category); ! 1617: if( needsCat) ! 1618: category = gIODefaultMatchCategoryKey; ! 1619: ! 1620: if( getClientWithCategory( category )) { ! 1621: #ifdef DEBUG ! 1622: if( debugFlags & kIOLogMatch) ! 1623: LOG("%s: match category %s exists\n", getName(), ! 1624: category->getCStringNoCopy()); ! 1625: #endif ! 1626: nextMatch->release(); ! 1627: continue; ! 1628: } ! 1629: ! 1630: // create a copy now in case its modified during matching ! 1631: props = OSDictionary::withDictionary( match, match->getCount()); ! 1632: nextMatch->release(); ! 1633: if( 0 == props) ! 1634: continue; ! 1635: props->setCapacityIncrement(1); ! 1636: ! 1637: // check the nub matches ! 1638: if( false == passiveMatch( props, true )) ! 1639: continue; ! 1640: ! 1641: // Check to see if driver reloc has been loaded. ! 1642: needReloc = (false == gIOCatalogue->isModuleLoaded( match )); ! 1643: if( needReloc) { ! 1644: #ifdef DEBUG ! 1645: if( debugFlags & kIOLogCatalogue) ! 1646: LOG("%s: stalling for module\n", getName()); ! 1647: #endif ! 1648: continue; ! 1649: } ! 1650: ! 1651: symbol = OSDynamicCast( OSSymbol, ! 1652: props->getObject( gIOClassKey)); ! 1653: if( !symbol) ! 1654: continue; ! 1655: ! 1656: // alloc the driver instance ! 1657: inst = (IOService *) OSMetaClass::allocClassWithName( symbol); ! 1658: ! 1659: if( !inst) { ! 1660: IOLog("Couldn't alloc %s; class not ", ! 1661: symbol->getCStringNoCopy()); ! 1662: if( OSMetaClass::getMetaClassWithName( symbol)) ! 1663: IOLog("using default constructor\n"); ! 1664: else ! 1665: IOLog("available\n"); ! 1666: continue; ! 1667: } ! 1668: ! 1669: // init driver instance ! 1670: if( !(inst->init( props ))) { ! 1671: #ifdef DEBUG ! 1672: if( debugFlags & kIOLogStart) ! 1673: IOLog("%s::init fails\n", symbol->getCStringNoCopy()); ! 1674: #endif ! 1675: continue; ! 1676: } ! 1677: if( __state[1] & kIOServiceSynchronousState) ! 1678: inst->__state[1] |= kIOServiceSynchronousState; ! 1679: ! 1680: // give the driver the default match category if not specified ! 1681: if( needsCat) ! 1682: inst->setProperty( gIOMatchCategoryKey, (OSObject *) category ); ! 1683: ! 1684: // attach driver instance ! 1685: if( !(inst->attach( this ))) ! 1686: continue; ! 1687: ! 1688: // pass in score from property table ! 1689: score = matches->orderObject( match ); ! 1690: ! 1691: // & probe the new driver instance ! 1692: #ifdef DEBUG ! 1693: if( debugFlags & kIOLogProbe) ! 1694: LOG("%s::probe(%s)\n", ! 1695: inst->getMetaClass()->getClassName(), getName()); ! 1696: #endif ! 1697: ! 1698: #if 1 ! 1699: newInst = inst->probe( this, &score ); ! 1700: inst->detach( this ); ! 1701: if( 0 == newInst) { ! 1702: #ifdef DEBUG ! 1703: if( debugFlags & kIOLogProbe) ! 1704: IOLog("%s::probe fails\n", symbol->getCStringNoCopy()); ! 1705: #endif ! 1706: continue; ! 1707: } ! 1708: #else ! 1709: if( 0 == (newInst = inst->probe( this, &score ))) { ! 1710: #ifdef DEBUG ! 1711: if( debugFlags & kIOLogProbe) ! 1712: IOLog("%s::probe fails\n", symbol->getCStringNoCopy()); ! 1713: #endif ! 1714: inst->detach( this ); ! 1715: continue; ! 1716: } ! 1717: ! 1718: if( newInst != inst) { ! 1719: // instance substitution ! 1720: inst->detach( this ); ! 1721: // attach the returned instance ! 1722: if( !(newInst->attach( this ))) ! 1723: continue; ! 1724: } ! 1725: #endif ! 1726: ! 1727: // save the score ! 1728: newPri = OSNumber::withNumber( score, 32 ); ! 1729: if( newPri) { ! 1730: newInst->setProperty( gIOProbeScoreKey, newPri ); ! 1731: newPri->release(); ! 1732: } ! 1733: ! 1734: // add to start list for the match category ! 1735: if( 0 == startDict) ! 1736: startDict = OSDictionary::withCapacity( 1 ); ! 1737: assert( startDict ); ! 1738: startList = (OSOrderedSet *) ! 1739: startDict->getObject( category ); ! 1740: if( 0 == startList) { ! 1741: startList = OSOrderedSet::withCapacity( 1, ! 1742: IOServiceOrdering, (void *) gIOProbeScoreKey ); ! 1743: if( startDict && startList) { ! 1744: startDict->setObject( category, startList ); ! 1745: startList->release(); ! 1746: } ! 1747: } ! 1748: assert( startList ); ! 1749: if( startList) ! 1750: startList->setObject( newInst ); ! 1751: ! 1752: } while( false ); ! 1753: ! 1754: if( props) ! 1755: props->release(); ! 1756: if( inst) ! 1757: inst->release(); ! 1758: ! 1759: // If reloc hasn't been loaded, exit out of function cleanly. ! 1760: // Re-probing will occur after reloc has been loaded. ! 1761: if( needReloc ) { ! 1762: if( startDict ) { ! 1763: startDict->release(); ! 1764: startDict = 0; ! 1765: } ! 1766: break; ! 1767: } ! 1768: } ! 1769: matches->release(); ! 1770: ! 1771: // start the best (until success) of each category ! 1772: ! 1773: iter = OSCollectionIterator::withCollection( startDict ); ! 1774: if( iter) { ! 1775: while( (category = (const OSSymbol *) iter->getNextObject())) { ! 1776: ! 1777: startList = (OSOrderedSet *) startDict->getObject( category ); ! 1778: assert( startList ); ! 1779: if( !startList) ! 1780: continue; ! 1781: ! 1782: started = false; ! 1783: while( true // (!started) ! 1784: && (inst = (IOService *)startList->getFirstObject())) { ! 1785: ! 1786: inst->retain(); ! 1787: startList->removeObject(inst); ! 1788: ! 1789: #ifdef DEBUG ! 1790: debugFlags = getDebugFlags( inst->getPropertyTable() ); ! 1791: ! 1792: if( debugFlags & kIOLogStart) { ! 1793: if( started) ! 1794: LOG( "match category exists, skipping " ); ! 1795: LOG( "%s::start(%s) <%d>\n", inst->getName(), ! 1796: getName(), inst->getRetainCount()); ! 1797: } ! 1798: #endif ! 1799: if( false == started) ! 1800: started = startCandidate( inst ); ! 1801: #ifdef DEBUG ! 1802: if( (debugFlags & kIOLogStart) && (false == started)) ! 1803: LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(), ! 1804: inst->getRetainCount()); ! 1805: #endif ! 1806: inst->release(); ! 1807: } ! 1808: } ! 1809: iter->release(); ! 1810: } ! 1811: ! 1812: if( startDict) ! 1813: startDict->release(); ! 1814: } ! 1815: ! 1816: /* ! 1817: * Start a previously attached & probed instance, ! 1818: * called on exporting object instance ! 1819: */ ! 1820: ! 1821: bool IOService::startCandidate( IOService * service ) ! 1822: { ! 1823: bool ok; ! 1824: ! 1825: ok = service->attach( this ); ! 1826: ! 1827: if( ok) { ! 1828: // stall for any nub resources ! 1829: checkResources(); ! 1830: // stall for any driver resources ! 1831: service->checkResources(); ! 1832: ! 1833: ok = service->start( this ); ! 1834: if( !ok) ! 1835: service->detach( this ); ! 1836: } ! 1837: return( ok ); ! 1838: } ! 1839: ! 1840: IOService * IOService::resources( void ) ! 1841: { ! 1842: return( gIOResources ); ! 1843: } ! 1844: ! 1845: void IOService::publishResource( const char * key, OSObject * value = 0 ) ! 1846: { ! 1847: const OSSymbol * sym; ! 1848: ! 1849: if( (sym = OSSymbol::withCString( key))) { ! 1850: publishResource( sym, value); ! 1851: sym->release(); ! 1852: } ! 1853: } ! 1854: ! 1855: void IOService::publishResource( const OSSymbol * key, OSObject * value = 0 ) ! 1856: { ! 1857: if( 0 == value) ! 1858: value = (OSObject *) gIOServiceKey; ! 1859: ! 1860: gIOResources->setProperty( key, value); ! 1861: ! 1862: gIOResourceGenerationCount++; ! 1863: gIOResources->registerService(); ! 1864: } ! 1865: ! 1866: bool IOService::addNeededResource( const char * key ) ! 1867: { ! 1868: OSObject * resources; ! 1869: OSSet * set; ! 1870: OSString * newKey; ! 1871: bool ret; ! 1872: ! 1873: resources = getProperty( gIOResourceMatchKey ); ! 1874: ! 1875: newKey = OSString::withCString( key ); ! 1876: if( (0 == resources) || (0 == newKey)) ! 1877: return( false); ! 1878: ! 1879: set = OSDynamicCast( OSSet, resources ); ! 1880: if( !set) { ! 1881: set = OSSet::withCapacity( 1 ); ! 1882: if( set) ! 1883: set->setObject( resources ); ! 1884: } ! 1885: else ! 1886: set->retain(); ! 1887: ! 1888: set->setObject( newKey ); ! 1889: newKey->release(); ! 1890: ret = setProperty( gIOResourceMatchKey, set ); ! 1891: set->release(); ! 1892: ! 1893: return( ret ); ! 1894: } ! 1895: ! 1896: bool IOService::checkResource( OSObject * matching ) ! 1897: { ! 1898: OSString * str; ! 1899: OSDictionary * table; ! 1900: ! 1901: if( (str = OSDynamicCast( OSString, matching ))) { ! 1902: if( gIOResources->getProperty( str )) ! 1903: return( true ); ! 1904: } ! 1905: ! 1906: if( str) ! 1907: table = resourceMatching( str ); ! 1908: else if( (table = OSDynamicCast( OSDictionary, matching ))) ! 1909: table->retain(); ! 1910: else { ! 1911: IOLog("%s: Can't match using: %s\n", getName(), ! 1912: matching->getMetaClass()->getClassName()); ! 1913: /* false would stall forever */ ! 1914: return( true ); ! 1915: } ! 1916: ! 1917: if( gIOKitDebug & kIOLogConfig) ! 1918: LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName()); ! 1919: ! 1920: waitForService( table ); ! 1921: ! 1922: if( gIOKitDebug & kIOLogConfig) ! 1923: LOG("config(%x): waking\n", (int) IOThreadSelf() ); ! 1924: ! 1925: return( true ); ! 1926: } ! 1927: ! 1928: bool IOService::checkResources( void ) ! 1929: { ! 1930: OSObject * resources; ! 1931: OSSet * set; ! 1932: OSIterator * iter; ! 1933: bool ok; ! 1934: ! 1935: resources = getProperty( gIOResourceMatchKey ); ! 1936: if( 0 == resources) ! 1937: return( true ); ! 1938: ! 1939: if( (set = OSDynamicCast( OSSet, resources ))) { ! 1940: ! 1941: iter = OSCollectionIterator::withCollection( set ); ! 1942: ok = (0 != iter); ! 1943: while( ok && (resources = iter->getNextObject()) ) ! 1944: ok = checkResource( resources ); ! 1945: if( iter) ! 1946: iter->release(); ! 1947: ! 1948: } else ! 1949: ok = checkResource( resources ); ! 1950: ! 1951: return( ok ); ! 1952: } ! 1953: ! 1954: ! 1955: _IOConfigThread * _IOConfigThread::configThread( void ) ! 1956: { ! 1957: _IOConfigThread * inst; ! 1958: ! 1959: do { ! 1960: if( !(inst = new _IOConfigThread)) ! 1961: continue; ! 1962: if( !inst->init()) ! 1963: continue; ! 1964: if( !(inst->thread = IOCreateThread ! 1965: ( (IOThreadFunc) &_IOConfigThread::main, inst ))) ! 1966: continue; ! 1967: ! 1968: return( inst ); ! 1969: ! 1970: } while( false); ! 1971: ! 1972: if( inst) ! 1973: inst->release(); ! 1974: ! 1975: return( 0 ); ! 1976: } ! 1977: ! 1978: void _IOConfigThread::free( void ) ! 1979: { ! 1980: OSObject::free(); ! 1981: } ! 1982: ! 1983: void IOService::doServiceMatch( void ) ! 1984: { ! 1985: _IOServiceNotifier * notify; ! 1986: OSIterator * iter; ! 1987: OSOrderedSet * matches; ! 1988: SInt32 catalogGeneration; ! 1989: bool keepGuessing = true; ! 1990: bool reRegistered = true; ! 1991: ! 1992: // job->nub->deliverNotification( gIOPublishNotification, ! 1993: // kIOServiceRegisteredState, 0xffffffff ); ! 1994: ! 1995: while( keepGuessing ) { ! 1996: ! 1997: matches = gIOCatalogue->findDrivers( this, &catalogGeneration ); ! 1998: // the matches list should always be created by findDrivers() ! 1999: if( matches) { ! 2000: ! 2001: lockForArbitration(); ! 2002: if( 0 == (__state[0] & kIOServiceFirstPublishState)) ! 2003: deliverNotification( gIOFirstPublishNotification, ! 2004: kIOServiceFirstPublishState, 0xffffffff ); ! 2005: LOCKREADNOTIFY(); ! 2006: __state[1] &= ~kIOServiceConfigState; ! 2007: __state[0] |= kIOServiceRegisteredState; ! 2008: ! 2009: if( reRegistered && (0 == (__state[0] & kIOServiceInactiveState))) { ! 2010: ! 2011: iter = OSCollectionIterator::withCollection( (OSOrderedSet *) ! 2012: gNotifications->getObject( gIOPublishNotification ) ); ! 2013: if( iter) { ! 2014: while((notify = (_IOServiceNotifier *) ! 2015: iter->getNextObject())) { ! 2016: if( passiveMatch( notify->matching )) ! 2017: matches->setObject( notify ); ! 2018: } ! 2019: iter->release(); ! 2020: } ! 2021: } ! 2022: ! 2023: UNLOCKNOTIFY(); ! 2024: unlockForArbitration(); ! 2025: ! 2026: if( matches->getCount() && (kIOReturnSuccess == getResources())) ! 2027: probeCandidates( matches ); ! 2028: else ! 2029: matches->release(); ! 2030: } ! 2031: ! 2032: lockForArbitration(); ! 2033: reRegistered = (0 != (__state[1] & kIOServiceConfigState)); ! 2034: keepGuessing = ! 2035: (reRegistered || (catalogGeneration != ! 2036: gIOCatalogue->getGenerationCount())) ! 2037: && (0 == (__state[0] & kIOServiceInactiveState)); ! 2038: ! 2039: if( keepGuessing) ! 2040: unlockForArbitration(); ! 2041: } ! 2042: ! 2043: if( 0 == (__state[0] & kIOServiceInactiveState)) { ! 2044: deliverNotification( gIOMatchedNotification, ! 2045: kIOServiceMatchedState, 0xffffffff ); ! 2046: if( 0 == (__state[0] & kIOServiceFirstMatchState)) ! 2047: deliverNotification( gIOFirstMatchNotification, ! 2048: kIOServiceFirstMatchState, 0xffffffff ); ! 2049: } ! 2050: ! 2051: unlockForArbitration(); ! 2052: ! 2053: adjustBusy( -1 ); ! 2054: } ! 2055: ! 2056: void IOService::adjustBusy( SInt32 delta ) ! 2057: { ! 2058: IOService * next; ! 2059: UInt32 count; ! 2060: bool wasQuiet, nowQuiet; ! 2061: ! 2062: if( 0 == delta) ! 2063: return; ! 2064: ! 2065: IOTakeLock( gIOServiceBusyLock ); ! 2066: next = this; ! 2067: ! 2068: do { ! 2069: count = next->__state[1] & kIOServiceBusyStateMask; ! 2070: assert( count < kIOServiceBusyMax); ! 2071: wasQuiet = (0 == count); ! 2072: assert( (!wasQuiet) || (delta > 0)); ! 2073: next->__state[1] += delta; ! 2074: nowQuiet = (0 == (next->__state[1] & kIOServiceBusyStateMask)); ! 2075: ! 2076: if( nowQuiet) ! 2077: thread_wakeup( (event_t) next); ! 2078: ! 2079: if( (wasQuiet || nowQuiet) ) { ! 2080: OSArray * array; ! 2081: unsigned int index; ! 2082: OSObject * interested; ! 2083: ! 2084: array = OSDynamicCast( OSArray, next->getProperty( gIOBusyInterest )); ! 2085: if( array) { ! 2086: LOCKREADNOTIFY(); ! 2087: for( index = 0; ! 2088: (interested = array->getObject( index )); ! 2089: index++) { ! 2090: next->messageClient(kIOMessageServiceBusyStateChange, ! 2091: interested, (void *) wasQuiet /* busy now */); ! 2092: } ! 2093: UNLOCKNOTIFY(); ! 2094: } ! 2095: } ! 2096: ! 2097: delta = nowQuiet ? -1 : +1; ! 2098: ! 2099: } while( (wasQuiet || nowQuiet) && (next = next->getProvider())); ! 2100: ! 2101: IOUnlock( gIOServiceBusyLock ); ! 2102: } ! 2103: ! 2104: UInt32 IOService::getBusyState( void ) ! 2105: { ! 2106: return( __state[1] & kIOServiceBusyStateMask ); ! 2107: } ! 2108: ! 2109: IOReturn IOService::waitForState( UInt32 mask, UInt32 value, ! 2110: mach_timespec_t * timeout = 0 ) ! 2111: { ! 2112: bool wait; ! 2113: ! 2114: do { ! 2115: IOTakeLock( gIOServiceBusyLock ); ! 2116: wait = (value != (__state[1] & mask)); ! 2117: if( wait) ! 2118: assert_wait( (event_t) this, THREAD_UNINT ); ! 2119: IOUnlock( gIOServiceBusyLock ); ! 2120: if( wait) ! 2121: thread_block((void (*)(void)) -6); ! 2122: ! 2123: } while( wait ); ! 2124: ! 2125: return( kIOReturnSuccess ); ! 2126: } ! 2127: ! 2128: IOReturn IOService::waitQuiet( mach_timespec_t * timeout = 0 ) ! 2129: { ! 2130: return( waitForState( kIOServiceBusyStateMask, 0, timeout )); ! 2131: } ! 2132: ! 2133: bool IOService::serializeProperties( OSSerialize * s ) const ! 2134: { ! 2135: #if 0 ! 2136: ((IOService *)this)->setProperty( ((IOService *)this)->__state, ! 2137: sizeof( __state), "__state"); ! 2138: #endif ! 2139: return( super::serializeProperties(s) ); ! 2140: } ! 2141: ! 2142: ! 2143: void _IOConfigThread::main( _IOConfigThread * self ) ! 2144: { ! 2145: _IOServiceJob * job; ! 2146: IOService * nub; ! 2147: bool alive = true; ! 2148: ! 2149: do { ! 2150: ! 2151: #if 0 ! 2152: #define randomDelay() \ ! 2153: int del = read_processor_clock(); \ ! 2154: del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \ ! 2155: IOSleep( del ); ! 2156: randomDelay(); ! 2157: #endif ! 2158: ! 2159: semaphore_wait( gJobsSemaphore ); ! 2160: ! 2161: IOTakeLock( gJobsLock ); ! 2162: job = (_IOServiceJob *) gJobs->getFirstObject(); ! 2163: job->retain(); ! 2164: gJobs->removeObject(job); ! 2165: if( job) { ! 2166: gOutstandingJobs--; ! 2167: #ifndef LESS_THREAD_CREATE ! 2168: // gNumConfigThreads--; // we're out of service ! 2169: gNumWaitingThreads--; // we're out of service ! 2170: #endif ! 2171: } ! 2172: IOUnlock( gJobsLock ); ! 2173: ! 2174: if( job) { ! 2175: ! 2176: nub = job->nub; ! 2177: ! 2178: if( gIOKitDebug & kIOLogConfig) ! 2179: LOG("config(%x): starting on %s, %d\n", ! 2180: (int) IOThreadSelf(), job->nub->getName(), job->type); ! 2181: ! 2182: switch( job->type) { ! 2183: ! 2184: case kMatchNubJob: ! 2185: nub->doServiceMatch(); ! 2186: break; ! 2187: ! 2188: case kTerminateNubJob: ! 2189: nub->doServiceTerminate( job->options ); ! 2190: break; ! 2191: ! 2192: default: ! 2193: LOG("config(%x): strange type (%d)\n", ! 2194: (int) IOThreadSelf(), job->type ); ! 2195: break; ! 2196: } ! 2197: ! 2198: nub->release(); ! 2199: job->release(); ! 2200: ! 2201: IOTakeLock( gJobsLock ); ! 2202: #ifndef LESS_THREAD_CREATE ! 2203: alive = (gOutstandingJobs > gNumWaitingThreads); ! 2204: if( alive) ! 2205: gNumWaitingThreads++; // back in service ! 2206: // gNumConfigThreads++; ! 2207: else ! 2208: gNumConfigThreads--; ! 2209: #endif ! 2210: IOUnlock( gJobsLock ); ! 2211: } ! 2212: ! 2213: } while( alive ); ! 2214: ! 2215: if( gIOKitDebug & kIOLogConfig) ! 2216: LOG("config(%x): terminating\n", (int) IOThreadSelf() ); ! 2217: ! 2218: self->release(); ! 2219: } ! 2220: ! 2221: void _IOServiceJob::pingConfig( _IOServiceJob * job ) ! 2222: { ! 2223: int count; ! 2224: bool create; ! 2225: ! 2226: assert( job ); ! 2227: ! 2228: IOTakeLock( gJobsLock ); ! 2229: ! 2230: gOutstandingJobs++; ! 2231: gJobs->setLastObject( job ); ! 2232: ! 2233: count = gNumWaitingThreads; ! 2234: // if( gNumConfigThreads) count++;// assume we're called from a config thread ! 2235: ! 2236: create = ( (gOutstandingJobs > count) ! 2237: && (gNumConfigThreads < kMaxConfigThreads) ); ! 2238: if( create) { ! 2239: gNumConfigThreads++; ! 2240: gNumWaitingThreads++; ! 2241: } ! 2242: ! 2243: IOUnlock( gJobsLock ); ! 2244: ! 2245: job->release(); ! 2246: ! 2247: if( create) { ! 2248: if( gIOKitDebug & kIOLogConfig) ! 2249: LOG("config(%d): creating\n", gNumConfigThreads - 1); ! 2250: _IOConfigThread::configThread(); ! 2251: } ! 2252: ! 2253: semaphore_signal( gJobsSemaphore ); ! 2254: } ! 2255: ! 2256: ! 2257: // internal - call with gNotificationLock ! 2258: OSObject * IOService::getExistingServices( OSDictionary * matching, ! 2259: IOOptionBits inState, IOOptionBits options = 0 ) ! 2260: { ! 2261: OSObject * current = 0; ! 2262: OSIterator * iter; ! 2263: IOService * service; ! 2264: ! 2265: if( !matching) ! 2266: return( 0 ); ! 2267: ! 2268: iter = IORegistryIterator::iterateOver( gIOServicePlane, ! 2269: kIORegistryIterateRecursively ); ! 2270: if( iter) { ! 2271: do { ! 2272: iter->reset(); ! 2273: while( (service = (IOService *) iter->getNextObject())) { ! 2274: if( (inState == (service->__state[0] & inState)) ! 2275: && (0 == (service->__state[0] & kIOServiceInactiveState)) ! 2276: && service->passiveMatch( matching )) { ! 2277: ! 2278: if( options & kIONotifyOnce) { ! 2279: current = service; ! 2280: break; ! 2281: } ! 2282: if( current) ! 2283: ((OSSet *)current)->setObject( service ); ! 2284: else ! 2285: current = OSSet::withObjects( ! 2286: (OSObject **) &service, 1, 1 ); ! 2287: } ! 2288: } ! 2289: } while( !service && !iter->isValid()); ! 2290: iter->release(); ! 2291: } ! 2292: ! 2293: if( current && (0 == (options & kIONotifyOnce))) { ! 2294: iter = OSCollectionIterator::withCollection( (OSSet *)current ); ! 2295: current->release(); ! 2296: current = iter; ! 2297: } ! 2298: ! 2299: return( current ); ! 2300: } ! 2301: ! 2302: // public version ! 2303: OSIterator * IOService::getMatchingServices( OSDictionary * matching ) ! 2304: { ! 2305: OSIterator * iter; ! 2306: ! 2307: // is a lock even needed? ! 2308: LOCKWRITENOTIFY(); ! 2309: ! 2310: iter = (OSIterator *) getExistingServices( matching, ! 2311: kIOServiceRegisteredState ); ! 2312: ! 2313: UNLOCKNOTIFY(); ! 2314: ! 2315: return( iter ); ! 2316: } ! 2317: ! 2318: ! 2319: // internal - call with gNotificationLock ! 2320: IONotifier * IOService::setNotification( ! 2321: const OSSymbol * type, OSDictionary * matching, ! 2322: IOServiceNotificationHandler handler, void * target, void * ref, ! 2323: SInt32 priority = 0 ) ! 2324: { ! 2325: _IOServiceNotifier * notify = 0; ! 2326: OSOrderedSet * set; ! 2327: ! 2328: if( !matching) ! 2329: return( 0 ); ! 2330: ! 2331: notify = new _IOServiceNotifier; ! 2332: if( notify && !notify->init()) { ! 2333: notify->release(); ! 2334: notify = 0; ! 2335: } ! 2336: ! 2337: if( notify) { ! 2338: notify->matching = matching; ! 2339: notify->handler = handler; ! 2340: notify->target = target; ! 2341: notify->ref = ref; ! 2342: notify->priority = priority; ! 2343: notify->fEnable = true; ! 2344: ! 2345: ////// queue ! 2346: ! 2347: if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) { ! 2348: set = OSOrderedSet::withCapacity( 1, ! 2349: IONotifyOrdering, 0 ); ! 2350: if( set) { ! 2351: gNotifications->setObject( type, set ); ! 2352: set->release(); ! 2353: } ! 2354: } ! 2355: notify->whence = set; ! 2356: if( set) ! 2357: set->setObject( notify ); ! 2358: } ! 2359: ! 2360: return( notify ); ! 2361: } ! 2362: ! 2363: // internal - call with gNotificationLock ! 2364: IONotifier * IOService::doInstallNotification( ! 2365: const OSSymbol * type, OSDictionary * matching, ! 2366: IOServiceNotificationHandler handler, ! 2367: void * target, void * ref, ! 2368: SInt32 priority, OSIterator ** existing ) ! 2369: { ! 2370: OSIterator * exist; ! 2371: IONotifier * notify; ! 2372: IOOptionBits inState; ! 2373: ! 2374: if( !matching) ! 2375: return( 0 ); ! 2376: ! 2377: if( (type == gIOPublishNotification) ! 2378: || (type == gIOFirstPublishNotification)) ! 2379: inState = kIOServiceRegisteredState; ! 2380: else if( (type == gIOMatchedNotification) ! 2381: || (type == gIOFirstMatchNotification)) ! 2382: inState = kIOServiceMatchedState; ! 2383: else if( type == gIOTerminatedNotification) ! 2384: inState = 0; ! 2385: else ! 2386: return( 0 ); ! 2387: ! 2388: notify = setNotification( type, matching, handler, target, ref, priority ); ! 2389: ! 2390: if( inState) ! 2391: // get the current set ! 2392: exist = (OSIterator *) getExistingServices( matching, inState ); ! 2393: else ! 2394: exist = 0; ! 2395: ! 2396: *existing = exist; ! 2397: ! 2398: return( notify ); ! 2399: } ! 2400: ! 2401: ! 2402: IONotifier * IOService::installNotification( ! 2403: const OSSymbol * type, OSDictionary * matching, ! 2404: IOServiceNotificationHandler handler, ! 2405: void * target, void * ref, ! 2406: SInt32 priority, OSIterator ** existing ) ! 2407: { ! 2408: IONotifier * notify; ! 2409: ! 2410: LOCKWRITENOTIFY(); ! 2411: ! 2412: notify = doInstallNotification( type, matching, handler, target, ref, ! 2413: priority, existing ); ! 2414: ! 2415: UNLOCKNOTIFY(); ! 2416: ! 2417: return( notify ); ! 2418: } ! 2419: ! 2420: IONotifier * IOService::addNotification( ! 2421: const OSSymbol * type, OSDictionary * matching, ! 2422: IOServiceNotificationHandler handler, ! 2423: void * target, void * ref = 0, ! 2424: SInt32 priority = 0 ) ! 2425: { ! 2426: OSIterator * existing; ! 2427: IONotifier * notify; ! 2428: IOService * next; ! 2429: ! 2430: notify = installNotification( type, matching, ! 2431: handler, target, ref, priority, &existing ); ! 2432: ! 2433: // send notifications for existing set ! 2434: if( existing) { ! 2435: ! 2436: while( (next = (IOService *) existing->getNextObject())) { ! 2437: ! 2438: next->lockForArbitration(); ! 2439: LOCKWRITENOTIFY(); ! 2440: if( 0 == (next->__state[0] & kIOServiceInactiveState)) ! 2441: (*handler)( target, ref, next ); ! 2442: UNLOCKNOTIFY(); ! 2443: next->unlockForArbitration(); ! 2444: } ! 2445: existing->release(); ! 2446: } ! 2447: ! 2448: return( notify ); ! 2449: } ! 2450: ! 2451: struct SyncNotifyVars { ! 2452: semaphore_port_t waitHere; ! 2453: IOService * result; ! 2454: }; ! 2455: ! 2456: bool IOService::syncNotificationHandler( ! 2457: void * /* target */, void * ref, ! 2458: IOService * newService ) ! 2459: { ! 2460: ! 2461: // result may get written more than once before the ! 2462: // notification is removed! ! 2463: ((SyncNotifyVars *) ref)->result = newService; ! 2464: semaphore_signal( ((SyncNotifyVars *) ref)->waitHere ); ! 2465: ! 2466: return( false ); ! 2467: } ! 2468: ! 2469: IOService * IOService::waitForService( OSDictionary * matching, ! 2470: mach_timespec_t * timeout = 0 ) ! 2471: { ! 2472: IONotifier * notify = 0; ! 2473: // priority doesn't help us much since we need a thread wakeup ! 2474: SInt32 priority = 0; ! 2475: SyncNotifyVars state; ! 2476: kern_return_t err = kIOReturnBadArgument; ! 2477: ! 2478: if( !matching) ! 2479: return( 0 ); ! 2480: ! 2481: state.waitHere = 0; ! 2482: state.result = 0; ! 2483: ! 2484: LOCKWRITENOTIFY(); ! 2485: ! 2486: do { ! 2487: ! 2488: state.result = (IOService *) getExistingServices( matching, ! 2489: kIOServiceMatchedState, kIONotifyOnce ); ! 2490: if( state.result) ! 2491: continue; ! 2492: ! 2493: err = semaphore_create( kernel_task, &state.waitHere, ! 2494: SYNC_POLICY_FIFO, 0 ); ! 2495: if( KERN_SUCCESS != err) ! 2496: continue; ! 2497: ! 2498: notify = IOService::setNotification( gIOMatchedNotification, matching, ! 2499: &IOService::syncNotificationHandler, (void *) 0, ! 2500: (void *) &state, priority ); ! 2501: ! 2502: } while( false ); ! 2503: ! 2504: UNLOCKNOTIFY(); ! 2505: ! 2506: if( notify) { ! 2507: if( timeout) ! 2508: err = semaphore_timedwait( state.waitHere, *timeout ); ! 2509: else ! 2510: err = semaphore_wait( state.waitHere ); ! 2511: } ! 2512: ! 2513: if( notify) ! 2514: notify->remove(); // dequeues ! 2515: if( state.waitHere) ! 2516: semaphore_destroy( kernel_task, state.waitHere ); ! 2517: ! 2518: return( state.result ); ! 2519: } ! 2520: ! 2521: void IOService::deliverNotification( const OSSymbol * type, ! 2522: IOOptionBits orNewState, IOOptionBits andNewState ) ! 2523: { ! 2524: _IOServiceNotifier * notify; ! 2525: OSIterator * iter; ! 2526: ! 2527: lockForArbitration(); ! 2528: ! 2529: if( (0 == (__state[0] & kIOServiceInactiveState)) ! 2530: || (type == gIOTerminatedNotification)) { ! 2531: ! 2532: LOCKREADNOTIFY(); ! 2533: ! 2534: iter = OSCollectionIterator::withCollection( (OSOrderedSet *) ! 2535: gNotifications->getObject( type ) ); ! 2536: ! 2537: if( iter) { ! 2538: while( (notify = (_IOServiceNotifier *) iter->getNextObject())) { ! 2539: ! 2540: if( passiveMatch( notify->matching) ! 2541: && notify->fEnable) ! 2542: (*notify->handler)( notify->target, notify->ref, this ); ! 2543: } ! 2544: iter->release(); ! 2545: } ! 2546: ! 2547: __state[0] = (__state[0] | orNewState) & andNewState; ! 2548: ! 2549: UNLOCKNOTIFY(); ! 2550: } ! 2551: ! 2552: unlockForArbitration(); ! 2553: } ! 2554: ! 2555: IOOptionBits IOService::getState( void ) const ! 2556: { ! 2557: return( __state[0] ); ! 2558: } ! 2559: ! 2560: /* ! 2561: * Helpers to make matching objects for simple cases ! 2562: */ ! 2563: ! 2564: OSDictionary * IOService::serviceMatching( const OSString * name, ! 2565: OSDictionary * table = 0 ) ! 2566: { ! 2567: if( !table) ! 2568: table = OSDictionary::withCapacity( 2 ); ! 2569: if( table) ! 2570: table->setObject(gIOProviderClassKey, (OSObject *)name ); ! 2571: ! 2572: return( table ); ! 2573: } ! 2574: ! 2575: OSDictionary * IOService::serviceMatching( const char * name, ! 2576: OSDictionary * table = 0 ) ! 2577: { ! 2578: const OSString * str; ! 2579: ! 2580: str = OSSymbol::withCString( name ); ! 2581: if( !str) ! 2582: return( 0 ); ! 2583: ! 2584: table = serviceMatching( str, table ); ! 2585: str->release(); ! 2586: return( table ); ! 2587: } ! 2588: ! 2589: OSDictionary * IOService::nameMatching( const OSString * name, ! 2590: OSDictionary * table = 0 ) ! 2591: { ! 2592: if( !table) ! 2593: table = OSDictionary::withCapacity( 2 ); ! 2594: if( table) ! 2595: table->setObject( gIONameMatchKey, (OSObject *)name ); ! 2596: ! 2597: return( table ); ! 2598: } ! 2599: ! 2600: OSDictionary * IOService::nameMatching( const char * name, ! 2601: OSDictionary * table = 0 ) ! 2602: { ! 2603: const OSString * str; ! 2604: ! 2605: str = OSSymbol::withCString( name ); ! 2606: if( !str) ! 2607: return( 0 ); ! 2608: ! 2609: table = nameMatching( str, table ); ! 2610: str->release(); ! 2611: return( table ); ! 2612: } ! 2613: ! 2614: OSDictionary * IOService::resourceMatching( const OSString * str, ! 2615: OSDictionary * table = 0 ) ! 2616: { ! 2617: table = serviceMatching( gIOResourcesKey, table ); ! 2618: if( table) ! 2619: table->setObject( gIOResourceMatchKey, (OSObject *) str ); ! 2620: ! 2621: return( table ); ! 2622: } ! 2623: ! 2624: OSDictionary * IOService::resourceMatching( const char * name, ! 2625: OSDictionary * table = 0 ) ! 2626: { ! 2627: const OSSymbol * str; ! 2628: ! 2629: str = OSSymbol::withCString( name ); ! 2630: if( !str) ! 2631: return( 0 ); ! 2632: ! 2633: table = resourceMatching( str, table ); ! 2634: str->release(); ! 2635: ! 2636: return( table ); ! 2637: } ! 2638: ! 2639: /* ! 2640: * _IOServiceNotifier ! 2641: */ ! 2642: ! 2643: void _IOServiceNotifier::remove() ! 2644: { ! 2645: LOCKWRITENOTIFY(); ! 2646: ! 2647: if( whence) { ! 2648: whence->removeObject( (OSObject *) this ); ! 2649: whence = 0; ! 2650: } ! 2651: if( matching) { ! 2652: matching->release(); ! 2653: matching = 0; ! 2654: } ! 2655: ! 2656: fEnable = false; ! 2657: ! 2658: UNLOCKNOTIFY(); ! 2659: ! 2660: release(); ! 2661: } ! 2662: ! 2663: bool _IOServiceNotifier::disable() ! 2664: { ! 2665: bool ret; ! 2666: ! 2667: LOCKWRITENOTIFY(); ! 2668: ret = fEnable; ! 2669: fEnable = false; ! 2670: UNLOCKNOTIFY(); ! 2671: ! 2672: return( ret ); ! 2673: } ! 2674: ! 2675: void _IOServiceNotifier::enable( bool was ) ! 2676: { ! 2677: LOCKWRITENOTIFY(); ! 2678: fEnable = was; ! 2679: UNLOCKNOTIFY(); ! 2680: } ! 2681: ! 2682: /* ! 2683: * IOResources ! 2684: */ ! 2685: ! 2686: IOService * IOResources::resources( void ) ! 2687: { ! 2688: IOResources * inst; ! 2689: ! 2690: inst = new IOResources; ! 2691: if( inst && !inst->init()) { ! 2692: inst->release(); ! 2693: inst = 0; ! 2694: } ! 2695: ! 2696: return( inst ); ! 2697: } ! 2698: ! 2699: bool IOResources::matchPropertyTable( OSDictionary * table ) ! 2700: { ! 2701: OSObject * prop; ! 2702: OSString * str; ! 2703: OSSet * set; ! 2704: OSIterator * iter; ! 2705: bool ok = false; ! 2706: ! 2707: prop = table->getObject( gIOResourceMatchKey ); ! 2708: str = OSDynamicCast( OSString, prop ); ! 2709: if( str) ! 2710: ok = (0 != getProperty( str )); ! 2711: ! 2712: else if( (set = OSDynamicCast( OSSet, prop))) { ! 2713: ! 2714: iter = OSCollectionIterator::withCollection( set ); ! 2715: ok = (iter != 0); ! 2716: while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) )) ! 2717: ok = (0 != getProperty( str )); ! 2718: ! 2719: if( iter) ! 2720: iter->release(); ! 2721: } ! 2722: ! 2723: return( ok ); ! 2724: } ! 2725: ! 2726: /* ! 2727: * Helpers for matching dictionaries. ! 2728: * Keys existing in matching are checked in properties. ! 2729: * Keys may be a string or OSCollection of IOStrings ! 2730: */ ! 2731: ! 2732: bool IOService::compareProperty( OSDictionary * matching, ! 2733: const char * key ) ! 2734: { ! 2735: OSObject * value; ! 2736: bool ok; ! 2737: ! 2738: value = matching->getObject( key ); ! 2739: if( value) ! 2740: ok = value->isEqualTo( getProperty( key )); ! 2741: else ! 2742: ok = true; ! 2743: ! 2744: return( ok ); ! 2745: } ! 2746: ! 2747: ! 2748: bool IOService::compareProperty( OSDictionary * matching, ! 2749: const OSString * key ) ! 2750: { ! 2751: OSObject * value; ! 2752: bool ok; ! 2753: ! 2754: value = matching->getObject( key ); ! 2755: if( value) ! 2756: ok = value->isEqualTo( getProperty( key )); ! 2757: else ! 2758: ok = true; ! 2759: ! 2760: return( ok ); ! 2761: } ! 2762: ! 2763: bool IOService::compareProperties( OSDictionary * matching, ! 2764: OSCollection * keys ) ! 2765: { ! 2766: OSCollectionIterator * iter; ! 2767: const OSString * key; ! 2768: bool ok = true; ! 2769: ! 2770: if( !matching || !keys) ! 2771: return( false ); ! 2772: ! 2773: iter = OSCollectionIterator::withCollection( keys ); ! 2774: ! 2775: if( iter) { ! 2776: while( ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) ! 2777: ok = compareProperty( matching, key ); ! 2778: ! 2779: iter->release(); ! 2780: } ! 2781: keys->release(); // !! consume a ref !! ! 2782: ! 2783: return( ok ); ! 2784: } ! 2785: ! 2786: /* Helper to add a location matching dict to the table */ ! 2787: ! 2788: OSDictionary * IOService::addLocation( OSDictionary * table ) ! 2789: { ! 2790: OSDictionary * dict; ! 2791: ! 2792: if( !table) ! 2793: return( 0 ); ! 2794: ! 2795: dict = OSDictionary::withCapacity( 1 ); ! 2796: if( dict) { ! 2797: table->setObject( gIOLocationMatchKey, dict ); ! 2798: dict->release(); ! 2799: } ! 2800: ! 2801: return( dict ); ! 2802: } ! 2803: ! 2804: /* ! 2805: * Go looking for a provider to match a location dict. ! 2806: */ ! 2807: ! 2808: IOService * IOService::matchLocation( IOService * /* client */ ) ! 2809: { ! 2810: IOService * parent; ! 2811: ! 2812: parent = getProvider(); ! 2813: ! 2814: if( parent) ! 2815: parent = parent->matchLocation( this ); ! 2816: ! 2817: return( parent ); ! 2818: } ! 2819: ! 2820: bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) ! 2821: { ! 2822: IOService * where; ! 2823: OSString * matched; ! 2824: OSObject * nameMatch; ! 2825: OSString * str1; ! 2826: OSString * str2; ! 2827: IORegistryEntry * entry; ! 2828: bool match = true; ! 2829: ! 2830: assert( table ); ! 2831: ! 2832: where = this; ! 2833: ! 2834: do { ! 2835: entry = 0; ! 2836: str1 = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); ! 2837: if( str1 && !(match = (0 != where->metaCast( str1 )))) ! 2838: break; ! 2839: ! 2840: nameMatch = table->getObject( gIONameMatchKey ); ! 2841: if( nameMatch && !(match = compareNames( nameMatch, ! 2842: changesOK ? &matched : 0 ))) ! 2843: break; ! 2844: if( changesOK && nameMatch && matched) { ! 2845: // leave a hint as to which name matched ! 2846: table->setObject( gIONameMatchedKey, matched ); ! 2847: matched->release(); ! 2848: } ! 2849: ! 2850: str2 = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); ! 2851: if( str2) { ! 2852: entry = IORegistryEntry::fromPath( str2->getCStringNoCopy() ); ! 2853: match = (where == entry); ! 2854: if( entry) ! 2855: entry->release(); ! 2856: if( !match) ! 2857: break; ! 2858: } ! 2859: ! 2860: if( (str1 || str2 || nameMatch) && (1 == table->getCount())) ! 2861: // only do the imports/path check - don't call family. ! 2862: break; ! 2863: ! 2864: // do family specific matching ! 2865: match = where->matchPropertyTable( table ); ! 2866: ! 2867: if( !match) { ! 2868: #ifdef DEBUG ! 2869: if( kIOLogMatch & getDebugFlags( table )) ! 2870: LOG("%s: family specific matching fails\n", where->getName()); ! 2871: #endif ! 2872: break; ! 2873: } ! 2874: ! 2875: if( !(match = where->compareProperty( table, kIOBSDName ))) ! 2876: break; ! 2877: ! 2878: table = OSDynamicCast( OSDictionary, ! 2879: table->getObject( gIOLocationMatchKey )); ! 2880: if( table) { ! 2881: match = false; ! 2882: where = where->getProvider(); ! 2883: if( where) ! 2884: where = where->matchLocation( where ); ! 2885: } ! 2886: ! 2887: } while( table && where ); ! 2888: ! 2889: if( kIOLogMatch & gIOKitDebug) ! 2890: if( where != this) ! 2891: LOG("match location @ %s = %d\n", ! 2892: where->getName(), match ); ! 2893: ! 2894: return( match ); ! 2895: } ! 2896: ! 2897: ! 2898: IOReturn IOService::newUserClient( task_t /* owningTask */, ! 2899: void * /* security_id */, ! 2900: UInt32 /* type */, ! 2901: IOUserClient ** /* handler */ ) ! 2902: { ! 2903: return( kIOReturnUnsupported); ! 2904: } ! 2905: ! 2906: IOReturn IOService::requestProbe( IOOptionBits options ) ! 2907: { ! 2908: return( kIOReturnUnsupported); ! 2909: } ! 2910: ! 2911: /* ! 2912: * Convert an IOReturn to text. Subclasses which add additional ! 2913: * IOReturn's should override this method and call ! 2914: * [super stringFromReturn] if the desired value is not found. ! 2915: */ ! 2916: ! 2917: const char * IOService::stringFromReturn( IOReturn rtn ) ! 2918: { ! 2919: static const IONamedValue IOReturn_values[] = { ! 2920: {kIOReturnSuccess, "success" }, ! 2921: {kIOReturnError, "general error" }, ! 2922: {kIOReturnNoMemory, "memory allocation error" }, ! 2923: {kIOReturnNoResources, "resource shortage" }, ! 2924: {kIOReturnIPCError, "Mach IPC failure" }, ! 2925: {kIOReturnNoDevice, "no such device" }, ! 2926: {kIOReturnNotPrivileged, "privilege violation" }, ! 2927: {kIOReturnBadArgument, "invalid argument" }, ! 2928: {kIOReturnLockedRead, "device is read locked" }, ! 2929: {kIOReturnLockedWrite, "device is write locked" }, ! 2930: {kIOReturnExclusiveAccess, "device is exclusive access" }, ! 2931: {kIOReturnBadMessageID, "bad IPC message ID" }, ! 2932: {kIOReturnUnsupported, "unsupported function" }, ! 2933: {kIOReturnVMError, "virtual memory error" }, ! 2934: {kIOReturnInternalError, "internal driver error" }, ! 2935: {kIOReturnIOError, "I/O error" }, ! 2936: {kIOReturnCannotLock, "cannot acquire lock" }, ! 2937: {kIOReturnNotOpen, "device is not open" }, ! 2938: {kIOReturnNotReadable, "device is not readable" }, ! 2939: {kIOReturnNotWritable, "device is not writeable" }, ! 2940: {kIOReturnNotAligned, "alignment error" }, ! 2941: {kIOReturnBadMedia, "media error" }, ! 2942: {kIOReturnStillOpen, "device is still open" }, ! 2943: {kIOReturnRLDError, "rld failure" }, ! 2944: {kIOReturnDMAError, "DMA failure" }, ! 2945: {kIOReturnBusy, "device is busy" }, ! 2946: {kIOReturnTimeout, "I/O timeout" }, ! 2947: {kIOReturnOffline, "device is offline" }, ! 2948: {kIOReturnNotReady, "device is not ready" }, ! 2949: {kIOReturnNotAttached, "device/channel is not attached" }, ! 2950: {kIOReturnNoChannels, "no DMA channels available" }, ! 2951: {kIOReturnNoSpace, "no space for data" }, ! 2952: {kIOReturnPortExists, "device port already exists" }, ! 2953: {kIOReturnCannotWire, "cannot wire physical memory" }, ! 2954: {kIOReturnNoInterrupt, "no interrupt attached" }, ! 2955: {kIOReturnNoFrames, "no DMA frames enqueued" }, ! 2956: {kIOReturnMessageTooLarge, "message is too large" }, ! 2957: {kIOReturnNotPermitted, "operation is not permitted" }, ! 2958: {kIOReturnNoPower, "device is without power" }, ! 2959: {kIOReturnNoMedia, "media is not present" }, ! 2960: {kIOReturnUnformattedMedia, "media is not formatted" }, ! 2961: {kIOReturnUnsupportedMode, "unsupported mode" }, ! 2962: {kIOReturnUnderrun, "data underrun" }, ! 2963: {kIOReturnOverrun, "data overrun" }, ! 2964: {kIOReturnDeviceError, "device error" }, ! 2965: {kIOReturnNoCompletion, "no completion routine" }, ! 2966: {kIOReturnAborted, "operation was aborted" }, ! 2967: {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" }, ! 2968: {kIOReturnNotResponding, "device is not responding" }, ! 2969: {kIOReturnInvalid, "unanticipated driver error" }, ! 2970: {0, NULL } ! 2971: }; ! 2972: ! 2973: return IOFindNameForValue(rtn, IOReturn_values); ! 2974: } ! 2975: ! 2976: /* ! 2977: * Convert an IOReturn to an errno. ! 2978: */ ! 2979: int IOService::errnoFromReturn( IOReturn rtn ) ! 2980: { ! 2981: switch(rtn) { ! 2982: // (obvious match) ! 2983: case kIOReturnSuccess: ! 2984: return(0); ! 2985: case kIOReturnNoMemory: ! 2986: return(ENOMEM); ! 2987: case kIOReturnNoDevice: ! 2988: return(ENXIO); ! 2989: case kIOReturnVMError: ! 2990: return(EFAULT); ! 2991: case kIOReturnNotPermitted: ! 2992: return(EPERM); ! 2993: case kIOReturnNotPrivileged: ! 2994: return(EACCES); ! 2995: case kIOReturnIOError: ! 2996: return(EIO); ! 2997: case kIOReturnNotWritable: ! 2998: return(EROFS); ! 2999: case kIOReturnBadArgument: ! 3000: return(EINVAL); ! 3001: case kIOReturnUnsupported: ! 3002: return(EOPNOTSUPP); ! 3003: case kIOReturnBusy: ! 3004: return(EBUSY); ! 3005: case kIOReturnNoPower: ! 3006: return(EPWROFF); ! 3007: case kIOReturnDeviceError: ! 3008: return(EDEVERR); ! 3009: case kIOReturnTimeout: ! 3010: return(ETIMEDOUT); ! 3011: case kIOReturnMessageTooLarge: ! 3012: return(EMSGSIZE); ! 3013: case kIOReturnNoSpace: ! 3014: return(ENOSPC); ! 3015: case kIOReturnCannotLock: ! 3016: return(ENOLCK); ! 3017: ! 3018: // (best match) ! 3019: case kIOReturnBadMessageID: ! 3020: case kIOReturnNoCompletion: ! 3021: case kIOReturnNotAligned: ! 3022: return(EINVAL); ! 3023: case kIOReturnNotReady: ! 3024: return(EBUSY); ! 3025: case kIOReturnRLDError: ! 3026: return(EBADMACHO); ! 3027: case kIOReturnPortExists: ! 3028: case kIOReturnStillOpen: ! 3029: return(EEXIST); ! 3030: case kIOReturnExclusiveAccess: ! 3031: case kIOReturnLockedRead: ! 3032: case kIOReturnLockedWrite: ! 3033: case kIOReturnNotAttached: ! 3034: case kIOReturnNotOpen: ! 3035: case kIOReturnNotReadable: ! 3036: return(EACCES); ! 3037: case kIOReturnCannotWire: ! 3038: case kIOReturnNoResources: ! 3039: return(ENOMEM); ! 3040: case kIOReturnAborted: ! 3041: case kIOReturnOffline: ! 3042: case kIOReturnNotResponding: ! 3043: return(EBUSY); ! 3044: case kIOReturnBadMedia: ! 3045: case kIOReturnNoMedia: ! 3046: case kIOReturnUnformattedMedia: ! 3047: return(EIO); // (media error) ! 3048: case kIOReturnDMAError: ! 3049: case kIOReturnOverrun: ! 3050: case kIOReturnUnderrun: ! 3051: return(EIO); // (transfer error) ! 3052: case kIOReturnNoBandwidth: ! 3053: case kIOReturnNoChannels: ! 3054: case kIOReturnNoFrames: ! 3055: case kIOReturnNoInterrupt: ! 3056: return(EIO); // (hardware error) ! 3057: case kIOReturnError: ! 3058: case kIOReturnInternalError: ! 3059: case kIOReturnInvalid: ! 3060: return(EIO); // (generic error) ! 3061: case kIOReturnIPCError: ! 3062: return(EIO); // (ipc error) ! 3063: default: ! 3064: return(EIO); // (all other errors) ! 3065: } ! 3066: } ! 3067: ! 3068: IOReturn IOService::message( UInt32 type, IOService * provider, ! 3069: void * argument ) ! 3070: { ! 3071: /* ! 3072: * Generic entry point for upstream object calls. A return value of ! 3073: * kIOReturnSuccess indicates the message was successful. ! 3074: */ ! 3075: ! 3076: return kIOReturnUnsupported; ! 3077: } ! 3078: ! 3079: /* ! 3080: * Device memory ! 3081: */ ! 3082: ! 3083: IOItemCount IOService::getDeviceMemoryCount( void ) ! 3084: { ! 3085: OSArray * array; ! 3086: IOItemCount count; ! 3087: ! 3088: array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); ! 3089: if( array) ! 3090: count = array->getCount(); ! 3091: else ! 3092: count = 0; ! 3093: ! 3094: return( count); ! 3095: } ! 3096: ! 3097: IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index ) ! 3098: { ! 3099: OSArray * array; ! 3100: IODeviceMemory * range; ! 3101: ! 3102: array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); ! 3103: if( array) ! 3104: range = (IODeviceMemory *) array->getObject( index ); ! 3105: else ! 3106: range = 0; ! 3107: ! 3108: return( range); ! 3109: } ! 3110: ! 3111: IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index, ! 3112: IOOptionBits options = 0 ) ! 3113: { ! 3114: IODeviceMemory * range; ! 3115: IOMemoryMap * map; ! 3116: ! 3117: range = getDeviceMemoryWithIndex( index ); ! 3118: if( range) ! 3119: map = range->map( options ); ! 3120: else ! 3121: map = 0; ! 3122: ! 3123: return( map ); ! 3124: } ! 3125: ! 3126: OSArray * IOService::getDeviceMemory( void ) ! 3127: { ! 3128: return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey))); ! 3129: } ! 3130: ! 3131: ! 3132: void IOService::setDeviceMemory( OSArray * array ) ! 3133: { ! 3134: setProperty( gIODeviceMemoryKey, array); ! 3135: } ! 3136: ! 3137: /* ! 3138: * Device interrupts ! 3139: */ ! 3140: ! 3141: IOReturn IOService::resolveInterrupt(IOService *nub, int source) ! 3142: { ! 3143: IOInterruptController *interruptController; ! 3144: OSDictionary *propTable; ! 3145: OSArray *array; ! 3146: OSData *data; ! 3147: OSSymbol *interruptControllerName; ! 3148: long numSources; ! 3149: IOInterruptSource *interruptSources; ! 3150: ! 3151: // Get the property table from the nub. ! 3152: propTable = nub->getPropertyTable(); ! 3153: if (propTable == 0) return kIOReturnNoResources; ! 3154: ! 3155: // Get the parents list from the property table. ! 3156: array = OSDynamicCast(OSArray, ! 3157: propTable->getObject(gIOInterruptControllersKey)); ! 3158: if (array == 0) return kIOReturnNoResources; ! 3159: ! 3160: // Allocate space for the IOInterruptSources if needed... then return early. ! 3161: if (nub->_interruptSources == 0) { ! 3162: numSources = array->getCount(); ! 3163: interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource)); ! 3164: if (interruptSources == 0) return kIOReturnNoMemory; ! 3165: ! 3166: bzero(interruptSources, numSources * sizeof(IOInterruptSource)); ! 3167: ! 3168: nub->_numInterruptSources = numSources; ! 3169: nub->_interruptSources = interruptSources; ! 3170: return kIOReturnSuccess; ! 3171: } ! 3172: ! 3173: interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source)); ! 3174: if (interruptControllerName == 0) return kIOReturnNoResources; ! 3175: ! 3176: interruptController = getPlatform()->lookUpInterruptController(interruptControllerName); ! 3177: if (interruptController == 0) return kIOReturnNoResources; ! 3178: ! 3179: // Get the interrupt numbers from the property table. ! 3180: array = OSDynamicCast(OSArray, ! 3181: propTable->getObject(gIOInterruptSpecifiersKey)); ! 3182: if (array == 0) return kIOReturnNoResources; ! 3183: data = OSDynamicCast(OSData, array->getObject(source)); ! 3184: if (data == 0) return kIOReturnNoResources; ! 3185: ! 3186: // Set the interruptController and interruptSource in the nub's table. ! 3187: interruptSources = nub->_interruptSources; ! 3188: interruptSources[source].interruptController = interruptController; ! 3189: interruptSources[source].vectorData = data; ! 3190: ! 3191: return kIOReturnSuccess; ! 3192: } ! 3193: ! 3194: IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController) ! 3195: { ! 3196: IOReturn ret; ! 3197: ! 3198: /* Make sure the _interruptSources are set */ ! 3199: if (_interruptSources == 0) { ! 3200: ret = resolveInterrupt(this, source); ! 3201: if (ret != kIOReturnSuccess) return ret; ! 3202: } ! 3203: ! 3204: /* Make sure the local source number is valid */ ! 3205: if ((source < 0) || (source >= _numInterruptSources)) ! 3206: return kIOReturnNoInterrupt; ! 3207: ! 3208: /* Look up the contoller for the local source */ ! 3209: *interruptController = _interruptSources[source].interruptController; ! 3210: ! 3211: if (*interruptController == NULL) { ! 3212: if (!resolve) return kIOReturnNoInterrupt; ! 3213: ! 3214: /* Try to reslove the interrupt */ ! 3215: ret = resolveInterrupt(this, source); ! 3216: if (ret != kIOReturnSuccess) return ret; ! 3217: ! 3218: *interruptController = _interruptSources[source].interruptController; ! 3219: } ! 3220: ! 3221: return kIOReturnSuccess; ! 3222: } ! 3223: ! 3224: IOReturn IOService::registerInterrupt(int source, OSObject *target, ! 3225: IOInterruptAction handler, ! 3226: void *refCon) ! 3227: { ! 3228: IOInterruptController *interruptController; ! 3229: IOReturn ret; ! 3230: ! 3231: ret = lookupInterrupt(source, true, &interruptController); ! 3232: if (ret != kIOReturnSuccess) return ret; ! 3233: ! 3234: /* Register the source */ ! 3235: return interruptController->registerInterrupt(this, source, target, ! 3236: (IOInterruptHandler)handler, ! 3237: refCon); ! 3238: } ! 3239: ! 3240: IOReturn IOService::unregisterInterrupt(int source) ! 3241: { ! 3242: IOInterruptController *interruptController; ! 3243: IOReturn ret; ! 3244: ! 3245: ret = lookupInterrupt(source, false, &interruptController); ! 3246: if (ret != kIOReturnSuccess) return ret; ! 3247: ! 3248: /* Unregister the source */ ! 3249: return interruptController->unregisterInterrupt(this, source); ! 3250: } ! 3251: ! 3252: IOReturn IOService::getInterruptType(int source, int *interruptType) ! 3253: { ! 3254: IOInterruptController *interruptController; ! 3255: IOReturn ret; ! 3256: ! 3257: ret = lookupInterrupt(source, true, &interruptController); ! 3258: if (ret != kIOReturnSuccess) return ret; ! 3259: ! 3260: /* Return the type */ ! 3261: return interruptController->getInterruptType(this, source, interruptType); ! 3262: } ! 3263: ! 3264: IOReturn IOService::enableInterrupt(int source) ! 3265: { ! 3266: IOInterruptController *interruptController; ! 3267: IOReturn ret; ! 3268: ! 3269: ret = lookupInterrupt(source, false, &interruptController); ! 3270: if (ret != kIOReturnSuccess) return ret; ! 3271: ! 3272: /* Enable the source */ ! 3273: return interruptController->enableInterrupt(this, source); ! 3274: } ! 3275: ! 3276: IOReturn IOService::disableInterrupt(int source) ! 3277: { ! 3278: IOInterruptController *interruptController; ! 3279: IOReturn ret; ! 3280: ! 3281: ret = lookupInterrupt(source, false, &interruptController); ! 3282: if (ret != kIOReturnSuccess) return ret; ! 3283: ! 3284: /* Disable the source */ ! 3285: return interruptController->disableInterrupt(this, source); ! 3286: } ! 3287: ! 3288: IOReturn IOService::causeInterrupt(int source) ! 3289: { ! 3290: IOInterruptController *interruptController; ! 3291: IOReturn ret; ! 3292: ! 3293: ret = lookupInterrupt(source, false, &interruptController); ! 3294: if (ret != kIOReturnSuccess) return ret; ! 3295: ! 3296: /* Cause an interrupt for the source */ ! 3297: return interruptController->causeInterrupt(this, source); ! 3298: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.