2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991-1999 Apple Computer, Inc. All rights reserved.
27 * 29-Jan-91 Portions from IODevice.m, Doug Mitchell at NeXT, Created.
28 * 18-Jun-98 start IOKit objc
29 * 10-Nov-98 start iokit cpp
30 * 25-Feb-99 sdouglas, add threads and locks to ensure deadlock
34 #include <IOKit/system.h>
36 #include <IOKit/IOService.h>
37 #include <libkern/c++/OSContainers.h>
38 #include <libkern/c++/OSUnserialize.h>
39 #include <IOKit/IOCatalogue.h>
40 #include <IOKit/IODeviceMemory.h>
41 #include <IOKit/IOInterrupts.h>
42 #include <IOKit/IOInterruptController.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/IOMessage.h>
45 #include <IOKit/IOLib.h>
46 #include <IOKit/IOKitKeys.h>
47 #include <IOKit/IOBSD.h>
48 #include <IOKit/IOUserClient.h>
49 #include <IOKit/IOWorkLoop.h>
50 #include <mach/sync_policy.h>
51 #include <IOKit/assert.h>
52 #include <sys/errno.h>
57 #include "IOServicePrivate.h"
59 // take lockForArbitration before LOCKNOTIFY
61 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
63 #define super IORegistryEntry
65 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
67 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
69 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
71 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
73 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
75 OSDefineMetaClassAndStructors(IOResources
, IOService
)
77 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
79 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
81 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
83 static IOPlatformExpert
* gIOPlatform
;
84 static class IOPMrootDomain
* gIOPMRootDomain
;
85 const IORegistryPlane
* gIOServicePlane
;
86 const IORegistryPlane
* gIOPowerPlane
;
87 const OSSymbol
* gIODeviceMemoryKey
;
88 const OSSymbol
* gIOInterruptControllersKey
;
89 const OSSymbol
* gIOInterruptSpecifiersKey
;
91 const OSSymbol
* gIOResourcesKey
;
92 const OSSymbol
* gIOResourceMatchKey
;
93 const OSSymbol
* gIOProviderClassKey
;
94 const OSSymbol
* gIONameMatchKey
;
95 const OSSymbol
* gIONameMatchedKey
;
96 const OSSymbol
* gIOPropertyMatchKey
;
97 const OSSymbol
* gIOLocationMatchKey
;
98 const OSSymbol
* gIOPathMatchKey
;
99 const OSSymbol
* gIOMatchCategoryKey
;
100 const OSSymbol
* gIODefaultMatchCategoryKey
;
101 const OSSymbol
* gIOMatchedServiceCountKey
;
103 const OSSymbol
* gIOUserClientClassKey
;
104 const OSSymbol
* gIOKitDebugKey
;
106 const OSSymbol
* gIOCommandPoolSizeKey
;
108 static int gIOResourceGenerationCount
;
110 const OSSymbol
* gIOServiceKey
;
111 const OSSymbol
* gIOPublishNotification
;
112 const OSSymbol
* gIOFirstPublishNotification
;
113 const OSSymbol
* gIOMatchedNotification
;
114 const OSSymbol
* gIOFirstMatchNotification
;
115 const OSSymbol
* gIOTerminatedNotification
;
117 const OSSymbol
* gIOGeneralInterest
;
118 const OSSymbol
* gIOBusyInterest
;
119 const OSSymbol
* gIOAppPowerStateInterest
;
120 const OSSymbol
* gIOPriorityPowerStateInterest
;
122 static OSDictionary
* gNotifications
;
123 static IORecursiveLock
* gNotificationLock
;
125 static IOService
* gIOResources
;
126 static IOService
* gIOServiceRoot
;
128 static OSOrderedSet
* gJobs
;
129 static semaphore_port_t gJobsSemaphore
;
130 static IOLock
* gJobsLock
;
131 static int gOutstandingJobs
;
132 static int gNumConfigThreads
;
133 static int gNumWaitingThreads
;
134 static IOLock
* gIOServiceBusyLock
;
136 static thread_t gIOTerminateThread
;
137 static UInt32 gIOTerminateWork
;
138 static OSArray
* gIOTerminatePhase2List
;
139 static OSArray
* gIOStopList
;
140 static OSArray
* gIOStopProviderList
;
141 static OSArray
* gIOFinalizeList
;
143 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
145 #define LOCKREADNOTIFY() \
146 IORecursiveLockLock( gNotificationLock )
147 #define LOCKWRITENOTIFY() \
148 IORecursiveLockLock( gNotificationLock )
149 #define LOCKWRITE2READNOTIFY()
150 #define UNLOCKNOTIFY() \
151 IORecursiveLockUnlock( gNotificationLock )
153 #define randomDelay() \
154 int del = read_processor_clock(); \
155 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
158 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
160 struct ArbitrationLockQueueElement
{
169 static queue_head_t gArbitrationLockQueueActive
;
170 static queue_head_t gArbitrationLockQueueWaiting
;
171 static queue_head_t gArbitrationLockQueueFree
;
172 static IOLock
* gArbitrationLockQueueLock
;
174 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
176 void IOService::initialize( void )
180 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
181 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
183 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
184 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
185 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
186 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
187 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
188 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
190 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
191 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
192 kIODefaultMatchCategoryKey
);
193 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
194 kIOMatchedServiceCountKey
);
196 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
198 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
199 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
201 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
202 gIOInterruptControllersKey
203 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
204 gIOInterruptSpecifiersKey
205 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
207 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
209 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
211 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
212 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
213 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
214 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
216 gNotifications
= OSDictionary::withCapacity( 1 );
217 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
218 kIOPublishNotification
);
219 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
220 kIOFirstPublishNotification
);
221 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
222 kIOMatchedNotification
);
223 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
224 kIOFirstMatchNotification
);
225 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
226 kIOTerminatedNotification
);
227 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
229 gNotificationLock
= IORecursiveLockAlloc();
231 assert( gIOServicePlane
&& gIODeviceMemoryKey
232 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
233 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
234 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
235 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
236 && gIOPublishNotification
&& gIOMatchedNotification
237 && gIOTerminatedNotification
&& gIOServiceKey
);
239 gJobsLock
= IOLockAlloc();
240 gJobs
= OSOrderedSet::withCapacity( 10 );
242 gIOServiceBusyLock
= IOLockAlloc();
244 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
246 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& (err
== KERN_SUCCESS
) );
248 gIOResources
= IOResources::resources();
249 assert( gIOResources
);
251 gArbitrationLockQueueLock
= IOLockAlloc();
252 queue_init(&gArbitrationLockQueueActive
);
253 queue_init(&gArbitrationLockQueueWaiting
);
254 queue_init(&gArbitrationLockQueueFree
);
256 assert( gArbitrationLockQueueLock
);
258 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
259 gIOStopList
= OSArray::withCapacity( 16 );
260 gIOStopProviderList
= OSArray::withCapacity( 16 );
261 gIOFinalizeList
= OSArray::withCapacity( 16 );
262 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
265 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
268 static UInt64
getDebugFlags( OSDictionary
* props
)
270 OSNumber
* debugProp
;
273 debugProp
= OSDynamicCast( OSNumber
,
274 props
->getObject( gIOKitDebugKey
));
276 debugFlags
= debugProp
->unsigned64BitValue();
278 debugFlags
= gIOKitDebug
;
280 return( debugFlags
);
284 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
286 // Probe a matched service and return an instance to be started.
287 // The default score is from the property table, & may be altered
288 // during probe to change the start order.
290 IOService
* IOService::probe( IOService
* provider
,
296 bool IOService::start( IOService
* provider
)
301 void IOService::stop( IOService
* provider
)
305 void IOService::free( void )
307 if( getPropertyTable())
308 unregisterAllInterest();
314 * Attach in service plane
316 bool IOService::attach( IOService
* provider
)
322 if( gIOKitDebug
& kIOLogAttach
)
323 LOG( "%s::attach(%s)\n", getName(),
324 provider
->getName());
326 provider
->lockForArbitration();
327 if( provider
->__state
[0] & kIOServiceInactiveState
)
330 ok
= attachToParent( provider
, gIOServicePlane
);
331 provider
->unlockForArbitration();
334 gIOServiceRoot
= this;
335 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
341 IOService
* IOService::getServiceRoot( void )
343 return( gIOServiceRoot
);
346 void IOService::detach( IOService
* provider
)
348 IOService
* newProvider
= 0;
352 if( gIOKitDebug
& kIOLogAttach
)
353 LOG("%s::detach(%s)\n", getName(), provider
->getName());
355 lockForArbitration();
357 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
358 && (provider
== getProvider()));
360 detachFromParent( provider
, gIOServicePlane
);
363 newProvider
= getProvider();
364 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
365 _adjustBusy( -busy
);
368 unlockForArbitration();
371 newProvider
->lockForArbitration();
372 newProvider
->_adjustBusy(1);
373 newProvider
->unlockForArbitration();
376 // check for last client detach from a terminated service
377 if( provider
->lockForArbitration( true )) {
379 provider
->_adjustBusy( -1 );
380 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
381 && (0 == provider
->getClient())) {
382 provider
->scheduleFinalize();
384 provider
->unlockForArbitration();
389 * Register instance - publish it for matching
392 void IOService::registerService( IOOptionBits options
= 0 )
398 enum { kMaxPathLen
= 256 };
399 enum { kMaxChars
= 63 };
401 IORegistryEntry
* parent
= this;
402 IORegistryEntry
* root
= getRegistryRoot();
403 while( parent
&& (parent
!= root
))
404 parent
= parent
->getParentEntry( gIOServicePlane
);
406 if( parent
!= root
) {
407 IOLog("%s: not registry member at registerService()\n", getName());
411 // Allow the Platform Expert to adjust this node.
412 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
415 if( (this != gIOResources
)
416 && (kIOLogRegister
& gIOKitDebug
)) {
418 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
420 IOLog( "Registering: " );
423 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
426 if( len
> kMaxChars
) {
430 if( (skip
= strchr( path
, '/')))
436 IOLog( "%s\n", path
);
439 IOFree( pathBuf
, kMaxPathLen
);
442 startMatching( options
);
445 void IOService::startMatching( IOOptionBits options
= 0 )
447 IOService
* provider
;
450 bool needWake
= false;
455 lockForArbitration();
457 sync
= (options
& kIOServiceSynchronous
)
458 || ((provider
= getProvider())
459 && (provider
->__state
[1] & kIOServiceSynchronousState
));
462 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
463 && (0 == (__state
[0] & kIOServiceInactiveState
));
465 __state
[1] |= kIOServiceNeedConfigState
;
467 // __state[0] &= ~kIOServiceInactiveState;
469 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
470 // OSKernelStackRemaining(), getName());
473 prevBusy
= _adjustBusy( 1 );
474 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
478 __state
[1] |= kIOServiceSynchronousState
;
480 __state
[1] &= ~kIOServiceSynchronousState
;
482 unlockForArbitration();
487 IOLockLock( gIOServiceBusyLock
);
488 thread_wakeup( (event_t
) this/*&__state[1]*/ );
489 IOLockUnlock( gIOServiceBusyLock
);
491 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
493 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
497 if( (__state
[1] & kIOServiceNeedConfigState
))
498 doServiceMatch( options
);
500 lockForArbitration();
501 IOLockLock( gIOServiceBusyLock
);
503 waitAgain
= (prevBusy
!= (__state
[1] & kIOServiceBusyStateMask
));
505 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
507 __state
[1] &= ~kIOServiceSyncPubState
;
509 unlockForArbitration();
512 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
514 IOLockUnlock( gIOServiceBusyLock
);
516 thread_block((void (*)(void)) 0);
518 } while( waitAgain
);
522 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
524 OSDictionary
* table
;
533 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
536 iter
= (OSIterator
*) getExistingServices( table
,
537 kIOServiceRegisteredState
);
540 while( (service
= (IOService
*) iter
->getNextObject())) {
541 service
->startMatching(kIOServiceAsynchronous
);
549 if( getDebugFlags( table
) & kIOLogMatch
)
550 LOG("Matching service count = %ld\n", count
);
552 newTables
->removeObject(table
);
555 newTables
->release();
557 return( kIOReturnSuccess
);
560 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
561 IOOptionBits options
= 0 )
565 job
= new _IOServiceJob
;
566 if( job
&& !job
->init()) {
574 job
->options
= options
;
575 nub
->retain(); // thread will release()
583 * Called on a registered service to see if it matches
587 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
589 return( matchPropertyTable(table
) );
592 bool IOService::matchPropertyTable( OSDictionary
* table
)
598 * Called on a matched service to allocate resources
599 * before first driver is attached.
602 IOReturn
IOService::getResources( void )
604 return( kIOReturnSuccess
);
608 * Client/provider accessors
611 IOService
* IOService::getProvider( void ) const
613 IOService
* self
= (IOService
*) this;
618 generation
= getGenerationCount();
619 if( __providerGeneration
== generation
)
622 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
623 if( parent
== IORegistryEntry::getRegistryRoot())
624 /* root is not an IOService */
627 self
->__provider
= parent
;
628 // save the count before getParentEntry()
629 self
->__providerGeneration
= generation
;
634 IOWorkLoop
* IOService::getWorkLoop() const
636 IOService
*provider
= getProvider();
639 return provider
->getWorkLoop();
644 OSIterator
* IOService::getProviderIterator( void ) const
646 return( getParentIterator( gIOServicePlane
));
649 IOService
* IOService::getClient( void ) const
651 return( (IOService
*) getChildEntry( gIOServicePlane
));
654 OSIterator
* IOService::getClientIterator( void ) const
656 return( getChildIterator( gIOServicePlane
));
659 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
660 const IOService
* client
,
661 const IOService
* provider
)
663 _IOOpenServiceIterator
* inst
;
668 inst
= new _IOOpenServiceIterator
;
670 if( inst
&& !inst
->init()) {
676 inst
->client
= client
;
677 inst
->provider
= provider
;
683 void _IOOpenServiceIterator::free()
687 last
->unlockForArbitration();
691 OSObject
* _IOOpenServiceIterator::getNextObject()
696 last
->unlockForArbitration();
698 while( (next
= (IOService
*) iter
->getNextObject())) {
700 next
->lockForArbitration();
701 if( (client
&& (next
->isOpen( client
)))
702 || (provider
&& (provider
->isOpen( next
))) )
704 next
->unlockForArbitration();
712 bool _IOOpenServiceIterator::isValid()
714 return( iter
->isValid() );
717 void _IOOpenServiceIterator::reset()
720 last
->unlockForArbitration();
726 OSIterator
* IOService::getOpenProviderIterator( void ) const
728 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
731 OSIterator
* IOService::getOpenClientIterator( void ) const
733 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
737 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
738 bool waitForFunction
,
739 void *param1
, void *param2
,
740 void *param3
, void *param4
)
742 IOReturn result
= kIOReturnUnsupported
;
743 IOService
*provider
= getProvider();
746 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
747 param1
, param2
, param3
, param4
);
753 IOReturn
IOService::callPlatformFunction( const char * functionName
,
754 bool waitForFunction
,
755 void *param1
, void *param2
,
756 void *param3
, void *param4
)
758 IOReturn result
= kIOReturnNoMemory
;
759 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
761 if (functionSymbol
!= 0) {
762 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
763 param1
, param2
, param3
, param4
);
764 functionSymbol
->release();
772 * Accessors for global services
775 IOPlatformExpert
* IOService::getPlatform( void )
777 return( gIOPlatform
);
780 class IOPMrootDomain
* IOService::getPMRootDomain( void )
782 return( gIOPMRootDomain
);
785 IOService
* IOService::getResourceService( void )
787 return( gIOResources
);
790 void IOService::setPlatform( IOPlatformExpert
* platform
)
792 gIOPlatform
= platform
;
793 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
796 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
798 gIOPMRootDomain
= rootDomain
;
799 publishResource("IOKit");
806 bool IOService::lockForArbitration( bool isSuccessRequired
= true )
810 ArbitrationLockQueueElement
* element
;
811 ArbitrationLockQueueElement
* active
;
812 ArbitrationLockQueueElement
* waiting
;
814 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
816 // lock global access
817 IOTakeLock( gArbitrationLockQueueLock
);
819 // obtain an unused queue element
820 if( !queue_empty( &gArbitrationLockQueueFree
)) {
821 queue_remove_first( &gArbitrationLockQueueFree
,
823 ArbitrationLockQueueElement
*,
826 element
= IONew( ArbitrationLockQueueElement
, 1 );
830 // prepare the queue element
831 element
->thread
= IOThreadSelf();
832 element
->service
= this;
834 element
->required
= isSuccessRequired
;
835 element
->aborted
= false;
837 // determine whether this object is already locked (ie. on active queue)
839 queue_iterate( &gArbitrationLockQueueActive
,
841 ArbitrationLockQueueElement
*,
844 if( active
->service
== element
->service
) {
850 if( found
) { // this object is already locked
852 // determine whether it is the same or a different thread trying to lock
853 if( active
->thread
!= element
->thread
) { // it is a different thread
855 ArbitrationLockQueueElement
* victim
= 0;
857 // before placing this new thread on the waiting queue, we look for
858 // a deadlock cycle...
861 // determine whether the active thread holding the object we
862 // want is waiting for another object to be unlocked
864 queue_iterate( &gArbitrationLockQueueWaiting
,
866 ArbitrationLockQueueElement
*,
869 if( waiting
->thread
== active
->thread
) {
870 assert( false == waiting
->aborted
);
876 if( found
) { // yes, active thread waiting for another object
878 // this may be a candidate for rejection if the required
879 // flag is not set, should we detect a deadlock later on
880 if( false == waiting
->required
)
883 // find the thread that is holding this other object, that
884 // is blocking the active thread from proceeding (fun :-)
886 queue_iterate( &gArbitrationLockQueueActive
,
887 active
, // (reuse active queue element)
888 ArbitrationLockQueueElement
*,
891 if( active
->service
== waiting
->service
) {
897 // someone must be holding it or it wouldn't be waiting
900 if( active
->thread
== element
->thread
) {
902 // doh, it's waiting for the thread that originated
903 // this whole lock (ie. current thread) -> deadlock
904 if( false == element
->required
) { // willing to fail?
906 // the originating thread doesn't have the required
907 // flag, so it can fail
908 success
= false; // (fail originating lock request)
909 break; // (out of while)
911 } else { // originating thread is not willing to fail
913 // see if we came across a waiting thread that did
914 // not have the 'required' flag set: we'll fail it
917 // we do have a willing victim, fail it's lock
918 victim
->aborted
= true;
920 // take the victim off the waiting queue
921 queue_remove( &gArbitrationLockQueueWaiting
,
923 ArbitrationLockQueueElement
*,
927 thread_wakeup_one(victim
);
929 // allow this thread to proceed (ie. wait)
930 success
= true; // (put request on wait queue)
931 break; // (out of while)
934 // all the waiting threads we came across in
935 // finding this loop had the 'required' flag
936 // set, so we've got a deadlock we can't avoid
937 panic("I/O Kit: Unrecoverable deadlock.");
941 // repeat while loop, redefining active thread to be the
942 // thread holding "this other object" (see above), and
943 // looking for threads waiting on it; note the active
944 // variable points to "this other object" already... so
945 // there nothing to do in this else clause.
947 } else { // no, active thread is not waiting for another object
949 success
= true; // (put request on wait queue)
950 break; // (out of while)
954 if( success
) { // put the request on the waiting queue?
955 kern_return_t wait_result
;
957 // place this thread on the waiting queue and put it to sleep;
958 // we place it at the tail of the queue...
959 queue_enter( &gArbitrationLockQueueWaiting
,
961 ArbitrationLockQueueElement
*,
964 // declare that this thread will wait for a given event
965 restart_sleep
: assert_wait( element
,
966 element
->required
? THREAD_UNINT
967 : THREAD_INTERRUPTIBLE
);
969 // unlock global access
970 IOUnlock( gArbitrationLockQueueLock
);
972 // put thread to sleep, waiting for our event to fire...
973 wait_result
= thread_block((void (*)(void)) 0);
975 // ...and we've been woken up; we might be in one of two states:
976 // (a) we've been aborted and our queue element is not on
977 // any of the three queues, but is floating around
978 // (b) we're allowed to proceed with the lock and we have
979 // already been moved from the waiting queue to the
981 // ...plus a 3rd state, should the thread have been interrupted:
982 // (c) we're still on the waiting queue
984 // determine whether we were interrupted out of our sleep
985 if( THREAD_INTERRUPTED
== wait_result
) {
987 // re-lock global access
988 IOTakeLock( gArbitrationLockQueueLock
);
990 // determine whether we're still on the waiting queue
992 queue_iterate( &gArbitrationLockQueueWaiting
,
993 waiting
, // (reuse waiting queue element)
994 ArbitrationLockQueueElement
*,
997 if( waiting
== element
) {
1003 if( found
) { // yes, we're still on the waiting queue
1005 // determine whether we're willing to fail
1006 if( false == element
->required
) {
1008 // mark us as aborted
1009 element
->aborted
= true;
1011 // take us off the waiting queue
1012 queue_remove( &gArbitrationLockQueueWaiting
,
1014 ArbitrationLockQueueElement
*,
1016 } else { // we are not willing to fail
1018 // ignore interruption, go back to sleep
1023 // unlock global access
1024 IOUnlock( gArbitrationLockQueueLock
);
1026 // proceed as though this were a normal wake up
1027 wait_result
= THREAD_AWAKENED
;
1030 assert( THREAD_AWAKENED
== wait_result
);
1032 // determine whether we've been aborted while we were asleep
1033 if( element
->aborted
) {
1034 assert( false == element
->required
);
1036 // re-lock global access
1037 IOTakeLock( gArbitrationLockQueueLock
);
1039 action
= kPutOnFreeQueue
;
1041 } else { // we weren't aborted, so we must be ready to go :-)
1043 // we've already been moved from waiting to active queue
1047 } else { // the lock request is to be failed
1049 // return unused queue element to queue
1050 action
= kPutOnFreeQueue
;
1052 } else { // it is the same thread, recursive access is allowed
1054 // add one level of recursion
1057 // return unused queue element to queue
1058 action
= kPutOnFreeQueue
;
1061 } else { // this object is not already locked, so let this thread through
1062 action
= kPutOnActiveQueue
;
1066 // put the new element on a queue
1067 if( kPutOnActiveQueue
== action
) {
1068 queue_enter( &gArbitrationLockQueueActive
,
1070 ArbitrationLockQueueElement
*,
1072 } else if( kPutOnFreeQueue
== action
) {
1073 queue_enter( &gArbitrationLockQueueFree
,
1075 ArbitrationLockQueueElement
*,
1078 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1081 // unlock global access
1082 IOUnlock( gArbitrationLockQueueLock
);
1087 void IOService::unlockForArbitration( void )
1090 ArbitrationLockQueueElement
* element
;
1092 // lock global access
1093 IOTakeLock( gArbitrationLockQueueLock
);
1095 // find the lock element for this object (ie. on active queue)
1097 queue_iterate( &gArbitrationLockQueueActive
,
1099 ArbitrationLockQueueElement
*,
1102 if( element
->service
== this ) {
1110 // determine whether the lock has been taken recursively
1111 if( element
->count
> 1 ) {
1112 // undo one level of recursion
1117 // remove it from the active queue
1118 queue_remove( &gArbitrationLockQueueActive
,
1120 ArbitrationLockQueueElement
*,
1123 // put it on the free queue
1124 queue_enter( &gArbitrationLockQueueFree
,
1126 ArbitrationLockQueueElement
*,
1129 // determine whether a thread is waiting for object (head to tail scan)
1131 queue_iterate( &gArbitrationLockQueueWaiting
,
1133 ArbitrationLockQueueElement
*,
1136 if( element
->service
== this ) {
1142 if ( found
) { // we found an interested thread on waiting queue
1144 // remove it from the waiting queue
1145 queue_remove( &gArbitrationLockQueueWaiting
,
1147 ArbitrationLockQueueElement
*,
1150 // put it on the active queue
1151 queue_enter( &gArbitrationLockQueueActive
,
1153 ArbitrationLockQueueElement
*,
1156 // wake the waiting thread
1157 thread_wakeup_one(element
);
1161 // unlock global access
1162 IOUnlock( gArbitrationLockQueueLock
);
1165 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1168 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1169 context
, gIOServicePlane
);
1172 void IOService::applyToClients( IOServiceApplierFunction applier
,
1175 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1176 context
, gIOServicePlane
);
1185 // send a message to a client or interested party of this service
1186 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1187 void * argument
= 0, vm_size_t argSize
= 0 )
1190 IOService
* service
;
1191 _IOServiceInterestNotifier
* notify
;
1193 if( (service
= OSDynamicCast( IOService
, client
)))
1194 ret
= service
->message( type
, this, argument
);
1196 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1198 _IOServiceNotifierInvocation invocation
;
1201 invocation
.thread
= current_thread();
1204 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1207 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1208 _IOServiceNotifierInvocation
*, link
);
1214 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1215 type
, this, argument
, argSize
);
1218 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1219 _IOServiceNotifierInvocation
*, link
);
1220 if( kIOServiceNotifyWaiter
& notify
->state
) {
1221 notify
->state
&= ~kIOServiceNotifyWaiter
;
1222 thread_wakeup( (event_t
) notify
);
1227 ret
= kIOReturnSuccess
;
1230 ret
= kIOReturnBadArgument
;
1235 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1236 OSObjectApplierFunction applier
,
1242 OSArray
* copyArray
;
1244 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1247 array
= OSDynamicCast( OSArray
, getProperty( typeOfInterest
));
1249 copyArray
= OSArray::withArray( array
);
1253 (next
= array
->getObject( index
));
1255 (*applier
)(next
, context
);
1257 copyArray
->release();
1263 struct MessageClientsContext
{
1264 IOService
* service
;
1271 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1274 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1276 ret
= context
->service
->messageClient( context
->type
,
1277 object
, context
->argument
, context
->argSize
);
1278 if( kIOReturnSuccess
!= ret
)
1282 // send a message to all clients
1283 IOReturn
IOService::messageClients( UInt32 type
,
1284 void * argument
= 0, vm_size_t argSize
= 0 )
1286 MessageClientsContext context
;
1288 context
.service
= this;
1289 context
.type
= type
;
1290 context
.argument
= argument
;
1291 context
.argSize
= argSize
;
1292 context
.ret
= kIOReturnSuccess
;
1294 applyToInterested( gIOGeneralInterest
,
1295 &messageClientsApplier
, &context
);
1297 return( context
.ret
);
1300 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1301 IOOptionBits response
)
1303 return( kIOReturnUnsupported
);
1306 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1307 IOServiceInterestHandler handler
, void * target
, void * ref
)
1309 _IOServiceInterestNotifier
* notify
= 0;
1312 if( (typeOfInterest
!= gIOGeneralInterest
)
1313 && (typeOfInterest
!= gIOBusyInterest
)
1314 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1315 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1318 lockForArbitration();
1319 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1321 notify
= new _IOServiceInterestNotifier
;
1322 if( notify
&& !notify
->init()) {
1328 notify
->handler
= handler
;
1329 notify
->target
= target
;
1331 notify
->state
= kIOServiceNotifyEnable
;
1332 queue_init( ¬ify
->handlerInvocations
);
1337 if( 0 == (set
= (OSArray
*) getProperty( typeOfInterest
))) {
1338 set
= OSArray::withCapacity( 1 );
1340 setProperty( typeOfInterest
, set
);
1344 notify
->whence
= set
;
1346 set
->setObject( notify
);
1350 unlockForArbitration();
1355 static void cleanInterestArray( OSObject
* object
)
1359 _IOServiceInterestNotifier
* next
;
1361 if( (array
= OSDynamicCast( OSArray
, object
))) {
1364 (next
= (_IOServiceInterestNotifier
*)
1365 array
->getObject( index
));
1373 void IOService::unregisterAllInterest( void )
1375 cleanInterestArray( getProperty( gIOGeneralInterest
));
1376 cleanInterestArray( getProperty( gIOBusyInterest
));
1377 cleanInterestArray( getProperty( gIOAppPowerStateInterest
));
1378 cleanInterestArray( getProperty( gIOPriorityPowerStateInterest
));
1382 * _IOServiceInterestNotifier
1385 // wait for all threads, other than the current one,
1386 // to exit the handler
1388 void _IOServiceInterestNotifier::wait()
1390 _IOServiceNotifierInvocation
* next
;
1395 queue_iterate( &handlerInvocations
, next
,
1396 _IOServiceNotifierInvocation
*, link
) {
1397 if( next
->thread
!= current_thread() ) {
1403 state
|= kIOServiceNotifyWaiter
;
1404 assert_wait( this, THREAD_UNINT
);
1406 thread_block((void (*)(void)) 0);
1413 void _IOServiceInterestNotifier::free()
1415 assert( queue_empty( &handlerInvocations
));
1419 void _IOServiceInterestNotifier::remove()
1424 whence
->removeObject(whence
->getNextIndexOfObject(
1425 (OSObject
*) this, 0 ));
1429 state
&= ~kIOServiceNotifyEnable
;
1438 bool _IOServiceInterestNotifier::disable()
1444 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1445 state
&= ~kIOServiceNotifyEnable
;
1454 void _IOServiceInterestNotifier::enable( bool was
)
1458 state
|= kIOServiceNotifyEnable
;
1460 state
&= ~kIOServiceNotifyEnable
;
1464 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1470 #define tailQ(o) setObject(o)
1471 #define headQ(o) setObject(0, o)
1472 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
1474 inline void _workLoopAction( IOWorkLoop::Action action
,
1475 IOService
* service
,
1476 void * p0
= 0, void * p1
= 0,
1477 void * p2
= 0, void * p3
= 0 )
1481 if( (wl
= service
->getWorkLoop())) {
1483 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1486 (*action
)( service
, p0
, p1
, p2
, p3
);
1489 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1493 // if its our only provider
1494 ok
= isParent( provider
, gIOServicePlane
, true);
1498 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1499 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1506 bool IOService::terminatePhase1( IOOptionBits options
= 0 )
1511 OSArray
* makeInactive
;
1514 bool startPhase2
= false;
1516 TLOG("%s::terminatePhase1(%08lx)\n", getName(), options
);
1519 if( options
& kIOServiceRecursing
) {
1520 __state
[1] |= kIOServiceRecursing
;
1525 makeInactive
= OSArray::withCapacity( 16 );
1534 didInactive
= victim
->lockForArbitration( true );
1536 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1538 victim
->__state
[0] |= kIOServiceInactiveState
;
1539 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1540 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1541 victim
->_adjustBusy( 1 );
1543 victim
->unlockForArbitration();
1546 startPhase2
= didInactive
;
1549 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1550 IOUserClient::destroyUserReferences( victim
);
1551 victim
->unregisterAllInterest();
1553 iter
= victim
->getClientIterator();
1555 while( (client
= (IOService
*) iter
->getNextObject())) {
1556 TLOG("%s::requestTerminate(%s, %08lx)\n",
1557 client
->getName(), victim
->getName(), options
);
1558 ok
= client
->requestTerminate( victim
, options
);
1559 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1560 client
->getName(), victim
->getName(), ok
);
1562 makeInactive
->setObject( client
);
1568 victim
= (IOService
*) makeInactive
->getObject(0);
1571 makeInactive
->removeObject(0);
1575 makeInactive
->release();
1578 scheduleTerminatePhase2( options
);
1583 void IOService::scheduleTerminatePhase2( IOOptionBits options
= 0 )
1585 AbsoluteTime deadline
;
1587 bool wait
, haveDeadline
= false;
1589 options
|= kIOServiceRequired
;
1593 IOLockLock( gJobsLock
);
1595 if( (options
& kIOServiceSynchronous
)
1596 && (current_thread() != gIOTerminateThread
)) {
1599 wait
= (gIOTerminateThread
!= 0);
1601 // wait to become the terminate thread
1602 assert_wait( (event_t
) &gIOTerminateThread
, THREAD_UNINT
);
1603 IOLockUnlock( gJobsLock
);
1604 thread_block((void (*)(void)) 0);
1605 IOLockLock( gJobsLock
);
1609 gIOTerminateThread
= current_thread();
1610 gIOTerminatePhase2List
->setObject( this );
1614 terminateWorker( options
);
1615 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1617 // wait for the victim to go non-busy
1618 assert_wait( (event_t
) &gIOTerminateWork
, THREAD_UNINT
);
1619 if( !haveDeadline
) {
1620 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1621 haveDeadline
= true;
1623 thread_set_timer_deadline( deadline
);
1624 IOLockUnlock( gJobsLock
);
1625 waitResult
= thread_block((void (*)(void)) 0);
1626 if( waitResult
== THREAD_TIMED_OUT
) {
1627 TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName());
1629 thread_cancel_timer();
1630 IOLockLock( gJobsLock
);
1632 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
1634 gIOTerminateThread
= 0;
1635 thread_wakeup( (event_t
) &gIOTerminateThread
);
1638 // ! kIOServiceSynchronous
1640 gIOTerminatePhase2List
->setObject( this );
1641 if( 0 == gIOTerminateWork
++)
1642 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) options
);
1645 IOLockUnlock( gJobsLock
);
1650 void IOService::terminateThread( void * arg
)
1652 IOLockLock( gJobsLock
);
1654 terminateWorker( (IOOptionBits
) arg
);
1656 gIOTerminateThread
= 0;
1657 thread_wakeup( (event_t
) &gIOTerminateThread
);
1659 IOLockUnlock( gJobsLock
);
1662 void IOService::scheduleStop( IOService
* provider
)
1664 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1666 IOLockLock( gJobsLock
);
1667 gIOStopList
->tailQ( this );
1668 gIOStopProviderList
->tailQ( provider
);
1670 if( 0 == gIOTerminateWork
++) {
1671 if( !gIOTerminateThread
)
1672 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1674 thread_wakeup( (event_t
) &gIOTerminateWork
);
1677 IOLockUnlock( gJobsLock
);
1680 void IOService::scheduleFinalize( void )
1682 TLOG("%s::scheduleFinalize\n", getName());
1684 IOLockLock( gJobsLock
);
1685 gIOFinalizeList
->tailQ( this );
1687 if( 0 == gIOTerminateWork
++) {
1688 if( !gIOTerminateThread
)
1689 gIOTerminateThread
= IOCreateThread( &terminateThread
, (void *) 0 );
1691 thread_wakeup( (event_t
) &gIOTerminateWork
);
1694 IOLockUnlock( gJobsLock
);
1697 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1702 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1704 if( false == *defer
) {
1706 if( lockForArbitration( true )) {
1707 if( false == provider
->handleIsOpen( this ))
1708 scheduleStop( provider
);
1711 message( kIOMessageServiceIsRequestingClose
, provider
, (void *) options
);
1712 if( false == provider
->handleIsOpen( this ))
1713 scheduleStop( provider
);
1716 unlockForArbitration();
1723 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
1724 OSArray
* doPhase2List
)
1730 iter
= victim
->getClientIterator();
1732 while( (client
= (IOService
*) iter
->getNextObject())) {
1733 TLOG("%s::willTerminate(%s, %08lx)\n",
1734 client
->getName(), victim
->getName(), options
);
1735 ok
= client
->willTerminate( victim
, options
);
1736 doPhase2List
->tailQ( client
);
1742 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
)
1748 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *) options
);
1750 iter
= victim
->getClientIterator();
1752 while( (client
= (IOService
*) iter
->getNextObject())) {
1753 TLOG("%s::didTerminate(%s, %08lx)\n",
1754 client
->getName(), victim
->getName(), options
);
1755 client
->didTerminate( victim
, options
, &defer
);
1756 TLOG("%s::didTerminate(%s, defer %d)\n",
1757 client
->getName(), victim
->getName(), defer
);
1763 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
)
1765 TLOG("%s::finalize(%08lx)\n", victim
->getName(), options
);
1766 victim
->finalize( options
);
1769 void IOService::actionStop( IOService
* provider
, IOService
* client
)
1771 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
1772 client
->stop( provider
);
1773 if( provider
->isOpen( client
))
1774 provider
->close( client
);
1775 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
1776 client
->detach( provider
);
1779 void IOService::terminateWorker( IOOptionBits options
)
1781 OSArray
* doPhase2List
;
1782 OSArray
* didPhase2List
;
1787 IOService
* provider
;
1793 options
|= kIOServiceRequired
;
1795 doPhase2List
= OSArray::withCapacity( 16 );
1796 didPhase2List
= OSArray::withCapacity( 16 );
1797 freeList
= OSSet::withCapacity( 16 );
1798 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
1802 workDone
= gIOTerminateWork
;
1804 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
1807 gIOTerminatePhase2List
->removeObject(0);
1808 IOLockUnlock( gJobsLock
);
1812 doPhase2
= victim
->lockForArbitration( true );
1814 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
1816 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
1817 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
1819 victim
->__state
[1] |= kIOServiceTermPhase2State
;
1821 victim
->unlockForArbitration();
1824 if( 0 == victim
->getClient()) {
1825 // no clients - will go to finalize
1826 IOLockLock( gJobsLock
);
1827 gIOFinalizeList
->tailQ( victim
);
1828 IOLockUnlock( gJobsLock
);
1830 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
1831 victim
, (void *) options
, (void *) doPhase2List
);
1833 didPhase2List
->headQ( victim
);
1836 victim
= (IOService
*) doPhase2List
->getObject(0);
1839 doPhase2List
->removeObject(0);
1843 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
1845 if( victim
->lockForArbitration( true )) {
1846 victim
->__state
[1] |= kIOServiceTermPhase3State
;
1847 victim
->unlockForArbitration();
1849 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
1850 victim
, (void *) options
);
1851 didPhase2List
->removeObject(0);
1853 IOLockLock( gJobsLock
);
1860 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
1862 IOLockUnlock( gJobsLock
);
1863 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
1864 victim
, (void *) options
);
1865 IOLockLock( gJobsLock
);
1867 freeList
->setObject( victim
);
1868 // safe if finalize list is append only
1869 gIOFinalizeList
->removeObject(0);
1873 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
1875 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
1878 if( !provider
->isChild( client
, gIOServicePlane
)) {
1879 // may be multiply queued - nop it
1880 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
1882 // not ready for stop if it has clients, skip it
1883 if( (client
->__state
[1] & kIOServiceTermPhase3State
) && client
->getClient()) {
1884 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
1889 IOLockUnlock( gJobsLock
);
1890 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
1891 provider
, (void *) client
);
1892 IOLockLock( gJobsLock
);
1893 // check the finalize list now
1897 freeList
->setObject( client
);
1898 freeList
->setObject( provider
);
1900 // safe if stop list is append only
1901 gIOStopList
->removeObject( idx
);
1902 gIOStopProviderList
->removeObject( idx
);
1906 } while( doPhase3
);
1908 gIOTerminateWork
-= workDone
;
1909 moreToDo
= (gIOTerminateWork
!= 0);
1912 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
1915 } while( moreToDo
);
1917 IOLockUnlock( gJobsLock
);
1919 freeList
->release();
1920 doPhase2List
->release();
1921 didPhase2List
->release();
1923 IOLockLock( gJobsLock
);
1926 bool IOService::finalize( IOOptionBits options
)
1929 IOService
* provider
;
1931 iter
= getProviderIterator();
1935 while( (provider
= (IOService
*) iter
->getNextObject())) {
1938 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
1939 /* we come down here on programmatic terminate */
1941 if( provider
->isOpen( this ))
1942 provider
->close( this );
1946 if( provider
->lockForArbitration( true )) {
1947 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
1948 scheduleStop( provider
);
1949 provider
->unlockForArbitration();
1966 void IOService::doServiceTerminate( IOOptionBits options
)
1970 // a method in case someone needs to override it
1971 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
1975 if( client
->isParent( this, gIOServicePlane
, true))
1976 // we are the clients only provider
1977 ok
= client
->terminate( options
);
1984 bool IOService::terminate( IOOptionBits options
= 0 )
1986 options
|= kIOServiceTerminate
;
1988 return( terminatePhase1( options
));
1991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997 struct ServiceOpenMessageContext
1999 IOService
* service
;
2001 IOService
* excludeClient
;
2002 IOOptionBits options
;
2005 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2007 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2009 if( object
!= context
->excludeClient
)
2010 context
->service
->messageClient( context
->type
, object
, (void *) context
->options
);
2013 bool IOService::open( IOService
* forClient
,
2014 IOOptionBits options
= 0,
2018 ServiceOpenMessageContext context
;
2020 context
.service
= this;
2021 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2022 context
.excludeClient
= forClient
;
2023 context
.options
= options
;
2025 applyToInterested( gIOGeneralInterest
,
2026 &serviceOpenMessageApplier
, &context
);
2028 if( false == lockForArbitration(false) )
2031 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2033 ok
= handleOpen( forClient
, options
, arg
);
2035 unlockForArbitration();
2040 void IOService::close( IOService
* forClient
,
2041 IOOptionBits options
= 0 )
2046 lockForArbitration();
2048 wasClosed
= handleIsOpen( forClient
);
2050 handleClose( forClient
, options
);
2051 last
= (__state
[1] & kIOServiceTermPhase3State
);
2054 unlockForArbitration();
2057 forClient
->scheduleStop( this );
2059 else if( wasClosed
) {
2061 ServiceOpenMessageContext context
;
2063 context
.service
= this;
2064 context
.type
= kIOMessageServiceWasClosed
;
2065 context
.excludeClient
= forClient
;
2066 context
.options
= options
;
2068 applyToInterested( gIOGeneralInterest
,
2069 &serviceOpenMessageApplier
, &context
);
2073 bool IOService::isOpen( const IOService
* forClient
= 0 ) const
2075 IOService
* self
= (IOService
*) this;
2078 self
->lockForArbitration();
2080 ok
= handleIsOpen( forClient
);
2082 self
->unlockForArbitration();
2087 bool IOService::handleOpen( IOService
* forClient
,
2088 IOOptionBits options
,
2093 ok
= (0 == __owner
);
2095 __owner
= forClient
;
2097 else if( options
& kIOServiceSeize
) {
2098 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2099 __owner
, (void *) options
));
2100 if( ok
&& (0 == __owner
))
2101 __owner
= forClient
;
2108 void IOService::handleClose( IOService
* forClient
,
2109 IOOptionBits options
)
2111 if( __owner
== forClient
)
2115 bool IOService::handleIsOpen( const IOService
* forClient
) const
2118 return( __owner
== forClient
);
2120 return( __owner
!= forClient
);
2124 * Probing & starting
2126 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2128 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2129 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2137 val1
= obj1
->priority
;
2140 val2
= obj2
->priority
;
2142 return ( val1
- val2
);
2145 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2147 OSDictionary
* dict
;
2148 IOService
* service
;
2149 _IOServiceNotifier
* notify
;
2150 OSSymbol
* key
= (OSSymbol
*) ref
;
2153 if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2154 return( notify
->priority
);
2156 else if( (service
= OSDynamicCast( IOService
, entry
)))
2157 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2158 else if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2159 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2166 return( (SInt32
) offset
->unsigned32BitValue());
2168 return( kIODefaultProbeScore
);
2171 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2173 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2174 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2182 val1
= IOServiceObjectOrder( obj1
, ref
);
2185 val2
= IOServiceObjectOrder( obj2
, ref
);
2187 return ( val1
- val2
);
2190 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2192 IOService
* service
= 0;
2194 const OSSymbol
* nextCat
;
2196 iter
= getClientIterator();
2198 while( (service
= (IOService
*) iter
->getNextObject())) {
2199 if( kIOServiceInactiveState
& service
->__state
[0])
2201 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2202 service
->getProperty( gIOMatchCategoryKey
));
2203 if( category
== nextCat
)
2211 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2213 _IOServiceNotifierInvocation invocation
;
2217 invocation
.thread
= current_thread();
2220 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2223 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2224 _IOServiceNotifierInvocation
*, link
);
2230 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
, this );
2233 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2234 _IOServiceNotifierInvocation
*, link
);
2235 if( kIOServiceNotifyWaiter
& notify
->state
) {
2236 notify
->state
&= ~kIOServiceNotifyWaiter
;
2237 thread_wakeup( (event_t
) notify
);
2246 * Alloc and probe matching classes,
2247 * called on the provider instance
2250 void IOService::probeCandidates( OSOrderedSet
* matches
)
2252 OSDictionary
* match
= 0;
2255 IOService
* newInst
;
2256 OSDictionary
* props
;
2259 OSOrderedSet
* familyMatches
= 0;
2260 OSOrderedSet
* startList
;
2261 OSDictionary
* startDict
= 0;
2262 const OSSymbol
* category
;
2264 _IOServiceNotifier
* notify
;
2265 OSObject
* nextMatch
= 0;
2267 bool needReloc
= false;
2273 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2275 nextMatch
->retain();
2276 matches
->removeObject(nextMatch
);
2278 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2280 lockForArbitration();
2281 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2282 invokeNotifer( notify
);
2283 unlockForArbitration();
2284 nextMatch
->release();
2288 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2289 nextMatch
->release();
2296 debugFlags
= getDebugFlags( match
);
2300 category
= OSDynamicCast( OSSymbol
,
2301 match
->getObject( gIOMatchCategoryKey
));
2303 category
= gIODefaultMatchCategoryKey
;
2305 if( getClientWithCategory( category
)) {
2307 if( debugFlags
& kIOLogMatch
)
2308 LOG("%s: match category %s exists\n", getName(),
2309 category
->getCStringNoCopy());
2311 nextMatch
->release();
2316 // create a copy now in case its modified during matching
2317 props
= OSDictionary::withDictionary( match
, match
->getCount());
2320 props
->setCapacityIncrement(1);
2322 // check the nub matches
2323 if( false == passiveMatch( props
, true ))
2326 // Check to see if driver reloc has been loaded.
2327 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2330 if( debugFlags
& kIOLogCatalogue
)
2331 LOG("%s: stalling for module\n", getName());
2333 // If reloc hasn't been loaded, exit;
2334 // reprobing will occur after reloc has been loaded.
2338 // reorder on family matchPropertyTable score.
2339 if( 0 == familyMatches
)
2340 familyMatches
= OSOrderedSet::withCapacity( 1,
2341 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2343 familyMatches
->setObject( props
);
2348 nextMatch
->release();
2357 if( familyMatches
) {
2360 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2363 familyMatches
->removeObject( props
);
2368 debugFlags
= getDebugFlags( props
);
2371 symbol
= OSDynamicCast( OSSymbol
,
2372 props
->getObject( gIOClassKey
));
2376 // alloc the driver instance
2377 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2380 IOLog("Couldn't alloc class \"%s\"\n",
2381 symbol
->getCStringNoCopy());
2385 // init driver instance
2386 if( !(inst
->init( props
))) {
2388 if( debugFlags
& kIOLogStart
)
2389 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2393 if( __state
[1] & kIOServiceSynchronousState
)
2394 inst
->__state
[1] |= kIOServiceSynchronousState
;
2396 // give the driver the default match category if not specified
2397 category
= OSDynamicCast( OSSymbol
,
2398 props
->getObject( gIOMatchCategoryKey
));
2400 category
= gIODefaultMatchCategoryKey
;
2401 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2403 // attach driver instance
2404 if( !(inst
->attach( this )))
2407 // pass in score from property table
2408 score
= familyMatches
->orderObject( props
);
2410 // & probe the new driver instance
2412 if( debugFlags
& kIOLogProbe
)
2413 LOG("%s::probe(%s)\n",
2414 inst
->getMetaClass()->getClassName(), getName());
2417 newInst
= inst
->probe( this, &score
);
2418 inst
->detach( this );
2421 if( debugFlags
& kIOLogProbe
)
2422 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2428 newPri
= OSNumber::withNumber( score
, 32 );
2430 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2434 // add to start list for the match category
2436 startDict
= OSDictionary::withCapacity( 1 );
2437 assert( startDict
);
2438 startList
= (OSOrderedSet
*)
2439 startDict
->getObject( category
);
2440 if( 0 == startList
) {
2441 startList
= OSOrderedSet::withCapacity( 1,
2442 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2443 if( startDict
&& startList
) {
2444 startDict
->setObject( category
, startList
);
2445 startList
->release();
2448 assert( startList
);
2450 startList
->setObject( newInst
);
2458 familyMatches
->release();
2462 // start the best (until success) of each category
2464 iter
= OSCollectionIterator::withCollection( startDict
);
2466 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2468 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2469 assert( startList
);
2474 while( true // (!started)
2475 && (inst
= (IOService
*)startList
->getFirstObject())) {
2478 startList
->removeObject(inst
);
2481 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2483 if( debugFlags
& kIOLogStart
) {
2485 LOG( "match category exists, skipping " );
2486 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2487 getName(), inst
->getRetainCount());
2490 if( false == started
)
2491 started
= startCandidate( inst
);
2493 if( (debugFlags
& kIOLogStart
) && (false == started
))
2494 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2495 inst
->getRetainCount());
2504 // adjust the busy count by -1 if matching is stalled for a module,
2505 // or +1 if a previously stalled matching is complete.
2506 lockForArbitration();
2509 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2511 __state
[1] |= kIOServiceModuleStallState
;
2513 } else if( __state
[1] & kIOServiceModuleStallState
) {
2514 __state
[1] &= ~kIOServiceModuleStallState
;
2518 _adjustBusy( adjBusy
);
2519 unlockForArbitration();
2522 startDict
->release();
2526 * Start a previously attached & probed instance,
2527 * called on exporting object instance
2530 bool IOService::startCandidate( IOService
* service
)
2534 ok
= service
->attach( this );
2537 // stall for any nub resources
2539 // stall for any driver resources
2540 service
->checkResources();
2543 ok
= service
->start( this );
2545 service
->detach( this );
2550 IOService
* IOService::resources( void )
2552 return( gIOResources
);
2555 void IOService::publishResource( const char * key
, OSObject
* value
= 0 )
2557 const OSSymbol
* sym
;
2559 if( (sym
= OSSymbol::withCString( key
))) {
2560 publishResource( sym
, value
);
2565 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
= 0 )
2568 value
= (OSObject
*) gIOServiceKey
;
2570 gIOResources
->setProperty( key
, value
);
2572 gIOResourceGenerationCount
++;
2573 gIOResources
->registerService();
2576 bool IOService::addNeededResource( const char * key
)
2578 OSObject
* resources
;
2583 resources
= getProperty( gIOResourceMatchKey
);
2585 newKey
= OSString::withCString( key
);
2586 if( (0 == resources
) || (0 == newKey
))
2589 set
= OSDynamicCast( OSSet
, resources
);
2591 set
= OSSet::withCapacity( 1 );
2593 set
->setObject( resources
);
2598 set
->setObject( newKey
);
2600 ret
= setProperty( gIOResourceMatchKey
, set
);
2606 bool IOService::checkResource( OSObject
* matching
)
2609 OSDictionary
* table
;
2611 if( (str
= OSDynamicCast( OSString
, matching
))) {
2612 if( gIOResources
->getProperty( str
))
2617 table
= resourceMatching( str
);
2618 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
2621 IOLog("%s: Can't match using: %s\n", getName(),
2622 matching
->getMetaClass()->getClassName());
2623 /* false would stall forever */
2627 if( gIOKitDebug
& kIOLogConfig
)
2628 LOG("config(%x): stalling %s\n", (int) IOThreadSelf(), getName());
2630 waitForService( table
);
2632 if( gIOKitDebug
& kIOLogConfig
)
2633 LOG("config(%x): waking\n", (int) IOThreadSelf() );
2638 bool IOService::checkResources( void )
2640 OSObject
* resources
;
2645 resources
= getProperty( gIOResourceMatchKey
);
2649 if( (set
= OSDynamicCast( OSSet
, resources
))) {
2651 iter
= OSCollectionIterator::withCollection( set
);
2653 while( ok
&& (resources
= iter
->getNextObject()) )
2654 ok
= checkResource( resources
);
2659 ok
= checkResource( resources
);
2665 _IOConfigThread
* _IOConfigThread::configThread( void )
2667 _IOConfigThread
* inst
;
2670 if( !(inst
= new _IOConfigThread
))
2674 if( !(inst
->thread
= IOCreateThread
2675 ( (IOThreadFunc
) &_IOConfigThread::main
, inst
)))
2688 void _IOConfigThread::free( void )
2693 void IOService::doServiceMatch( IOOptionBits options
)
2695 _IOServiceNotifier
* notify
;
2697 OSOrderedSet
* matches
;
2698 SInt32 catalogGeneration
;
2699 bool keepGuessing
= true;
2700 bool reRegistered
= true;
2702 // job->nub->deliverNotification( gIOPublishNotification,
2703 // kIOServiceRegisteredState, 0xffffffff );
2705 while( keepGuessing
) {
2707 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
2708 // the matches list should always be created by findDrivers()
2711 lockForArbitration();
2712 if( 0 == (__state
[0] & kIOServiceFirstPublishState
))
2713 deliverNotification( gIOFirstPublishNotification
,
2714 kIOServiceFirstPublishState
, 0xffffffff );
2716 __state
[1] &= ~kIOServiceNeedConfigState
;
2717 __state
[1] |= kIOServiceConfigState
;
2718 __state
[0] |= kIOServiceRegisteredState
;
2720 if( reRegistered
&& (0 == (__state
[0] & kIOServiceInactiveState
))) {
2722 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
2723 gNotifications
->getObject( gIOPublishNotification
) );
2725 while((notify
= (_IOServiceNotifier
*)
2726 iter
->getNextObject())) {
2728 if( passiveMatch( notify
->matching
)
2729 && (kIOServiceNotifyEnable
& notify
->state
))
2730 matches
->setObject( notify
);
2737 unlockForArbitration();
2739 if( matches
->getCount() && (kIOReturnSuccess
== getResources()))
2740 probeCandidates( matches
);
2745 lockForArbitration();
2746 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
2748 (reRegistered
|| (catalogGeneration
!=
2749 gIOCatalogue
->getGenerationCount()))
2750 && (0 == (__state
[0] & kIOServiceInactiveState
));
2753 unlockForArbitration();
2756 if( (0 == (__state
[0] & kIOServiceInactiveState
))
2757 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
2758 deliverNotification( gIOMatchedNotification
,
2759 kIOServiceMatchedState
, 0xffffffff );
2760 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
2761 deliverNotification( gIOFirstMatchNotification
,
2762 kIOServiceFirstMatchState
, 0xffffffff );
2765 __state
[1] &= ~kIOServiceConfigState
;
2766 if( __state
[0] & kIOServiceInactiveState
)
2767 scheduleTerminatePhase2();
2770 unlockForArbitration();
2773 UInt32
IOService::_adjustBusy( SInt32 delta
)
2778 bool wasQuiet
, nowQuiet
, needWake
;
2781 result
= __state
[1] & kIOServiceBusyStateMask
;
2785 next
->lockForArbitration();
2786 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
2787 assert( count
< kIOServiceBusyMax
);
2788 wasQuiet
= (0 == count
);
2789 assert( (!wasQuiet
) || (delta
> 0));
2790 next
->__state
[1] += delta
;
2791 nowQuiet
= (0 == (next
->__state
[1] & kIOServiceBusyStateMask
));
2792 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
2795 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
2796 IOLockLock( gIOServiceBusyLock
);
2797 thread_wakeup( (event_t
) next
);
2798 IOLockUnlock( gIOServiceBusyLock
);
2801 next
->unlockForArbitration();
2803 if( (wasQuiet
|| nowQuiet
) ) {
2806 OSObject
* interested
;
2808 array
= OSDynamicCast( OSArray
, next
->getProperty( gIOBusyInterest
));
2812 (interested
= array
->getObject( index
));
2814 next
->messageClient(kIOMessageServiceBusyStateChange
,
2815 interested
, (void *) wasQuiet
/* busy now */);
2820 if( nowQuiet
&& (next
== gIOServiceRoot
))
2821 OSMetaClass::considerUnloads();
2824 delta
= nowQuiet
? -1 : +1;
2826 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
2831 void IOService::adjustBusy( SInt32 delta
)
2833 lockForArbitration();
2834 _adjustBusy( delta
);
2835 unlockForArbitration();
2838 UInt32
IOService::getBusyState( void )
2840 return( __state
[1] & kIOServiceBusyStateMask
);
2843 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
2844 mach_timespec_t
* timeout
= 0 )
2847 int waitResult
= THREAD_AWAKENED
;
2848 bool computeDeadline
= true;
2849 AbsoluteTime abstime
;
2852 lockForArbitration();
2853 IOLockLock( gIOServiceBusyLock
);
2854 wait
= (value
!= (__state
[1] & mask
));
2856 __state
[1] |= kIOServiceBusyWaiterState
;
2857 unlockForArbitration();
2858 assert_wait( (event_t
) this, THREAD_UNINT
);
2860 if( computeDeadline
) {
2861 AbsoluteTime nsinterval
;
2862 clock_interval_to_absolutetime_interval(
2863 timeout
->tv_sec
, kSecondScale
, &abstime
);
2864 clock_interval_to_absolutetime_interval(
2865 timeout
->tv_nsec
, kNanosecondScale
, &nsinterval
);
2866 ADD_ABSOLUTETIME( &abstime
, &nsinterval
);
2867 clock_absolutetime_interval_to_deadline(
2868 abstime
, &abstime
);
2869 computeDeadline
= false;
2871 thread_set_timer_deadline( abstime
);
2874 unlockForArbitration();
2875 IOLockUnlock( gIOServiceBusyLock
);
2877 waitResult
= thread_block((void (*)(void)) 0);
2878 if( timeout
&& (waitResult
!= THREAD_TIMED_OUT
))
2879 thread_cancel_timer();
2882 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2884 if( waitResult
== THREAD_TIMED_OUT
)
2885 return( kIOReturnTimeout
);
2887 return( kIOReturnSuccess
);
2890 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
= 0 )
2892 return( waitForState( kIOServiceBusyStateMask
, 0, timeout
));
2895 bool IOService::serializeProperties( OSSerialize
* s
) const
2898 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
2899 sizeof( __state
), "__state");
2901 return( super::serializeProperties(s
) );
2905 void _IOConfigThread::main( _IOConfigThread
* self
)
2907 _IOServiceJob
* job
;
2915 semaphore_wait( gJobsSemaphore
);
2917 IOTakeLock( gJobsLock
);
2918 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
2920 gJobs
->removeObject(job
);
2923 // gNumConfigThreads--; // we're out of service
2924 gNumWaitingThreads
--; // we're out of service
2926 IOUnlock( gJobsLock
);
2932 if( gIOKitDebug
& kIOLogConfig
)
2933 LOG("config(%x): starting on %s, %d\n",
2934 (int) IOThreadSelf(), job
->nub
->getName(), job
->type
);
2936 switch( job
->type
) {
2939 nub
->doServiceMatch( job
->options
);
2943 LOG("config(%x): strange type (%d)\n",
2944 (int) IOThreadSelf(), job
->type
);
2951 IOTakeLock( gJobsLock
);
2952 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
2954 gNumWaitingThreads
++; // back in service
2955 // gNumConfigThreads++;
2957 if( 0 == --gNumConfigThreads
) {
2958 // IOLog("MATCH IDLE\n");
2959 thread_wakeup( (event_t
) &gNumConfigThreads
);
2962 IOUnlock( gJobsLock
);
2967 if( gIOKitDebug
& kIOLogConfig
)
2968 LOG("config(%x): terminating\n", (int) IOThreadSelf() );
2973 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
2976 int waitResult
= THREAD_AWAKENED
;
2977 bool computeDeadline
= true;
2978 AbsoluteTime abstime
;
2981 IOLockLock( gJobsLock
);
2982 wait
= (0 != gNumConfigThreads
);
2984 assert_wait( (event_t
) &gNumConfigThreads
, THREAD_UNINT
);
2986 if( computeDeadline
) {
2987 clock_interval_to_absolutetime_interval(
2988 msToWait
, kMillisecondScale
, &abstime
);
2989 clock_absolutetime_interval_to_deadline(
2990 abstime
, &abstime
);
2991 computeDeadline
= false;
2993 thread_set_timer_deadline( abstime
);
2996 IOUnlock( gJobsLock
);
2998 waitResult
= thread_block((void (*)(void)) 0);
2999 if( msToWait
&& (waitResult
!= THREAD_TIMED_OUT
))
3000 thread_cancel_timer();
3003 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3005 if( waitResult
== THREAD_TIMED_OUT
)
3006 return( kIOReturnTimeout
);
3008 return( kIOReturnSuccess
);
3011 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3018 IOTakeLock( gJobsLock
);
3021 gJobs
->setLastObject( job
);
3023 count
= gNumWaitingThreads
;
3024 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3026 create
= ( (gOutstandingJobs
> count
)
3027 && (gNumConfigThreads
< kMaxConfigThreads
) );
3029 gNumConfigThreads
++;
3030 gNumWaitingThreads
++;
3033 IOUnlock( gJobsLock
);
3038 if( gIOKitDebug
& kIOLogConfig
)
3039 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3040 _IOConfigThread::configThread();
3043 semaphore_signal( gJobsSemaphore
);
3047 // internal - call with gNotificationLock
3048 OSObject
* IOService::getExistingServices( OSDictionary
* matching
,
3049 IOOptionBits inState
, IOOptionBits options
= 0 )
3051 OSObject
* current
= 0;
3053 IOService
* service
;
3058 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3059 kIORegistryIterateRecursively
);
3063 while( (service
= (IOService
*) iter
->getNextObject())) {
3064 if( (inState
== (service
->__state
[0] & inState
))
3065 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3066 && service
->passiveMatch( matching
)) {
3068 if( options
& kIONotifyOnce
) {
3073 ((OSSet
*)current
)->setObject( service
);
3075 current
= OSSet::withObjects(
3076 & (const OSObject
*) service
, 1, 1 );
3079 } while( !service
&& !iter
->isValid());
3083 if( current
&& (0 == (options
& kIONotifyOnce
))) {
3084 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3093 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3097 // is a lock even needed?
3100 iter
= (OSIterator
*) getExistingServices( matching
,
3101 kIOServiceMatchedState
);
3109 // internal - call with gNotificationLock
3110 IONotifier
* IOService::setNotification(
3111 const OSSymbol
* type
, OSDictionary
* matching
,
3112 IOServiceNotificationHandler handler
, void * target
, void * ref
,
3113 SInt32 priority
= 0 )
3115 _IOServiceNotifier
* notify
= 0;
3121 notify
= new _IOServiceNotifier
;
3122 if( notify
&& !notify
->init()) {
3128 notify
->matching
= matching
;
3129 notify
->handler
= handler
;
3130 notify
->target
= target
;
3132 notify
->priority
= priority
;
3133 notify
->state
= kIOServiceNotifyEnable
;
3134 queue_init( ¬ify
->handlerInvocations
);
3138 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3139 set
= OSOrderedSet::withCapacity( 1,
3140 IONotifyOrdering
, 0 );
3142 gNotifications
->setObject( type
, set
);
3146 notify
->whence
= set
;
3148 set
->setObject( notify
);
3154 // internal - call with gNotificationLock
3155 IONotifier
* IOService::doInstallNotification(
3156 const OSSymbol
* type
, OSDictionary
* matching
,
3157 IOServiceNotificationHandler handler
,
3158 void * target
, void * ref
,
3159 SInt32 priority
, OSIterator
** existing
)
3162 IONotifier
* notify
;
3163 IOOptionBits inState
;
3168 if( type
== gIOPublishNotification
)
3169 inState
= kIOServiceRegisteredState
;
3171 else if( type
== gIOFirstPublishNotification
)
3172 inState
= kIOServiceFirstPublishState
;
3174 else if( (type
== gIOMatchedNotification
)
3175 || (type
== gIOFirstMatchNotification
))
3176 inState
= kIOServiceMatchedState
;
3177 else if( type
== gIOTerminatedNotification
)
3182 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3185 // get the current set
3186 exist
= (OSIterator
*) getExistingServices( matching
, inState
);
3196 IONotifier
* IOService::installNotification(
3197 const OSSymbol
* type
, OSDictionary
* matching
,
3198 IOServiceNotificationHandler handler
,
3199 void * target
, void * ref
,
3200 SInt32 priority
, OSIterator
** existing
)
3202 IONotifier
* notify
;
3206 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3207 priority
, existing
);
3214 IONotifier
* IOService::addNotification(
3215 const OSSymbol
* type
, OSDictionary
* matching
,
3216 IOServiceNotificationHandler handler
,
3217 void * target
, void * ref
= 0,
3218 SInt32 priority
= 0 )
3220 OSIterator
* existing
;
3221 _IOServiceNotifier
* notify
;
3224 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3225 handler
, target
, ref
, priority
, &existing
);
3227 // send notifications for existing set
3230 notify
->retain(); // in case handler remove()s
3231 while( (next
= (IOService
*) existing
->getNextObject())) {
3233 next
->lockForArbitration();
3234 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3235 next
->invokeNotifer( notify
);
3236 next
->unlockForArbitration();
3239 existing
->release();
3245 struct SyncNotifyVars
{
3246 semaphore_port_t waitHere
;
3250 bool IOService::syncNotificationHandler(
3251 void * /* target */, void * ref
,
3252 IOService
* newService
)
3255 // result may get written more than once before the
3256 // notification is removed!
3257 ((SyncNotifyVars
*) ref
)->result
= newService
;
3258 semaphore_signal( ((SyncNotifyVars
*) ref
)->waitHere
);
3263 IOService
* IOService::waitForService( OSDictionary
* matching
,
3264 mach_timespec_t
* timeout
= 0 )
3266 IONotifier
* notify
= 0;
3267 // priority doesn't help us much since we need a thread wakeup
3268 SInt32 priority
= 0;
3269 SyncNotifyVars state
;
3270 kern_return_t err
= kIOReturnBadArgument
;
3282 state
.result
= (IOService
*) getExistingServices( matching
,
3283 kIOServiceMatchedState
, kIONotifyOnce
);
3287 err
= semaphore_create( kernel_task
, &state
.waitHere
,
3288 SYNC_POLICY_FIFO
, 0 );
3289 if( KERN_SUCCESS
!= err
)
3292 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
3293 &IOService::syncNotificationHandler
, (void *) 0,
3294 (void *) &state
, priority
);
3302 err
= semaphore_timedwait( state
.waitHere
, *timeout
);
3304 err
= semaphore_wait( state
.waitHere
);
3308 notify
->remove(); // dequeues
3310 matching
->release();
3312 semaphore_destroy( kernel_task
, state
.waitHere
);
3314 return( state
.result
);
3317 void IOService::deliverNotification( const OSSymbol
* type
,
3318 IOOptionBits orNewState
, IOOptionBits andNewState
)
3320 _IOServiceNotifier
* notify
;
3322 OSArray
* willSend
= 0;
3324 lockForArbitration();
3326 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3327 || (type
== gIOTerminatedNotification
)) {
3331 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3332 gNotifications
->getObject( type
) );
3335 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
3337 if( passiveMatch( notify
->matching
)
3338 && (kIOServiceNotifyEnable
& notify
->state
)) {
3340 willSend
= OSArray::withCapacity(8);
3342 willSend
->setObject( notify
);
3348 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
3354 for( unsigned int idx
= 0;
3355 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
3357 invokeNotifer( notify
);
3359 willSend
->release();
3361 unlockForArbitration();
3364 IOOptionBits
IOService::getState( void ) const
3366 return( __state
[0] );
3370 * Helpers to make matching objects for simple cases
3373 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
3374 OSDictionary
* table
= 0 )
3377 table
= OSDictionary::withCapacity( 2 );
3379 table
->setObject(gIOProviderClassKey
, (OSObject
*)name
);
3384 OSDictionary
* IOService::serviceMatching( const char * name
,
3385 OSDictionary
* table
= 0 )
3387 const OSString
* str
;
3389 str
= OSSymbol::withCString( name
);
3393 table
= serviceMatching( str
, table
);
3398 OSDictionary
* IOService::nameMatching( const OSString
* name
,
3399 OSDictionary
* table
= 0 )
3402 table
= OSDictionary::withCapacity( 2 );
3404 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
3409 OSDictionary
* IOService::nameMatching( const char * name
,
3410 OSDictionary
* table
= 0 )
3412 const OSString
* str
;
3414 str
= OSSymbol::withCString( name
);
3418 table
= nameMatching( str
, table
);
3423 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
3424 OSDictionary
* table
= 0 )
3426 table
= serviceMatching( gIOResourcesKey
, table
);
3428 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
3433 OSDictionary
* IOService::resourceMatching( const char * name
,
3434 OSDictionary
* table
= 0 )
3436 const OSSymbol
* str
;
3438 str
= OSSymbol::withCString( name
);
3442 table
= resourceMatching( str
, table
);
3449 * _IOServiceNotifier
3452 // wait for all threads, other than the current one,
3453 // to exit the handler
3455 void _IOServiceNotifier::wait()
3457 _IOServiceNotifierInvocation
* next
;
3462 queue_iterate( &handlerInvocations
, next
,
3463 _IOServiceNotifierInvocation
*, link
) {
3464 if( next
->thread
!= current_thread() ) {
3470 state
|= kIOServiceNotifyWaiter
;
3471 assert_wait( this, THREAD_UNINT
);
3473 thread_block((void (*)(void)) 0);
3480 void _IOServiceNotifier::free()
3482 assert( queue_empty( &handlerInvocations
));
3486 void _IOServiceNotifier::remove()
3491 whence
->removeObject( (OSObject
*) this );
3495 matching
->release();
3499 state
&= ~kIOServiceNotifyEnable
;
3508 bool _IOServiceNotifier::disable()
3514 ret
= (0 != (kIOServiceNotifyEnable
& state
));
3515 state
&= ~kIOServiceNotifyEnable
;
3524 void _IOServiceNotifier::enable( bool was
)
3528 state
|= kIOServiceNotifyEnable
;
3530 state
&= ~kIOServiceNotifyEnable
;
3538 IOService
* IOResources::resources( void )
3542 inst
= new IOResources
;
3543 if( inst
&& !inst
->init()) {
3551 IOWorkLoop
* IOResources::getWorkLoop() const
3553 // If we are the resource root then bringe over to the
3554 // platform to get its workloop
3555 if (this == (IOResources
*) gIOResources
)
3556 return getPlatform()->getWorkLoop();
3558 return IOService::getWorkLoop();
3561 bool IOResources::matchPropertyTable( OSDictionary
* table
)
3569 prop
= table
->getObject( gIOResourceMatchKey
);
3570 str
= OSDynamicCast( OSString
, prop
);
3572 ok
= (0 != getProperty( str
));
3574 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
3576 iter
= OSCollectionIterator::withCollection( set
);
3578 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
3579 ok
= (0 != getProperty( str
));
3589 * Helpers for matching dictionaries.
3590 * Keys existing in matching are checked in properties.
3591 * Keys may be a string or OSCollection of IOStrings
3594 bool IOService::compareProperty( OSDictionary
* matching
,
3600 value
= matching
->getObject( key
);
3602 ok
= value
->isEqualTo( getProperty( key
));
3610 bool IOService::compareProperty( OSDictionary
* matching
,
3611 const OSString
* key
)
3616 value
= matching
->getObject( key
);
3618 ok
= value
->isEqualTo( getProperty( key
));
3625 bool IOService::compareProperties( OSDictionary
* matching
,
3626 OSCollection
* keys
)
3628 OSCollectionIterator
* iter
;
3629 const OSString
* key
;
3632 if( !matching
|| !keys
)
3635 iter
= OSCollectionIterator::withCollection( keys
);
3638 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
3639 ok
= compareProperty( matching
, key
);
3643 keys
->release(); // !! consume a ref !!
3648 /* Helper to add a location matching dict to the table */
3650 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
3652 OSDictionary
* dict
;
3657 dict
= OSDictionary::withCapacity( 1 );
3659 table
->setObject( gIOLocationMatchKey
, dict
);
3667 * Go looking for a provider to match a location dict.
3670 IOService
* IOService::matchLocation( IOService
* /* client */ )
3674 parent
= getProvider();
3677 parent
= parent
->matchLocation( this );
3682 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
3688 IORegistryEntry
* entry
;
3702 str
= OSDynamicCast( OSString
, table
->getObject( gIOProviderClassKey
));
3705 match
= (0 != where
->metaCast( str
));
3710 obj
= table
->getObject( gIONameMatchKey
);
3713 match
= compareNames( obj
, changesOK
? &matched
: 0 );
3716 if( changesOK
&& matched
) {
3717 // leave a hint as to which name matched
3718 table
->setObject( gIONameMatchedKey
, matched
);
3722 obj
= table
->getObject( gIOPropertyMatchKey
);
3725 OSDictionary
* dict
;
3726 OSDictionary
* nextDict
;
3730 dict
= where
->dictionaryWithProperties();
3732 nextDict
= OSDynamicCast( OSDictionary
, obj
);
3736 iter
= OSCollectionIterator::withCollection(
3737 OSDynamicCast(OSCollection
, obj
));
3740 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
3741 iter
->getNextObject()))))) {
3742 match
= dict
->isEqualTo( nextDict
, nextDict
);
3755 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
3758 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
3759 match
= (where
== entry
);
3766 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
3770 IOService
* service
= 0;
3771 UInt32 serviceCount
= 0;
3774 iter
= getClientIterator();
3776 while( (service
= (IOService
*) iter
->getNextObject())) {
3777 if( kIOServiceInactiveState
& service
->__state
[0])
3779 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
3785 match
= (serviceCount
== num
->unsigned32BitValue());
3790 if( done
== table
->getCount())
3791 // don't call family if we've done all the entries in the table
3794 // pass in score from property table
3795 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
3797 // do family specific matching
3798 match
= where
->matchPropertyTable( table
, &score
);
3802 if( kIOLogMatch
& getDebugFlags( table
))
3803 LOG("%s: family specific matching fails\n", where
->getName());
3810 newPri
= OSNumber::withNumber( score
, 32 );
3812 table
->setObject( gIOProbeScoreKey
, newPri
);
3817 if( !(match
= where
->compareProperty( table
, kIOBSDNameKey
)))
3820 table
= OSDynamicCast( OSDictionary
,
3821 table
->getObject( gIOLocationMatchKey
));
3824 where
= where
->getProvider();
3826 where
= where
->matchLocation( where
);
3829 } while( table
&& where
);
3831 if( kIOLogMatch
& gIOKitDebug
)
3833 LOG("match location @ %s = %d\n",
3834 where
->getName(), match
);
3840 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3841 UInt32 type
, OSDictionary
* properties
,
3842 IOUserClient
** handler
)
3844 const OSSymbol
*userClientClass
= 0;
3845 IOUserClient
*client
;
3848 // First try my own properties for a user client class name
3849 temp
= getProperty(gIOUserClientClassKey
);
3851 if (OSDynamicCast(OSSymbol
, temp
))
3852 userClientClass
= (const OSSymbol
*) temp
;
3853 else if (OSDynamicCast(OSString
, temp
)) {
3854 userClientClass
= OSSymbol::withString((OSString
*) temp
);
3855 if (userClientClass
)
3856 setProperty(kIOUserClientClassKey
,
3857 (OSObject
*) userClientClass
);
3861 // Didn't find one so lets just bomb out now without further ado.
3862 if (!userClientClass
)
3863 return kIOReturnUnsupported
;
3865 temp
= OSMetaClass::allocClassWithName(userClientClass
);
3867 return kIOReturnNoMemory
;
3869 if (OSDynamicCast(IOUserClient
, temp
))
3870 client
= (IOUserClient
*) temp
;
3873 return kIOReturnUnsupported
;
3876 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
3878 return kIOReturnBadArgument
;
3881 if ( !client
->attach(this) ) {
3883 return kIOReturnUnsupported
;
3886 if ( !client
->start(this) ) {
3887 client
->detach(this);
3889 return kIOReturnUnsupported
;
3893 return kIOReturnSuccess
;
3896 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
3897 UInt32 type
, IOUserClient
** handler
)
3899 return( newUserClient( owningTask
, securityID
, type
, 0, handler
));
3902 IOReturn
IOService::requestProbe( IOOptionBits options
)
3904 return( kIOReturnUnsupported
);
3908 * Convert an IOReturn to text. Subclasses which add additional
3909 * IOReturn's should override this method and call
3910 * super::stringFromReturn if the desired value is not found.
3913 const char * IOService::stringFromReturn( IOReturn rtn
)
3915 static const IONamedValue IOReturn_values
[] = {
3916 {kIOReturnSuccess
, "success" },
3917 {kIOReturnError
, "general error" },
3918 {kIOReturnNoMemory
, "memory allocation error" },
3919 {kIOReturnNoResources
, "resource shortage" },
3920 {kIOReturnIPCError
, "Mach IPC failure" },
3921 {kIOReturnNoDevice
, "no such device" },
3922 {kIOReturnNotPrivileged
, "privilege violation" },
3923 {kIOReturnBadArgument
, "invalid argument" },
3924 {kIOReturnLockedRead
, "device is read locked" },
3925 {kIOReturnLockedWrite
, "device is write locked" },
3926 {kIOReturnExclusiveAccess
, "device is exclusive access" },
3927 {kIOReturnBadMessageID
, "bad IPC message ID" },
3928 {kIOReturnUnsupported
, "unsupported function" },
3929 {kIOReturnVMError
, "virtual memory error" },
3930 {kIOReturnInternalError
, "internal driver error" },
3931 {kIOReturnIOError
, "I/O error" },
3932 {kIOReturnCannotLock
, "cannot acquire lock" },
3933 {kIOReturnNotOpen
, "device is not open" },
3934 {kIOReturnNotReadable
, "device is not readable" },
3935 {kIOReturnNotWritable
, "device is not writeable" },
3936 {kIOReturnNotAligned
, "alignment error" },
3937 {kIOReturnBadMedia
, "media error" },
3938 {kIOReturnStillOpen
, "device is still open" },
3939 {kIOReturnRLDError
, "rld failure" },
3940 {kIOReturnDMAError
, "DMA failure" },
3941 {kIOReturnBusy
, "device is busy" },
3942 {kIOReturnTimeout
, "I/O timeout" },
3943 {kIOReturnOffline
, "device is offline" },
3944 {kIOReturnNotReady
, "device is not ready" },
3945 {kIOReturnNotAttached
, "device/channel is not attached" },
3946 {kIOReturnNoChannels
, "no DMA channels available" },
3947 {kIOReturnNoSpace
, "no space for data" },
3948 {kIOReturnPortExists
, "device port already exists" },
3949 {kIOReturnCannotWire
, "cannot wire physical memory" },
3950 {kIOReturnNoInterrupt
, "no interrupt attached" },
3951 {kIOReturnNoFrames
, "no DMA frames enqueued" },
3952 {kIOReturnMessageTooLarge
, "message is too large" },
3953 {kIOReturnNotPermitted
, "operation is not permitted" },
3954 {kIOReturnNoPower
, "device is without power" },
3955 {kIOReturnNoMedia
, "media is not present" },
3956 {kIOReturnUnformattedMedia
, "media is not formatted" },
3957 {kIOReturnUnsupportedMode
, "unsupported mode" },
3958 {kIOReturnUnderrun
, "data underrun" },
3959 {kIOReturnOverrun
, "data overrun" },
3960 {kIOReturnDeviceError
, "device error" },
3961 {kIOReturnNoCompletion
, "no completion routine" },
3962 {kIOReturnAborted
, "operation was aborted" },
3963 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
3964 {kIOReturnNotResponding
, "device is not responding" },
3965 {kIOReturnInvalid
, "unanticipated driver error" },
3969 return IOFindNameForValue(rtn
, IOReturn_values
);
3973 * Convert an IOReturn to an errno.
3975 int IOService::errnoFromReturn( IOReturn rtn
)
3979 case kIOReturnSuccess
:
3981 case kIOReturnNoMemory
:
3983 case kIOReturnNoDevice
:
3985 case kIOReturnVMError
:
3987 case kIOReturnNotPermitted
:
3989 case kIOReturnNotPrivileged
:
3991 case kIOReturnIOError
:
3993 case kIOReturnNotWritable
:
3995 case kIOReturnBadArgument
:
3997 case kIOReturnUnsupported
:
4001 case kIOReturnNoPower
:
4003 case kIOReturnDeviceError
:
4005 case kIOReturnTimeout
:
4007 case kIOReturnMessageTooLarge
:
4009 case kIOReturnNoSpace
:
4011 case kIOReturnCannotLock
:
4015 case kIOReturnBadMessageID
:
4016 case kIOReturnNoCompletion
:
4017 case kIOReturnNotAligned
:
4019 case kIOReturnNotReady
:
4021 case kIOReturnRLDError
:
4023 case kIOReturnPortExists
:
4024 case kIOReturnStillOpen
:
4026 case kIOReturnExclusiveAccess
:
4027 case kIOReturnLockedRead
:
4028 case kIOReturnLockedWrite
:
4029 case kIOReturnNotAttached
:
4030 case kIOReturnNotOpen
:
4031 case kIOReturnNotReadable
:
4033 case kIOReturnCannotWire
:
4034 case kIOReturnNoResources
:
4036 case kIOReturnAborted
:
4037 case kIOReturnOffline
:
4038 case kIOReturnNotResponding
:
4040 case kIOReturnBadMedia
:
4041 case kIOReturnNoMedia
:
4042 case kIOReturnUnformattedMedia
:
4043 return(EIO
); // (media error)
4044 case kIOReturnDMAError
:
4045 case kIOReturnOverrun
:
4046 case kIOReturnUnderrun
:
4047 return(EIO
); // (transfer error)
4048 case kIOReturnNoBandwidth
:
4049 case kIOReturnNoChannels
:
4050 case kIOReturnNoFrames
:
4051 case kIOReturnNoInterrupt
:
4052 return(EIO
); // (hardware error)
4053 case kIOReturnError
:
4054 case kIOReturnInternalError
:
4055 case kIOReturnInvalid
:
4056 return(EIO
); // (generic error)
4057 case kIOReturnIPCError
:
4058 return(EIO
); // (ipc error)
4060 return(EIO
); // (all other errors)
4064 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
4068 * Generic entry point for calls from the provider. A return value of
4069 * kIOReturnSuccess indicates that the message was received, and where
4070 * applicable, that it was successful.
4073 return kIOReturnUnsupported
;
4080 IOItemCount
IOService::getDeviceMemoryCount( void )
4085 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4087 count
= array
->getCount();
4094 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
4097 IODeviceMemory
* range
;
4099 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
4101 range
= (IODeviceMemory
*) array
->getObject( index
);
4108 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
4109 IOOptionBits options
= 0 )
4111 IODeviceMemory
* range
;
4114 range
= getDeviceMemoryWithIndex( index
);
4116 map
= range
->map( options
);
4123 OSArray
* IOService::getDeviceMemory( void )
4125 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
4129 void IOService::setDeviceMemory( OSArray
* array
)
4131 setProperty( gIODeviceMemoryKey
, array
);
4138 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
4140 IOInterruptController
*interruptController
;
4143 OSSymbol
*interruptControllerName
;
4145 IOInterruptSource
*interruptSources
;
4147 // Get the parents list from the nub.
4148 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
4149 if (array
== 0) return kIOReturnNoResources
;
4151 // Allocate space for the IOInterruptSources if needed... then return early.
4152 if (nub
->_interruptSources
== 0) {
4153 numSources
= array
->getCount();
4154 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
4155 if (interruptSources
== 0) return kIOReturnNoMemory
;
4157 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
4159 nub
->_numInterruptSources
= numSources
;
4160 nub
->_interruptSources
= interruptSources
;
4161 return kIOReturnSuccess
;
4164 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
4165 if (interruptControllerName
== 0) return kIOReturnNoResources
;
4167 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
4168 if (interruptController
== 0) return kIOReturnNoResources
;
4170 // Get the interrupt numbers from the nub.
4171 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
4172 if (array
== 0) return kIOReturnNoResources
;
4173 data
= OSDynamicCast(OSData
, array
->getObject(source
));
4174 if (data
== 0) return kIOReturnNoResources
;
4176 // Set the interruptController and interruptSource in the nub's table.
4177 interruptSources
= nub
->_interruptSources
;
4178 interruptSources
[source
].interruptController
= interruptController
;
4179 interruptSources
[source
].vectorData
= data
;
4181 return kIOReturnSuccess
;
4184 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
4188 /* Make sure the _interruptSources are set */
4189 if (_interruptSources
== 0) {
4190 ret
= resolveInterrupt(this, source
);
4191 if (ret
!= kIOReturnSuccess
) return ret
;
4194 /* Make sure the local source number is valid */
4195 if ((source
< 0) || (source
>= _numInterruptSources
))
4196 return kIOReturnNoInterrupt
;
4198 /* Look up the contoller for the local source */
4199 *interruptController
= _interruptSources
[source
].interruptController
;
4201 if (*interruptController
== NULL
) {
4202 if (!resolve
) return kIOReturnNoInterrupt
;
4204 /* Try to reslove the interrupt */
4205 ret
= resolveInterrupt(this, source
);
4206 if (ret
!= kIOReturnSuccess
) return ret
;
4208 *interruptController
= _interruptSources
[source
].interruptController
;
4211 return kIOReturnSuccess
;
4214 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
4215 IOInterruptAction handler
,
4218 IOInterruptController
*interruptController
;
4221 ret
= lookupInterrupt(source
, true, &interruptController
);
4222 if (ret
!= kIOReturnSuccess
) return ret
;
4224 /* Register the source */
4225 return interruptController
->registerInterrupt(this, source
, target
,
4226 (IOInterruptHandler
)handler
,
4230 IOReturn
IOService::unregisterInterrupt(int source
)
4232 IOInterruptController
*interruptController
;
4235 ret
= lookupInterrupt(source
, false, &interruptController
);
4236 if (ret
!= kIOReturnSuccess
) return ret
;
4238 /* Unregister the source */
4239 return interruptController
->unregisterInterrupt(this, source
);
4242 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
4244 IOInterruptController
*interruptController
;
4247 ret
= lookupInterrupt(source
, true, &interruptController
);
4248 if (ret
!= kIOReturnSuccess
) return ret
;
4250 /* Return the type */
4251 return interruptController
->getInterruptType(this, source
, interruptType
);
4254 IOReturn
IOService::enableInterrupt(int source
)
4256 IOInterruptController
*interruptController
;
4259 ret
= lookupInterrupt(source
, false, &interruptController
);
4260 if (ret
!= kIOReturnSuccess
) return ret
;
4262 /* Enable the source */
4263 return interruptController
->enableInterrupt(this, source
);
4266 IOReturn
IOService::disableInterrupt(int source
)
4268 IOInterruptController
*interruptController
;
4271 ret
= lookupInterrupt(source
, false, &interruptController
);
4272 if (ret
!= kIOReturnSuccess
) return ret
;
4274 /* Disable the source */
4275 return interruptController
->disableInterrupt(this, source
);
4278 IOReturn
IOService::causeInterrupt(int source
)
4280 IOInterruptController
*interruptController
;
4283 ret
= lookupInterrupt(source
, false, &interruptController
);
4284 if (ret
!= kIOReturnSuccess
) return ret
;
4286 /* Cause an interrupt for the source */
4287 return interruptController
->causeInterrupt(this, source
);
4290 OSMetaClassDefineReservedUsed(IOService
, 0);
4291 OSMetaClassDefineReservedUsed(IOService
, 1);
4292 OSMetaClassDefineReservedUsed(IOService
, 2);
4294 OSMetaClassDefineReservedUnused(IOService
, 3);
4295 OSMetaClassDefineReservedUnused(IOService
, 4);
4296 OSMetaClassDefineReservedUnused(IOService
, 5);
4297 OSMetaClassDefineReservedUnused(IOService
, 6);
4298 OSMetaClassDefineReservedUnused(IOService
, 7);
4299 OSMetaClassDefineReservedUnused(IOService
, 8);
4300 OSMetaClassDefineReservedUnused(IOService
, 9);
4301 OSMetaClassDefineReservedUnused(IOService
, 10);
4302 OSMetaClassDefineReservedUnused(IOService
, 11);
4303 OSMetaClassDefineReservedUnused(IOService
, 12);
4304 OSMetaClassDefineReservedUnused(IOService
, 13);
4305 OSMetaClassDefineReservedUnused(IOService
, 14);
4306 OSMetaClassDefineReservedUnused(IOService
, 15);
4307 OSMetaClassDefineReservedUnused(IOService
, 16);
4308 OSMetaClassDefineReservedUnused(IOService
, 17);
4309 OSMetaClassDefineReservedUnused(IOService
, 18);
4310 OSMetaClassDefineReservedUnused(IOService
, 19);
4311 OSMetaClassDefineReservedUnused(IOService
, 20);
4312 OSMetaClassDefineReservedUnused(IOService
, 21);
4313 OSMetaClassDefineReservedUnused(IOService
, 22);
4314 OSMetaClassDefineReservedUnused(IOService
, 23);
4315 OSMetaClassDefineReservedUnused(IOService
, 24);
4316 OSMetaClassDefineReservedUnused(IOService
, 25);
4317 OSMetaClassDefineReservedUnused(IOService
, 26);
4318 OSMetaClassDefineReservedUnused(IOService
, 27);
4319 OSMetaClassDefineReservedUnused(IOService
, 28);
4320 OSMetaClassDefineReservedUnused(IOService
, 29);
4321 OSMetaClassDefineReservedUnused(IOService
, 30);
4322 OSMetaClassDefineReservedUnused(IOService
, 31);
4323 OSMetaClassDefineReservedUnused(IOService
, 32);
4324 OSMetaClassDefineReservedUnused(IOService
, 33);
4325 OSMetaClassDefineReservedUnused(IOService
, 34);
4326 OSMetaClassDefineReservedUnused(IOService
, 35);
4327 OSMetaClassDefineReservedUnused(IOService
, 36);
4328 OSMetaClassDefineReservedUnused(IOService
, 37);
4329 OSMetaClassDefineReservedUnused(IOService
, 38);
4330 OSMetaClassDefineReservedUnused(IOService
, 39);
4331 OSMetaClassDefineReservedUnused(IOService
, 40);
4332 OSMetaClassDefineReservedUnused(IOService
, 41);
4333 OSMetaClassDefineReservedUnused(IOService
, 42);
4334 OSMetaClassDefineReservedUnused(IOService
, 43);
4335 OSMetaClassDefineReservedUnused(IOService
, 44);
4336 OSMetaClassDefineReservedUnused(IOService
, 45);
4337 OSMetaClassDefineReservedUnused(IOService
, 46);
4338 OSMetaClassDefineReservedUnused(IOService
, 47);
4339 OSMetaClassDefineReservedUnused(IOService
, 48);
4340 OSMetaClassDefineReservedUnused(IOService
, 49);
4341 OSMetaClassDefineReservedUnused(IOService
, 50);
4342 OSMetaClassDefineReservedUnused(IOService
, 51);
4343 OSMetaClassDefineReservedUnused(IOService
, 52);
4344 OSMetaClassDefineReservedUnused(IOService
, 53);
4345 OSMetaClassDefineReservedUnused(IOService
, 54);
4346 OSMetaClassDefineReservedUnused(IOService
, 55);
4347 OSMetaClassDefineReservedUnused(IOService
, 56);
4348 OSMetaClassDefineReservedUnused(IOService
, 57);
4349 OSMetaClassDefineReservedUnused(IOService
, 58);
4350 OSMetaClassDefineReservedUnused(IOService
, 59);
4351 OSMetaClassDefineReservedUnused(IOService
, 60);
4352 OSMetaClassDefineReservedUnused(IOService
, 61);
4353 OSMetaClassDefineReservedUnused(IOService
, 62);
4354 OSMetaClassDefineReservedUnused(IOService
, 63);