2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 #include <IOKit/system.h>
28 #include <IOKit/IOService.h>
29 #include <libkern/c++/OSContainers.h>
30 #include <libkern/c++/OSUnserialize.h>
31 #include <IOKit/IOCatalogue.h>
32 #include <IOKit/IODeviceMemory.h>
33 #include <IOKit/IOInterrupts.h>
34 #include <IOKit/IOInterruptController.h>
35 #include <IOKit/IOPlatformExpert.h>
36 #include <IOKit/IOMessage.h>
37 #include <IOKit/IOLib.h>
38 #include <IOKit/IOKitKeysPrivate.h>
39 #include <IOKit/IOBSD.h>
40 #include <IOKit/IOUserClient.h>
41 #include <IOKit/IOWorkLoop.h>
42 #include <mach/sync_policy.h>
43 #include <IOKit/assert.h>
44 #include <sys/errno.h>
49 #include "IOServicePrivate.h"
51 // take lockForArbitration before LOCKNOTIFY
53 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
55 #define super IORegistryEntry
57 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
59 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
61 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
63 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
65 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
67 OSDefineMetaClassAndStructors(IOResources
, IOService
)
69 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
71 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
73 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 static IOPlatformExpert
* gIOPlatform
;
76 static class IOPMrootDomain
* gIOPMRootDomain
;
77 const IORegistryPlane
* gIOServicePlane
;
78 const IORegistryPlane
* gIOPowerPlane
;
79 const OSSymbol
* gIODeviceMemoryKey
;
80 const OSSymbol
* gIOInterruptControllersKey
;
81 const OSSymbol
* gIOInterruptSpecifiersKey
;
83 const OSSymbol
* gIOResourcesKey
;
84 const OSSymbol
* gIOResourceMatchKey
;
85 const OSSymbol
* gIOProviderClassKey
;
86 const OSSymbol
* gIONameMatchKey
;
87 const OSSymbol
* gIONameMatchedKey
;
88 const OSSymbol
* gIOPropertyMatchKey
;
89 const OSSymbol
* gIOLocationMatchKey
;
90 const OSSymbol
* gIOParentMatchKey
;
91 const OSSymbol
* gIOPathMatchKey
;
92 const OSSymbol
* gIOMatchCategoryKey
;
93 const OSSymbol
* gIODefaultMatchCategoryKey
;
94 const OSSymbol
* gIOMatchedServiceCountKey
;
96 const OSSymbol
* gIOUserClientClassKey
;
97 const OSSymbol
* gIOKitDebugKey
;
99 const OSSymbol
* gIOCommandPoolSizeKey
;
101 const OSSymbol
* gIOConsoleUsersKey
;
102 const OSSymbol
* gIOConsoleSessionUIDKey
;
103 const OSSymbol
* gIOConsoleUsersSeedKey
;
105 static int gIOResourceGenerationCount
;
107 const OSSymbol
* gIOServiceKey
;
108 const OSSymbol
* gIOPublishNotification
;
109 const OSSymbol
* gIOFirstPublishNotification
;
110 const OSSymbol
* gIOMatchedNotification
;
111 const OSSymbol
* gIOFirstMatchNotification
;
112 const OSSymbol
* gIOTerminatedNotification
;
114 const OSSymbol
* gIOGeneralInterest
;
115 const OSSymbol
* gIOBusyInterest
;
116 const OSSymbol
* gIOAppPowerStateInterest
;
117 const OSSymbol
* gIOPriorityPowerStateInterest
;
119 static OSDictionary
* gNotifications
;
120 static IORecursiveLock
* gNotificationLock
;
122 static IOService
* gIOResources
;
123 static IOService
* gIOServiceRoot
;
125 static OSOrderedSet
* gJobs
;
126 static semaphore_port_t gJobsSemaphore
;
127 static IOLock
* gJobsLock
;
128 static int gOutstandingJobs
;
129 static int gNumConfigThreads
;
130 static int gNumWaitingThreads
;
131 static IOLock
* gIOServiceBusyLock
;
133 static thread_t gIOTerminateThread
;
134 static UInt32 gIOTerminateWork
;
135 static OSArray
* gIOTerminatePhase2List
;
136 static OSArray
* gIOStopList
;
137 static OSArray
* gIOStopProviderList
;
138 static OSArray
* gIOFinalizeList
;
140 static SInt32 gIOConsoleUsersSeed
;
141 static OSData
* gIOConsoleUsersSeedValue
;
143 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
145 #define LOCKREADNOTIFY() \
146 IORecursiveLockLock( gNotificationLock )
147 #define LOCKWRITENOTIFY() \
148 IORecursiveLockLock( gNotificationLock )
149 #define LOCKWRITE2READNOTIFY()
150 #define UNLOCKNOTIFY() \
151 IORecursiveLockUnlock( gNotificationLock )
152 #define SLEEPNOTIFY(event) \
153 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
154 #define WAKEUPNOTIFY(event) \
155 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
157 #define randomDelay() \
158 int del = read_processor_clock(); \
159 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
162 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
164 struct ArbitrationLockQueueElement
{
173 static queue_head_t gArbitrationLockQueueActive
;
174 static queue_head_t gArbitrationLockQueueWaiting
;
175 static queue_head_t gArbitrationLockQueueFree
;
176 static IOLock
* gArbitrationLockQueueLock
;
178 bool IOService::isInactive( void ) const
179 { return( 0 != (kIOServiceInactiveState
& getState())); }
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
183 void IOService::initialize( void )
187 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
188 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
190 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
191 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
192 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
193 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
194 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
195 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
196 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
198 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
199 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
200 kIODefaultMatchCategoryKey
);
201 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
202 kIOMatchedServiceCountKey
);
204 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
206 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
207 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
209 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
210 gIOInterruptControllersKey
211 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
212 gIOInterruptSpecifiersKey
213 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
215 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
217 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
219 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
220 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
221 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
222 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
224 gNotifications
= OSDictionary::withCapacity( 1 );
225 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
226 kIOPublishNotification
);
227 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
228 kIOFirstPublishNotification
);
229 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
230 kIOMatchedNotification
);
231 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
232 kIOFirstMatchNotification
);
233 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
234 kIOTerminatedNotification
);
235 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
237 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
238 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
239 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey
);
240 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
242 gNotificationLock
= IORecursiveLockAlloc();
244 assert( gIOServicePlane
&& gIODeviceMemoryKey
245 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
246 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
247 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
248 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
249 && gIOPublishNotification
&& gIOMatchedNotification
250 && gIOTerminatedNotification
&& gIOServiceKey
251 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
252 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
254 gJobsLock
= IOLockAlloc();
255 gJobs
= OSOrderedSet::withCapacity( 10 );
257 gIOServiceBusyLock
= IOLockAlloc();
259 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
261 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
263 gIOResources
= IOResources::resources();
264 assert( gIOResources
);
266 gArbitrationLockQueueLock
= IOLockAlloc();
267 queue_init(&gArbitrationLockQueueActive
);
268 queue_init(&gArbitrationLockQueueWaiting
);
269 queue_init(&gArbitrationLockQueueFree
);
271 assert( gArbitrationLockQueueLock
);
273 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
274 gIOStopList
= OSArray::withCapacity( 16 );
275 gIOStopProviderList
= OSArray::withCapacity( 16 );
276 gIOFinalizeList
= OSArray::withCapacity( 16 );
277 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
280 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
283 static UInt64
getDebugFlags( OSDictionary
* props
)
285 OSNumber
* debugProp
;
288 debugProp
= OSDynamicCast( OSNumber
,
289 props
->getObject( gIOKitDebugKey
));
291 debugFlags
= debugProp
->unsigned64BitValue();
293 debugFlags
= gIOKitDebug
;
295 return( debugFlags
);
299 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
301 // Probe a matched service and return an instance to be started.
302 // The default score is from the property table, & may be altered
303 // during probe to change the start order.
305 IOService
* IOService::probe( IOService
* provider
,
311 bool IOService::start( IOService
* provider
)
316 void IOService::stop( IOService
* provider
)
320 void IOService::free( void )
322 if( getPropertyTable())
323 unregisterAllInterest();
329 * Attach in service plane
331 bool IOService::attach( IOService
* provider
)
337 if( gIOKitDebug
& kIOLogAttach
)
338 LOG( "%s::attach(%s)\n", getName(),
339 provider
->getName());
341 provider
->lockForArbitration();
342 if( provider
->__state
[0] & kIOServiceInactiveState
)
345 ok
= attachToParent( provider
, gIOServicePlane
);
346 provider
->unlockForArbitration();
349 gIOServiceRoot
= this;
350 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
356 IOService
* IOService::getServiceRoot( void )
358 return( gIOServiceRoot
);
361 void IOService::detach( IOService
* provider
)
363 IOService
* newProvider
= 0;
367 if( gIOKitDebug
& kIOLogAttach
)
368 LOG("%s::detach(%s)\n", getName(), provider
->getName());
370 lockForArbitration();
372 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
373 && (provider
== getProvider()));
375 detachFromParent( provider
, gIOServicePlane
);
378 newProvider
= getProvider();
379 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
380 _adjustBusy( -busy
);
383 unlockForArbitration();
386 newProvider
->lockForArbitration();
387 newProvider
->_adjustBusy(1);
388 newProvider
->unlockForArbitration();
391 // check for last client detach from a terminated service
392 if( provider
->lockForArbitration( true )) {
394 provider
->_adjustBusy( -1 );
395 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
396 && (0 == provider
->getClient())) {
397 provider
->scheduleFinalize();
399 provider
->unlockForArbitration();
404 * Register instance - publish it for matching
407 void IOService::registerService( IOOptionBits options
)
413 enum { kMaxPathLen
= 256 };
414 enum { kMaxChars
= 63 };
416 IORegistryEntry
* parent
= this;
417 IORegistryEntry
* root
= getRegistryRoot();
418 while( parent
&& (parent
!= root
))
419 parent
= parent
->getParentEntry( gIOServicePlane
);
421 if( parent
!= root
) {
422 IOLog("%s: not registry member at registerService()\n", getName());
426 // Allow the Platform Expert to adjust this node.
427 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
430 if( (this != gIOResources
)
431 && (kIOLogRegister
& gIOKitDebug
)) {
433 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
435 IOLog( "Registering: " );
438 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
441 if( len
> kMaxChars
) {
445 if( (skip
= strchr( path
, '/')))
451 IOLog( "%s\n", path
);
454 IOFree( pathBuf
, kMaxPathLen
);
457 startMatching( options
);
460 void IOService::startMatching( IOOptionBits options
)
462 IOService
* provider
;
465 bool needWake
= false;
470 lockForArbitration();
472 sync
= (options
& kIOServiceSynchronous
)
473 || ((provider
= getProvider())
474 && (provider
->__state
[1] & kIOServiceSynchronousState
));
477 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
478 && (0 == (__state
[0] & kIOServiceInactiveState
));
480 __state
[1] |= kIOServiceNeedConfigState
;
482 // __state[0] &= ~kIOServiceInactiveState;
484 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
485 // OSKernelStackRemaining(), getName());
488 prevBusy
= _adjustBusy( 1 );
489 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
493 __state
[1] |= kIOServiceSynchronousState
;
495 __state
[1] &= ~kIOServiceSynchronousState
;
497 unlockForArbitration();
502 IOLockLock( gIOServiceBusyLock
);
503 thread_wakeup( (event_t
) this/*&__state[1]*/ );
504 IOLockUnlock( gIOServiceBusyLock
);
506 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
508 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
512 if( (__state
[1] & kIOServiceNeedConfigState
))
513 doServiceMatch( options
);
515 lockForArbitration();
516 IOLockLock( gIOServiceBusyLock
);
518 waitAgain
= (prevBusy
!= (__state
[1] & kIOServiceBusyStateMask
));
520 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
522 __state
[1] &= ~kIOServiceSyncPubState
;
524 unlockForArbitration();
527 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
529 IOLockUnlock( gIOServiceBusyLock
);
531 thread_block(THREAD_CONTINUE_NULL
);
533 } while( waitAgain
);
537 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
539 OSDictionary
* table
;
548 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
551 iter
= (OSIterator
*) getExistingServices( table
,
552 kIOServiceRegisteredState
);
555 while( (service
= (IOService
*) iter
->getNextObject())) {
556 service
->startMatching(kIOServiceAsynchronous
);
564 if( getDebugFlags( table
) & kIOLogMatch
)
565 LOG("Matching service count = %ld\n", count
);
567 newTables
->removeObject(table
);
570 newTables
->release();
572 return( kIOReturnSuccess
);
575 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
576 IOOptionBits options
)
580 job
= new _IOServiceJob
;
581 if( job
&& !job
->init()) {
589 job
->options
= options
;
590 nub
->retain(); // thread will release()
598 * Called on a registered service to see if it matches
602 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
604 return( matchPropertyTable(table
) );
607 bool IOService::matchPropertyTable( OSDictionary
* table
)
613 * Called on a matched service to allocate resources
614 * before first driver is attached.
617 IOReturn
IOService::getResources( void )
619 return( kIOReturnSuccess
);
623 * Client/provider accessors
626 IOService
* IOService::getProvider( void ) const
628 IOService
* self
= (IOService
*) this;
633 generation
= getGenerationCount();
634 if( __providerGeneration
== generation
)
637 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
638 if( parent
== IORegistryEntry::getRegistryRoot())
639 /* root is not an IOService */
642 self
->__provider
= parent
;
643 // save the count before getParentEntry()
644 self
->__providerGeneration
= generation
;
649 IOWorkLoop
* IOService::getWorkLoop() const
651 IOService
*provider
= getProvider();
654 return provider
->getWorkLoop();
659 OSIterator
* IOService::getProviderIterator( void ) const
661 return( getParentIterator( gIOServicePlane
));
664 IOService
* IOService::getClient( void ) const
666 return( (IOService
*) getChildEntry( gIOServicePlane
));
669 OSIterator
* IOService::getClientIterator( void ) const
671 return( getChildIterator( gIOServicePlane
));
674 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
675 const IOService
* client
,
676 const IOService
* provider
)
678 _IOOpenServiceIterator
* inst
;
683 inst
= new _IOOpenServiceIterator
;
685 if( inst
&& !inst
->init()) {
691 inst
->client
= client
;
692 inst
->provider
= provider
;
698 void _IOOpenServiceIterator::free()
702 last
->unlockForArbitration();
706 OSObject
* _IOOpenServiceIterator::getNextObject()
711 last
->unlockForArbitration();
713 while( (next
= (IOService
*) iter
->getNextObject())) {
715 next
->lockForArbitration();
716 if( (client
&& (next
->isOpen( client
)))
717 || (provider
&& (provider
->isOpen( next
))) )
719 next
->unlockForArbitration();
727 bool _IOOpenServiceIterator::isValid()
729 return( iter
->isValid() );
732 void _IOOpenServiceIterator::reset()
735 last
->unlockForArbitration();
741 OSIterator
* IOService::getOpenProviderIterator( void ) const
743 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
746 OSIterator
* IOService::getOpenClientIterator( void ) const
748 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
752 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
753 bool waitForFunction
,
754 void *param1
, void *param2
,
755 void *param3
, void *param4
)
757 IOReturn result
= kIOReturnUnsupported
;
758 IOService
*provider
= getProvider();
761 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
762 param1
, param2
, param3
, param4
);
768 IOReturn
IOService::callPlatformFunction( const char * functionName
,
769 bool waitForFunction
,
770 void *param1
, void *param2
,
771 void *param3
, void *param4
)
773 IOReturn result
= kIOReturnNoMemory
;
774 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
776 if (functionSymbol
!= 0) {
777 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
778 param1
, param2
, param3
, param4
);
779 functionSymbol
->release();
787 * Accessors for global services
790 IOPlatformExpert
* IOService::getPlatform( void )
792 return( gIOPlatform
);
795 class IOPMrootDomain
* IOService::getPMRootDomain( void )
797 return( gIOPMRootDomain
);
800 IOService
* IOService::getResourceService( void )
802 return( gIOResources
);
805 void IOService::setPlatform( IOPlatformExpert
* platform
)
807 gIOPlatform
= platform
;
808 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
811 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
813 gIOPMRootDomain
= rootDomain
;
814 publishResource("IOKit");
821 bool IOService::lockForArbitration( bool isSuccessRequired
)
825 ArbitrationLockQueueElement
* element
;
826 ArbitrationLockQueueElement
* active
;
827 ArbitrationLockQueueElement
* waiting
;
829 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
831 // lock global access
832 IOTakeLock( gArbitrationLockQueueLock
);
834 // obtain an unused queue element
835 if( !queue_empty( &gArbitrationLockQueueFree
)) {
836 queue_remove_first( &gArbitrationLockQueueFree
,
838 ArbitrationLockQueueElement
*,
841 element
= IONew( ArbitrationLockQueueElement
, 1 );
845 // prepare the queue element
846 element
->thread
= IOThreadSelf();
847 element
->service
= this;
849 element
->required
= isSuccessRequired
;
850 element
->aborted
= false;
852 // determine whether this object is already locked (ie. on active queue)
854 queue_iterate( &gArbitrationLockQueueActive
,
856 ArbitrationLockQueueElement
*,
859 if( active
->service
== element
->service
) {
865 if( found
) { // this object is already locked
867 // determine whether it is the same or a different thread trying to lock
868 if( active
->thread
!= element
->thread
) { // it is a different thread
870 ArbitrationLockQueueElement
* victim
= 0;
872 // before placing this new thread on the waiting queue, we look for
873 // a deadlock cycle...
876 // determine whether the active thread holding the object we
877 // want is waiting for another object to be unlocked
879 queue_iterate( &gArbitrationLockQueueWaiting
,
881 ArbitrationLockQueueElement
*,
884 if( waiting
->thread
== active
->thread
) {
885 assert( false == waiting
->aborted
);
891 if( found
) { // yes, active thread waiting for another object
893 // this may be a candidate for rejection if the required
894 // flag is not set, should we detect a deadlock later on
895 if( false == waiting
->required
)
898 // find the thread that is holding this other object, that
899 // is blocking the active thread from proceeding (fun :-)
901 queue_iterate( &gArbitrationLockQueueActive
,
902 active
, // (reuse active queue element)
903 ArbitrationLockQueueElement
*,
906 if( active
->service
== waiting
->service
) {
912 // someone must be holding it or it wouldn't be waiting
915 if( active
->thread
== element
->thread
) {
917 // doh, it's waiting for the thread that originated
918 // this whole lock (ie. current thread) -> deadlock
919 if( false == element
->required
) { // willing to fail?
921 // the originating thread doesn't have the required
922 // flag, so it can fail
923 success
= false; // (fail originating lock request)
924 break; // (out of while)
926 } else { // originating thread is not willing to fail
928 // see if we came across a waiting thread that did
929 // not have the 'required' flag set: we'll fail it
932 // we do have a willing victim, fail it's lock
933 victim
->aborted
= true;
935 // take the victim off the waiting queue
936 queue_remove( &gArbitrationLockQueueWaiting
,
938 ArbitrationLockQueueElement
*,
942 IOLockWakeup( gArbitrationLockQueueLock
,
944 /* one thread */ true );
946 // allow this thread to proceed (ie. wait)
947 success
= true; // (put request on wait queue)
948 break; // (out of while)
951 // all the waiting threads we came across in
952 // finding this loop had the 'required' flag
953 // set, so we've got a deadlock we can't avoid
954 panic("I/O Kit: Unrecoverable deadlock.");
958 // repeat while loop, redefining active thread to be the
959 // thread holding "this other object" (see above), and
960 // looking for threads waiting on it; note the active
961 // variable points to "this other object" already... so
962 // there nothing to do in this else clause.
964 } else { // no, active thread is not waiting for another object
966 success
= true; // (put request on wait queue)
967 break; // (out of while)
971 if( success
) { // put the request on the waiting queue?
972 kern_return_t wait_result
;
974 // place this thread on the waiting queue and put it to sleep;
975 // we place it at the tail of the queue...
976 queue_enter( &gArbitrationLockQueueWaiting
,
978 ArbitrationLockQueueElement
*,
981 // declare that this thread will wait for a given event
982 restart_sleep
: wait_result
= assert_wait( element
,
983 element
->required
? THREAD_UNINT
984 : THREAD_INTERRUPTIBLE
);
986 // unlock global access
987 IOUnlock( gArbitrationLockQueueLock
);
989 // put thread to sleep, waiting for our event to fire...
990 if (wait_result
== THREAD_WAITING
)
991 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
994 // ...and we've been woken up; we might be in one of two states:
995 // (a) we've been aborted and our queue element is not on
996 // any of the three queues, but is floating around
997 // (b) we're allowed to proceed with the lock and we have
998 // already been moved from the waiting queue to the
1000 // ...plus a 3rd state, should the thread have been interrupted:
1001 // (c) we're still on the waiting queue
1003 // determine whether we were interrupted out of our sleep
1004 if( THREAD_INTERRUPTED
== wait_result
) {
1006 // re-lock global access
1007 IOTakeLock( gArbitrationLockQueueLock
);
1009 // determine whether we're still on the waiting queue
1011 queue_iterate( &gArbitrationLockQueueWaiting
,
1012 waiting
, // (reuse waiting queue element)
1013 ArbitrationLockQueueElement
*,
1016 if( waiting
== element
) {
1022 if( found
) { // yes, we're still on the waiting queue
1024 // determine whether we're willing to fail
1025 if( false == element
->required
) {
1027 // mark us as aborted
1028 element
->aborted
= true;
1030 // take us off the waiting queue
1031 queue_remove( &gArbitrationLockQueueWaiting
,
1033 ArbitrationLockQueueElement
*,
1035 } else { // we are not willing to fail
1037 // ignore interruption, go back to sleep
1042 // unlock global access
1043 IOUnlock( gArbitrationLockQueueLock
);
1045 // proceed as though this were a normal wake up
1046 wait_result
= THREAD_AWAKENED
;
1049 assert( THREAD_AWAKENED
== wait_result
);
1051 // determine whether we've been aborted while we were asleep
1052 if( element
->aborted
) {
1053 assert( false == element
->required
);
1055 // re-lock global access
1056 IOTakeLock( gArbitrationLockQueueLock
);
1058 action
= kPutOnFreeQueue
;
1060 } else { // we weren't aborted, so we must be ready to go :-)
1062 // we've already been moved from waiting to active queue
1066 } else { // the lock request is to be failed
1068 // return unused queue element to queue
1069 action
= kPutOnFreeQueue
;
1071 } else { // it is the same thread, recursive access is allowed
1073 // add one level of recursion
1076 // return unused queue element to queue
1077 action
= kPutOnFreeQueue
;
1080 } else { // this object is not already locked, so let this thread through
1081 action
= kPutOnActiveQueue
;
1085 // put the new element on a queue
1086 if( kPutOnActiveQueue
== action
) {
1087 queue_enter( &gArbitrationLockQueueActive
,
1089 ArbitrationLockQueueElement
*,
1091 } else if( kPutOnFreeQueue
== action
) {
1092 queue_enter( &gArbitrationLockQueueFree
,
1094 ArbitrationLockQueueElement
*,
1097 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1100 // unlock global access
1101 IOUnlock( gArbitrationLockQueueLock
);
1106 void IOService::unlockForArbitration( void )
1109 ArbitrationLockQueueElement
* element
;
1111 // lock global access
1112 IOTakeLock( gArbitrationLockQueueLock
);
1114 // find the lock element for this object (ie. on active queue)
1116 queue_iterate( &gArbitrationLockQueueActive
,
1118 ArbitrationLockQueueElement
*,
1121 if( element
->service
== this ) {
1129 // determine whether the lock has been taken recursively
1130 if( element
->count
> 1 ) {
1131 // undo one level of recursion
1136 // remove it from the active queue
1137 queue_remove( &gArbitrationLockQueueActive
,
1139 ArbitrationLockQueueElement
*,
1142 // put it on the free queue
1143 queue_enter( &gArbitrationLockQueueFree
,
1145 ArbitrationLockQueueElement
*,
1148 // determine whether a thread is waiting for object (head to tail scan)
1150 queue_iterate( &gArbitrationLockQueueWaiting
,
1152 ArbitrationLockQueueElement
*,
1155 if( element
->service
== this ) {
1161 if ( found
) { // we found an interested thread on waiting queue
1163 // remove it from the waiting queue
1164 queue_remove( &gArbitrationLockQueueWaiting
,
1166 ArbitrationLockQueueElement
*,
1169 // put it on the active queue
1170 queue_enter( &gArbitrationLockQueueActive
,
1172 ArbitrationLockQueueElement
*,
1175 // wake the waiting thread
1176 IOLockWakeup( gArbitrationLockQueueLock
,
1178 /* one thread */ true );
1182 // unlock global access
1183 IOUnlock( gArbitrationLockQueueLock
);
1186 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1189 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1190 context
, gIOServicePlane
);
1193 void IOService::applyToClients( IOServiceApplierFunction applier
,
1196 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1197 context
, gIOServicePlane
);
1206 // send a message to a client or interested party of this service
1207 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1208 void * argument
, vm_size_t argSize
)
1211 IOService
* service
;
1212 _IOServiceInterestNotifier
* notify
;
1214 if( (service
= OSDynamicCast( IOService
, client
)))
1215 ret
= service
->message( type
, this, argument
);
1217 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1219 _IOServiceNotifierInvocation invocation
;
1222 invocation
.thread
= current_thread();
1225 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1228 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1229 _IOServiceNotifierInvocation
*, link
);
1235 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1236 type
, this, argument
, argSize
);
1239 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1240 _IOServiceNotifierInvocation
*, link
);
1241 if( kIOServiceNotifyWaiter
& notify
->state
) {
1242 notify
->state
&= ~kIOServiceNotifyWaiter
;
1243 WAKEUPNOTIFY( notify
);
1248 ret
= kIOReturnSuccess
;
1251 ret
= kIOReturnBadArgument
;
1256 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1257 OSObjectApplierFunction applier
,
1263 OSArray
* copyArray
;
1265 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1268 array
= OSDynamicCast( OSArray
, getProperty( typeOfInterest
));
1270 copyArray
= OSArray::withArray( array
);
1274 (next
= copyArray
->getObject( index
));
1276 (*applier
)(next
, context
);
1278 copyArray
->release();
1284 struct MessageClientsContext
{
1285 IOService
* service
;
1292 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1295 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1297 ret
= context
->service
->messageClient( context
->type
,
1298 object
, context
->argument
, context
->argSize
);
1299 if( kIOReturnSuccess
!= ret
)
1303 // send a message to all clients
1304 IOReturn
IOService::messageClients( UInt32 type
,
1305 void * argument
, vm_size_t argSize
)
1307 MessageClientsContext context
;
1309 context
.service
= this;
1310 context
.type
= type
;
1311 context
.argument
= argument
;
1312 context
.argSize
= argSize
;
1313 context
.ret
= kIOReturnSuccess
;
1315 applyToInterested( gIOGeneralInterest
,
1316 &messageClientsApplier
, &context
);
1318 return( context
.ret
);
1321 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1322 IOOptionBits response
)
1324 return( kIOReturnUnsupported
);
1327 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1328 IOServiceInterestHandler handler
, void * target
, void * ref
)
1330 _IOServiceInterestNotifier
* notify
= 0;
1333 if( (typeOfInterest
!= gIOGeneralInterest
)
1334 && (typeOfInterest
!= gIOBusyInterest
)
1335 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1336 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1339 lockForArbitration();
1340 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1342 notify
= new _IOServiceInterestNotifier
;
1343 if( notify
&& !notify
->init()) {
1349 notify
->handler
= handler
;
1350 notify
->target
= target
;
1352 notify
->state
= kIOServiceNotifyEnable
;
1353 queue_init( ¬ify
->handlerInvocations
);
1358 if( 0 == (set
= (OSArray
*) getProperty( typeOfInterest
))) {
1359 set
= OSArray::withCapacity( 1 );
1361 setProperty( typeOfInterest
, set
);
1365 notify
->whence
= set
;
1367 set
->setObject( notify
);
1371 unlockForArbitration();
1376 static void cleanInterestArray( OSObject
* object
)
1380 _IOServiceInterestNotifier
* next
;
1382 if( (array
= OSDynamicCast( OSArray
, object
))) {
1385 (next
= (_IOServiceInterestNotifier
*)
1386 array
->getObject( index
));
1394 void IOService::unregisterAllInterest( void )
1396 cleanInterestArray( getProperty( gIOGeneralInterest
));
1397 cleanInterestArray( getProperty( gIOBusyInterest
));
1398 cleanInterestArray( getProperty( gIOAppPowerStateInterest
));
1399 cleanInterestArray( getProperty( gIOPriorityPowerStateInterest
));
1403 * _IOServiceInterestNotifier
1406 // wait for all threads, other than the current one,
1407 // to exit the handler
1409 void _IOServiceInterestNotifier::wait()
1411 _IOServiceNotifierInvocation
* next
;
1416 queue_iterate( &handlerInvocations
, next
,
1417 _IOServiceNotifierInvocation
*, link
) {
1418 if( next
->thread
!= current_thread() ) {
1424 state
|= kIOServiceNotifyWaiter
;
1431 void _IOServiceInterestNotifier::free()
1433 assert( queue_empty( &handlerInvocations
));
1437 void _IOServiceInterestNotifier::remove()
1442 whence
->removeObject(whence
->getNextIndexOfObject(
1443 (OSObject
*) this, 0 ));
1447 state
&= ~kIOServiceNotifyEnable
;
1456 bool _IOServiceInterestNotifier::disable()
1462 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1463 state
&= ~kIOServiceNotifyEnable
;
1472 void _IOServiceInterestNotifier::enable( bool was
)
1476 state
|= kIOServiceNotifyEnable
;
1478 state
&= ~kIOServiceNotifyEnable
;
1482 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1488 #define tailQ(o) setObject(o)
1489 #define headQ(o) setObject(0, o)
1490 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1492 inline void _workLoopAction( IOWorkLoop::Action action
,
1493 IOService
* service
,
1494 void * p0
= 0, void * p1
= 0,
1495 void * p2
= 0, void * p3
= 0 )
1499 if( (wl
= service
->getWorkLoop())) {
1501 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1504 (*action
)( service
, p0
, p1
, p2
, p3
);
1507 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1511 // if its our only provider
1512 ok
= isParent( provider
, gIOServicePlane
, true);
1516 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1517 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1524 bool IOService::terminatePhase1( IOOptionBits options
)
1529 OSArray
* makeInactive
;
1532 bool startPhase2
= false;
1534 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1537 if( options
& kIOServiceRecursing
) {
1538 __state
[1] |= kIOServiceRecursing
;
1543 makeInactive
= OSArray::withCapacity( 16 );
1552 didInactive
= victim
->lockForArbitration( true );
1554 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1556 victim
->__state
[0] |= kIOServiceInactiveState
;
1557 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1558 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1559 victim
->_adjustBusy( 1 );
1561 victim
->unlockForArbitration();
1564 startPhase2
= didInactive
;
1567 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1568 IOUserClient::destroyUserReferences( victim
);
1569 victim
->unregisterAllInterest();
1571 iter
= victim
->getClientIterator();
1573 while( (client
= (IOService
*) iter
->getNextObject())) {
1574 TLOG("%s::requestTerminate(%s, %08lx)\n",
1575 client
->getName(), victim
->getName(), options
);
1576 ok
= client
->requestTerminate( victim
, options
);
1577 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1578 client
->getName(), victim
->getName(), ok
);
1580 makeInactive
->setObject( client
);
1586 victim
= (IOService
*) makeInactive
->getObject(0);
1589 makeInactive
->removeObject(0);
1593 makeInactive
->release();
1596 scheduleTerminatePhase2( options
);
1601 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1603 AbsoluteTime deadline
;
1605 bool wait
, haveDeadline
= false;
1607 options
|= kIOServiceRequired
;
1611 IOLockLock( gJobsLock
);
1613 if( (options
& kIOServiceSynchronous
)
1614 && (current_thread() != gIOTerminateThread
)) {
1617 wait
= (gIOTerminateThread
!= 0);
1619 // wait to become the terminate thread
1620 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1624 gIOTerminateThread
= current_thread();
1625 gIOTerminatePhase2List
->setObject( this );
1629 while( gIOTerminateWork
)
1630 terminateWorker( options
);
1631 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1633 // wait for the victim to go non-busy
1634 if( !haveDeadline
) {
1635 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1636 haveDeadline
= true;
1638 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1639 deadline
, THREAD_UNINT
);
1640 if( waitResult
== THREAD_TIMED_OUT
) {
1641 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1643 thread_cancel_timer();
1645 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1647 gIOTerminateThread
= 0;
1648 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1651 // ! kIOServiceSynchronous
1653 gIOTerminatePhase2List
->setObject( this );
1654 if( 0 == gIOTerminateWork
++) {
1655 if( !gIOTerminateThread
)
1656 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1658 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1662 IOLockUnlock( gJobsLock
);
1667 void IOService::terminateThread( void * arg
)
1669 IOLockLock( gJobsLock
);
1671 while (gIOTerminateWork
)
1672 terminateWorker( (IOOptionBits
) arg
);
1674 gIOTerminateThread
= 0;
1675 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1677 IOLockUnlock( gJobsLock
);
1680 void IOService::scheduleStop( IOService
* provider
)
1682 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1684 IOLockLock( gJobsLock
);
1685 gIOStopList
->tailQ( this );
1686 gIOStopProviderList
->tailQ( provider
);
1688 if( 0 == gIOTerminateWork
++) {
1689 if( !gIOTerminateThread
)
1690 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1692 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1695 IOLockUnlock( gJobsLock
);
1698 void IOService::scheduleFinalize( void )
1700 TLOG("%s::scheduleFinalize\n", getName());
1702 IOLockLock( gJobsLock
);
1703 gIOFinalizeList
->tailQ( this );
1705 if( 0 == gIOTerminateWork
++) {
1706 if( !gIOTerminateThread
)
1707 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1709 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1712 IOLockUnlock( gJobsLock
);
1715 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1720 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1722 if( false == *defer
) {
1724 if( lockForArbitration( true )) {
1725 if( false == provider
->handleIsOpen( this ))
1726 scheduleStop( provider
);
1729 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1730 if( false == provider
->handleIsOpen( this ))
1731 scheduleStop( provider
);
1734 unlockForArbitration();
1741 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1742 OSArray
* doPhase2List
)
1748 iter
= victim
->getClientIterator();
1750 while( (client
= (IOService
*) iter
->getNextObject())) {
1751 TLOG("%s::willTerminate(%s, %08lx)\n",
1752 client
->getName(), victim
->getName(), options
);
1753 ok
= client
->willTerminate( victim
, options
);
1754 doPhase2List
->tailQ( client
);
1760 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1766 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1768 iter
= victim
->getClientIterator();
1770 while( (client
= (IOService
*) iter
->getNextObject())) {
1771 TLOG("%s::didTerminate(%s, %08lx)\n",
1772 client
->getName(), victim
->getName(), options
);
1773 client
->didTerminate( victim
, options
, &defer
);
1774 TLOG("%s::didTerminate(%s, defer %d)\n",
1775 client
->getName(), victim
->getName(), defer
);
1781 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1783 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1784 victim
->finalize( options
);
1787 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1789 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1790 client
->stop( provider
);
1791 if( provider
->isOpen( client
))
1792 provider
->close( client
);
1793 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1794 client
->detach( provider
);
1797 void IOService::terminateWorker( IOOptionBits options
)
1799 OSArray
* doPhase2List
;
1800 OSArray
* didPhase2List
;
1805 IOService
* provider
;
1811 options
|= kIOServiceRequired
;
1813 doPhase2List
= OSArray::withCapacity( 16 );
1814 didPhase2List
= OSArray::withCapacity( 16 );
1815 freeList
= OSSet::withCapacity( 16 );
1816 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1820 workDone
= gIOTerminateWork
;
1822 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1825 gIOTerminatePhase2List
->removeObject(0);
1826 IOLockUnlock( gJobsLock
);
1830 doPhase2
= victim
->lockForArbitration( true );
1832 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1834 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1835 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1837 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1839 victim
->unlockForArbitration();
1842 if( 0 == victim
->getClient()) {
1843 // no clients - will go to finalize
1844 IOLockLock( gJobsLock
);
1845 gIOFinalizeList
->tailQ( victim
);
1846 IOLockUnlock( gJobsLock
);
1848 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1849 victim
, (void *) options
, (void *) doPhase2List
);
1851 didPhase2List
->headQ( victim
);
1854 victim
= (IOService
*) doPhase2List
->getObject(0);
1857 doPhase2List
->removeObject(0);
1861 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1863 if( victim
->lockForArbitration( true )) {
1864 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1865 victim
->unlockForArbitration();
1867 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1868 victim
, (void *) options
);
1869 didPhase2List
->removeObject(0);
1871 IOLockLock( gJobsLock
);
1878 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1880 IOLockUnlock( gJobsLock
);
1881 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1882 victim
, (void *) options
);
1883 IOLockLock( gJobsLock
);
1885 freeList
->setObject( victim
);
1886 // safe if finalize list is append only
1887 gIOFinalizeList
->removeObject(0);
1891 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1893 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1896 if( !provider
->isChild( client
, gIOServicePlane
)) {
1897 // may be multiply queued - nop it
1898 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1900 // not ready for stop if it has clients, skip it
1901 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1902 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1907 IOLockUnlock( gJobsLock
);
1908 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1909 provider
, (void *) client
);
1910 IOLockLock( gJobsLock
);
1911 // check the finalize list now
1915 freeList
->setObject( client
);
1916 freeList
->setObject( provider
);
1918 // safe if stop list is append only
1919 gIOStopList
->removeObject( idx
);
1920 gIOStopProviderList
->removeObject( idx
);
1924 } while( doPhase3
);
1926 gIOTerminateWork
-= workDone
;
1927 moreToDo
= (gIOTerminateWork
!= 0);
1930 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1933 } while( moreToDo
);
1935 IOLockUnlock( gJobsLock
);
1937 freeList
->release();
1938 doPhase2List
->release();
1939 didPhase2List
->release();
1941 IOLockLock( gJobsLock
);
1944 bool IOService::finalize( IOOptionBits options
)
1947 IOService
* provider
;
1949 iter
= getProviderIterator();
1953 while( (provider
= (IOService
*) iter
->getNextObject())) {
1956 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
1957 /* we come down here on programmatic terminate */
1959 if( provider
->isOpen( this ))
1960 provider
->close( this );
1964 if( provider
->lockForArbitration( true )) {
1965 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
1966 scheduleStop( provider
);
1967 provider
->unlockForArbitration();
1984 void IOService::doServiceTerminate( IOOptionBits options
)
1988 // a method in case someone needs to override it
1989 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
1993 if( client
->isParent( this, gIOServicePlane
, true))
1994 // we are the clients only provider
1995 ok
= client
->terminate( options
);
2002 bool IOService::terminate( IOOptionBits options
)
2004 options
|= kIOServiceTerminate
;
2006 return( terminatePhase1( options
));
2009 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015 struct ServiceOpenMessageContext
2017 IOService
* service
;
2019 IOService
* excludeClient
;
2020 IOOptionBits options
;
2023 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2025 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2027 if( object
!= context
->excludeClient
)
2028 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2031 bool IOService::open( IOService
* forClient
,
2032 IOOptionBits options
,
2036 ServiceOpenMessageContext context
;
2038 context
.service
= this;
2039 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2040 context
.excludeClient
= forClient
;
2041 context
.options
= options
;
2043 applyToInterested( gIOGeneralInterest
,
2044 &serviceOpenMessageApplier
, &context
);
2046 if( false == lockForArbitration(false) )
2049 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2051 ok
= handleOpen( forClient
, options
, arg
);
2053 unlockForArbitration();
2058 void IOService::close( IOService
* forClient
,
2059 IOOptionBits options
)
2064 lockForArbitration();
2066 wasClosed
= handleIsOpen( forClient
);
2068 handleClose( forClient
, options
);
2069 last
= (__state
[1] & kIOServiceTermPhase3State
);
2072 unlockForArbitration();
2075 forClient
->scheduleStop( this );
2077 else if( wasClosed
) {
2079 ServiceOpenMessageContext context
;
2081 context
.service
= this;
2082 context
.type
= kIOMessageServiceWasClosed
;
2083 context
.excludeClient
= forClient
;
2084 context
.options
= options
;
2086 applyToInterested( gIOGeneralInterest
,
2087 &serviceOpenMessageApplier
, &context
);
2091 bool IOService::isOpen( const IOService
* forClient
) const
2093 IOService
* self
= (IOService
*) this;
2096 self
->lockForArbitration();
2098 ok
= handleIsOpen( forClient
);
2100 self
->unlockForArbitration();
2105 bool IOService::handleOpen( IOService
* forClient
,
2106 IOOptionBits options
,
2111 ok
= (0 == __owner
);
2113 __owner
= forClient
;
2115 else if( options
& kIOServiceSeize
) {
2116 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2117 __owner
, (void *) options
));
2118 if( ok
&& (0 == __owner
))
2119 __owner
= forClient
;
2126 void IOService::handleClose( IOService
* forClient
,
2127 IOOptionBits options
)
2129 if( __owner
== forClient
)
2133 bool IOService::handleIsOpen( const IOService
* forClient
) const
2136 return( __owner
== forClient
);
2138 return( __owner
!= forClient
);
2142 * Probing & starting
2144 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2146 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2147 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2155 val1
= obj1
->priority
;
2158 val2
= obj2
->priority
;
2160 return ( val1
- val2
);
2163 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2165 OSDictionary
* dict
;
2166 IOService
* service
;
2167 _IOServiceNotifier
* notify
;
2168 OSSymbol
* key
= (OSSymbol
*) ref
;
2171 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2172 return( notify
->priority
);
2174 else if( (service
= OSDynamicCast( IOService
, entry
)))
2175 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2176 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2177 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2184 return( (SInt32
) offset
->unsigned32BitValue());
2186 return( kIODefaultProbeScore
);
2189 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2191 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2192 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2200 val1
= IOServiceObjectOrder( obj1
, ref
);
2203 val2
= IOServiceObjectOrder( obj2
, ref
);
2205 return ( val1
- val2
);
2208 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2210 IOService
* service
= 0;
2212 const OSSymbol
* nextCat
;
2214 iter
= getClientIterator();
2216 while( (service
= (IOService
*) iter
->getNextObject())) {
2217 if( kIOServiceInactiveState
& service
->__state
[0])
2219 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2220 service
->getProperty( gIOMatchCategoryKey
));
2221 if( category
== nextCat
)
2229 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2231 _IOServiceNotifierInvocation invocation
;
2235 invocation
.thread
= current_thread();
2238 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2241 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2242 _IOServiceNotifierInvocation
*, link
);
2248 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2251 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2252 _IOServiceNotifierInvocation
*, link
);
2253 if( kIOServiceNotifyWaiter
& notify
->state
) {
2254 notify
->state
&= ~kIOServiceNotifyWaiter
;
2255 WAKEUPNOTIFY( notify
);
2264 * Alloc and probe matching classes,
2265 * called on the provider instance
2268 void IOService::probeCandidates( OSOrderedSet
* matches
)
2270 OSDictionary
* match
= 0;
2273 IOService
* newInst
;
2274 OSDictionary
* props
;
2277 OSOrderedSet
* familyMatches
= 0;
2278 OSOrderedSet
* startList
;
2279 OSDictionary
* startDict
= 0;
2280 const OSSymbol
* category
;
2282 _IOServiceNotifier
* notify
;
2283 OSObject
* nextMatch
= 0;
2285 bool needReloc
= false;
2291 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2293 nextMatch
->retain();
2294 matches
->removeObject(nextMatch
);
2296 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2298 lockForArbitration();
2299 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2300 invokeNotifer( notify
);
2301 unlockForArbitration();
2302 nextMatch
->release();
2306 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2307 nextMatch
->release();
2314 debugFlags
= getDebugFlags( match
);
2318 category
= OSDynamicCast( OSSymbol
,
2319 match
->getObject( gIOMatchCategoryKey
));
2321 category
= gIODefaultMatchCategoryKey
;
2323 if( getClientWithCategory( category
)) {
2325 if( debugFlags
& kIOLogMatch
)
2326 LOG("%s: match category %s exists\n", getName(),
2327 category
->getCStringNoCopy());
2329 nextMatch
->release();
2334 // create a copy now in case its modified during matching
2335 props
= OSDictionary::withDictionary( match
, match
->getCount());
2338 props
->setCapacityIncrement(1);
2340 // check the nub matches
2341 if( false == passiveMatch( props
, true ))
2344 // Check to see if driver reloc has been loaded.
2345 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2348 if( debugFlags
& kIOLogCatalogue
)
2349 LOG("%s: stalling for module\n", getName());
2351 // If reloc hasn't been loaded, exit;
2352 // reprobing will occur after reloc has been loaded.
2356 // reorder on family matchPropertyTable score.
2357 if( 0 == familyMatches
)
2358 familyMatches
= OSOrderedSet::withCapacity( 1,
2359 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2361 familyMatches
->setObject( props
);
2366 nextMatch
->release();
2375 if( familyMatches
) {
2378 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2381 familyMatches
->removeObject( props
);
2386 debugFlags
= getDebugFlags( props
);
2389 symbol
= OSDynamicCast( OSSymbol
,
2390 props
->getObject( gIOClassKey
));
2394 // alloc the driver instance
2395 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2398 IOLog("Couldn't alloc class \"%s\"\n",
2399 symbol
->getCStringNoCopy());
2403 // init driver instance
2404 if( !(inst
->init( props
))) {
2406 if( debugFlags
& kIOLogStart
)
2407 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2411 if( __state
[1] & kIOServiceSynchronousState
)
2412 inst
->__state
[1] |= kIOServiceSynchronousState
;
2414 // give the driver the default match category if not specified
2415 category
= OSDynamicCast( OSSymbol
,
2416 props
->getObject( gIOMatchCategoryKey
));
2418 category
= gIODefaultMatchCategoryKey
;
2419 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2421 // attach driver instance
2422 if( !(inst
->attach( this )))
2425 // pass in score from property table
2426 score
= familyMatches
->orderObject( props
);
2428 // & probe the new driver instance
2430 if( debugFlags
& kIOLogProbe
)
2431 LOG("%s::probe(%s)\n",
2432 inst
->getMetaClass()->getClassName(), getName());
2435 newInst
= inst
->probe( this, &score
);
2436 inst
->detach( this );
2439 if( debugFlags
& kIOLogProbe
)
2440 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2446 newPri
= OSNumber::withNumber( score
, 32 );
2448 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2452 // add to start list for the match category
2454 startDict
= OSDictionary::withCapacity( 1 );
2455 assert( startDict
);
2456 startList
= (OSOrderedSet
*)
2457 startDict
->getObject( category
);
2458 if( 0 == startList
) {
2459 startList
= OSOrderedSet::withCapacity( 1,
2460 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2461 if( startDict
&& startList
) {
2462 startDict
->setObject( category
, startList
);
2463 startList
->release();
2466 assert( startList
);
2468 startList
->setObject( newInst
);
2476 familyMatches
->release();
2480 // start the best (until success) of each category
2482 iter
= OSCollectionIterator::withCollection( startDict
);
2484 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2486 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2487 assert( startList
);
2492 while( true // (!started)
2493 && (inst
= (IOService
*)startList
->getFirstObject())) {
2496 startList
->removeObject(inst
);
2499 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2501 if( debugFlags
& kIOLogStart
) {
2503 LOG( "match category exists, skipping " );
2504 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2505 getName(), inst
->getRetainCount());
2508 if( false == started
)
2509 started
= startCandidate( inst
);
2511 if( (debugFlags
& kIOLogStart
) && (false == started
))
2512 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2513 inst
->getRetainCount());
2522 // adjust the busy count by -1 if matching is stalled for a module,
2523 // or +1 if a previously stalled matching is complete.
2524 lockForArbitration();
2527 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2529 __state
[1] |= kIOServiceModuleStallState
;
2531 } else if( __state
[1] & kIOServiceModuleStallState
) {
2532 __state
[1] &= ~kIOServiceModuleStallState
;
2536 _adjustBusy( adjBusy
);
2537 unlockForArbitration();
2540 startDict
->release();
2544 * Start a previously attached & probed instance,
2545 * called on exporting object instance
2548 bool IOService::startCandidate( IOService
* service
)
2552 ok
= service
->attach( this );
2555 // stall for any nub resources
2557 // stall for any driver resources
2558 service
->checkResources();
2560 AbsoluteTime startTime
;
2561 AbsoluteTime endTime
;
2564 if (kIOLogStart
& gIOKitDebug
)
2565 clock_get_uptime(&startTime
);
2567 ok
= service
->start(this);
2569 if (kIOLogStart
& gIOKitDebug
)
2571 clock_get_uptime(&endTime
);
2573 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2575 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2576 absolutetime_to_nanoseconds(endTime
, &nano
);
2577 if (nano
> 500000000ULL)
2578 IOLog("%s::start took %ld ms\n", service
->getName(), (UInt32
)(nano
/ 1000000ULL));
2582 service
->detach( this );
2587 IOService
* IOService::resources( void )
2589 return( gIOResources
);
2592 void IOService::publishResource( const char * key
, OSObject
* value
)
2594 const OSSymbol
* sym
;
2596 if( (sym
= OSSymbol::withCString( key
))) {
2597 publishResource( sym
, value
);
2602 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2605 value
= (OSObject
*) gIOServiceKey
;
2607 gIOResources
->setProperty( key
, value
);
2609 if( IORecursiveLockHaveLock( gNotificationLock
))
2612 gIOResourceGenerationCount
++;
2613 gIOResources
->registerService();
2616 bool IOService::addNeededResource( const char * key
)
2618 OSObject
* resources
;
2623 resources
= getProperty( gIOResourceMatchKey
);
2625 newKey
= OSString::withCString( key
);
2626 if( (0 == resources
) || (0 == newKey
))
2629 set
= OSDynamicCast( OSSet
, resources
);
2631 set
= OSSet::withCapacity( 1 );
2633 set
->setObject( resources
);
2638 set
->setObject( newKey
);
2640 ret
= setProperty( gIOResourceMatchKey
, set
);
2646 bool IOService::checkResource( OSObject
* matching
)
2649 OSDictionary
* table
;
2651 if( (str
= OSDynamicCast( OSString
, matching
))) {
2652 if( gIOResources
->getProperty( str
))
2657 table
= resourceMatching( str
);
2658 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2661 IOLog("%s: Can't match using: %s\n", getName(),
2662 matching
->getMetaClass()->getClassName());
2663 /* false would stall forever */
2667 if( gIOKitDebug
& kIOLogConfig
)
2668 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2670 waitForService( table
);
2672 if( gIOKitDebug
& kIOLogConfig
)
2673 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2678 bool IOService::checkResources( void )
2680 OSObject
* resources
;
2685 resources
= getProperty( gIOResourceMatchKey
);
2689 if( (set
= OSDynamicCast( OSSet
, resources
))) {
2691 iter
= OSCollectionIterator::withCollection( set
);
2693 while( ok
&& (resources
= iter
->getNextObject()) )
2694 ok
= checkResource( resources
);
2699 ok
= checkResource( resources
);
2705 _IOConfigThread
* _IOConfigThread::configThread( void )
2707 _IOConfigThread
* inst
;
2710 if( !(inst
= new _IOConfigThread
))
2714 if( !(inst
->thread
= IOCreateThread
2715 ( (IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2728 void _IOConfigThread::free( void )
2733 void IOService::doServiceMatch( IOOptionBits options
)
2735 _IOServiceNotifier
* notify
;
2737 OSOrderedSet
* matches
;
2738 SInt32 catalogGeneration
;
2739 bool keepGuessing
= true;
2740 bool reRegistered
= true;
2742 // job->nub->deliverNotification( gIOPublishNotification,
2743 // kIOServiceRegisteredState, 0xffffffff );
2745 while( keepGuessing
) {
2747 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2748 // the matches list should always be created by findDrivers()
2751 lockForArbitration();
2752 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2753 deliverNotification( gIOFirstPublishNotification
,
2754 kIOServiceFirstPublishState
, 0xffffffff );
2756 __state
[1] &= ~kIOServiceNeedConfigState
;
2757 __state
[1] |= kIOServiceConfigState
;
2758 __state
[0] |= kIOServiceRegisteredState
;
2760 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2762 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2763 gNotifications
->getObject( gIOPublishNotification
) );
2765 while((notify
= (_IOServiceNotifier
*)
2766 iter
->getNextObject())) {
2768 if( passiveMatch( notify
->matching
)
2769 && (kIOServiceNotifyEnable
& notify
->state
))
2770 matches
->setObject( notify
);
2777 unlockForArbitration();
2779 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2780 probeCandidates( matches
);
2785 lockForArbitration();
2786 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2788 (reRegistered
|| (catalogGeneration
!=
2789 gIOCatalogue
->getGenerationCount()))
2790 && (0 == (__state
[0] & kIOServiceInactiveState
));
2793 unlockForArbitration();
2796 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2797 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2798 deliverNotification( gIOMatchedNotification
,
2799 kIOServiceMatchedState
, 0xffffffff );
2800 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2801 deliverNotification( gIOFirstMatchNotification
,
2802 kIOServiceFirstMatchState
, 0xffffffff );
2805 __state
[1] &= ~kIOServiceConfigState
;
2806 if( __state
[0] & kIOServiceInactiveState
)
2807 scheduleTerminatePhase2();
2810 unlockForArbitration();
2813 UInt32
IOService::_adjustBusy( SInt32 delta
)
2818 bool wasQuiet
, nowQuiet
, needWake
;
2821 result
= __state
[1] & kIOServiceBusyStateMask
;
2825 next
->lockForArbitration();
2826 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2827 assert( count
< kIOServiceBusyMax
);
2828 wasQuiet
= (0 == count
);
2829 assert( (!wasQuiet
) || (delta
> 0));
2830 next
->__state
[1] += delta
;
2831 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2832 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2835 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2836 IOLockLock( gIOServiceBusyLock
);
2837 thread_wakeup( (event_t
) next
);
2838 IOLockUnlock( gIOServiceBusyLock
);
2841 next
->unlockForArbitration();
2843 if( (wasQuiet
|| nowQuiet
) ) {
2846 OSObject
* interested
;
2848 array
= OSDynamicCast( OSArray
, next
->getProperty( gIOBusyInterest
));
2852 (interested
= array
->getObject( index
));
2854 next
->messageClient(kIOMessageServiceBusyStateChange
,
2855 interested
, (void *) wasQuiet
/* busy now */);
2860 if( nowQuiet
&& (next
== gIOServiceRoot
))
2861 OSMetaClass::considerUnloads();
2864 delta
= nowQuiet
? -1 : +1;
2866 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2871 void IOService::adjustBusy( SInt32 delta
)
2873 lockForArbitration();
2874 _adjustBusy( delta
);
2875 unlockForArbitration();
2878 UInt32
IOService::getBusyState( void )
2880 return( __state
[1] & kIOServiceBusyStateMask
);
2883 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2884 mach_timespec_t
* timeout
)
2887 int waitResult
= THREAD_AWAKENED
;
2888 bool computeDeadline
= true;
2889 AbsoluteTime abstime
;
2892 lockForArbitration();
2893 IOLockLock( gIOServiceBusyLock
);
2894 wait
= (value
!= (__state
[1] & mask
));
2896 __state
[1] |= kIOServiceBusyWaiterState
;
2897 unlockForArbitration();
2898 assert_wait( (event_t
) this, THREAD_UNINT
);
2900 if( computeDeadline
) {
2901 AbsoluteTime nsinterval
;
2902 clock_interval_to_absolutetime_interval(
2903 timeout
->tv_sec
, kSecondScale
, &abstime
);
2904 clock_interval_to_absolutetime_interval(
2905 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2906 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2907 clock_absolutetime_interval_to_deadline(
2908 abstime
, &abstime
);
2909 computeDeadline
= false;
2911 thread_set_timer_deadline( abstime
);
2914 unlockForArbitration();
2915 IOLockUnlock( gIOServiceBusyLock
);
2917 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2918 if( timeout
&& (waitResult
!= THREAD_TIMED_OUT
))
2919 thread_cancel_timer();
2922 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2924 if( waitResult
== THREAD_TIMED_OUT
)
2925 return( kIOReturnTimeout
);
2927 return( kIOReturnSuccess
);
2930 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
2932 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2935 bool IOService::serializeProperties( OSSerialize
* s
) const
2938 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2939 sizeof( __state
), "__state");
2941 return( super::serializeProperties(s
) );
2945 void _IOConfigThread::main( _IOConfigThread
* self
)
2947 _IOServiceJob
* job
;
2955 semaphore_wait( gJobsSemaphore
);
2957 IOTakeLock( gJobsLock
);
2958 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
2960 gJobs
->removeObject(job
);
2963 // gNumConfigThreads--; // we're out of service
2964 gNumWaitingThreads
--; // we're out of service
2966 IOUnlock( gJobsLock
);
2972 if( gIOKitDebug
& kIOLogConfig
)
2973 LOG("config(%x): starting on %s, %d\n",
2974 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
2976 switch( job
->type
) {
2979 nub
->doServiceMatch( job
->options
);
2983 LOG("config(%x): strange type (%d)\n",
2984 (int) IOThreadSelf(), job
->type
);
2991 IOTakeLock( gJobsLock
);
2992 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
2994 gNumWaitingThreads
++; // back in service
2995 // gNumConfigThreads++;
2997 if( 0 == --gNumConfigThreads
) {
2998 // IOLog("MATCH IDLE\n");
2999 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3002 IOUnlock( gJobsLock
);
3007 if( gIOKitDebug
& kIOLogConfig
)
3008 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
3013 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3016 int waitResult
= THREAD_AWAKENED
;
3017 bool computeDeadline
= true;
3018 AbsoluteTime abstime
;
3020 IOLockLock( gJobsLock
);
3022 wait
= (0 != gNumConfigThreads
);
3025 if( computeDeadline
) {
3026 clock_interval_to_absolutetime_interval(
3027 msToWait
, kMillisecondScale
, &abstime
);
3028 clock_absolutetime_interval_to_deadline(
3029 abstime
, &abstime
);
3030 computeDeadline
= false;
3032 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3033 abstime
, THREAD_UNINT
);
3035 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3039 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3040 IOLockUnlock( gJobsLock
);
3042 if( waitResult
== THREAD_TIMED_OUT
)
3043 return( kIOReturnTimeout
);
3045 return( kIOReturnSuccess
);
3048 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3055 IOTakeLock( gJobsLock
);
3058 gJobs
->setLastObject( job
);
3060 count
= gNumWaitingThreads
;
3061 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3063 create
= ( (gOutstandingJobs
> count
)
3064 && (gNumConfigThreads
< kMaxConfigThreads
) );
3066 gNumConfigThreads
++;
3067 gNumWaitingThreads
++;
3070 IOUnlock( gJobsLock
);
3075 if( gIOKitDebug
& kIOLogConfig
)
3076 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3077 _IOConfigThread::configThread();
3080 semaphore_signal( gJobsSemaphore
);
3084 // internal - call with gNotificationLock
3085 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3086 IOOptionBits inState
, IOOptionBits options
)
3088 OSObject
* current
= 0;
3090 IOService
* service
;
3095 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3096 kIORegistryIterateRecursively
);
3100 while( (service
= (IOService
*) iter
->getNextObject())) {
3101 if( (inState
== (service
->__state
[0] & inState
))
3102 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3103 && service
->passiveMatch( matching
)) {
3105 if( options
& kIONotifyOnce
) {
3110 ((OSSet
*)current
)->setObject( service
);
3112 current
= OSSet::withObjects(
3113 (const OSObject
**) &service
, 1, 1 );
3116 } while( !service
&& !iter
->isValid());
3120 if( current
&& (0 == (options
& kIONotifyOnce
))) {
3121 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3130 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3134 // is a lock even needed?
3137 iter
= (OSIterator
*) getExistingServices( matching
,
3138 kIOServiceMatchedState
);
3146 // internal - call with gNotificationLock
3147 IONotifier
* IOService::setNotification(
3148 const OSSymbol
* type
, OSDictionary
* matching
,
3149 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3152 _IOServiceNotifier
* notify
= 0;
3158 notify
= new _IOServiceNotifier
;
3159 if( notify
&& !notify
->init()) {
3165 notify
->matching
= matching
;
3166 notify
->handler
= handler
;
3167 notify
->target
= target
;
3169 notify
->priority
= priority
;
3170 notify
->state
= kIOServiceNotifyEnable
;
3171 queue_init( ¬ify
->handlerInvocations
);
3175 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3176 set
= OSOrderedSet::withCapacity( 1,
3177 IONotifyOrdering
, 0 );
3179 gNotifications
->setObject( type
, set
);
3183 notify
->whence
= set
;
3185 set
->setObject( notify
);
3191 // internal - call with gNotificationLock
3192 IONotifier
* IOService::doInstallNotification(
3193 const OSSymbol
* type
, OSDictionary
* matching
,
3194 IOServiceNotificationHandler handler
,
3195 void * target
, void * ref
,
3196 SInt32 priority
, OSIterator
** existing
)
3199 IONotifier
* notify
;
3200 IOOptionBits inState
;
3205 if( type
== gIOPublishNotification
)
3206 inState
= kIOServiceRegisteredState
;
3208 else if( type
== gIOFirstPublishNotification
)
3209 inState
= kIOServiceFirstPublishState
;
3211 else if( (type
== gIOMatchedNotification
)
3212 || (type
== gIOFirstMatchNotification
))
3213 inState
= kIOServiceMatchedState
;
3214 else if( type
== gIOTerminatedNotification
)
3219 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3222 // get the current set
3223 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3233 IONotifier
* IOService::installNotification(
3234 const OSSymbol
* type
, OSDictionary
* matching
,
3235 IOServiceNotificationHandler handler
,
3236 void * target
, void * ref
,
3237 SInt32 priority
, OSIterator
** existing
)
3239 IONotifier
* notify
;
3243 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3244 priority
, existing
);
3251 IONotifier
* IOService::addNotification(
3252 const OSSymbol
* type
, OSDictionary
* matching
,
3253 IOServiceNotificationHandler handler
,
3254 void * target
, void * ref
,
3257 OSIterator
* existing
;
3258 _IOServiceNotifier
* notify
;
3261 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3262 handler
, target
, ref
, priority
, &existing
);
3264 // send notifications for existing set
3267 notify
->retain(); // in case handler remove()s
3268 while( (next
= (IOService
*) existing
->getNextObject())) {
3270 next
->lockForArbitration();
3271 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3272 next
->invokeNotifer( notify
);
3273 next
->unlockForArbitration();
3276 existing
->release();
3282 struct SyncNotifyVars
{
3283 semaphore_port_t waitHere
;
3287 bool IOService::syncNotificationHandler(
3288 void * /* target */, void * ref
,
3289 IOService
* newService
)
3292 // result may get written more than once before the
3293 // notification is removed!
3294 ((SyncNotifyVars
*) ref
)->result
= newService
;
3295 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3300 IOService
* IOService::waitForService( OSDictionary
* matching
,
3301 mach_timespec_t
* timeout
)
3303 IONotifier
* notify
= 0;
3304 // priority doesn't help us much since we need a thread wakeup
3305 SInt32 priority
= 0;
3306 SyncNotifyVars state
;
3307 kern_return_t err
= kIOReturnBadArgument
;
3319 state
.result
= (IOService
*) getExistingServices( matching
,
3320 kIOServiceMatchedState
, kIONotifyOnce
);
3324 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3325 SYNC_POLICY_FIFO
, 0 );
3326 if( KERN_SUCCESS
!= err
)
3329 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3330 &IOService::syncNotificationHandler
, (void *) 0,
3331 (void *) &state
, priority
);
3339 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3341 err
= semaphore_wait( state
.waitHere
);
3345 notify
->remove(); // dequeues
3347 matching
->release();
3349 semaphore_destroy( kernel_task
, state
.waitHere
);
3351 return( state
.result
);
3354 void IOService::deliverNotification( const OSSymbol
* type
,
3355 IOOptionBits orNewState
, IOOptionBits andNewState
)
3357 _IOServiceNotifier
* notify
;
3359 OSArray
* willSend
= 0;
3361 lockForArbitration();
3363 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3364 || (type
== gIOTerminatedNotification
)) {
3368 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3369 gNotifications
->getObject( type
) );
3372 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3374 if( passiveMatch( notify
->matching
)
3375 && (kIOServiceNotifyEnable
& notify
->state
)) {
3377 willSend
= OSArray::withCapacity(8);
3379 willSend
->setObject( notify
);
3385 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3391 for( unsigned int idx
= 0;
3392 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3394 invokeNotifer( notify
);
3396 willSend
->release();
3398 unlockForArbitration();
3401 IOOptionBits
IOService::getState( void ) const
3403 return( __state
[0] );
3407 * Helpers to make matching objects for simple cases
3410 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3411 OSDictionary
* table
)
3414 table
= OSDictionary::withCapacity( 2 );
3416 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3421 OSDictionary
* IOService::serviceMatching( const char * name
,
3422 OSDictionary
* table
)
3424 const OSString
* str
;
3426 str
= OSSymbol::withCString( name
);
3430 table
= serviceMatching( str
, table
);
3435 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3436 OSDictionary
* table
)
3439 table
= OSDictionary::withCapacity( 2 );
3441 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3446 OSDictionary
* IOService::nameMatching( const char * name
,
3447 OSDictionary
* table
)
3449 const OSString
* str
;
3451 str
= OSSymbol::withCString( name
);
3455 table
= nameMatching( str
, table
);
3460 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3461 OSDictionary
* table
)
3463 table
= serviceMatching( gIOResourcesKey
, table
);
3465 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3470 OSDictionary
* IOService::resourceMatching( const char * name
,
3471 OSDictionary
* table
)
3473 const OSSymbol
* str
;
3475 str
= OSSymbol::withCString( name
);
3479 table
= resourceMatching( str
, table
);
3486 * _IOServiceNotifier
3489 // wait for all threads, other than the current one,
3490 // to exit the handler
3492 void _IOServiceNotifier::wait()
3494 _IOServiceNotifierInvocation
* next
;
3499 queue_iterate( &handlerInvocations
, next
,
3500 _IOServiceNotifierInvocation
*, link
) {
3501 if( next
->thread
!= current_thread() ) {
3507 state
|= kIOServiceNotifyWaiter
;
3514 void _IOServiceNotifier::free()
3516 assert( queue_empty( &handlerInvocations
));
3520 void _IOServiceNotifier::remove()
3525 whence
->removeObject( (OSObject
*) this );
3529 matching
->release();
3533 state
&= ~kIOServiceNotifyEnable
;
3542 bool _IOServiceNotifier::disable()
3548 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3549 state
&= ~kIOServiceNotifyEnable
;
3558 void _IOServiceNotifier::enable( bool was
)
3562 state
|= kIOServiceNotifyEnable
;
3564 state
&= ~kIOServiceNotifyEnable
;
3572 IOService
* IOResources::resources( void )
3576 inst
= new IOResources
;
3577 if( inst
&& !inst
->init()) {
3585 IOWorkLoop
* IOResources::getWorkLoop() const
3587 // If we are the resource root then bringe over to the
3588 // platform to get its workloop
3589 if (this == (IOResources
*) gIOResources
)
3590 return getPlatform()->getWorkLoop();
3592 return IOService::getWorkLoop();
3595 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3603 prop
= table
->getObject( gIOResourceMatchKey
);
3604 str
= OSDynamicCast( OSString
, prop
);
3606 ok
= (0 != getProperty( str
));
3608 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3610 iter
= OSCollectionIterator::withCollection( set
);
3612 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3613 ok
= (0 != getProperty( str
));
3622 IOReturn
IOResources::setProperties( OSObject
* properties
)
3625 const OSSymbol
* key
;
3626 OSDictionary
* dict
;
3627 OSCollectionIterator
* iter
;
3629 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
3630 if ( kIOReturnSuccess
!= err
)
3633 dict
= OSDynamicCast(OSDictionary
, properties
);
3635 return( kIOReturnBadArgument
);
3637 iter
= OSCollectionIterator::withCollection( dict
);
3639 return( kIOReturnBadArgument
);
3641 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3643 if (gIOConsoleUsersKey
== key
)
3645 IORegistryEntry::getRegistryRoot()->setProperty(key
, dict
->getObject(key
));
3646 OSIncrementAtomic( &gIOConsoleUsersSeed
);
3647 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
3651 publishResource( key
, dict
->getObject(key
) );
3656 return( kIOReturnSuccess
);
3660 * Helpers for matching dictionaries.
3661 * Keys existing in matching are checked in properties.
3662 * Keys may be a string or OSCollection of IOStrings
3665 bool IOService::compareProperty( OSDictionary
* matching
,
3671 value
= matching
->getObject( key
);
3673 ok
= value
->isEqualTo( getProperty( key
));
3681 bool IOService::compareProperty( OSDictionary
* matching
,
3682 const OSString
* key
)
3687 value
= matching
->getObject( key
);
3689 ok
= value
->isEqualTo( getProperty( key
));
3696 bool IOService::compareProperties( OSDictionary
* matching
,
3697 OSCollection
* keys
)
3699 OSCollectionIterator
* iter
;
3700 const OSString
* key
;
3703 if( !matching
|| !keys
)
3706 iter
= OSCollectionIterator::withCollection( keys
);
3709 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3710 ok
= compareProperty( matching
, key
);
3714 keys
->release(); // !! consume a ref !!
3719 /* Helper to add a location matching dict to the table */
3721 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3723 OSDictionary
* dict
;
3728 dict
= OSDictionary::withCapacity( 1 );
3730 table
->setObject( gIOLocationMatchKey
, dict
);
3738 * Go looking for a provider to match a location dict.
3741 IOService
* IOService::matchLocation( IOService
* /* client */ )
3745 parent
= getProvider();
3748 parent
= parent
->matchLocation( this );
3753 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3759 IORegistryEntry
* entry
;
3764 bool matchParent
= false;
3775 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3778 match
= (0 != where
->metaCast( str
));
3783 obj
= table
->getObject( gIONameMatchKey
);
3786 match
= where
->compareNames( obj
, changesOK
? &matched
: 0 );
3789 if( changesOK
&& matched
) {
3790 // leave a hint as to which name matched
3791 table
->setObject( gIONameMatchedKey
, matched
);
3796 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
3799 const OSSymbol
* sym
;
3803 sym
= where
->copyLocation();
3805 match
= sym
->isEqualTo( str
);
3812 obj
= table
->getObject( gIOPropertyMatchKey
);
3815 OSDictionary
* dict
;
3816 OSDictionary
* nextDict
;
3821 dict
= where
->dictionaryWithProperties();
3823 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3827 iter
= OSCollectionIterator::withCollection(
3828 OSDynamicCast(OSCollection
, obj
));
3831 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3832 iter
->getNextObject()))))) {
3833 match
= dict
->isEqualTo( nextDict
, nextDict
);
3846 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3849 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3850 match
= (where
== entry
);
3857 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3861 IOService
* service
= 0;
3862 UInt32 serviceCount
= 0;
3865 iter
= where
->getClientIterator();
3867 while( (service
= (IOService
*) iter
->getNextObject())) {
3868 if( kIOServiceInactiveState
& service
->__state
[0])
3870 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3876 match
= (serviceCount
== num
->unsigned32BitValue());
3881 if( done
== table
->getCount()) {
3882 // don't call family if we've done all the entries in the table
3883 matchParent
= false;
3887 // pass in score from property table
3888 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3890 // do family specific matching
3891 match
= where
->matchPropertyTable( table
, &score
);
3895 if( kIOLogMatch
& getDebugFlags( table
))
3896 LOG("%s: family specific matching fails\n", where
->getName());
3903 newPri
= OSNumber::withNumber( score
, 32 );
3905 table
->setObject( gIOProbeScoreKey
, newPri
);
3910 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3913 matchParent
= false;
3915 obj
= OSDynamicCast( OSDictionary
,
3916 table
->getObject( gIOParentMatchKey
));
3920 table
= (OSDictionary
*) obj
;
3924 table
= OSDynamicCast( OSDictionary
,
3925 table
->getObject( gIOLocationMatchKey
));
3928 where
= where
->getProvider();
3930 where
= where
->matchLocation( where
);
3933 } while( table
&& where
);
3935 } while( matchParent
&& (where
= where
->getProvider()) );
3937 if( kIOLogMatch
& gIOKitDebug
)
3939 LOG("match parent @ %s = %d\n",
3940 where
->getName(), match
);
3946 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3947 UInt32 type
, OSDictionary
* properties
,
3948 IOUserClient
** handler
)
3950 const OSSymbol
*userClientClass
= 0;
3951 IOUserClient
*client
;
3954 // First try my own properties for a user client class name
3955 temp
= getProperty(gIOUserClientClassKey
);
3957 if (OSDynamicCast(OSSymbol
, temp
))
3958 userClientClass
= (const OSSymbol
*) temp
;
3959 else if (OSDynamicCast(OSString
, temp
)) {
3960 userClientClass
= OSSymbol::withString((OSString
*) temp
);
3961 if (userClientClass
)
3962 setProperty(kIOUserClientClassKey
,
3963 (OSObject
*) userClientClass
);
3967 // Didn't find one so lets just bomb out now without further ado.
3968 if (!userClientClass
)
3969 return kIOReturnUnsupported
;
3971 temp
= OSMetaClass::allocClassWithName(userClientClass
);
3973 return kIOReturnNoMemory
;
3975 if (OSDynamicCast(IOUserClient
, temp
))
3976 client
= (IOUserClient
*) temp
;
3979 return kIOReturnUnsupported
;
3982 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
3984 return kIOReturnBadArgument
;
3987 if ( !client
->attach(this) ) {
3989 return kIOReturnUnsupported
;
3992 if ( !client
->start(this) ) {
3993 client
->detach(this);
3995 return kIOReturnUnsupported
;
3999 return kIOReturnSuccess
;
4002 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4003 UInt32 type
, IOUserClient
** handler
)
4005 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
4008 IOReturn
IOService::requestProbe( IOOptionBits options
)
4010 return( kIOReturnUnsupported
);
4014 * Convert an IOReturn to text. Subclasses which add additional
4015 * IOReturn's should override this method and call
4016 * super::stringFromReturn if the desired value is not found.
4019 const char * IOService::stringFromReturn( IOReturn rtn
)
4021 static const IONamedValue IOReturn_values
[] = {
4022 {kIOReturnSuccess
, "success" },
4023 {kIOReturnError
, "general error" },
4024 {kIOReturnNoMemory
, "memory allocation error" },
4025 {kIOReturnNoResources
, "resource shortage" },
4026 {kIOReturnIPCError
, "Mach IPC failure" },
4027 {kIOReturnNoDevice
, "no such device" },
4028 {kIOReturnNotPrivileged
, "privilege violation" },
4029 {kIOReturnBadArgument
, "invalid argument" },
4030 {kIOReturnLockedRead
, "device is read locked" },
4031 {kIOReturnLockedWrite
, "device is write locked" },
4032 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4033 {kIOReturnBadMessageID
, "bad IPC message ID" },
4034 {kIOReturnUnsupported
, "unsupported function" },
4035 {kIOReturnVMError
, "virtual memory error" },
4036 {kIOReturnInternalError
, "internal driver error" },
4037 {kIOReturnIOError
, "I/O error" },
4038 {kIOReturnCannotLock
, "cannot acquire lock" },
4039 {kIOReturnNotOpen
, "device is not open" },
4040 {kIOReturnNotReadable
, "device is not readable" },
4041 {kIOReturnNotWritable
, "device is not writeable" },
4042 {kIOReturnNotAligned
, "alignment error" },
4043 {kIOReturnBadMedia
, "media error" },
4044 {kIOReturnStillOpen
, "device is still open" },
4045 {kIOReturnRLDError
, "rld failure" },
4046 {kIOReturnDMAError
, "DMA failure" },
4047 {kIOReturnBusy
, "device is busy" },
4048 {kIOReturnTimeout
, "I/O timeout" },
4049 {kIOReturnOffline
, "device is offline" },
4050 {kIOReturnNotReady
, "device is not ready" },
4051 {kIOReturnNotAttached
, "device/channel is not attached" },
4052 {kIOReturnNoChannels
, "no DMA channels available" },
4053 {kIOReturnNoSpace
, "no space for data" },
4054 {kIOReturnPortExists
, "device port already exists" },
4055 {kIOReturnCannotWire
, "cannot wire physical memory" },
4056 {kIOReturnNoInterrupt
, "no interrupt attached" },
4057 {kIOReturnNoFrames
, "no DMA frames enqueued" },
4058 {kIOReturnMessageTooLarge
, "message is too large" },
4059 {kIOReturnNotPermitted
, "operation is not permitted" },
4060 {kIOReturnNoPower
, "device is without power" },
4061 {kIOReturnNoMedia
, "media is not present" },
4062 {kIOReturnUnformattedMedia
, "media is not formatted" },
4063 {kIOReturnUnsupportedMode
, "unsupported mode" },
4064 {kIOReturnUnderrun
, "data underrun" },
4065 {kIOReturnOverrun
, "data overrun" },
4066 {kIOReturnDeviceError
, "device error" },
4067 {kIOReturnNoCompletion
, "no completion routine" },
4068 {kIOReturnAborted
, "operation was aborted" },
4069 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
4070 {kIOReturnNotResponding
, "device is not responding" },
4071 {kIOReturnInvalid
, "unanticipated driver error" },
4075 return IOFindNameForValue(rtn
, IOReturn_values
);
4079 * Convert an IOReturn to an errno.
4081 int IOService::errnoFromReturn( IOReturn rtn
)
4085 case kIOReturnSuccess
:
4087 case kIOReturnNoMemory
:
4089 case kIOReturnNoDevice
:
4091 case kIOReturnVMError
:
4093 case kIOReturnNotPermitted
:
4095 case kIOReturnNotPrivileged
:
4097 case kIOReturnIOError
:
4099 case kIOReturnNotWritable
:
4101 case kIOReturnBadArgument
:
4103 case kIOReturnUnsupported
:
4107 case kIOReturnNoPower
:
4109 case kIOReturnDeviceError
:
4111 case kIOReturnTimeout
:
4113 case kIOReturnMessageTooLarge
:
4115 case kIOReturnNoSpace
:
4117 case kIOReturnCannotLock
:
4121 case kIOReturnBadMessageID
:
4122 case kIOReturnNoCompletion
:
4123 case kIOReturnNotAligned
:
4125 case kIOReturnNotReady
:
4127 case kIOReturnRLDError
:
4129 case kIOReturnPortExists
:
4130 case kIOReturnStillOpen
:
4132 case kIOReturnExclusiveAccess
:
4133 case kIOReturnLockedRead
:
4134 case kIOReturnLockedWrite
:
4135 case kIOReturnNotAttached
:
4136 case kIOReturnNotOpen
:
4137 case kIOReturnNotReadable
:
4139 case kIOReturnCannotWire
:
4140 case kIOReturnNoResources
:
4142 case kIOReturnAborted
:
4143 case kIOReturnOffline
:
4144 case kIOReturnNotResponding
:
4146 case kIOReturnBadMedia
:
4147 case kIOReturnNoMedia
:
4148 case kIOReturnUnformattedMedia
:
4149 return(ENXIO
); // (media error)
4150 case kIOReturnDMAError
:
4151 case kIOReturnOverrun
:
4152 case kIOReturnUnderrun
:
4153 return(EIO
); // (transfer error)
4154 case kIOReturnNoBandwidth
:
4155 case kIOReturnNoChannels
:
4156 case kIOReturnNoFrames
:
4157 case kIOReturnNoInterrupt
:
4158 return(EIO
); // (hardware error)
4159 case kIOReturnError
:
4160 case kIOReturnInternalError
:
4161 case kIOReturnInvalid
:
4162 return(EIO
); // (generic error)
4163 case kIOReturnIPCError
:
4164 return(EIO
); // (ipc error)
4166 return(EIO
); // (all other errors)
4170 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4174 * Generic entry point for calls from the provider. A return value of
4175 * kIOReturnSuccess indicates that the message was received, and where
4176 * applicable, that it was successful.
4179 return kIOReturnUnsupported
;
4186 IOItemCount
IOService::getDeviceMemoryCount( void )
4191 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4193 count
= array
->getCount();
4200 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4203 IODeviceMemory
* range
;
4205 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4207 range
= (IODeviceMemory
*) array
->getObject( index
);
4214 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4215 IOOptionBits options
)
4217 IODeviceMemory
* range
;
4220 range
= getDeviceMemoryWithIndex( index
);
4222 map
= range
->map( options
);
4229 OSArray
* IOService::getDeviceMemory( void )
4231 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4235 void IOService::setDeviceMemory( OSArray
* array
)
4237 setProperty( gIODeviceMemoryKey
, array
);
4244 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4246 IOInterruptController
*interruptController
;
4249 OSSymbol
*interruptControllerName
;
4251 IOInterruptSource
*interruptSources
;
4253 // Get the parents list from the nub.
4254 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4255 if (array
== 0) return kIOReturnNoResources
;
4257 // Allocate space for the IOInterruptSources if needed... then return early.
4258 if (nub
->_interruptSources
== 0) {
4259 numSources
= array
->getCount();
4260 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4261 if (interruptSources
== 0) return kIOReturnNoMemory
;
4263 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4265 nub
->_numInterruptSources
= numSources
;
4266 nub
->_interruptSources
= interruptSources
;
4267 return kIOReturnSuccess
;
4270 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4271 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4273 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4274 if (interruptController
== 0) return kIOReturnNoResources
;
4276 // Get the interrupt numbers from the nub.
4277 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4278 if (array
== 0) return kIOReturnNoResources
;
4279 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4280 if (data
== 0) return kIOReturnNoResources
;
4282 // Set the interruptController and interruptSource in the nub's table.
4283 interruptSources
= nub
->_interruptSources
;
4284 interruptSources
[source
].interruptController
= interruptController
;
4285 interruptSources
[source
].vectorData
= data
;
4287 return kIOReturnSuccess
;
4290 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4294 /* Make sure the _interruptSources are set */
4295 if (_interruptSources
== 0) {
4296 ret
= resolveInterrupt(this, source
);
4297 if (ret
!= kIOReturnSuccess
) return ret
;
4300 /* Make sure the local source number is valid */
4301 if ((source
< 0) || (source
>= _numInterruptSources
))
4302 return kIOReturnNoInterrupt
;
4304 /* Look up the contoller for the local source */
4305 *interruptController
= _interruptSources
[source
].interruptController
;
4307 if (*interruptController
== NULL
) {
4308 if (!resolve
) return kIOReturnNoInterrupt
;
4310 /* Try to reslove the interrupt */
4311 ret
= resolveInterrupt(this, source
);
4312 if (ret
!= kIOReturnSuccess
) return ret
;
4314 *interruptController
= _interruptSources
[source
].interruptController
;
4317 return kIOReturnSuccess
;
4320 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4321 IOInterruptAction handler
,
4324 IOInterruptController
*interruptController
;
4327 ret
= lookupInterrupt(source
, true, &interruptController
);
4328 if (ret
!= kIOReturnSuccess
) return ret
;
4330 /* Register the source */
4331 return interruptController
->registerInterrupt(this, source
, target
,
4332 (IOInterruptHandler
)handler
,
4336 IOReturn
IOService::unregisterInterrupt(int source
)
4338 IOInterruptController
*interruptController
;
4341 ret
= lookupInterrupt(source
, false, &interruptController
);
4342 if (ret
!= kIOReturnSuccess
) return ret
;
4344 /* Unregister the source */
4345 return interruptController
->unregisterInterrupt(this, source
);
4348 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4350 IOInterruptController
*interruptController
;
4353 ret
= lookupInterrupt(source
, true, &interruptController
);
4354 if (ret
!= kIOReturnSuccess
) return ret
;
4356 /* Return the type */
4357 return interruptController
->getInterruptType(this, source
, interruptType
);
4360 IOReturn
IOService::enableInterrupt(int source
)
4362 IOInterruptController
*interruptController
;
4365 ret
= lookupInterrupt(source
, false, &interruptController
);
4366 if (ret
!= kIOReturnSuccess
) return ret
;
4368 /* Enable the source */
4369 return interruptController
->enableInterrupt(this, source
);
4372 IOReturn
IOService::disableInterrupt(int source
)
4374 IOInterruptController
*interruptController
;
4377 ret
= lookupInterrupt(source
, false, &interruptController
);
4378 if (ret
!= kIOReturnSuccess
) return ret
;
4380 /* Disable the source */
4381 return interruptController
->disableInterrupt(this, source
);
4384 IOReturn
IOService::causeInterrupt(int source
)
4386 IOInterruptController
*interruptController
;
4389 ret
= lookupInterrupt(source
, false, &interruptController
);
4390 if (ret
!= kIOReturnSuccess
) return ret
;
4392 /* Cause an interrupt for the source */
4393 return interruptController
->causeInterrupt(this, source
);
4396 OSMetaClassDefineReservedUsed(IOService
, 0);
4397 OSMetaClassDefineReservedUsed(IOService
, 1);
4398 OSMetaClassDefineReservedUsed(IOService
, 2);
4400 OSMetaClassDefineReservedUnused(IOService
, 3);
4401 OSMetaClassDefineReservedUnused(IOService
, 4);
4402 OSMetaClassDefineReservedUnused(IOService
, 5);
4403 OSMetaClassDefineReservedUnused(IOService
, 6);
4404 OSMetaClassDefineReservedUnused(IOService
, 7);
4405 OSMetaClassDefineReservedUnused(IOService
, 8);
4406 OSMetaClassDefineReservedUnused(IOService
, 9);
4407 OSMetaClassDefineReservedUnused(IOService
, 10);
4408 OSMetaClassDefineReservedUnused(IOService
, 11);
4409 OSMetaClassDefineReservedUnused(IOService
, 12);
4410 OSMetaClassDefineReservedUnused(IOService
, 13);
4411 OSMetaClassDefineReservedUnused(IOService
, 14);
4412 OSMetaClassDefineReservedUnused(IOService
, 15);
4413 OSMetaClassDefineReservedUnused(IOService
, 16);
4414 OSMetaClassDefineReservedUnused(IOService
, 17);
4415 OSMetaClassDefineReservedUnused(IOService
, 18);
4416 OSMetaClassDefineReservedUnused(IOService
, 19);
4417 OSMetaClassDefineReservedUnused(IOService
, 20);
4418 OSMetaClassDefineReservedUnused(IOService
, 21);
4419 OSMetaClassDefineReservedUnused(IOService
, 22);
4420 OSMetaClassDefineReservedUnused(IOService
, 23);
4421 OSMetaClassDefineReservedUnused(IOService
, 24);
4422 OSMetaClassDefineReservedUnused(IOService
, 25);
4423 OSMetaClassDefineReservedUnused(IOService
, 26);
4424 OSMetaClassDefineReservedUnused(IOService
, 27);
4425 OSMetaClassDefineReservedUnused(IOService
, 28);
4426 OSMetaClassDefineReservedUnused(IOService
, 29);
4427 OSMetaClassDefineReservedUnused(IOService
, 30);
4428 OSMetaClassDefineReservedUnused(IOService
, 31);
4429 OSMetaClassDefineReservedUnused(IOService
, 32);
4430 OSMetaClassDefineReservedUnused(IOService
, 33);
4431 OSMetaClassDefineReservedUnused(IOService
, 34);
4432 OSMetaClassDefineReservedUnused(IOService
, 35);
4433 OSMetaClassDefineReservedUnused(IOService
, 36);
4434 OSMetaClassDefineReservedUnused(IOService
, 37);
4435 OSMetaClassDefineReservedUnused(IOService
, 38);
4436 OSMetaClassDefineReservedUnused(IOService
, 39);
4437 OSMetaClassDefineReservedUnused(IOService
, 40);
4438 OSMetaClassDefineReservedUnused(IOService
, 41);
4439 OSMetaClassDefineReservedUnused(IOService
, 42);
4440 OSMetaClassDefineReservedUnused(IOService
, 43);
4441 OSMetaClassDefineReservedUnused(IOService
, 44);
4442 OSMetaClassDefineReservedUnused(IOService
, 45);
4443 OSMetaClassDefineReservedUnused(IOService
, 46);
4444 OSMetaClassDefineReservedUnused(IOService
, 47);
4445 OSMetaClassDefineReservedUnused(IOService
, 48);
4446 OSMetaClassDefineReservedUnused(IOService
, 49);
4447 OSMetaClassDefineReservedUnused(IOService
, 50);
4448 OSMetaClassDefineReservedUnused(IOService
, 51);
4449 OSMetaClassDefineReservedUnused(IOService
, 52);
4450 OSMetaClassDefineReservedUnused(IOService
, 53);
4451 OSMetaClassDefineReservedUnused(IOService
, 54);
4452 OSMetaClassDefineReservedUnused(IOService
, 55);
4453 OSMetaClassDefineReservedUnused(IOService
, 56);
4454 OSMetaClassDefineReservedUnused(IOService
, 57);
4455 OSMetaClassDefineReservedUnused(IOService
, 58);
4456 OSMetaClassDefineReservedUnused(IOService
, 59);
4457 OSMetaClassDefineReservedUnused(IOService
, 60);
4458 OSMetaClassDefineReservedUnused(IOService
, 61);
4459 OSMetaClassDefineReservedUnused(IOService
, 62);
4460 OSMetaClassDefineReservedUnused(IOService
, 63);