2 * Copyright (c) 1998-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
31 #include <IOKit/IOService.h>
32 #include <libkern/c++/OSContainers.h>
33 #include <libkern/c++/OSUnserialize.h>
34 #include <IOKit/IOCatalogue.h>
35 #include <IOKit/IOCommand.h>
36 #include <IOKit/IODeviceMemory.h>
37 #include <IOKit/IOInterrupts.h>
38 #include <IOKit/IOInterruptController.h>
39 #include <IOKit/IOPlatformExpert.h>
40 #include <IOKit/IOMessage.h>
41 #include <IOKit/IOLib.h>
42 #include <IOKit/IOKitKeysPrivate.h>
43 #include <IOKit/IOBSD.h>
44 #include <IOKit/IOUserClient.h>
45 #include <IOKit/IOWorkLoop.h>
46 #include <mach/sync_policy.h>
47 #include <IOKit/assert.h>
48 #include <sys/errno.h>
53 #include "IOServicePrivate.h"
55 // take lockForArbitration before LOCKNOTIFY
57 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
59 #define super IORegistryEntry
61 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
63 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
65 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
67 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
69 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
71 OSDefineMetaClassAndStructors(IOResources
, IOService
)
73 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
75 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
77 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
79 static IOPlatformExpert
* gIOPlatform
;
80 static class IOPMrootDomain
* gIOPMRootDomain
;
81 const IORegistryPlane
* gIOServicePlane
;
82 const IORegistryPlane
* gIOPowerPlane
;
83 const OSSymbol
* gIODeviceMemoryKey
;
84 const OSSymbol
* gIOInterruptControllersKey
;
85 const OSSymbol
* gIOInterruptSpecifiersKey
;
87 const OSSymbol
* gIOResourcesKey
;
88 const OSSymbol
* gIOResourceMatchKey
;
89 const OSSymbol
* gIOProviderClassKey
;
90 const OSSymbol
* gIONameMatchKey
;
91 const OSSymbol
* gIONameMatchedKey
;
92 const OSSymbol
* gIOPropertyMatchKey
;
93 const OSSymbol
* gIOLocationMatchKey
;
94 const OSSymbol
* gIOParentMatchKey
;
95 const OSSymbol
* gIOPathMatchKey
;
96 const OSSymbol
* gIOMatchCategoryKey
;
97 const OSSymbol
* gIODefaultMatchCategoryKey
;
98 const OSSymbol
* gIOMatchedServiceCountKey
;
100 const OSSymbol
* gIOUserClientClassKey
;
101 const OSSymbol
* gIOKitDebugKey
;
103 const OSSymbol
* gIOCommandPoolSizeKey
;
105 const OSSymbol
* gIOConsoleUsersKey
;
106 const OSSymbol
* gIOConsoleSessionUIDKey
;
107 const OSSymbol
* gIOConsoleUsersSeedKey
;
108 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
109 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
111 static int gIOResourceGenerationCount
;
113 const OSSymbol
* gIOServiceKey
;
114 const OSSymbol
* gIOPublishNotification
;
115 const OSSymbol
* gIOFirstPublishNotification
;
116 const OSSymbol
* gIOMatchedNotification
;
117 const OSSymbol
* gIOFirstMatchNotification
;
118 const OSSymbol
* gIOTerminatedNotification
;
120 const OSSymbol
* gIOGeneralInterest
;
121 const OSSymbol
* gIOBusyInterest
;
122 const OSSymbol
* gIOAppPowerStateInterest
;
123 const OSSymbol
* gIOPriorityPowerStateInterest
;
125 static OSDictionary
* gNotifications
;
126 static IORecursiveLock
* gNotificationLock
;
128 static IOService
* gIOResources
;
129 static IOService
* gIOServiceRoot
;
131 static OSOrderedSet
* gJobs
;
132 static semaphore_port_t gJobsSemaphore
;
133 static IOLock
* gJobsLock
;
134 static int gOutstandingJobs
;
135 static int gNumConfigThreads
;
136 static int gNumWaitingThreads
;
137 static IOLock
* gIOServiceBusyLock
;
139 static thread_t gIOTerminateThread
;
140 static UInt32 gIOTerminateWork
;
141 static OSArray
* gIOTerminatePhase2List
;
142 static OSArray
* gIOStopList
;
143 static OSArray
* gIOStopProviderList
;
144 static OSArray
* gIOFinalizeList
;
146 static SInt32 gIOConsoleUsersSeed
;
147 static OSData
* gIOConsoleUsersSeedValue
;
149 extern const OSSymbol
* gIODTPHandleKey
;
151 const OSSymbol
* gIOPlatformSleepActionKey
;
152 const OSSymbol
* gIOPlatformWakeActionKey
;
153 const OSSymbol
* gIOPlatformQuiesceActionKey
;
154 const OSSymbol
* gIOPlatformActiveActionKey
;
156 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
160 #define LOCKREADNOTIFY() \
161 IORecursiveLockLock( gNotificationLock )
162 #define LOCKWRITENOTIFY() \
163 IORecursiveLockLock( gNotificationLock )
164 #define LOCKWRITE2READNOTIFY()
165 #define UNLOCKNOTIFY() \
166 IORecursiveLockUnlock( gNotificationLock )
167 #define SLEEPNOTIFY(event) \
168 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
169 #define WAKEUPNOTIFY(event) \
170 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
172 #define randomDelay() \
173 int del = read_processor_clock(); \
174 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
179 #define queue_element(entry, element, type, field) do { \
180 vm_address_t __ele = (vm_address_t) (entry); \
181 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
182 (element) = (type) __ele; \
185 #define iterqueue(que, elt) \
186 for (queue_entry_t elt = queue_first(que); \
187 !queue_end(que, elt); \
188 elt = queue_next(elt))
190 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
192 struct ArbitrationLockQueueElement
{
201 static queue_head_t gArbitrationLockQueueActive
;
202 static queue_head_t gArbitrationLockQueueWaiting
;
203 static queue_head_t gArbitrationLockQueueFree
;
204 static IOLock
* gArbitrationLockQueueLock
;
206 bool IOService::isInactive( void ) const
207 { return( 0 != (kIOServiceInactiveState
& getState())); }
209 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211 #if defined(__i386__)
213 // Only used by the intel implementation of
214 // IOService::requireMaxBusStall(UInt32 ns)
215 // IOService::requireMaxInterruptDelay(uint32_t ns)
218 IOService
* fService
;
224 kCpuDelayBusStall
, kCpuDelayInterrupt
,
228 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
229 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
230 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
231 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
234 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
236 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
238 #endif /* defined(__i386__) */
240 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
242 void IOService::initialize( void )
246 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
247 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
249 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
250 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
251 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
252 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
253 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
254 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
255 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
257 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
258 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
259 kIODefaultMatchCategoryKey
);
260 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
261 kIOMatchedServiceCountKey
);
263 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
265 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
266 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
268 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
269 gIOInterruptControllersKey
270 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
271 gIOInterruptSpecifiersKey
272 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
274 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
276 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
278 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
279 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
280 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
281 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
283 gNotifications
= OSDictionary::withCapacity( 1 );
284 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
285 kIOPublishNotification
);
286 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
287 kIOFirstPublishNotification
);
288 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
289 kIOMatchedNotification
);
290 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
291 kIOFirstMatchNotification
);
292 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
293 kIOTerminatedNotification
);
294 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
296 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
297 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
298 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
299 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey
);
300 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey
);
301 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
303 gIOPlatformSleepActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey
);
304 gIOPlatformWakeActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey
);
305 gIOPlatformQuiesceActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey
);
306 gIOPlatformActiveActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey
);
308 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
309 #if defined(__i386__)
310 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
311 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
313 gNotificationLock
= IORecursiveLockAlloc();
315 assert( gIOServicePlane
&& gIODeviceMemoryKey
316 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
317 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
318 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
319 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
320 && gIOPublishNotification
&& gIOMatchedNotification
321 && gIOTerminatedNotification
&& gIOServiceKey
322 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
323 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
324 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
326 gJobsLock
= IOLockAlloc();
327 gJobs
= OSOrderedSet::withCapacity( 10 );
329 gIOServiceBusyLock
= IOLockAlloc();
331 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
333 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
335 gIOResources
= IOResources::resources();
336 assert( gIOResources
);
338 gArbitrationLockQueueLock
= IOLockAlloc();
339 queue_init(&gArbitrationLockQueueActive
);
340 queue_init(&gArbitrationLockQueueWaiting
);
341 queue_init(&gArbitrationLockQueueFree
);
343 assert( gArbitrationLockQueueLock
);
345 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
346 gIOStopList
= OSArray::withCapacity( 16 );
347 gIOStopProviderList
= OSArray::withCapacity( 16 );
348 gIOFinalizeList
= OSArray::withCapacity( 16 );
349 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
352 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
355 static UInt64
getDebugFlags( OSDictionary
* props
)
357 OSNumber
* debugProp
;
360 debugProp
= OSDynamicCast( OSNumber
,
361 props
->getObject( gIOKitDebugKey
));
363 debugFlags
= debugProp
->unsigned64BitValue();
365 debugFlags
= gIOKitDebug
;
367 return( debugFlags
);
371 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
373 // Probe a matched service and return an instance to be started.
374 // The default score is from the property table, & may be altered
375 // during probe to change the start order.
377 IOService
* IOService::probe( IOService
* provider
,
383 bool IOService::start( IOService
* provider
)
388 void IOService::stop( IOService
* provider
)
392 void IOService::free( void )
394 requireMaxBusStall(0);
395 if( getPropertyTable())
396 unregisterAllInterest();
402 * Attach in service plane
404 bool IOService::attach( IOService
* provider
)
410 if( gIOKitDebug
& kIOLogAttach
)
411 LOG( "%s::attach(%s)\n", getName(),
412 provider
->getName());
414 provider
->lockForArbitration();
415 if( provider
->__state
[0] & kIOServiceInactiveState
)
418 ok
= attachToParent( provider
, gIOServicePlane
);
419 provider
->unlockForArbitration();
422 gIOServiceRoot
= this;
423 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
429 IOService
* IOService::getServiceRoot( void )
431 return( gIOServiceRoot
);
434 void IOService::detach( IOService
* provider
)
436 IOService
* newProvider
= 0;
440 if( gIOKitDebug
& kIOLogAttach
)
441 LOG("%s::detach(%s)\n", getName(), provider
->getName());
443 lockForArbitration();
445 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
446 && (provider
== getProvider()));
448 detachFromParent( provider
, gIOServicePlane
);
451 newProvider
= getProvider();
452 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
453 _adjustBusy( -busy
);
456 unlockForArbitration();
459 newProvider
->lockForArbitration();
460 newProvider
->_adjustBusy(1);
461 newProvider
->unlockForArbitration();
464 // check for last client detach from a terminated service
465 if( provider
->lockForArbitration( true )) {
467 provider
->_adjustBusy( -1 );
468 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
469 && (0 == provider
->getClient())) {
470 provider
->scheduleFinalize();
472 provider
->unlockForArbitration();
477 * Register instance - publish it for matching
480 void IOService::registerService( IOOptionBits options
)
486 enum { kMaxPathLen
= 256 };
487 enum { kMaxChars
= 63 };
489 IORegistryEntry
* parent
= this;
490 IORegistryEntry
* root
= getRegistryRoot();
491 while( parent
&& (parent
!= root
))
492 parent
= parent
->getParentEntry( gIOServicePlane
);
494 if( parent
!= root
) {
495 IOLog("%s: not registry member at registerService()\n", getName());
499 // Allow the Platform Expert to adjust this node.
500 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
503 if( (this != gIOResources
)
504 && (kIOLogRegister
& gIOKitDebug
)) {
506 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
508 IOLog( "Registering: " );
511 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
514 if( len
> kMaxChars
) {
518 if( (skip
= strchr( path
, '/')))
524 IOLog( "%s\n", path
);
527 IOFree( pathBuf
, kMaxPathLen
);
530 startMatching( options
);
533 void IOService::startMatching( IOOptionBits options
)
535 IOService
* provider
;
538 bool needWake
= false;
543 lockForArbitration();
545 sync
= (options
& kIOServiceSynchronous
)
546 || ((provider
= getProvider())
547 && (provider
->__state
[1] & kIOServiceSynchronousState
));
549 if ( options
& kIOServiceAsynchronous
)
552 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
553 && (0 == (__state
[0] & kIOServiceInactiveState
));
555 __state
[1] |= kIOServiceNeedConfigState
;
557 // __state[0] &= ~kIOServiceInactiveState;
559 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
560 // OSKernelStackRemaining(), getName());
563 prevBusy
= _adjustBusy( 1 );
564 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
568 __state
[1] |= kIOServiceSynchronousState
;
570 __state
[1] &= ~kIOServiceSynchronousState
;
572 unlockForArbitration();
577 IOLockLock( gIOServiceBusyLock
);
578 thread_wakeup( (event_t
) this/*&__state[1]*/ );
579 IOLockUnlock( gIOServiceBusyLock
);
581 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
583 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
587 if( (__state
[1] & kIOServiceNeedConfigState
))
588 doServiceMatch( options
);
590 lockForArbitration();
591 IOLockLock( gIOServiceBusyLock
);
593 waitAgain
= (prevBusy
< (__state
[1] & kIOServiceBusyStateMask
));
595 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
597 __state
[1] &= ~kIOServiceSyncPubState
;
599 unlockForArbitration();
602 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
604 IOLockUnlock( gIOServiceBusyLock
);
606 thread_block(THREAD_CONTINUE_NULL
);
608 } while( waitAgain
);
612 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
614 OSDictionary
* table
;
624 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
627 set
= (OSSet
*) getExistingServices( table
,
628 kIOServiceRegisteredState
,
629 kIOServiceExistingSet
);
634 count
+= set
->getCount();
637 allSet
->merge((const OSSet
*) set
);
645 if( getDebugFlags( table
) & kIOLogMatch
)
646 LOG("Matching service count = %ld\n", count
);
648 newTables
->removeObject(table
);
652 while( (service
= (IOService
*) allSet
->getAnyObject())) {
653 service
->startMatching(kIOServiceAsynchronous
);
654 allSet
->removeObject(service
);
659 newTables
->release();
661 return( kIOReturnSuccess
);
664 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
665 IOOptionBits options
)
669 job
= new _IOServiceJob
;
670 if( job
&& !job
->init()) {
678 job
->options
= options
;
679 nub
->retain(); // thread will release()
687 * Called on a registered service to see if it matches
691 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
693 return( matchPropertyTable(table
) );
696 bool IOService::matchPropertyTable( OSDictionary
* table
)
702 * Called on a matched service to allocate resources
703 * before first driver is attached.
706 IOReturn
IOService::getResources( void )
708 return( kIOReturnSuccess
);
712 * Client/provider accessors
715 IOService
* IOService::getProvider( void ) const
717 IOService
* self
= (IOService
*) this;
722 generation
= getGenerationCount();
723 if( __providerGeneration
== generation
)
726 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
727 if( parent
== IORegistryEntry::getRegistryRoot())
728 /* root is not an IOService */
731 self
->__provider
= parent
;
732 // save the count before getParentEntry()
733 self
->__providerGeneration
= generation
;
738 IOWorkLoop
* IOService::getWorkLoop() const
740 IOService
*provider
= getProvider();
743 return provider
->getWorkLoop();
748 OSIterator
* IOService::getProviderIterator( void ) const
750 return( getParentIterator( gIOServicePlane
));
753 IOService
* IOService::getClient( void ) const
755 return( (IOService
*) getChildEntry( gIOServicePlane
));
758 OSIterator
* IOService::getClientIterator( void ) const
760 return( getChildIterator( gIOServicePlane
));
763 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
764 const IOService
* client
,
765 const IOService
* provider
)
767 _IOOpenServiceIterator
* inst
;
772 inst
= new _IOOpenServiceIterator
;
774 if( inst
&& !inst
->init()) {
780 inst
->client
= client
;
781 inst
->provider
= provider
;
787 void _IOOpenServiceIterator::free()
791 last
->unlockForArbitration();
795 OSObject
* _IOOpenServiceIterator::getNextObject()
800 last
->unlockForArbitration();
802 while( (next
= (IOService
*) iter
->getNextObject())) {
804 next
->lockForArbitration();
805 if( (client
&& (next
->isOpen( client
)))
806 || (provider
&& (provider
->isOpen( next
))) )
808 next
->unlockForArbitration();
816 bool _IOOpenServiceIterator::isValid()
818 return( iter
->isValid() );
821 void _IOOpenServiceIterator::reset()
824 last
->unlockForArbitration();
830 OSIterator
* IOService::getOpenProviderIterator( void ) const
832 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
835 OSIterator
* IOService::getOpenClientIterator( void ) const
837 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
841 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
842 bool waitForFunction
,
843 void *param1
, void *param2
,
844 void *param3
, void *param4
)
846 IOReturn result
= kIOReturnUnsupported
;
849 if (gIOPlatformFunctionHandlerSet
== functionName
)
851 #if defined(__i386__)
852 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
853 IOService
* target
= (IOService
*) param2
;
854 bool enable
= (param3
!= 0);
856 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
857 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
858 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
859 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
860 #endif /* defined(__i386__) */
863 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
864 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
865 param1
, param2
, param3
, param4
);
871 IOReturn
IOService::callPlatformFunction( const char * functionName
,
872 bool waitForFunction
,
873 void *param1
, void *param2
,
874 void *param3
, void *param4
)
876 IOReturn result
= kIOReturnNoMemory
;
877 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
879 if (functionSymbol
!= 0) {
880 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
881 param1
, param2
, param3
, param4
);
882 functionSymbol
->release();
890 * Accessors for global services
893 IOPlatformExpert
* IOService::getPlatform( void )
895 return( gIOPlatform
);
898 class IOPMrootDomain
* IOService::getPMRootDomain( void )
900 return( gIOPMRootDomain
);
903 IOService
* IOService::getResourceService( void )
905 return( gIOResources
);
908 void IOService::setPlatform( IOPlatformExpert
* platform
)
910 gIOPlatform
= platform
;
911 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
914 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
916 gIOPMRootDomain
= rootDomain
;
917 publishResource("IOKit");
924 bool IOService::lockForArbitration( bool isSuccessRequired
)
928 ArbitrationLockQueueElement
* element
;
929 ArbitrationLockQueueElement
* active
;
930 ArbitrationLockQueueElement
* waiting
;
932 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
934 // lock global access
935 IOTakeLock( gArbitrationLockQueueLock
);
937 // obtain an unused queue element
938 if( !queue_empty( &gArbitrationLockQueueFree
)) {
939 queue_remove_first( &gArbitrationLockQueueFree
,
941 ArbitrationLockQueueElement
*,
944 element
= IONew( ArbitrationLockQueueElement
, 1 );
948 // prepare the queue element
949 element
->thread
= IOThreadSelf();
950 element
->service
= this;
952 element
->required
= isSuccessRequired
;
953 element
->aborted
= false;
955 // determine whether this object is already locked (ie. on active queue)
957 queue_iterate( &gArbitrationLockQueueActive
,
959 ArbitrationLockQueueElement
*,
962 if( active
->service
== element
->service
) {
968 if( found
) { // this object is already locked
970 // determine whether it is the same or a different thread trying to lock
971 if( active
->thread
!= element
->thread
) { // it is a different thread
973 ArbitrationLockQueueElement
* victim
= 0;
975 // before placing this new thread on the waiting queue, we look for
976 // a deadlock cycle...
979 // determine whether the active thread holding the object we
980 // want is waiting for another object to be unlocked
982 queue_iterate( &gArbitrationLockQueueWaiting
,
984 ArbitrationLockQueueElement
*,
987 if( waiting
->thread
== active
->thread
) {
988 assert( false == waiting
->aborted
);
994 if( found
) { // yes, active thread waiting for another object
996 // this may be a candidate for rejection if the required
997 // flag is not set, should we detect a deadlock later on
998 if( false == waiting
->required
)
1001 // find the thread that is holding this other object, that
1002 // is blocking the active thread from proceeding (fun :-)
1004 queue_iterate( &gArbitrationLockQueueActive
,
1005 active
, // (reuse active queue element)
1006 ArbitrationLockQueueElement
*,
1009 if( active
->service
== waiting
->service
) {
1015 // someone must be holding it or it wouldn't be waiting
1018 if( active
->thread
== element
->thread
) {
1020 // doh, it's waiting for the thread that originated
1021 // this whole lock (ie. current thread) -> deadlock
1022 if( false == element
->required
) { // willing to fail?
1024 // the originating thread doesn't have the required
1025 // flag, so it can fail
1026 success
= false; // (fail originating lock request)
1027 break; // (out of while)
1029 } else { // originating thread is not willing to fail
1031 // see if we came across a waiting thread that did
1032 // not have the 'required' flag set: we'll fail it
1035 // we do have a willing victim, fail it's lock
1036 victim
->aborted
= true;
1038 // take the victim off the waiting queue
1039 queue_remove( &gArbitrationLockQueueWaiting
,
1041 ArbitrationLockQueueElement
*,
1045 IOLockWakeup( gArbitrationLockQueueLock
,
1047 /* one thread */ true );
1049 // allow this thread to proceed (ie. wait)
1050 success
= true; // (put request on wait queue)
1051 break; // (out of while)
1054 // all the waiting threads we came across in
1055 // finding this loop had the 'required' flag
1056 // set, so we've got a deadlock we can't avoid
1057 panic("I/O Kit: Unrecoverable deadlock.");
1061 // repeat while loop, redefining active thread to be the
1062 // thread holding "this other object" (see above), and
1063 // looking for threads waiting on it; note the active
1064 // variable points to "this other object" already... so
1065 // there nothing to do in this else clause.
1067 } else { // no, active thread is not waiting for another object
1069 success
= true; // (put request on wait queue)
1070 break; // (out of while)
1074 if( success
) { // put the request on the waiting queue?
1075 kern_return_t wait_result
;
1077 // place this thread on the waiting queue and put it to sleep;
1078 // we place it at the tail of the queue...
1079 queue_enter( &gArbitrationLockQueueWaiting
,
1081 ArbitrationLockQueueElement
*,
1084 // declare that this thread will wait for a given event
1085 restart_sleep
: wait_result
= assert_wait( element
,
1086 element
->required
? THREAD_UNINT
1087 : THREAD_INTERRUPTIBLE
);
1089 // unlock global access
1090 IOUnlock( gArbitrationLockQueueLock
);
1092 // put thread to sleep, waiting for our event to fire...
1093 if (wait_result
== THREAD_WAITING
)
1094 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1097 // ...and we've been woken up; we might be in one of two states:
1098 // (a) we've been aborted and our queue element is not on
1099 // any of the three queues, but is floating around
1100 // (b) we're allowed to proceed with the lock and we have
1101 // already been moved from the waiting queue to the
1103 // ...plus a 3rd state, should the thread have been interrupted:
1104 // (c) we're still on the waiting queue
1106 // determine whether we were interrupted out of our sleep
1107 if( THREAD_INTERRUPTED
== wait_result
) {
1109 // re-lock global access
1110 IOTakeLock( gArbitrationLockQueueLock
);
1112 // determine whether we're still on the waiting queue
1114 queue_iterate( &gArbitrationLockQueueWaiting
,
1115 waiting
, // (reuse waiting queue element)
1116 ArbitrationLockQueueElement
*,
1119 if( waiting
== element
) {
1125 if( found
) { // yes, we're still on the waiting queue
1127 // determine whether we're willing to fail
1128 if( false == element
->required
) {
1130 // mark us as aborted
1131 element
->aborted
= true;
1133 // take us off the waiting queue
1134 queue_remove( &gArbitrationLockQueueWaiting
,
1136 ArbitrationLockQueueElement
*,
1138 } else { // we are not willing to fail
1140 // ignore interruption, go back to sleep
1145 // unlock global access
1146 IOUnlock( gArbitrationLockQueueLock
);
1148 // proceed as though this were a normal wake up
1149 wait_result
= THREAD_AWAKENED
;
1152 assert( THREAD_AWAKENED
== wait_result
);
1154 // determine whether we've been aborted while we were asleep
1155 if( element
->aborted
) {
1156 assert( false == element
->required
);
1158 // re-lock global access
1159 IOTakeLock( gArbitrationLockQueueLock
);
1161 action
= kPutOnFreeQueue
;
1163 } else { // we weren't aborted, so we must be ready to go :-)
1165 // we've already been moved from waiting to active queue
1169 } else { // the lock request is to be failed
1171 // return unused queue element to queue
1172 action
= kPutOnFreeQueue
;
1174 } else { // it is the same thread, recursive access is allowed
1176 // add one level of recursion
1179 // return unused queue element to queue
1180 action
= kPutOnFreeQueue
;
1183 } else { // this object is not already locked, so let this thread through
1184 action
= kPutOnActiveQueue
;
1188 // put the new element on a queue
1189 if( kPutOnActiveQueue
== action
) {
1190 queue_enter( &gArbitrationLockQueueActive
,
1192 ArbitrationLockQueueElement
*,
1194 } else if( kPutOnFreeQueue
== action
) {
1195 queue_enter( &gArbitrationLockQueueFree
,
1197 ArbitrationLockQueueElement
*,
1200 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1203 // unlock global access
1204 IOUnlock( gArbitrationLockQueueLock
);
1209 void IOService::unlockForArbitration( void )
1212 ArbitrationLockQueueElement
* element
;
1214 // lock global access
1215 IOTakeLock( gArbitrationLockQueueLock
);
1217 // find the lock element for this object (ie. on active queue)
1219 queue_iterate( &gArbitrationLockQueueActive
,
1221 ArbitrationLockQueueElement
*,
1224 if( element
->service
== this ) {
1232 // determine whether the lock has been taken recursively
1233 if( element
->count
> 1 ) {
1234 // undo one level of recursion
1239 // remove it from the active queue
1240 queue_remove( &gArbitrationLockQueueActive
,
1242 ArbitrationLockQueueElement
*,
1245 // put it on the free queue
1246 queue_enter( &gArbitrationLockQueueFree
,
1248 ArbitrationLockQueueElement
*,
1251 // determine whether a thread is waiting for object (head to tail scan)
1253 queue_iterate( &gArbitrationLockQueueWaiting
,
1255 ArbitrationLockQueueElement
*,
1258 if( element
->service
== this ) {
1264 if ( found
) { // we found an interested thread on waiting queue
1266 // remove it from the waiting queue
1267 queue_remove( &gArbitrationLockQueueWaiting
,
1269 ArbitrationLockQueueElement
*,
1272 // put it on the active queue
1273 queue_enter( &gArbitrationLockQueueActive
,
1275 ArbitrationLockQueueElement
*,
1278 // wake the waiting thread
1279 IOLockWakeup( gArbitrationLockQueueLock
,
1281 /* one thread */ true );
1285 // unlock global access
1286 IOUnlock( gArbitrationLockQueueLock
);
1289 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1292 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1293 context
, gIOServicePlane
);
1296 void IOService::applyToClients( IOServiceApplierFunction applier
,
1299 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1300 context
, gIOServicePlane
);
1309 // send a message to a client or interested party of this service
1310 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1311 void * argument
, vm_size_t argSize
)
1314 IOService
* service
;
1315 _IOServiceInterestNotifier
* notify
;
1317 if( (service
= OSDynamicCast( IOService
, client
)))
1318 ret
= service
->message( type
, this, argument
);
1320 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1322 _IOServiceNotifierInvocation invocation
;
1325 invocation
.thread
= current_thread();
1328 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1331 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1332 _IOServiceNotifierInvocation
*, link
);
1338 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1339 type
, this, argument
, argSize
);
1342 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1343 _IOServiceNotifierInvocation
*, link
);
1344 if( kIOServiceNotifyWaiter
& notify
->state
) {
1345 notify
->state
&= ~kIOServiceNotifyWaiter
;
1346 WAKEUPNOTIFY( notify
);
1351 ret
= kIOReturnSuccess
;
1354 ret
= kIOReturnBadArgument
;
1360 applyToInterestNotifiers(const IORegistryEntry
*target
,
1361 const OSSymbol
* typeOfInterest
,
1362 OSObjectApplierFunction applier
,
1365 OSArray
* copyArray
= 0;
1369 IOCommand
*notifyList
=
1370 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1373 copyArray
= OSArray::withCapacity(1);
1375 // iterate over queue, entry is set to each element in the list
1376 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1377 _IOServiceInterestNotifier
* notify
;
1379 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1380 copyArray
->setObject(notify
);
1389 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1390 (*applier
)(next
, context
);
1391 copyArray
->release();
1395 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1396 OSObjectApplierFunction applier
,
1399 if (gIOGeneralInterest
== typeOfInterest
)
1400 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1401 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1404 struct MessageClientsContext
{
1405 IOService
* service
;
1412 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1415 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1417 ret
= context
->service
->messageClient( context
->type
,
1418 object
, context
->argument
, context
->argSize
);
1419 if( kIOReturnSuccess
!= ret
)
1423 // send a message to all clients
1424 IOReturn
IOService::messageClients( UInt32 type
,
1425 void * argument
, vm_size_t argSize
)
1427 MessageClientsContext context
;
1429 context
.service
= this;
1430 context
.type
= type
;
1431 context
.argument
= argument
;
1432 context
.argSize
= argSize
;
1433 context
.ret
= kIOReturnSuccess
;
1435 applyToInterested( gIOGeneralInterest
,
1436 &messageClientsApplier
, &context
);
1438 return( context
.ret
);
1441 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1442 IOOptionBits response
)
1444 return( kIOReturnUnsupported
);
1447 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1448 IOServiceInterestHandler handler
, void * target
, void * ref
)
1450 _IOServiceInterestNotifier
* notify
= 0;
1452 if( (typeOfInterest
!= gIOGeneralInterest
)
1453 && (typeOfInterest
!= gIOBusyInterest
)
1454 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1455 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1458 lockForArbitration();
1459 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1461 notify
= new _IOServiceInterestNotifier
;
1462 if( notify
&& !notify
->init()) {
1468 notify
->handler
= handler
;
1469 notify
->target
= target
;
1471 notify
->state
= kIOServiceNotifyEnable
;
1472 queue_init( ¬ify
->handlerInvocations
);
1478 // Get the head of the notifier linked list
1479 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1480 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1481 notifyList
= OSTypeAlloc(IOCommand
);
1484 setProperty( typeOfInterest
, notifyList
);
1485 notifyList
->release();
1490 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1491 notify
->retain(); // ref'ed while in list
1497 unlockForArbitration();
1502 static void cleanInterestList( OSObject
* head
)
1504 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1509 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1510 queue_next(entry
) = queue_prev(entry
) = 0;
1512 _IOServiceInterestNotifier
* notify
;
1514 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1520 void IOService::unregisterAllInterest( void )
1522 cleanInterestList( getProperty( gIOGeneralInterest
));
1523 cleanInterestList( getProperty( gIOBusyInterest
));
1524 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1525 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1529 * _IOServiceInterestNotifier
1532 // wait for all threads, other than the current one,
1533 // to exit the handler
1535 void _IOServiceInterestNotifier::wait()
1537 _IOServiceNotifierInvocation
* next
;
1542 queue_iterate( &handlerInvocations
, next
,
1543 _IOServiceNotifierInvocation
*, link
) {
1544 if( next
->thread
!= current_thread() ) {
1550 state
|= kIOServiceNotifyWaiter
;
1557 void _IOServiceInterestNotifier::free()
1559 assert( queue_empty( &handlerInvocations
));
1563 void _IOServiceInterestNotifier::remove()
1567 if( queue_next( &chain
)) {
1568 remqueue( 0, &chain
);
1569 queue_next( &chain
) = queue_prev( &chain
) = 0;
1573 state
&= ~kIOServiceNotifyEnable
;
1582 bool _IOServiceInterestNotifier::disable()
1588 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1589 state
&= ~kIOServiceNotifyEnable
;
1598 void _IOServiceInterestNotifier::enable( bool was
)
1602 state
|= kIOServiceNotifyEnable
;
1604 state
&= ~kIOServiceNotifyEnable
;
1608 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1614 #define tailQ(o) setObject(o)
1615 #define headQ(o) setObject(0, o)
1616 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1618 inline void _workLoopAction( IOWorkLoop::Action action
,
1619 IOService
* service
,
1620 void * p0
= 0, void * p1
= 0,
1621 void * p2
= 0, void * p3
= 0 )
1625 if( (wl
= service
->getWorkLoop())) {
1627 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1630 (*action
)( service
, p0
, p1
, p2
, p3
);
1633 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1637 // if its our only provider
1638 ok
= isParent( provider
, gIOServicePlane
, true);
1642 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1643 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1650 bool IOService::terminatePhase1( IOOptionBits options
)
1655 OSArray
* makeInactive
;
1658 bool startPhase2
= false;
1660 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1663 if( options
& kIOServiceRecursing
) {
1664 __state
[1] |= kIOServiceRecursing
;
1669 makeInactive
= OSArray::withCapacity( 16 );
1678 didInactive
= victim
->lockForArbitration( true );
1680 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1682 victim
->__state
[0] |= kIOServiceInactiveState
;
1683 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1684 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1685 victim
->_adjustBusy( 1 );
1687 victim
->unlockForArbitration();
1690 startPhase2
= didInactive
;
1693 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1694 IOUserClient::destroyUserReferences( victim
);
1696 iter
= victim
->getClientIterator();
1698 while( (client
= (IOService
*) iter
->getNextObject())) {
1699 TLOG("%s::requestTerminate(%s, %08lx)\n",
1700 client
->getName(), victim
->getName(), options
);
1701 ok
= client
->requestTerminate( victim
, options
);
1702 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1703 client
->getName(), victim
->getName(), ok
);
1705 makeInactive
->setObject( client
);
1711 victim
= (IOService
*) makeInactive
->getObject(0);
1714 makeInactive
->removeObject(0);
1718 makeInactive
->release();
1721 scheduleTerminatePhase2( options
);
1726 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1728 AbsoluteTime deadline
;
1729 int waitResult
= THREAD_AWAKENED
;
1730 bool wait
, haveDeadline
= false;
1732 options
|= kIOServiceRequired
;
1736 IOLockLock( gJobsLock
);
1738 if( (options
& kIOServiceSynchronous
)
1739 && (current_thread() != gIOTerminateThread
)) {
1742 wait
= (gIOTerminateThread
!= 0);
1744 // wait to become the terminate thread
1745 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1749 gIOTerminateThread
= current_thread();
1750 gIOTerminatePhase2List
->setObject( this );
1754 while( gIOTerminateWork
)
1755 terminateWorker( options
);
1756 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1758 // wait for the victim to go non-busy
1759 if( !haveDeadline
) {
1760 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1761 haveDeadline
= true;
1763 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1764 deadline
, THREAD_UNINT
);
1765 if( waitResult
== THREAD_TIMED_OUT
) {
1766 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1769 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1771 gIOTerminateThread
= 0;
1772 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1775 // ! kIOServiceSynchronous
1777 gIOTerminatePhase2List
->setObject( this );
1778 if( 0 == gIOTerminateWork
++) {
1779 if( !gIOTerminateThread
)
1780 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1782 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1786 IOLockUnlock( gJobsLock
);
1791 void IOService::terminateThread( void * arg
)
1793 IOLockLock( gJobsLock
);
1795 while (gIOTerminateWork
)
1796 terminateWorker( (IOOptionBits
) arg
);
1798 gIOTerminateThread
= 0;
1799 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1801 IOLockUnlock( gJobsLock
);
1804 void IOService::scheduleStop( IOService
* provider
)
1806 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1808 IOLockLock( gJobsLock
);
1809 gIOStopList
->tailQ( this );
1810 gIOStopProviderList
->tailQ( provider
);
1812 if( 0 == gIOTerminateWork
++) {
1813 if( !gIOTerminateThread
)
1814 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1816 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1819 IOLockUnlock( gJobsLock
);
1822 void IOService::scheduleFinalize( void )
1824 TLOG("%s::scheduleFinalize\n", getName());
1826 IOLockLock( gJobsLock
);
1827 gIOFinalizeList
->tailQ( this );
1829 if( 0 == gIOTerminateWork
++) {
1830 if( !gIOTerminateThread
)
1831 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1833 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1836 IOLockUnlock( gJobsLock
);
1839 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1844 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1846 if( false == *defer
) {
1848 if( lockForArbitration( true )) {
1849 if( false == provider
->handleIsOpen( this ))
1850 scheduleStop( provider
);
1853 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1854 if( false == provider
->handleIsOpen( this ))
1855 scheduleStop( provider
);
1858 unlockForArbitration();
1865 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1866 OSArray
* doPhase2List
)
1872 iter
= victim
->getClientIterator();
1874 while( (client
= (IOService
*) iter
->getNextObject())) {
1875 TLOG("%s::willTerminate(%s, %08lx)\n",
1876 client
->getName(), victim
->getName(), options
);
1877 ok
= client
->willTerminate( victim
, options
);
1878 doPhase2List
->tailQ( client
);
1884 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1890 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1892 iter
= victim
->getClientIterator();
1894 while( (client
= (IOService
*) iter
->getNextObject())) {
1895 TLOG("%s::didTerminate(%s, %08lx)\n",
1896 client
->getName(), victim
->getName(), options
);
1897 client
->didTerminate( victim
, options
, &defer
);
1898 TLOG("%s::didTerminate(%s, defer %d)\n",
1899 client
->getName(), victim
->getName(), defer
);
1905 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1907 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1908 victim
->finalize( options
);
1911 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1913 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1914 client
->stop( provider
);
1915 if( provider
->isOpen( client
))
1916 provider
->close( client
);
1917 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1918 client
->detach( provider
);
1921 void IOService::terminateWorker( IOOptionBits options
)
1923 OSArray
* doPhase2List
;
1924 OSArray
* didPhase2List
;
1929 IOService
* provider
;
1935 options
|= kIOServiceRequired
;
1937 doPhase2List
= OSArray::withCapacity( 16 );
1938 didPhase2List
= OSArray::withCapacity( 16 );
1939 freeList
= OSSet::withCapacity( 16 );
1940 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1944 workDone
= gIOTerminateWork
;
1946 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1949 gIOTerminatePhase2List
->removeObject(0);
1950 IOLockUnlock( gJobsLock
);
1954 doPhase2
= victim
->lockForArbitration( true );
1956 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1958 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1959 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1961 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1963 victim
->unlockForArbitration();
1966 if( 0 == victim
->getClient()) {
1967 // no clients - will go to finalize
1968 IOLockLock( gJobsLock
);
1969 gIOFinalizeList
->tailQ( victim
);
1970 IOLockUnlock( gJobsLock
);
1972 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1973 victim
, (void *) options
, (void *) doPhase2List
);
1975 didPhase2List
->headQ( victim
);
1978 victim
= (IOService
*) doPhase2List
->getObject(0);
1981 doPhase2List
->removeObject(0);
1985 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1987 if( victim
->lockForArbitration( true )) {
1988 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1989 victim
->unlockForArbitration();
1991 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1992 victim
, (void *) options
);
1993 didPhase2List
->removeObject(0);
1995 IOLockLock( gJobsLock
);
2002 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2004 IOLockUnlock( gJobsLock
);
2005 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2006 victim
, (void *) options
);
2007 IOLockLock( gJobsLock
);
2009 freeList
->setObject( victim
);
2010 // safe if finalize list is append only
2011 gIOFinalizeList
->removeObject(0);
2015 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2017 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2020 if( !provider
->isChild( client
, gIOServicePlane
)) {
2021 // may be multiply queued - nop it
2022 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
2024 // not ready for stop if it has clients, skip it
2025 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
2026 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
2031 IOLockUnlock( gJobsLock
);
2032 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2033 provider
, (void *) client
);
2034 IOLockLock( gJobsLock
);
2035 // check the finalize list now
2039 freeList
->setObject( client
);
2040 freeList
->setObject( provider
);
2042 // safe if stop list is append only
2043 gIOStopList
->removeObject( idx
);
2044 gIOStopProviderList
->removeObject( idx
);
2048 } while( doPhase3
);
2050 gIOTerminateWork
-= workDone
;
2051 moreToDo
= (gIOTerminateWork
!= 0);
2054 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2057 } while( moreToDo
);
2059 IOLockUnlock( gJobsLock
);
2061 freeList
->release();
2062 doPhase2List
->release();
2063 didPhase2List
->release();
2065 IOLockLock( gJobsLock
);
2068 bool IOService::finalize( IOOptionBits options
)
2071 IOService
* provider
;
2073 iter
= getProviderIterator();
2077 while( (provider
= (IOService
*) iter
->getNextObject())) {
2080 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2081 /* we come down here on programmatic terminate */
2083 if( provider
->isOpen( this ))
2084 provider
->close( this );
2088 if( provider
->lockForArbitration( true )) {
2089 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2090 scheduleStop( provider
);
2091 provider
->unlockForArbitration();
2108 void IOService::doServiceTerminate( IOOptionBits options
)
2112 // a method in case someone needs to override it
2113 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2117 if( client
->isParent( this, gIOServicePlane
, true))
2118 // we are the clients only provider
2119 ok
= client
->terminate( options
);
2126 bool IOService::terminate( IOOptionBits options
)
2128 options
|= kIOServiceTerminate
;
2130 return( terminatePhase1( options
));
2133 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2139 struct ServiceOpenMessageContext
2141 IOService
* service
;
2143 IOService
* excludeClient
;
2144 IOOptionBits options
;
2147 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2149 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2151 if( object
!= context
->excludeClient
)
2152 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2155 bool IOService::open( IOService
* forClient
,
2156 IOOptionBits options
,
2160 ServiceOpenMessageContext context
;
2162 context
.service
= this;
2163 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2164 context
.excludeClient
= forClient
;
2165 context
.options
= options
;
2167 applyToInterested( gIOGeneralInterest
,
2168 &serviceOpenMessageApplier
, &context
);
2170 if( false == lockForArbitration(false) )
2173 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2175 ok
= handleOpen( forClient
, options
, arg
);
2177 unlockForArbitration();
2182 void IOService::close( IOService
* forClient
,
2183 IOOptionBits options
)
2188 lockForArbitration();
2190 wasClosed
= handleIsOpen( forClient
);
2192 handleClose( forClient
, options
);
2193 last
= (__state
[1] & kIOServiceTermPhase3State
);
2196 unlockForArbitration();
2199 forClient
->scheduleStop( this );
2201 else if( wasClosed
) {
2203 ServiceOpenMessageContext context
;
2205 context
.service
= this;
2206 context
.type
= kIOMessageServiceWasClosed
;
2207 context
.excludeClient
= forClient
;
2208 context
.options
= options
;
2210 applyToInterested( gIOGeneralInterest
,
2211 &serviceOpenMessageApplier
, &context
);
2215 bool IOService::isOpen( const IOService
* forClient
) const
2217 IOService
* self
= (IOService
*) this;
2220 self
->lockForArbitration();
2222 ok
= handleIsOpen( forClient
);
2224 self
->unlockForArbitration();
2229 bool IOService::handleOpen( IOService
* forClient
,
2230 IOOptionBits options
,
2235 ok
= (0 == __owner
);
2237 __owner
= forClient
;
2239 else if( options
& kIOServiceSeize
) {
2240 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2241 __owner
, (void *) options
));
2242 if( ok
&& (0 == __owner
))
2243 __owner
= forClient
;
2250 void IOService::handleClose( IOService
* forClient
,
2251 IOOptionBits options
)
2253 if( __owner
== forClient
)
2257 bool IOService::handleIsOpen( const IOService
* forClient
) const
2260 return( __owner
== forClient
);
2262 return( __owner
!= forClient
);
2266 * Probing & starting
2268 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2270 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2271 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2279 val1
= obj1
->priority
;
2282 val2
= obj2
->priority
;
2284 return ( val1
- val2
);
2287 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2289 OSDictionary
* dict
;
2290 IOService
* service
;
2291 _IOServiceNotifier
* notify
;
2292 OSSymbol
* key
= (OSSymbol
*) ref
;
2295 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2296 return( notify
->priority
);
2298 else if( (service
= OSDynamicCast( IOService
, entry
)))
2299 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2300 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2301 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2308 return( (SInt32
) offset
->unsigned32BitValue());
2310 return( kIODefaultProbeScore
);
2313 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2315 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2316 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2324 val1
= IOServiceObjectOrder( obj1
, ref
);
2327 val2
= IOServiceObjectOrder( obj2
, ref
);
2329 return ( val1
- val2
);
2332 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2334 IOService
* service
= 0;
2336 const OSSymbol
* nextCat
;
2338 iter
= getClientIterator();
2340 while( (service
= (IOService
*) iter
->getNextObject())) {
2341 if( kIOServiceInactiveState
& service
->__state
[0])
2343 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2344 service
->getProperty( gIOMatchCategoryKey
));
2345 if( category
== nextCat
)
2353 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2355 _IOServiceNotifierInvocation invocation
;
2359 invocation
.thread
= current_thread();
2362 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2365 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2366 _IOServiceNotifierInvocation
*, link
);
2372 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2375 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2376 _IOServiceNotifierInvocation
*, link
);
2377 if( kIOServiceNotifyWaiter
& notify
->state
) {
2378 notify
->state
&= ~kIOServiceNotifyWaiter
;
2379 WAKEUPNOTIFY( notify
);
2388 * Alloc and probe matching classes,
2389 * called on the provider instance
2392 void IOService::probeCandidates( OSOrderedSet
* matches
)
2394 OSDictionary
* match
= 0;
2397 IOService
* newInst
;
2398 OSDictionary
* props
;
2401 OSOrderedSet
* familyMatches
= 0;
2402 OSOrderedSet
* startList
;
2403 OSDictionary
* startDict
= 0;
2404 const OSSymbol
* category
;
2406 _IOServiceNotifier
* notify
;
2407 OSObject
* nextMatch
= 0;
2409 bool needReloc
= false;
2410 #if CONFIG_MACF_KEXT
2411 OSBoolean
* isSandbox
= 0;
2412 bool useSandbox
= false;
2419 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2421 nextMatch
->retain();
2422 matches
->removeObject(nextMatch
);
2424 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2426 lockForArbitration();
2427 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2428 invokeNotifer( notify
);
2429 unlockForArbitration();
2430 nextMatch
->release();
2434 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2435 nextMatch
->release();
2442 debugFlags
= getDebugFlags( match
);
2446 category
= OSDynamicCast( OSSymbol
,
2447 match
->getObject( gIOMatchCategoryKey
));
2449 category
= gIODefaultMatchCategoryKey
;
2451 if( getClientWithCategory( category
)) {
2453 if( debugFlags
& kIOLogMatch
)
2454 LOG("%s: match category %s exists\n", getName(),
2455 category
->getCStringNoCopy());
2457 nextMatch
->release();
2462 // create a copy now in case its modified during matching
2463 props
= OSDictionary::withDictionary( match
, match
->getCount());
2466 props
->setCapacityIncrement(1);
2468 // check the nub matches
2469 if( false == passiveMatch( props
, true ))
2472 // Check to see if driver reloc has been loaded.
2473 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2476 if( debugFlags
& kIOLogCatalogue
)
2477 LOG("%s: stalling for module\n", getName());
2479 // If reloc hasn't been loaded, exit;
2480 // reprobing will occur after reloc has been loaded.
2484 // reorder on family matchPropertyTable score.
2485 if( 0 == familyMatches
)
2486 familyMatches
= OSOrderedSet::withCapacity( 1,
2487 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2489 familyMatches
->setObject( props
);
2494 nextMatch
->release();
2503 if( familyMatches
) {
2506 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2509 familyMatches
->removeObject( props
);
2514 debugFlags
= getDebugFlags( props
);
2517 symbol
= OSDynamicCast( OSSymbol
,
2518 props
->getObject( gIOClassKey
));
2522 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), symbol, props);
2524 // alloc the driver instance
2525 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2528 IOLog("Couldn't alloc class \"%s\"\n",
2529 symbol
->getCStringNoCopy());
2533 // init driver instance
2534 if( !(inst
->init( props
))) {
2536 if( debugFlags
& kIOLogStart
)
2537 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2541 if( __state
[1] & kIOServiceSynchronousState
)
2542 inst
->__state
[1] |= kIOServiceSynchronousState
;
2544 // give the driver the default match category if not specified
2545 category
= OSDynamicCast( OSSymbol
,
2546 props
->getObject( gIOMatchCategoryKey
));
2548 category
= gIODefaultMatchCategoryKey
;
2549 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2550 #if CONFIG_MACF_KEXT
2551 isSandbox
= OSDynamicCast(OSBoolean
,
2552 props
->getObject("IOKitForceMatch"));
2554 // attach driver instance
2555 if( !(inst
->attach( this )))
2558 // pass in score from property table
2559 score
= familyMatches
->orderObject( props
);
2561 // & probe the new driver instance
2563 if( debugFlags
& kIOLogProbe
)
2564 LOG("%s::probe(%s)\n",
2565 inst
->getMetaClass()->getClassName(), getName());
2568 newInst
= inst
->probe( this, &score
);
2569 inst
->detach( this );
2570 #if CONFIG_MACF_KEXT
2572 * If this is the Sandbox driver and it matched, this is a
2573 * disallowed device; toss any drivers that were already
2576 if (isSandbox
&& isSandbox
->isTrue() && newInst
!= 0) {
2577 if (startDict
!= 0) {
2578 startDict
->flushCollection();
2579 startDict
->release();
2587 if( debugFlags
& kIOLogProbe
)
2588 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2594 newPri
= OSNumber::withNumber( score
, 32 );
2596 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2600 // add to start list for the match category
2602 startDict
= OSDictionary::withCapacity( 1 );
2603 assert( startDict
);
2604 startList
= (OSOrderedSet
*)
2605 startDict
->getObject( category
);
2606 if( 0 == startList
) {
2607 startList
= OSOrderedSet::withCapacity( 1,
2608 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2609 if( startDict
&& startList
) {
2610 startDict
->setObject( category
, startList
);
2611 startList
->release();
2614 assert( startList
);
2616 startList
->setObject( newInst
);
2623 #if CONFIG_MACF_KEXT
2625 * If we're forcing the sandbox, drop out of the loop.
2627 if (isSandbox
&& isSandbox
->isTrue() && useSandbox
)
2631 familyMatches
->release();
2635 // start the best (until success) of each category
2637 iter
= OSCollectionIterator::withCollection( startDict
);
2639 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2641 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2642 assert( startList
);
2647 while( true // (!started)
2648 && (inst
= (IOService
*)startList
->getFirstObject())) {
2651 startList
->removeObject(inst
);
2654 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2656 if( debugFlags
& kIOLogStart
) {
2658 LOG( "match category exists, skipping " );
2659 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2660 getName(), inst
->getRetainCount());
2663 if( false == started
)
2664 started
= startCandidate( inst
);
2666 if( (debugFlags
& kIOLogStart
) && (false == started
))
2667 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2668 inst
->getRetainCount());
2677 // adjust the busy count by -1 if matching is stalled for a module,
2678 // or +1 if a previously stalled matching is complete.
2679 lockForArbitration();
2682 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2684 __state
[1] |= kIOServiceModuleStallState
;
2686 } else if( __state
[1] & kIOServiceModuleStallState
) {
2687 __state
[1] &= ~kIOServiceModuleStallState
;
2691 _adjustBusy( adjBusy
);
2692 unlockForArbitration();
2695 startDict
->release();
2699 * Start a previously attached & probed instance,
2700 * called on exporting object instance
2703 bool IOService::startCandidate( IOService
* service
)
2707 ok
= service
->attach( this );
2711 if (this != gIOResources
)
2713 // stall for any nub resources
2715 // stall for any driver resources
2716 service
->checkResources();
2719 AbsoluteTime startTime
;
2720 AbsoluteTime endTime
;
2723 if (kIOLogStart
& gIOKitDebug
)
2724 clock_get_uptime(&startTime
);
2726 ok
= service
->start(this);
2728 if (kIOLogStart
& gIOKitDebug
)
2730 clock_get_uptime(&endTime
);
2732 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2734 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2735 absolutetime_to_nanoseconds(endTime
, &nano
);
2736 if (nano
> 500000000ULL)
2737 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2741 service
->detach( this );
2746 IOService
* IOService::resources( void )
2748 return( gIOResources
);
2751 void IOService::publishResource( const char * key
, OSObject
* value
)
2753 const OSSymbol
* sym
;
2755 if( (sym
= OSSymbol::withCString( key
))) {
2756 publishResource( sym
, value
);
2761 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2764 value
= (OSObject
*) gIOServiceKey
;
2766 gIOResources
->setProperty( key
, value
);
2768 if( IORecursiveLockHaveLock( gNotificationLock
))
2771 gIOResourceGenerationCount
++;
2772 gIOResources
->registerService();
2775 bool IOService::addNeededResource( const char * key
)
2777 OSObject
* resourcesProp
;
2782 resourcesProp
= getProperty( gIOResourceMatchKey
);
2784 newKey
= OSString::withCString( key
);
2785 if( (0 == resourcesProp
) || (0 == newKey
))
2788 set
= OSDynamicCast( OSSet
, resourcesProp
);
2790 set
= OSSet::withCapacity( 1 );
2792 set
->setObject( resourcesProp
);
2797 set
->setObject( newKey
);
2799 ret
= setProperty( gIOResourceMatchKey
, set
);
2805 bool IOService::checkResource( OSObject
* matching
)
2808 OSDictionary
* table
;
2810 if( (str
= OSDynamicCast( OSString
, matching
))) {
2811 if( gIOResources
->getProperty( str
))
2816 table
= resourceMatching( str
);
2817 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2820 IOLog("%s: Can't match using: %s\n", getName(),
2821 matching
->getMetaClass()->getClassName());
2822 /* false would stall forever */
2826 if( gIOKitDebug
& kIOLogConfig
)
2827 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2829 waitForService( table
);
2831 if( gIOKitDebug
& kIOLogConfig
)
2832 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2837 bool IOService::checkResources( void )
2839 OSObject
* resourcesProp
;
2844 resourcesProp
= getProperty( gIOResourceMatchKey
);
2845 if( 0 == resourcesProp
)
2848 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
2850 iter
= OSCollectionIterator::withCollection( set
);
2852 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
2853 ok
= checkResource( resourcesProp
);
2858 ok
= checkResource( resourcesProp
);
2864 void _IOConfigThread::configThread( void )
2866 _IOConfigThread
* inst
;
2869 if( !(inst
= new _IOConfigThread
))
2873 if( !(IOCreateThread((IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2886 void _IOConfigThread::free( void )
2891 void IOService::doServiceMatch( IOOptionBits options
)
2893 _IOServiceNotifier
* notify
;
2895 OSOrderedSet
* matches
;
2896 SInt32 catalogGeneration
;
2897 bool keepGuessing
= true;
2898 bool reRegistered
= true;
2900 // job->nub->deliverNotification( gIOPublishNotification,
2901 // kIOServiceRegisteredState, 0xffffffff );
2903 while( keepGuessing
) {
2905 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2906 // the matches list should always be created by findDrivers()
2909 lockForArbitration();
2910 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2911 deliverNotification( gIOFirstPublishNotification
,
2912 kIOServiceFirstPublishState
, 0xffffffff );
2914 __state
[1] &= ~kIOServiceNeedConfigState
;
2915 __state
[1] |= kIOServiceConfigState
;
2916 __state
[0] |= kIOServiceRegisteredState
;
2918 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2920 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2921 gNotifications
->getObject( gIOPublishNotification
) );
2923 while((notify
= (_IOServiceNotifier
*)
2924 iter
->getNextObject())) {
2926 if( passiveMatch( notify
->matching
)
2927 && (kIOServiceNotifyEnable
& notify
->state
))
2928 matches
->setObject( notify
);
2935 unlockForArbitration();
2937 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2938 probeCandidates( matches
);
2943 lockForArbitration();
2944 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2946 (reRegistered
|| (catalogGeneration
!=
2947 gIOCatalogue
->getGenerationCount()))
2948 && (0 == (__state
[0] & kIOServiceInactiveState
));
2951 unlockForArbitration();
2954 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2955 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2956 deliverNotification( gIOMatchedNotification
,
2957 kIOServiceMatchedState
, 0xffffffff );
2958 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2959 deliverNotification( gIOFirstMatchNotification
,
2960 kIOServiceFirstMatchState
, 0xffffffff );
2963 __state
[1] &= ~kIOServiceConfigState
;
2964 if( __state
[0] & kIOServiceInactiveState
)
2965 scheduleTerminatePhase2();
2968 unlockForArbitration();
2971 UInt32
IOService::_adjustBusy( SInt32 delta
)
2976 bool wasQuiet
, nowQuiet
, needWake
;
2979 result
= __state
[1] & kIOServiceBusyStateMask
;
2983 next
->lockForArbitration();
2984 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2985 assert( count
< kIOServiceBusyMax
);
2986 wasQuiet
= (0 == count
);
2987 assert( (!wasQuiet
) || (delta
> 0));
2988 next
->__state
[1] += delta
;
2989 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2990 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2993 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2994 IOLockLock( gIOServiceBusyLock
);
2995 thread_wakeup( (event_t
) next
);
2996 IOLockUnlock( gIOServiceBusyLock
);
2999 next
->unlockForArbitration();
3001 if( (wasQuiet
|| nowQuiet
) ) {
3002 MessageClientsContext context
;
3004 context
.service
= next
;
3005 context
.type
= kIOMessageServiceBusyStateChange
;
3006 context
.argument
= (void *) wasQuiet
; // busy now
3007 context
.argSize
= 0;
3009 applyToInterestNotifiers( next
, gIOBusyInterest
,
3010 &messageClientsApplier
, &context
);
3013 if( nowQuiet
&& (next
== gIOServiceRoot
))
3014 OSMetaClass::considerUnloads();
3018 delta
= nowQuiet
? -1 : +1;
3020 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3025 void IOService::adjustBusy( SInt32 delta
)
3027 lockForArbitration();
3028 _adjustBusy( delta
);
3029 unlockForArbitration();
3032 UInt32
IOService::getBusyState( void )
3034 return( __state
[1] & kIOServiceBusyStateMask
);
3037 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3038 mach_timespec_t
* timeout
)
3041 int waitResult
= THREAD_AWAKENED
;
3042 bool computeDeadline
= true;
3043 AbsoluteTime abstime
;
3046 lockForArbitration();
3047 IOLockLock( gIOServiceBusyLock
);
3048 wait
= (value
!= (__state
[1] & mask
));
3050 __state
[1] |= kIOServiceBusyWaiterState
;
3051 unlockForArbitration();
3053 if( computeDeadline
) {
3054 AbsoluteTime nsinterval
;
3055 clock_interval_to_absolutetime_interval(
3056 timeout
->tv_sec
, kSecondScale
, &abstime
);
3057 clock_interval_to_absolutetime_interval(
3058 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
3059 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
3060 clock_absolutetime_interval_to_deadline(
3061 abstime
, &abstime
);
3062 computeDeadline
= false;
3065 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3068 assert_wait((event_t
)this, THREAD_UNINT
);
3070 unlockForArbitration();
3071 IOLockUnlock( gIOServiceBusyLock
);
3073 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3075 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3077 if( waitResult
== THREAD_TIMED_OUT
)
3078 return( kIOReturnTimeout
);
3080 return( kIOReturnSuccess
);
3083 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3085 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
3088 bool IOService::serializeProperties( OSSerialize
* s
) const
3091 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3092 sizeof( __state
), "__state");
3094 return( super::serializeProperties(s
) );
3098 void _IOConfigThread::main( _IOConfigThread
* self
)
3100 _IOServiceJob
* job
;
3104 thread_precedence_policy_data_t precedence
= { -1 };
3106 kr
= thread_policy_set(current_thread(),
3107 THREAD_PRECEDENCE_POLICY
,
3108 (thread_policy_t
) &precedence
,
3109 THREAD_PRECEDENCE_POLICY_COUNT
);
3110 if (KERN_SUCCESS
!= kr
)
3111 IOLog("thread_policy_set(%d)\n", kr
);
3117 semaphore_wait( gJobsSemaphore
);
3119 IOTakeLock( gJobsLock
);
3120 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3122 gJobs
->removeObject(job
);
3125 // gNumConfigThreads--; // we're out of service
3126 gNumWaitingThreads
--; // we're out of service
3128 IOUnlock( gJobsLock
);
3134 if( gIOKitDebug
& kIOLogConfig
)
3135 LOG("config(%x): starting on %s, %d\n",
3136 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
3138 switch( job
->type
) {
3141 nub
->doServiceMatch( job
->options
);
3145 LOG("config(%x): strange type (%d)\n",
3146 (int) IOThreadSelf(), job
->type
);
3153 IOTakeLock( gJobsLock
);
3154 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3156 gNumWaitingThreads
++; // back in service
3157 // gNumConfigThreads++;
3159 if( 0 == --gNumConfigThreads
) {
3160 // IOLog("MATCH IDLE\n");
3161 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3164 IOUnlock( gJobsLock
);
3169 if( gIOKitDebug
& kIOLogConfig
)
3170 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3175 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3178 int waitResult
= THREAD_AWAKENED
;
3179 bool computeDeadline
= true;
3180 AbsoluteTime abstime
;
3182 IOLockLock( gJobsLock
);
3184 wait
= (0 != gNumConfigThreads
);
3187 if( computeDeadline
) {
3188 clock_interval_to_absolutetime_interval(
3189 msToWait
, kMillisecondScale
, &abstime
);
3190 clock_absolutetime_interval_to_deadline(
3191 abstime
, &abstime
);
3192 computeDeadline
= false;
3194 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3195 abstime
, THREAD_UNINT
);
3197 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3201 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3202 IOLockUnlock( gJobsLock
);
3204 if( waitResult
== THREAD_TIMED_OUT
)
3205 return( kIOReturnTimeout
);
3207 return( kIOReturnSuccess
);
3210 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3217 IOTakeLock( gJobsLock
);
3220 gJobs
->setLastObject( job
);
3222 count
= gNumWaitingThreads
;
3223 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3225 create
= ( (gOutstandingJobs
> count
)
3226 && (gNumConfigThreads
< kMaxConfigThreads
) );
3228 gNumConfigThreads
++;
3229 gNumWaitingThreads
++;
3232 IOUnlock( gJobsLock
);
3237 if( gIOKitDebug
& kIOLogConfig
)
3238 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3239 _IOConfigThread::configThread();
3242 semaphore_signal( gJobsSemaphore
);
3245 // internal - call with gNotificationLock
3246 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3247 IOOptionBits inState
, IOOptionBits options
)
3249 OSObject
* current
= 0;
3251 IOService
* service
;
3258 && (obj
= matching
->getObject(gIOProviderClassKey
))
3260 && gIOResourcesKey
->isEqualTo(obj
)
3261 && (service
= gIOResources
))
3263 if( (inState
== (service
->__state
[0] & inState
))
3264 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3265 && service
->passiveMatch( matching
))
3267 if( options
& kIONotifyOnce
)
3270 current
= OSSet::withObjects(
3271 (const OSObject
**) &service
, 1, 1 );
3276 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3277 kIORegistryIterateRecursively
);
3281 while( (service
= (IOService
*) iter
->getNextObject())) {
3282 if( (inState
== (service
->__state
[0] & inState
))
3283 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3284 && service
->passiveMatch( matching
)) {
3286 if( options
& kIONotifyOnce
) {
3291 ((OSSet
*)current
)->setObject( service
);
3293 current
= OSSet::withObjects(
3294 (const OSObject
**) &service
, 1, 1 );
3297 } while( !service
&& !iter
->isValid());
3302 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3303 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3312 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3316 // is a lock even needed?
3319 iter
= (OSIterator
*) getExistingServices( matching
,
3320 kIOServiceMatchedState
);
3328 // internal - call with gNotificationLock
3329 IONotifier
* IOService::setNotification(
3330 const OSSymbol
* type
, OSDictionary
* matching
,
3331 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3334 _IOServiceNotifier
* notify
= 0;
3340 notify
= new _IOServiceNotifier
;
3341 if( notify
&& !notify
->init()) {
3347 notify
->matching
= matching
;
3348 notify
->handler
= handler
;
3349 notify
->target
= target
;
3351 notify
->priority
= priority
;
3352 notify
->state
= kIOServiceNotifyEnable
;
3353 queue_init( ¬ify
->handlerInvocations
);
3357 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3358 set
= OSOrderedSet::withCapacity( 1,
3359 IONotifyOrdering
, 0 );
3361 gNotifications
->setObject( type
, set
);
3365 notify
->whence
= set
;
3367 set
->setObject( notify
);
3373 // internal - call with gNotificationLock
3374 IONotifier
* IOService::doInstallNotification(
3375 const OSSymbol
* type
, OSDictionary
* matching
,
3376 IOServiceNotificationHandler handler
,
3377 void * target
, void * ref
,
3378 SInt32 priority
, OSIterator
** existing
)
3381 IONotifier
* notify
;
3382 IOOptionBits inState
;
3387 if( type
== gIOPublishNotification
)
3388 inState
= kIOServiceRegisteredState
;
3390 else if( type
== gIOFirstPublishNotification
)
3391 inState
= kIOServiceFirstPublishState
;
3393 else if( (type
== gIOMatchedNotification
)
3394 || (type
== gIOFirstMatchNotification
))
3395 inState
= kIOServiceMatchedState
;
3396 else if( type
== gIOTerminatedNotification
)
3401 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3404 // get the current set
3405 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3415 IONotifier
* IOService::installNotification(
3416 const OSSymbol
* type
, OSDictionary
* matching
,
3417 IOServiceNotificationHandler handler
,
3418 void * target
, void * ref
,
3419 SInt32 priority
, OSIterator
** existing
)
3421 IONotifier
* notify
;
3425 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3426 priority
, existing
);
3433 IONotifier
* IOService::addNotification(
3434 const OSSymbol
* type
, OSDictionary
* matching
,
3435 IOServiceNotificationHandler handler
,
3436 void * target
, void * ref
,
3439 OSIterator
* existing
= NULL
;
3440 _IOServiceNotifier
* notify
;
3443 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3444 handler
, target
, ref
, priority
, &existing
);
3446 // send notifications for existing set
3449 notify
->retain(); // in case handler remove()s
3450 while( (next
= (IOService
*) existing
->getNextObject())) {
3452 next
->lockForArbitration();
3453 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3454 next
->invokeNotifer( notify
);
3455 next
->unlockForArbitration();
3458 existing
->release();
3464 struct SyncNotifyVars
{
3465 semaphore_port_t waitHere
;
3469 bool IOService::syncNotificationHandler(
3470 void * /* target */, void * ref
,
3471 IOService
* newService
)
3474 // result may get written more than once before the
3475 // notification is removed!
3476 ((SyncNotifyVars
*) ref
)->result
= newService
;
3477 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3482 IOService
* IOService::waitForService( OSDictionary
* matching
,
3483 mach_timespec_t
* timeout
)
3485 IONotifier
* notify
= 0;
3486 // priority doesn't help us much since we need a thread wakeup
3487 SInt32 priority
= 0;
3488 SyncNotifyVars state
;
3489 kern_return_t err
= kIOReturnBadArgument
;
3501 state
.result
= (IOService
*) getExistingServices( matching
,
3502 kIOServiceMatchedState
, kIONotifyOnce
);
3506 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3507 SYNC_POLICY_FIFO
, 0 );
3508 if( KERN_SUCCESS
!= err
)
3511 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3512 &IOService::syncNotificationHandler
, (void *) 0,
3513 (void *) &state
, priority
);
3521 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3523 err
= semaphore_wait( state
.waitHere
);
3527 notify
->remove(); // dequeues
3529 matching
->release();
3531 semaphore_destroy( kernel_task
, state
.waitHere
);
3533 return( state
.result
);
3536 void IOService::deliverNotification( const OSSymbol
* type
,
3537 IOOptionBits orNewState
, IOOptionBits andNewState
)
3539 _IOServiceNotifier
* notify
;
3541 OSArray
* willSend
= 0;
3543 lockForArbitration();
3545 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3546 || (type
== gIOTerminatedNotification
)) {
3550 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3551 gNotifications
->getObject( type
) );
3554 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3556 if( passiveMatch( notify
->matching
)
3557 && (kIOServiceNotifyEnable
& notify
->state
)) {
3559 willSend
= OSArray::withCapacity(8);
3561 willSend
->setObject( notify
);
3567 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3573 for( unsigned int idx
= 0;
3574 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3576 invokeNotifer( notify
);
3578 willSend
->release();
3580 unlockForArbitration();
3583 IOOptionBits
IOService::getState( void ) const
3585 return( __state
[0] );
3589 * Helpers to make matching objects for simple cases
3592 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3593 OSDictionary
* table
)
3596 table
= OSDictionary::withCapacity( 2 );
3598 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3603 OSDictionary
* IOService::serviceMatching( const char * name
,
3604 OSDictionary
* table
)
3606 const OSString
* str
;
3608 str
= OSSymbol::withCString( name
);
3612 table
= serviceMatching( str
, table
);
3617 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3618 OSDictionary
* table
)
3621 table
= OSDictionary::withCapacity( 2 );
3623 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3628 OSDictionary
* IOService::nameMatching( const char * name
,
3629 OSDictionary
* table
)
3631 const OSString
* str
;
3633 str
= OSSymbol::withCString( name
);
3637 table
= nameMatching( str
, table
);
3642 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3643 OSDictionary
* table
)
3645 table
= serviceMatching( gIOResourcesKey
, table
);
3647 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3652 OSDictionary
* IOService::resourceMatching( const char * name
,
3653 OSDictionary
* table
)
3655 const OSSymbol
* str
;
3657 str
= OSSymbol::withCString( name
);
3661 table
= resourceMatching( str
, table
);
3667 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
3668 OSDictionary
* table
)
3670 OSDictionary
* properties
;
3672 properties
= OSDictionary::withCapacity( 2 );
3675 properties
->setObject( key
, value
);
3678 table
= OSDictionary::withCapacity( 2 );
3680 table
->setObject( gIOPropertyMatchKey
, properties
);
3682 properties
->release();
3688 * _IOServiceNotifier
3691 // wait for all threads, other than the current one,
3692 // to exit the handler
3694 void _IOServiceNotifier::wait()
3696 _IOServiceNotifierInvocation
* next
;
3701 queue_iterate( &handlerInvocations
, next
,
3702 _IOServiceNotifierInvocation
*, link
) {
3703 if( next
->thread
!= current_thread() ) {
3709 state
|= kIOServiceNotifyWaiter
;
3716 void _IOServiceNotifier::free()
3718 assert( queue_empty( &handlerInvocations
));
3722 void _IOServiceNotifier::remove()
3727 whence
->removeObject( (OSObject
*) this );
3731 matching
->release();
3735 state
&= ~kIOServiceNotifyEnable
;
3744 bool _IOServiceNotifier::disable()
3750 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3751 state
&= ~kIOServiceNotifyEnable
;
3760 void _IOServiceNotifier::enable( bool was
)
3764 state
|= kIOServiceNotifyEnable
;
3766 state
&= ~kIOServiceNotifyEnable
;
3774 IOService
* IOResources::resources( void )
3778 inst
= new IOResources
;
3779 if( inst
&& !inst
->init()) {
3787 IOWorkLoop
* IOResources::getWorkLoop() const
3789 // If we are the resource root then bringe over to the
3790 // platform to get its workloop
3791 if (this == (IOResources
*) gIOResources
)
3792 return getPlatform()->getWorkLoop();
3794 return IOService::getWorkLoop();
3797 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3805 prop
= table
->getObject( gIOResourceMatchKey
);
3806 str
= OSDynamicCast( OSString
, prop
);
3808 ok
= (0 != getProperty( str
));
3810 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3812 iter
= OSCollectionIterator::withCollection( set
);
3814 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3815 ok
= (0 != getProperty( str
));
3824 IOReturn
IOResources::setProperties( OSObject
* properties
)
3827 const OSSymbol
* key
;
3828 OSDictionary
* dict
;
3829 OSCollectionIterator
* iter
;
3831 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3832 if ( kIOReturnSuccess
!= err
)
3835 dict
= OSDynamicCast(OSDictionary
, properties
);
3837 return( kIOReturnBadArgument
);
3839 iter
= OSCollectionIterator::withCollection( dict
);
3841 return( kIOReturnBadArgument
);
3843 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3845 if (gIOConsoleUsersKey
== key
)
3847 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3848 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3849 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3853 publishResource( key
, dict
->getObject(key
) );
3858 return( kIOReturnSuccess
);
3862 * Helpers for matching dictionaries.
3863 * Keys existing in matching are checked in properties.
3864 * Keys may be a string or OSCollection of IOStrings
3867 bool IOService::compareProperty( OSDictionary
* matching
,
3873 value
= matching
->getObject( key
);
3875 ok
= value
->isEqualTo( getProperty( key
));
3883 bool IOService::compareProperty( OSDictionary
* matching
,
3884 const OSString
* key
)
3889 value
= matching
->getObject( key
);
3891 ok
= value
->isEqualTo( getProperty( key
));
3898 bool IOService::compareProperties( OSDictionary
* matching
,
3899 OSCollection
* keys
)
3901 OSCollectionIterator
* iter
;
3902 const OSString
* key
;
3905 if( !matching
|| !keys
)
3908 iter
= OSCollectionIterator::withCollection( keys
);
3911 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3912 ok
= compareProperty( matching
, key
);
3916 keys
->release(); // !! consume a ref !!
3921 /* Helper to add a location matching dict to the table */
3923 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3925 OSDictionary
* dict
;
3930 dict
= OSDictionary::withCapacity( 1 );
3932 table
->setObject( gIOLocationMatchKey
, dict
);
3940 * Go looking for a provider to match a location dict.
3943 IOService
* IOService::matchLocation( IOService
* /* client */ )
3947 parent
= getProvider();
3950 parent
= parent
->matchLocation( this );
3955 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3961 IORegistryEntry
* entry
;
3966 bool matchParent
= false;
3977 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3980 match
= (0 != where
->metaCast( str
));
3985 obj
= table
->getObject( gIONameMatchKey
);
3988 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3991 if( changesOK
&& matched
) {
3992 // leave a hint as to which name matched
3993 table
->setObject( gIONameMatchedKey
, matched
);
3998 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
4001 const OSSymbol
* sym
;
4005 sym
= where
->copyLocation();
4007 match
= sym
->isEqualTo( str
);
4014 obj
= table
->getObject( gIOPropertyMatchKey
);
4017 OSDictionary
* dict
;
4018 OSDictionary
* nextDict
;
4023 dict
= where
->dictionaryWithProperties();
4025 nextDict
= OSDynamicCast( OSDictionary
, obj
);
4029 iter
= OSCollectionIterator::withCollection(
4030 OSDynamicCast(OSCollection
, obj
));
4033 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
4034 iter
->getNextObject()))))) {
4035 match
= dict
->isEqualTo( nextDict
, nextDict
);
4048 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
4051 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
4052 match
= (where
== entry
);
4059 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
4063 IOService
* service
= 0;
4064 UInt32 serviceCount
= 0;
4067 iter
= where
->getClientIterator();
4069 while( (service
= (IOService
*) iter
->getNextObject())) {
4070 if( kIOServiceInactiveState
& service
->__state
[0])
4072 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
4078 match
= (serviceCount
== num
->unsigned32BitValue());
4083 if( done
== table
->getCount()) {
4084 // don't call family if we've done all the entries in the table
4085 matchParent
= false;
4089 // pass in score from property table
4090 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
4092 // do family specific matching
4093 match
= where
->matchPropertyTable( table
, &score
);
4097 if( kIOLogMatch
& getDebugFlags( table
))
4098 LOG("%s: family specific matching fails\n", where
->getName());
4105 newPri
= OSNumber::withNumber( score
, 32 );
4107 table
->setObject( gIOProbeScoreKey
, newPri
);
4112 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
4114 if( !(match
= where
->compareProperty( table
, kIOBSDMajorKey
)))
4116 if( !(match
= where
->compareProperty( table
, kIOBSDMinorKey
)))
4118 if( !(match
= where
->compareProperty( table
, kIOBSDUnitKey
)))
4121 matchParent
= false;
4123 obj
= OSDynamicCast( OSDictionary
,
4124 table
->getObject( gIOParentMatchKey
));
4128 table
= (OSDictionary
*) obj
;
4132 table
= OSDynamicCast( OSDictionary
,
4133 table
->getObject( gIOLocationMatchKey
));
4136 where
= where
->getProvider();
4138 where
= where
->matchLocation( where
);
4141 } while( table
&& where
);
4143 } while( matchParent
&& (where
= where
->getProvider()) );
4145 if( kIOLogMatch
& gIOKitDebug
)
4147 LOG("match parent @ %s = %d\n",
4148 where
->getName(), match
);
4154 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4155 UInt32 type
, OSDictionary
* properties
,
4156 IOUserClient
** handler
)
4158 const OSSymbol
*userClientClass
= 0;
4159 IOUserClient
*client
;
4162 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4163 return kIOReturnSuccess
;
4165 // First try my own properties for a user client class name
4166 temp
= getProperty(gIOUserClientClassKey
);
4168 if (OSDynamicCast(OSSymbol
, temp
))
4169 userClientClass
= (const OSSymbol
*) temp
;
4170 else if (OSDynamicCast(OSString
, temp
)) {
4171 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4172 if (userClientClass
)
4173 setProperty(kIOUserClientClassKey
,
4174 (OSObject
*) userClientClass
);
4178 // Didn't find one so lets just bomb out now without further ado.
4179 if (!userClientClass
)
4180 return kIOReturnUnsupported
;
4182 // This reference is consumed by the IOServiceOpen call
4183 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4185 return kIOReturnNoMemory
;
4187 if (OSDynamicCast(IOUserClient
, temp
))
4188 client
= (IOUserClient
*) temp
;
4191 return kIOReturnUnsupported
;
4194 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4196 return kIOReturnBadArgument
;
4199 if ( !client
->attach(this) ) {
4201 return kIOReturnUnsupported
;
4204 if ( !client
->start(this) ) {
4205 client
->detach(this);
4207 return kIOReturnUnsupported
;
4211 return kIOReturnSuccess
;
4214 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4215 UInt32 type
, IOUserClient
** handler
)
4217 return( kIOReturnUnsupported
);
4220 IOReturn
IOService::requestProbe( IOOptionBits options
)
4222 return( kIOReturnUnsupported
);
4226 * Convert an IOReturn to text. Subclasses which add additional
4227 * IOReturn's should override this method and call
4228 * super::stringFromReturn if the desired value is not found.
4231 const char * IOService::stringFromReturn( IOReturn rtn
)
4233 static const IONamedValue IOReturn_values
[] = {
4234 {kIOReturnSuccess
, "success" },
4235 {kIOReturnError
, "general error" },
4236 {kIOReturnNoMemory
, "memory allocation error" },
4237 {kIOReturnNoResources
, "resource shortage" },
4238 {kIOReturnIPCError
, "Mach IPC failure" },
4239 {kIOReturnNoDevice
, "no such device" },
4240 {kIOReturnNotPrivileged
, "privilege violation" },
4241 {kIOReturnBadArgument
, "invalid argument" },
4242 {kIOReturnLockedRead
, "device is read locked" },
4243 {kIOReturnLockedWrite
, "device is write locked" },
4244 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4245 {kIOReturnBadMessageID
, "bad IPC message ID" },
4246 {kIOReturnUnsupported
, "unsupported function" },
4247 {kIOReturnVMError
, "virtual memory error" },
4248 {kIOReturnInternalError
, "internal driver error" },
4249 {kIOReturnIOError
, "I/O error" },
4250 {kIOReturnCannotLock
, "cannot acquire lock" },
4251 {kIOReturnNotOpen
, "device is not open" },
4252 {kIOReturnNotReadable
, "device is not readable" },
4253 {kIOReturnNotWritable
, "device is not writeable" },
4254 {kIOReturnNotAligned
, "alignment error" },
4255 {kIOReturnBadMedia
, "media error" },
4256 {kIOReturnStillOpen
, "device is still open" },
4257 {kIOReturnRLDError
, "rld failure" },
4258 {kIOReturnDMAError
, "DMA failure" },
4259 {kIOReturnBusy
, "device is busy" },
4260 {kIOReturnTimeout
, "I/O timeout" },
4261 {kIOReturnOffline
, "device is offline" },
4262 {kIOReturnNotReady
, "device is not ready" },
4263 {kIOReturnNotAttached
, "device/channel is not attached" },
4264 {kIOReturnNoChannels
, "no DMA channels available" },
4265 {kIOReturnNoSpace
, "no space for data" },
4266 {kIOReturnPortExists
, "device port already exists" },
4267 {kIOReturnCannotWire
, "cannot wire physical memory" },
4268 {kIOReturnNoInterrupt
, "no interrupt attached" },
4269 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4270 {kIOReturnMessageTooLarge
, "message is too large" },
4271 {kIOReturnNotPermitted
, "operation is not permitted" },
4272 {kIOReturnNoPower
, "device is without power" },
4273 {kIOReturnNoMedia
, "media is not present" },
4274 {kIOReturnUnformattedMedia
, "media is not formatted" },
4275 {kIOReturnUnsupportedMode
, "unsupported mode" },
4276 {kIOReturnUnderrun
, "data underrun" },
4277 {kIOReturnOverrun
, "data overrun" },
4278 {kIOReturnDeviceError
, "device error" },
4279 {kIOReturnNoCompletion
, "no completion routine" },
4280 {kIOReturnAborted
, "operation was aborted" },
4281 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4282 {kIOReturnNotResponding
, "device is not responding" },
4283 {kIOReturnInvalid
, "unanticipated driver error" },
4287 return IOFindNameForValue(rtn
, IOReturn_values
);
4291 * Convert an IOReturn to an errno.
4293 int IOService::errnoFromReturn( IOReturn rtn
)
4297 case kIOReturnSuccess
:
4299 case kIOReturnNoMemory
:
4301 case kIOReturnNoDevice
:
4303 case kIOReturnVMError
:
4305 case kIOReturnNotPermitted
:
4307 case kIOReturnNotPrivileged
:
4309 case kIOReturnIOError
:
4311 case kIOReturnNotWritable
:
4313 case kIOReturnBadArgument
:
4315 case kIOReturnUnsupported
:
4319 case kIOReturnNoPower
:
4321 case kIOReturnDeviceError
:
4323 case kIOReturnTimeout
:
4325 case kIOReturnMessageTooLarge
:
4327 case kIOReturnNoSpace
:
4329 case kIOReturnCannotLock
:
4333 case kIOReturnBadMessageID
:
4334 case kIOReturnNoCompletion
:
4335 case kIOReturnNotAligned
:
4337 case kIOReturnNotReady
:
4339 case kIOReturnRLDError
:
4341 case kIOReturnPortExists
:
4342 case kIOReturnStillOpen
:
4344 case kIOReturnExclusiveAccess
:
4345 case kIOReturnLockedRead
:
4346 case kIOReturnLockedWrite
:
4347 case kIOReturnNotAttached
:
4348 case kIOReturnNotOpen
:
4349 case kIOReturnNotReadable
:
4351 case kIOReturnCannotWire
:
4352 case kIOReturnNoResources
:
4354 case kIOReturnAborted
:
4355 case kIOReturnOffline
:
4356 case kIOReturnNotResponding
:
4358 case kIOReturnBadMedia
:
4359 case kIOReturnNoMedia
:
4360 case kIOReturnUnformattedMedia
:
4361 return(ENXIO
); // (media error)
4362 case kIOReturnDMAError
:
4363 case kIOReturnOverrun
:
4364 case kIOReturnUnderrun
:
4365 return(EIO
); // (transfer error)
4366 case kIOReturnNoBandwidth
:
4367 case kIOReturnNoChannels
:
4368 case kIOReturnNoFrames
:
4369 case kIOReturnNoInterrupt
:
4370 return(EIO
); // (hardware error)
4371 case kIOReturnError
:
4372 case kIOReturnInternalError
:
4373 case kIOReturnInvalid
:
4374 return(EIO
); // (generic error)
4375 case kIOReturnIPCError
:
4376 return(EIO
); // (ipc error)
4378 return(EIO
); // (all other errors)
4382 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4386 * Generic entry point for calls from the provider. A return value of
4387 * kIOReturnSuccess indicates that the message was received, and where
4388 * applicable, that it was successful.
4391 return kIOReturnUnsupported
;
4398 IOItemCount
IOService::getDeviceMemoryCount( void )
4403 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4405 count
= array
->getCount();
4412 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4415 IODeviceMemory
* range
;
4417 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4419 range
= (IODeviceMemory
*) array
->getObject( index
);
4426 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4427 IOOptionBits options
)
4429 IODeviceMemory
* range
;
4432 range
= getDeviceMemoryWithIndex( index
);
4434 map
= range
->map( options
);
4441 OSArray
* IOService::getDeviceMemory( void )
4443 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4447 void IOService::setDeviceMemory( OSArray
* array
)
4449 setProperty( gIODeviceMemoryKey
, array
);
4453 * For machines where the transfers on an I/O bus can stall because
4454 * the CPU is in an idle mode, These APIs allow a driver to specify
4455 * the maximum bus stall that they can handle. 0 indicates no limit.
4458 setCPUSnoopDelay(UInt32 __unused ns
)
4460 #if defined(__i386__)
4461 ml_set_maxsnoop(ns
);
4462 #endif /* defined(__i386__) */
4468 #if defined(__i386__)
4469 return ml_get_maxsnoop();
4472 #endif /* defined(__i386__) */
4475 #if defined(__i386__)
4477 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
4479 static const UInt kNoReplace
= -1U; // Must be an illegal index
4480 UInt replace
= kNoReplace
;
4481 bool setCpuDelay
= false;
4483 IORecursiveLockLock(sCpuDelayLock
);
4485 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
4486 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
4487 IOService
* holder
= NULL
;
4490 const CpuDelayEntry ne
= {service
, ns
, delayType
};
4492 // Set maximum delay.
4493 for (UInt i
= 0; i
< count
; i
++) {
4494 IOService
*thisService
= entries
[i
].fService
;
4495 bool sameType
= (delayType
== entries
[i
].fDelayType
);
4496 if ((service
== thisService
) && sameType
)
4498 else if (!thisService
) {
4499 if (kNoReplace
== replace
)
4502 else if (sameType
) {
4503 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
4507 holder
= thisService
;
4513 if (kNoReplace
== replace
)
4514 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
4516 entries
[replace
] = ne
;
4519 ns
= -1U; // Set to max unsigned, i.e. no restriction
4521 for (UInt i
= 0; i
< count
; i
++) {
4522 // Clear a maximum delay.
4523 IOService
*thisService
= entries
[i
].fService
;
4524 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
4525 UInt32 thisMax
= entries
[i
].fMaxDelay
;
4526 if (service
== thisService
)
4528 else if (thisMax
< ns
) {
4530 holder
= thisService
;
4535 // Check if entry found
4536 if (kNoReplace
!= replace
) {
4537 entries
[replace
].fService
= 0; // Null the entry
4544 // Must be safe to call from locked context
4545 if (delayType
== kCpuDelayBusStall
)
4547 ml_set_maxbusdelay(ns
);
4549 else if (delayType
== kCpuDelayInterrupt
)
4551 ml_set_maxintdelay(ns
);
4554 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
4556 if (handlers
) for (unsigned int idx
= 0;
4557 (target
= (IOService
*) handlers
->getObject(idx
));
4560 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
4561 (void *) (uintptr_t) ns
, holder
,
4566 IORecursiveLockUnlock(sCpuDelayLock
);
4570 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
4572 IOReturn result
= kIOReturnNotFound
;
4576 IORecursiveLockLock(sCpuDelayLock
);
4580 if (enable
&& !sCpuLatencyHandlers
[delayType
])
4581 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
4582 array
= sCpuLatencyHandlers
[delayType
];
4585 idx
= array
->getNextIndexOfObject(target
, 0);
4590 array
->removeObject(idx
);
4591 result
= kIOReturnSuccess
;
4597 result
= kIOReturnExclusiveAccess
;
4600 array
->setObject(target
);
4602 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
4603 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
4604 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
4605 IOService
* holder
= NULL
;
4607 for (UInt i
= 0; i
< count
; i
++) {
4608 if (entries
[i
].fService
4609 && (delayType
== entries
[i
].fDelayType
)
4610 && (entries
[i
].fMaxDelay
< ns
)) {
4611 ns
= entries
[i
].fMaxDelay
;
4612 holder
= entries
[i
].fService
;
4615 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
4616 (void *) (uintptr_t) ns
, holder
,
4618 result
= kIOReturnSuccess
;
4623 IORecursiveLockUnlock(sCpuDelayLock
);
4628 #endif /* defined(__i386__) */
4631 requireMaxBusStall(UInt32 __unused ns
)
4633 #if defined(__i386__)
4634 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
4642 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4644 IOInterruptController
*interruptController
;
4647 OSSymbol
*interruptControllerName
;
4649 IOInterruptSource
*interruptSources
;
4651 // Get the parents list from the nub.
4652 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4653 if (array
== 0) return kIOReturnNoResources
;
4655 // Allocate space for the IOInterruptSources if needed... then return early.
4656 if (nub
->_interruptSources
== 0) {
4657 numSources
= array
->getCount();
4658 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4659 if (interruptSources
== 0) return kIOReturnNoMemory
;
4661 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4663 nub
->_numInterruptSources
= numSources
;
4664 nub
->_interruptSources
= interruptSources
;
4665 return kIOReturnSuccess
;
4668 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4669 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4671 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4672 if (interruptController
== 0) return kIOReturnNoResources
;
4674 // Get the interrupt numbers from the nub.
4675 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4676 if (array
== 0) return kIOReturnNoResources
;
4677 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4678 if (data
== 0) return kIOReturnNoResources
;
4680 // Set the interruptController and interruptSource in the nub's table.
4681 interruptSources
= nub
->_interruptSources
;
4682 interruptSources
[source
].interruptController
= interruptController
;
4683 interruptSources
[source
].vectorData
= data
;
4685 return kIOReturnSuccess
;
4688 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4692 /* Make sure the _interruptSources are set */
4693 if (_interruptSources
== 0) {
4694 ret
= resolveInterrupt(this, source
);
4695 if (ret
!= kIOReturnSuccess
) return ret
;
4698 /* Make sure the local source number is valid */
4699 if ((source
< 0) || (source
>= _numInterruptSources
))
4700 return kIOReturnNoInterrupt
;
4702 /* Look up the contoller for the local source */
4703 *interruptController
= _interruptSources
[source
].interruptController
;
4705 if (*interruptController
== NULL
) {
4706 if (!resolve
) return kIOReturnNoInterrupt
;
4708 /* Try to reslove the interrupt */
4709 ret
= resolveInterrupt(this, source
);
4710 if (ret
!= kIOReturnSuccess
) return ret
;
4712 *interruptController
= _interruptSources
[source
].interruptController
;
4715 return kIOReturnSuccess
;
4718 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4719 IOInterruptAction handler
,
4722 IOInterruptController
*interruptController
;
4725 ret
= lookupInterrupt(source
, true, &interruptController
);
4726 if (ret
!= kIOReturnSuccess
) return ret
;
4728 /* Register the source */
4729 return interruptController
->registerInterrupt(this, source
, target
,
4730 (IOInterruptHandler
)handler
,
4734 IOReturn
IOService::unregisterInterrupt(int source
)
4736 IOInterruptController
*interruptController
;
4739 ret
= lookupInterrupt(source
, false, &interruptController
);
4740 if (ret
!= kIOReturnSuccess
) return ret
;
4742 /* Unregister the source */
4743 return interruptController
->unregisterInterrupt(this, source
);
4746 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4748 IOInterruptController
*interruptController
;
4751 ret
= lookupInterrupt(source
, true, &interruptController
);
4752 if (ret
!= kIOReturnSuccess
) return ret
;
4754 /* Return the type */
4755 return interruptController
->getInterruptType(this, source
, interruptType
);
4758 IOReturn
IOService::enableInterrupt(int source
)
4760 IOInterruptController
*interruptController
;
4763 ret
= lookupInterrupt(source
, false, &interruptController
);
4764 if (ret
!= kIOReturnSuccess
) return ret
;
4766 /* Enable the source */
4767 return interruptController
->enableInterrupt(this, source
);
4770 IOReturn
IOService::disableInterrupt(int source
)
4772 IOInterruptController
*interruptController
;
4775 ret
= lookupInterrupt(source
, false, &interruptController
);
4776 if (ret
!= kIOReturnSuccess
) return ret
;
4778 /* Disable the source */
4779 return interruptController
->disableInterrupt(this, source
);
4782 IOReturn
IOService::causeInterrupt(int source
)
4784 IOInterruptController
*interruptController
;
4787 ret
= lookupInterrupt(source
, false, &interruptController
);
4788 if (ret
!= kIOReturnSuccess
) return ret
;
4790 /* Cause an interrupt for the source */
4791 return interruptController
->causeInterrupt(this, source
);
4794 OSMetaClassDefineReservedUsed(IOService
, 0);
4795 OSMetaClassDefineReservedUsed(IOService
, 1);
4796 OSMetaClassDefineReservedUsed(IOService
, 2);
4797 OSMetaClassDefineReservedUsed(IOService
, 3);
4798 OSMetaClassDefineReservedUsed(IOService
, 4);
4800 OSMetaClassDefineReservedUnused(IOService
, 5);
4801 OSMetaClassDefineReservedUnused(IOService
, 6);
4802 OSMetaClassDefineReservedUnused(IOService
, 7);
4803 OSMetaClassDefineReservedUnused(IOService
, 8);
4804 OSMetaClassDefineReservedUnused(IOService
, 9);
4805 OSMetaClassDefineReservedUnused(IOService
, 10);
4806 OSMetaClassDefineReservedUnused(IOService
, 11);
4807 OSMetaClassDefineReservedUnused(IOService
, 12);
4808 OSMetaClassDefineReservedUnused(IOService
, 13);
4809 OSMetaClassDefineReservedUnused(IOService
, 14);
4810 OSMetaClassDefineReservedUnused(IOService
, 15);
4811 OSMetaClassDefineReservedUnused(IOService
, 16);
4812 OSMetaClassDefineReservedUnused(IOService
, 17);
4813 OSMetaClassDefineReservedUnused(IOService
, 18);
4814 OSMetaClassDefineReservedUnused(IOService
, 19);
4815 OSMetaClassDefineReservedUnused(IOService
, 20);
4816 OSMetaClassDefineReservedUnused(IOService
, 21);
4817 OSMetaClassDefineReservedUnused(IOService
, 22);
4818 OSMetaClassDefineReservedUnused(IOService
, 23);
4819 OSMetaClassDefineReservedUnused(IOService
, 24);
4820 OSMetaClassDefineReservedUnused(IOService
, 25);
4821 OSMetaClassDefineReservedUnused(IOService
, 26);
4822 OSMetaClassDefineReservedUnused(IOService
, 27);
4823 OSMetaClassDefineReservedUnused(IOService
, 28);
4824 OSMetaClassDefineReservedUnused(IOService
, 29);
4825 OSMetaClassDefineReservedUnused(IOService
, 30);
4826 OSMetaClassDefineReservedUnused(IOService
, 31);
4827 OSMetaClassDefineReservedUnused(IOService
, 32);
4828 OSMetaClassDefineReservedUnused(IOService
, 33);
4829 OSMetaClassDefineReservedUnused(IOService
, 34);
4830 OSMetaClassDefineReservedUnused(IOService
, 35);
4831 OSMetaClassDefineReservedUnused(IOService
, 36);
4832 OSMetaClassDefineReservedUnused(IOService
, 37);
4833 OSMetaClassDefineReservedUnused(IOService
, 38);
4834 OSMetaClassDefineReservedUnused(IOService
, 39);
4835 OSMetaClassDefineReservedUnused(IOService
, 40);
4836 OSMetaClassDefineReservedUnused(IOService
, 41);
4837 OSMetaClassDefineReservedUnused(IOService
, 42);
4838 OSMetaClassDefineReservedUnused(IOService
, 43);
4839 OSMetaClassDefineReservedUnused(IOService
, 44);
4840 OSMetaClassDefineReservedUnused(IOService
, 45);
4841 OSMetaClassDefineReservedUnused(IOService
, 46);
4842 OSMetaClassDefineReservedUnused(IOService
, 47);
4845 OSMetaClassDefineReservedUnused(IOService
, 48);
4846 OSMetaClassDefineReservedUnused(IOService
, 49);
4847 OSMetaClassDefineReservedUnused(IOService
, 50);
4848 OSMetaClassDefineReservedUnused(IOService
, 51);
4849 OSMetaClassDefineReservedUnused(IOService
, 52);
4850 OSMetaClassDefineReservedUnused(IOService
, 53);
4851 OSMetaClassDefineReservedUnused(IOService
, 54);
4852 OSMetaClassDefineReservedUnused(IOService
, 55);
4853 OSMetaClassDefineReservedUnused(IOService
, 56);
4854 OSMetaClassDefineReservedUnused(IOService
, 57);
4855 OSMetaClassDefineReservedUnused(IOService
, 58);
4856 OSMetaClassDefineReservedUnused(IOService
, 59);
4857 OSMetaClassDefineReservedUnused(IOService
, 60);
4858 OSMetaClassDefineReservedUnused(IOService
, 61);
4859 OSMetaClassDefineReservedUnused(IOService
, 62);
4860 OSMetaClassDefineReservedUnused(IOService
, 63);