2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
31 #include <IOKit/IOService.h>
32 #include <libkern/OSDebug.h>
33 #include <libkern/c++/OSContainers.h>
34 #include <libkern/c++/OSKext.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <IOKit/IOCatalogue.h>
37 #include <IOKit/IOCommand.h>
38 #include <IOKit/IODeviceTreeSupport.h>
39 #include <IOKit/IODeviceMemory.h>
40 #include <IOKit/IOInterrupts.h>
41 #include <IOKit/IOInterruptController.h>
42 #include <IOKit/IOPlatformExpert.h>
43 #include <IOKit/IOMessage.h>
44 #include <IOKit/IOLib.h>
45 #include <IOKit/IOKitKeysPrivate.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/IOUserClient.h>
48 #include <IOKit/IOWorkLoop.h>
49 #include <IOKit/IOTimeStamp.h>
50 #include <IOKit/IOHibernatePrivate.h>
51 #include <mach/sync_policy.h>
52 #include <IOKit/assert.h>
53 #include <sys/errno.h>
55 #include <machine/pal_routines.h>
60 #define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
62 #include "IOServicePrivate.h"
63 #include "IOKitKernelInternal.h"
65 // take lockForArbitration before LOCKNOTIFY
67 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
69 #define super IORegistryEntry
71 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
73 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
75 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
77 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
79 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
81 OSDefineMetaClassAndStructors(IOResources
, IOService
)
83 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
85 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
87 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
89 static IOPlatformExpert
* gIOPlatform
;
90 static class IOPMrootDomain
* gIOPMRootDomain
;
91 const IORegistryPlane
* gIOServicePlane
;
92 const IORegistryPlane
* gIOPowerPlane
;
93 const OSSymbol
* gIODeviceMemoryKey
;
94 const OSSymbol
* gIOInterruptControllersKey
;
95 const OSSymbol
* gIOInterruptSpecifiersKey
;
97 const OSSymbol
* gIOResourcesKey
;
98 const OSSymbol
* gIOResourceMatchKey
;
99 const OSSymbol
* gIOProviderClassKey
;
100 const OSSymbol
* gIONameMatchKey
;
101 const OSSymbol
* gIONameMatchedKey
;
102 const OSSymbol
* gIOPropertyMatchKey
;
103 const OSSymbol
* gIOLocationMatchKey
;
104 const OSSymbol
* gIOParentMatchKey
;
105 const OSSymbol
* gIOPathMatchKey
;
106 const OSSymbol
* gIOMatchCategoryKey
;
107 const OSSymbol
* gIODefaultMatchCategoryKey
;
108 const OSSymbol
* gIOMatchedServiceCountKey
;
110 const OSSymbol
* gIOMapperIDKey
;
111 const OSSymbol
* gIOUserClientClassKey
;
112 const OSSymbol
* gIOKitDebugKey
;
114 const OSSymbol
* gIOCommandPoolSizeKey
;
116 const OSSymbol
* gIOConsoleLockedKey
;
117 const OSSymbol
* gIOConsoleUsersKey
;
118 const OSSymbol
* gIOConsoleSessionUIDKey
;
119 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
120 const OSSymbol
* gIOConsoleUsersSeedKey
;
121 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
122 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
123 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
124 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
126 clock_sec_t gIOConsoleLockTime
;
127 static bool gIOConsoleLoggedIn
;
129 static uint32_t gIOScreenLockState
;
131 static IORegistryEntry
* gIOChosenEntry
;
133 static int gIOResourceGenerationCount
;
135 const OSSymbol
* gIOServiceKey
;
136 const OSSymbol
* gIOPublishNotification
;
137 const OSSymbol
* gIOFirstPublishNotification
;
138 const OSSymbol
* gIOMatchedNotification
;
139 const OSSymbol
* gIOFirstMatchNotification
;
140 const OSSymbol
* gIOTerminatedNotification
;
142 const OSSymbol
* gIOGeneralInterest
;
143 const OSSymbol
* gIOBusyInterest
;
144 const OSSymbol
* gIOAppPowerStateInterest
;
145 const OSSymbol
* gIOPriorityPowerStateInterest
;
146 const OSSymbol
* gIOConsoleSecurityInterest
;
148 static OSDictionary
* gNotifications
;
149 static IORecursiveLock
* gNotificationLock
;
151 static IOService
* gIOResources
;
152 static IOService
* gIOServiceRoot
;
154 static OSOrderedSet
* gJobs
;
155 static semaphore_port_t gJobsSemaphore
;
156 static IOLock
* gJobsLock
;
157 static int gOutstandingJobs
;
158 static int gNumConfigThreads
;
159 static int gNumWaitingThreads
;
160 static IOLock
* gIOServiceBusyLock
;
162 static thread_t gIOTerminateThread
;
163 static UInt32 gIOTerminateWork
;
164 static OSArray
* gIOTerminatePhase2List
;
165 static OSArray
* gIOStopList
;
166 static OSArray
* gIOStopProviderList
;
167 static OSArray
* gIOFinalizeList
;
169 static SInt32 gIOConsoleUsersSeed
;
170 static OSData
* gIOConsoleUsersSeedValue
;
172 extern const OSSymbol
* gIODTPHandleKey
;
174 const OSSymbol
* gIOPlatformSleepActionKey
;
175 const OSSymbol
* gIOPlatformWakeActionKey
;
176 const OSSymbol
* gIOPlatformQuiesceActionKey
;
177 const OSSymbol
* gIOPlatformActiveActionKey
;
179 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
181 static IOLock
* gIOConsoleUsersLock
;
182 static thread_call_t gIOConsoleLockCallout
;
184 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
186 #define LOCKREADNOTIFY() \
187 IORecursiveLockLock( gNotificationLock )
188 #define LOCKWRITENOTIFY() \
189 IORecursiveLockLock( gNotificationLock )
190 #define LOCKWRITE2READNOTIFY()
191 #define UNLOCKNOTIFY() \
192 IORecursiveLockUnlock( gNotificationLock )
193 #define SLEEPNOTIFY(event) \
194 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
195 #define SLEEPNOTIFYTO(event, deadline) \
196 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
197 #define WAKEUPNOTIFY(event) \
198 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
200 #define randomDelay() \
201 int del = read_processor_clock(); \
202 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
205 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
207 #define queue_element(entry, element, type, field) do { \
208 vm_address_t __ele = (vm_address_t) (entry); \
209 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
210 (element) = (type) __ele; \
213 #define iterqueue(que, elt) \
214 for (queue_entry_t elt = queue_first(que); \
215 !queue_end(que, elt); \
216 elt = queue_next(elt))
218 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
220 struct ArbitrationLockQueueElement
{
229 static queue_head_t gArbitrationLockQueueActive
;
230 static queue_head_t gArbitrationLockQueueWaiting
;
231 static queue_head_t gArbitrationLockQueueFree
;
232 static IOLock
* gArbitrationLockQueueLock
;
234 bool IOService::isInactive( void ) const
235 { return( 0 != (kIOServiceInactiveState
& getState())); }
237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
239 #if defined(__i386__) || defined(__x86_64__)
241 // Only used by the intel implementation of
242 // IOService::requireMaxBusStall(UInt32 ns)
243 // IOService::requireMaxInterruptDelay(uint32_t ns)
246 IOService
* fService
;
252 kCpuDelayBusStall
, kCpuDelayInterrupt
,
256 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
257 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
258 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
259 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
262 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
264 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
266 #endif /* defined(__i386__) || defined(__x86_64__) */
268 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
270 void IOService::initialize( void )
274 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
275 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
277 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
278 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
279 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
280 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
281 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
282 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
283 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
285 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
286 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
287 kIODefaultMatchCategoryKey
);
288 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
289 kIOMatchedServiceCountKey
);
291 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
293 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
294 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
296 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
297 gIOInterruptControllersKey
298 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
299 gIOInterruptSpecifiersKey
300 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
302 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
304 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
306 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
308 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
309 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
310 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
311 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
312 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
314 gNotifications
= OSDictionary::withCapacity( 1 );
315 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
316 kIOPublishNotification
);
317 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
318 kIOFirstPublishNotification
);
319 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
320 kIOMatchedNotification
);
321 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
322 kIOFirstMatchNotification
);
323 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
324 kIOTerminatedNotification
);
325 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
327 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
328 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
329 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
330 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
332 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
333 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
334 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
335 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
336 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
338 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
340 gIOPlatformSleepActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey
);
341 gIOPlatformWakeActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey
);
342 gIOPlatformQuiesceActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey
);
343 gIOPlatformActiveActionKey
= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey
);
345 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
346 #if defined(__i386__) || defined(__x86_64__)
347 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
348 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
350 gNotificationLock
= IORecursiveLockAlloc();
352 assert( gIOServicePlane
&& gIODeviceMemoryKey
353 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
354 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
355 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
356 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
357 && gIOPublishNotification
&& gIOMatchedNotification
358 && gIOTerminatedNotification
&& gIOServiceKey
359 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
360 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
361 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
363 gJobsLock
= IOLockAlloc();
364 gJobs
= OSOrderedSet::withCapacity( 10 );
366 gIOServiceBusyLock
= IOLockAlloc();
368 gIOConsoleUsersLock
= IOLockAlloc();
370 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
372 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
374 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
376 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
377 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
) );
379 gIOResources
= IOResources::resources();
380 assert( gIOResources
);
382 gArbitrationLockQueueLock
= IOLockAlloc();
383 queue_init(&gArbitrationLockQueueActive
);
384 queue_init(&gArbitrationLockQueueWaiting
);
385 queue_init(&gArbitrationLockQueueFree
);
387 assert( gArbitrationLockQueueLock
);
389 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
390 gIOStopList
= OSArray::withCapacity( 16 );
391 gIOStopProviderList
= OSArray::withCapacity( 16 );
392 gIOFinalizeList
= OSArray::withCapacity( 16 );
393 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
396 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
399 static UInt64
getDebugFlags( OSDictionary
* props
)
401 OSNumber
* debugProp
;
404 debugProp
= OSDynamicCast( OSNumber
,
405 props
->getObject( gIOKitDebugKey
));
407 debugFlags
= debugProp
->unsigned64BitValue();
409 debugFlags
= gIOKitDebug
;
411 return( debugFlags
);
415 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
417 // Probe a matched service and return an instance to be started.
418 // The default score is from the property table, & may be altered
419 // during probe to change the start order.
421 IOService
* IOService::probe( IOService
* provider
,
427 bool IOService::start( IOService
* provider
)
432 void IOService::stop( IOService
* provider
)
436 void IOService::free( void )
438 requireMaxBusStall(0);
439 requireMaxInterruptDelay(0);
440 if( getPropertyTable())
441 unregisterAllInterest();
447 * Attach in service plane
449 bool IOService::attach( IOService
* provider
)
455 if( gIOKitDebug
& kIOLogAttach
)
456 LOG( "%s::attach(%s)\n", getName(),
457 provider
->getName());
459 provider
->lockForArbitration();
460 if( provider
->__state
[0] & kIOServiceInactiveState
)
463 ok
= attachToParent( provider
, gIOServicePlane
);
464 provider
->unlockForArbitration();
467 gIOServiceRoot
= this;
468 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
471 if (ok
&& !__provider
) (void) getProvider();
476 IOService
* IOService::getServiceRoot( void )
478 return( gIOServiceRoot
);
481 void IOService::detach( IOService
* provider
)
483 IOService
* newProvider
= 0;
487 if( gIOKitDebug
& kIOLogAttach
)
488 LOG("%s::detach(%s)\n", getName(), provider
->getName());
490 lockForArbitration();
492 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
493 && (provider
== getProvider()));
495 detachFromParent( provider
, gIOServicePlane
);
498 newProvider
= getProvider();
499 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
500 _adjustBusy( -busy
);
503 if (kIOServiceInactiveState
& __state
[0]) {
504 getMetaClass()->removeInstance(this);
507 unlockForArbitration();
510 newProvider
->lockForArbitration();
511 newProvider
->_adjustBusy(1);
512 newProvider
->unlockForArbitration();
515 // check for last client detach from a terminated service
516 if( provider
->lockForArbitration( true )) {
518 provider
->_adjustBusy( -1 );
519 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
520 && (0 == provider
->getClient())) {
521 provider
->scheduleFinalize();
523 provider
->unlockForArbitration();
528 * Register instance - publish it for matching
531 void IOService::registerService( IOOptionBits options
)
537 enum { kMaxPathLen
= 256 };
538 enum { kMaxChars
= 63 };
540 IORegistryEntry
* parent
= this;
541 IORegistryEntry
* root
= getRegistryRoot();
542 while( parent
&& (parent
!= root
))
543 parent
= parent
->getParentEntry( gIOServicePlane
);
545 if( parent
!= root
) {
546 IOLog("%s: not registry member at registerService()\n", getName());
550 // Allow the Platform Expert to adjust this node.
551 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
554 if( (this != gIOResources
)
555 && (kIOLogRegister
& gIOKitDebug
)) {
557 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
559 IOLog( "Registering: " );
562 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
565 if( len
> kMaxChars
) {
569 if( (skip
= strchr( path
, '/')))
575 IOLog( "%s\n", path
);
578 IOFree( pathBuf
, kMaxPathLen
);
581 startMatching( options
);
584 void IOService::startMatching( IOOptionBits options
)
586 IOService
* provider
;
589 bool needWake
= false;
594 lockForArbitration();
596 sync
= (options
& kIOServiceSynchronous
)
597 || ((provider
= getProvider())
598 && (provider
->__state
[1] & kIOServiceSynchronousState
));
600 if ( options
& kIOServiceAsynchronous
)
603 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
604 && (0 == (__state
[0] & kIOServiceInactiveState
));
606 __state
[1] |= kIOServiceNeedConfigState
;
608 // __state[0] &= ~kIOServiceInactiveState;
610 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
611 // OSKernelStackRemaining(), getName());
614 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
618 __state
[1] |= kIOServiceSynchronousState
;
620 __state
[1] &= ~kIOServiceSynchronousState
;
622 if( needConfig
) prevBusy
= _adjustBusy( 1 );
624 unlockForArbitration();
629 IOLockLock( gIOServiceBusyLock
);
630 thread_wakeup( (event_t
) this/*&__state[1]*/ );
631 IOLockUnlock( gIOServiceBusyLock
);
633 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
635 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
639 if( (__state
[1] & kIOServiceNeedConfigState
))
640 doServiceMatch( options
);
642 lockForArbitration();
643 IOLockLock( gIOServiceBusyLock
);
645 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
646 && (0 == (__state
[0] & kIOServiceInactiveState
)));
649 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
651 __state
[1] &= ~kIOServiceSyncPubState
;
653 unlockForArbitration();
656 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
658 IOLockUnlock( gIOServiceBusyLock
);
660 thread_block(THREAD_CONTINUE_NULL
);
662 } while( waitAgain
);
666 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
668 OSDictionary
* table
;
678 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
681 set
= (OSSet
*) copyExistingServices( table
,
682 kIOServiceRegisteredState
,
683 kIOServiceExistingSet
);
688 count
+= set
->getCount();
691 allSet
->merge((const OSSet
*) set
);
699 if( getDebugFlags( table
) & kIOLogMatch
)
700 LOG("Matching service count = %ld\n", (long)count
);
702 newTables
->removeObject(table
);
706 while( (service
= (IOService
*) allSet
->getAnyObject())) {
707 service
->startMatching(kIOServiceAsynchronous
);
708 allSet
->removeObject(service
);
713 newTables
->release();
715 return( kIOReturnSuccess
);
718 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
719 IOOptionBits options
)
723 job
= new _IOServiceJob
;
724 if( job
&& !job
->init()) {
732 job
->options
= options
;
733 nub
->retain(); // thread will release()
741 * Called on a registered service to see if it matches
745 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
747 return( matchPropertyTable(table
) );
750 bool IOService::matchPropertyTable( OSDictionary
* table
)
756 * Called on a matched service to allocate resources
757 * before first driver is attached.
760 IOReturn
IOService::getResources( void )
762 return( kIOReturnSuccess
);
766 * Client/provider accessors
769 IOService
* IOService::getProvider( void ) const
771 IOService
* self
= (IOService
*) this;
775 generation
= getGenerationCount();
776 if( __providerGeneration
== generation
)
777 return( __provider
);
779 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
780 if( parent
== IORegistryEntry::getRegistryRoot())
781 /* root is not an IOService */
784 self
->__provider
= parent
;
786 // save the count from before call to getParentEntry()
787 self
->__providerGeneration
= generation
;
792 IOWorkLoop
* IOService::getWorkLoop() const
794 IOService
*provider
= getProvider();
797 return provider
->getWorkLoop();
802 OSIterator
* IOService::getProviderIterator( void ) const
804 return( getParentIterator( gIOServicePlane
));
807 IOService
* IOService::getClient( void ) const
809 return( (IOService
*) getChildEntry( gIOServicePlane
));
812 OSIterator
* IOService::getClientIterator( void ) const
814 return( getChildIterator( gIOServicePlane
));
817 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
818 const IOService
* client
,
819 const IOService
* provider
)
821 _IOOpenServiceIterator
* inst
;
826 inst
= new _IOOpenServiceIterator
;
828 if( inst
&& !inst
->init()) {
834 inst
->client
= client
;
835 inst
->provider
= provider
;
841 void _IOOpenServiceIterator::free()
845 last
->unlockForArbitration();
849 OSObject
* _IOOpenServiceIterator::getNextObject()
854 last
->unlockForArbitration();
856 while( (next
= (IOService
*) iter
->getNextObject())) {
858 next
->lockForArbitration();
859 if( (client
&& (next
->isOpen( client
)))
860 || (provider
&& (provider
->isOpen( next
))) )
862 next
->unlockForArbitration();
870 bool _IOOpenServiceIterator::isValid()
872 return( iter
->isValid() );
875 void _IOOpenServiceIterator::reset()
878 last
->unlockForArbitration();
884 OSIterator
* IOService::getOpenProviderIterator( void ) const
886 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
889 OSIterator
* IOService::getOpenClientIterator( void ) const
891 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
895 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
896 bool waitForFunction
,
897 void *param1
, void *param2
,
898 void *param3
, void *param4
)
900 IOReturn result
= kIOReturnUnsupported
;
903 if (gIOPlatformFunctionHandlerSet
== functionName
)
905 #if defined(__i386__) || defined(__x86_64__)
906 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
907 IOService
* target
= (IOService
*) param2
;
908 bool enable
= (param3
!= 0);
910 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
911 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
912 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
913 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
914 #endif /* defined(__i386__) || defined(__x86_64__) */
917 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
918 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
919 param1
, param2
, param3
, param4
);
925 IOReturn
IOService::callPlatformFunction( const char * functionName
,
926 bool waitForFunction
,
927 void *param1
, void *param2
,
928 void *param3
, void *param4
)
930 IOReturn result
= kIOReturnNoMemory
;
931 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
933 if (functionSymbol
!= 0) {
934 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
935 param1
, param2
, param3
, param4
);
936 functionSymbol
->release();
944 * Accessors for global services
947 IOPlatformExpert
* IOService::getPlatform( void )
949 return( gIOPlatform
);
952 class IOPMrootDomain
* IOService::getPMRootDomain( void )
954 return( gIOPMRootDomain
);
957 IOService
* IOService::getResourceService( void )
959 return( gIOResources
);
962 void IOService::setPlatform( IOPlatformExpert
* platform
)
964 gIOPlatform
= platform
;
965 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
968 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
970 gIOPMRootDomain
= rootDomain
;
971 publishResource("IOKit");
978 bool IOService::lockForArbitration( bool isSuccessRequired
)
982 ArbitrationLockQueueElement
* element
;
983 ArbitrationLockQueueElement
* active
;
984 ArbitrationLockQueueElement
* waiting
;
986 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
988 // lock global access
989 IOTakeLock( gArbitrationLockQueueLock
);
991 // obtain an unused queue element
992 if( !queue_empty( &gArbitrationLockQueueFree
)) {
993 queue_remove_first( &gArbitrationLockQueueFree
,
995 ArbitrationLockQueueElement
*,
998 element
= IONew( ArbitrationLockQueueElement
, 1 );
1002 // prepare the queue element
1003 element
->thread
= IOThreadSelf();
1004 element
->service
= this;
1006 element
->required
= isSuccessRequired
;
1007 element
->aborted
= false;
1009 // determine whether this object is already locked (ie. on active queue)
1011 queue_iterate( &gArbitrationLockQueueActive
,
1013 ArbitrationLockQueueElement
*,
1016 if( active
->service
== element
->service
) {
1022 if( found
) { // this object is already locked
1024 // determine whether it is the same or a different thread trying to lock
1025 if( active
->thread
!= element
->thread
) { // it is a different thread
1027 ArbitrationLockQueueElement
* victim
= 0;
1029 // before placing this new thread on the waiting queue, we look for
1030 // a deadlock cycle...
1033 // determine whether the active thread holding the object we
1034 // want is waiting for another object to be unlocked
1036 queue_iterate( &gArbitrationLockQueueWaiting
,
1038 ArbitrationLockQueueElement
*,
1041 if( waiting
->thread
== active
->thread
) {
1042 assert( false == waiting
->aborted
);
1048 if( found
) { // yes, active thread waiting for another object
1050 // this may be a candidate for rejection if the required
1051 // flag is not set, should we detect a deadlock later on
1052 if( false == waiting
->required
)
1055 // find the thread that is holding this other object, that
1056 // is blocking the active thread from proceeding (fun :-)
1058 queue_iterate( &gArbitrationLockQueueActive
,
1059 active
, // (reuse active queue element)
1060 ArbitrationLockQueueElement
*,
1063 if( active
->service
== waiting
->service
) {
1069 // someone must be holding it or it wouldn't be waiting
1072 if( active
->thread
== element
->thread
) {
1074 // doh, it's waiting for the thread that originated
1075 // this whole lock (ie. current thread) -> deadlock
1076 if( false == element
->required
) { // willing to fail?
1078 // the originating thread doesn't have the required
1079 // flag, so it can fail
1080 success
= false; // (fail originating lock request)
1081 break; // (out of while)
1083 } else { // originating thread is not willing to fail
1085 // see if we came across a waiting thread that did
1086 // not have the 'required' flag set: we'll fail it
1089 // we do have a willing victim, fail it's lock
1090 victim
->aborted
= true;
1092 // take the victim off the waiting queue
1093 queue_remove( &gArbitrationLockQueueWaiting
,
1095 ArbitrationLockQueueElement
*,
1099 IOLockWakeup( gArbitrationLockQueueLock
,
1101 /* one thread */ true );
1103 // allow this thread to proceed (ie. wait)
1104 success
= true; // (put request on wait queue)
1105 break; // (out of while)
1108 // all the waiting threads we came across in
1109 // finding this loop had the 'required' flag
1110 // set, so we've got a deadlock we can't avoid
1111 panic("I/O Kit: Unrecoverable deadlock.");
1115 // repeat while loop, redefining active thread to be the
1116 // thread holding "this other object" (see above), and
1117 // looking for threads waiting on it; note the active
1118 // variable points to "this other object" already... so
1119 // there nothing to do in this else clause.
1121 } else { // no, active thread is not waiting for another object
1123 success
= true; // (put request on wait queue)
1124 break; // (out of while)
1128 if( success
) { // put the request on the waiting queue?
1129 kern_return_t wait_result
;
1131 // place this thread on the waiting queue and put it to sleep;
1132 // we place it at the tail of the queue...
1133 queue_enter( &gArbitrationLockQueueWaiting
,
1135 ArbitrationLockQueueElement
*,
1138 // declare that this thread will wait for a given event
1139 restart_sleep
: wait_result
= assert_wait( element
,
1140 element
->required
? THREAD_UNINT
1141 : THREAD_INTERRUPTIBLE
);
1143 // unlock global access
1144 IOUnlock( gArbitrationLockQueueLock
);
1146 // put thread to sleep, waiting for our event to fire...
1147 if (wait_result
== THREAD_WAITING
)
1148 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1151 // ...and we've been woken up; we might be in one of two states:
1152 // (a) we've been aborted and our queue element is not on
1153 // any of the three queues, but is floating around
1154 // (b) we're allowed to proceed with the lock and we have
1155 // already been moved from the waiting queue to the
1157 // ...plus a 3rd state, should the thread have been interrupted:
1158 // (c) we're still on the waiting queue
1160 // determine whether we were interrupted out of our sleep
1161 if( THREAD_INTERRUPTED
== wait_result
) {
1163 // re-lock global access
1164 IOTakeLock( gArbitrationLockQueueLock
);
1166 // determine whether we're still on the waiting queue
1168 queue_iterate( &gArbitrationLockQueueWaiting
,
1169 waiting
, // (reuse waiting queue element)
1170 ArbitrationLockQueueElement
*,
1173 if( waiting
== element
) {
1179 if( found
) { // yes, we're still on the waiting queue
1181 // determine whether we're willing to fail
1182 if( false == element
->required
) {
1184 // mark us as aborted
1185 element
->aborted
= true;
1187 // take us off the waiting queue
1188 queue_remove( &gArbitrationLockQueueWaiting
,
1190 ArbitrationLockQueueElement
*,
1192 } else { // we are not willing to fail
1194 // ignore interruption, go back to sleep
1199 // unlock global access
1200 IOUnlock( gArbitrationLockQueueLock
);
1202 // proceed as though this were a normal wake up
1203 wait_result
= THREAD_AWAKENED
;
1206 assert( THREAD_AWAKENED
== wait_result
);
1208 // determine whether we've been aborted while we were asleep
1209 if( element
->aborted
) {
1210 assert( false == element
->required
);
1212 // re-lock global access
1213 IOTakeLock( gArbitrationLockQueueLock
);
1215 action
= kPutOnFreeQueue
;
1217 } else { // we weren't aborted, so we must be ready to go :-)
1219 // we've already been moved from waiting to active queue
1223 } else { // the lock request is to be failed
1225 // return unused queue element to queue
1226 action
= kPutOnFreeQueue
;
1228 } else { // it is the same thread, recursive access is allowed
1230 // add one level of recursion
1233 // return unused queue element to queue
1234 action
= kPutOnFreeQueue
;
1237 } else { // this object is not already locked, so let this thread through
1238 action
= kPutOnActiveQueue
;
1242 // put the new element on a queue
1243 if( kPutOnActiveQueue
== action
) {
1244 queue_enter( &gArbitrationLockQueueActive
,
1246 ArbitrationLockQueueElement
*,
1248 } else if( kPutOnFreeQueue
== action
) {
1249 queue_enter( &gArbitrationLockQueueFree
,
1251 ArbitrationLockQueueElement
*,
1254 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1257 // unlock global access
1258 IOUnlock( gArbitrationLockQueueLock
);
1263 void IOService::unlockForArbitration( void )
1266 ArbitrationLockQueueElement
* element
;
1268 // lock global access
1269 IOTakeLock( gArbitrationLockQueueLock
);
1271 // find the lock element for this object (ie. on active queue)
1273 queue_iterate( &gArbitrationLockQueueActive
,
1275 ArbitrationLockQueueElement
*,
1278 if( element
->service
== this ) {
1286 // determine whether the lock has been taken recursively
1287 if( element
->count
> 1 ) {
1288 // undo one level of recursion
1293 // remove it from the active queue
1294 queue_remove( &gArbitrationLockQueueActive
,
1296 ArbitrationLockQueueElement
*,
1299 // put it on the free queue
1300 queue_enter( &gArbitrationLockQueueFree
,
1302 ArbitrationLockQueueElement
*,
1305 // determine whether a thread is waiting for object (head to tail scan)
1307 queue_iterate( &gArbitrationLockQueueWaiting
,
1309 ArbitrationLockQueueElement
*,
1312 if( element
->service
== this ) {
1318 if ( found
) { // we found an interested thread on waiting queue
1320 // remove it from the waiting queue
1321 queue_remove( &gArbitrationLockQueueWaiting
,
1323 ArbitrationLockQueueElement
*,
1326 // put it on the active queue
1327 queue_enter( &gArbitrationLockQueueActive
,
1329 ArbitrationLockQueueElement
*,
1332 // wake the waiting thread
1333 IOLockWakeup( gArbitrationLockQueueLock
,
1335 /* one thread */ true );
1339 // unlock global access
1340 IOUnlock( gArbitrationLockQueueLock
);
1343 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1346 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1347 context
, gIOServicePlane
);
1350 void IOService::applyToClients( IOServiceApplierFunction applier
,
1353 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1354 context
, gIOServicePlane
);
1363 // send a message to a client or interested party of this service
1364 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1365 void * argument
, vm_size_t argSize
)
1368 IOService
* service
;
1369 _IOServiceInterestNotifier
* notify
;
1371 if( (service
= OSDynamicCast( IOService
, client
)))
1372 ret
= service
->message( type
, this, argument
);
1374 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1376 _IOServiceNotifierInvocation invocation
;
1379 invocation
.thread
= current_thread();
1382 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1385 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1386 _IOServiceNotifierInvocation
*, link
);
1392 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1393 type
, this, argument
, argSize
);
1396 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1397 _IOServiceNotifierInvocation
*, link
);
1398 if( kIOServiceNotifyWaiter
& notify
->state
) {
1399 notify
->state
&= ~kIOServiceNotifyWaiter
;
1400 WAKEUPNOTIFY( notify
);
1405 ret
= kIOReturnSuccess
;
1408 ret
= kIOReturnBadArgument
;
1414 applyToInterestNotifiers(const IORegistryEntry
*target
,
1415 const OSSymbol
* typeOfInterest
,
1416 OSObjectApplierFunction applier
,
1419 OSArray
* copyArray
= 0;
1423 IOCommand
*notifyList
=
1424 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1427 copyArray
= OSArray::withCapacity(1);
1429 // iterate over queue, entry is set to each element in the list
1430 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1431 _IOServiceInterestNotifier
* notify
;
1433 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1434 copyArray
->setObject(notify
);
1443 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1444 (*applier
)(next
, context
);
1445 copyArray
->release();
1449 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1450 OSObjectApplierFunction applier
,
1453 if (gIOGeneralInterest
== typeOfInterest
)
1454 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1455 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1458 struct MessageClientsContext
{
1459 IOService
* service
;
1466 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1469 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1471 ret
= context
->service
->messageClient( context
->type
,
1472 object
, context
->argument
, context
->argSize
);
1473 if( kIOReturnSuccess
!= ret
)
1477 // send a message to all clients
1478 IOReturn
IOService::messageClients( UInt32 type
,
1479 void * argument
, vm_size_t argSize
)
1481 MessageClientsContext context
;
1483 context
.service
= this;
1484 context
.type
= type
;
1485 context
.argument
= argument
;
1486 context
.argSize
= argSize
;
1487 context
.ret
= kIOReturnSuccess
;
1489 applyToInterested( gIOGeneralInterest
,
1490 &messageClientsApplier
, &context
);
1492 return( context
.ret
);
1495 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1496 IOOptionBits response
)
1498 return( kIOReturnUnsupported
);
1501 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1502 IOServiceInterestHandler handler
, void * target
, void * ref
)
1504 _IOServiceInterestNotifier
* notify
= 0;
1506 if( (typeOfInterest
!= gIOGeneralInterest
)
1507 && (typeOfInterest
!= gIOBusyInterest
)
1508 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1509 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
1510 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1513 lockForArbitration();
1514 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1516 notify
= new _IOServiceInterestNotifier
;
1517 if( notify
&& !notify
->init()) {
1523 notify
->handler
= handler
;
1524 notify
->target
= target
;
1526 notify
->state
= kIOServiceNotifyEnable
;
1527 queue_init( ¬ify
->handlerInvocations
);
1533 // Get the head of the notifier linked list
1534 IOCommand
*notifyList
= (IOCommand
*) getProperty( typeOfInterest
);
1535 if (!notifyList
|| !OSDynamicCast(IOCommand
, notifyList
)) {
1536 notifyList
= OSTypeAlloc(IOCommand
);
1539 setProperty( typeOfInterest
, notifyList
);
1540 notifyList
->release();
1545 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1546 notify
->retain(); // ref'ed while in list
1552 unlockForArbitration();
1557 static void cleanInterestList( OSObject
* head
)
1559 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1564 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1565 queue_next(entry
) = queue_prev(entry
) = 0;
1567 _IOServiceInterestNotifier
* notify
;
1569 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1575 void IOService::unregisterAllInterest( void )
1577 cleanInterestList( getProperty( gIOGeneralInterest
));
1578 cleanInterestList( getProperty( gIOBusyInterest
));
1579 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1580 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1581 cleanInterestList( getProperty( gIOConsoleSecurityInterest
));
1585 * _IOServiceInterestNotifier
1588 // wait for all threads, other than the current one,
1589 // to exit the handler
1591 void _IOServiceInterestNotifier::wait()
1593 _IOServiceNotifierInvocation
* next
;
1598 queue_iterate( &handlerInvocations
, next
,
1599 _IOServiceNotifierInvocation
*, link
) {
1600 if( next
->thread
!= current_thread() ) {
1606 state
|= kIOServiceNotifyWaiter
;
1613 void _IOServiceInterestNotifier::free()
1615 assert( queue_empty( &handlerInvocations
));
1619 void _IOServiceInterestNotifier::remove()
1623 if( queue_next( &chain
)) {
1625 queue_next( &chain
) = queue_prev( &chain
) = 0;
1629 state
&= ~kIOServiceNotifyEnable
;
1638 bool _IOServiceInterestNotifier::disable()
1644 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1645 state
&= ~kIOServiceNotifyEnable
;
1654 void _IOServiceInterestNotifier::enable( bool was
)
1658 state
|= kIOServiceNotifyEnable
;
1660 state
&= ~kIOServiceNotifyEnable
;
1664 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1670 #define tailQ(o) setObject(o)
1671 #define headQ(o) setObject(0, o)
1672 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1674 static void _workLoopAction( IOWorkLoop::Action action
,
1675 IOService
* service
,
1676 void * p0
= 0, void * p1
= 0,
1677 void * p2
= 0, void * p3
= 0 )
1681 if( (wl
= service
->getWorkLoop())) {
1683 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1686 (*action
)( service
, p0
, p1
, p2
, p3
);
1689 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1693 // if its our only provider
1694 ok
= isParent( provider
, gIOServicePlane
, true);
1698 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1699 ok
= (0 != (__state
[1] & kIOServiceRecursing
));
1706 bool IOService::terminatePhase1( IOOptionBits options
)
1711 OSArray
* makeInactive
;
1712 int waitResult
= THREAD_AWAKENED
;
1716 bool startPhase2
= false;
1718 TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options
);
1720 uint64_t regID
= getRegistryEntryID();
1722 IOSERVICE_TERMINATE_PHASE1
,
1724 (uintptr_t) (regID
>> 32),
1726 (uintptr_t) options
);
1729 if( options
& kIOServiceRecursing
) {
1730 lockForArbitration();
1731 __state
[1] |= kIOServiceRecursing
;
1732 unlockForArbitration();
1737 makeInactive
= OSArray::withCapacity( 16 );
1746 didInactive
= victim
->lockForArbitration( true );
1748 didInactive
= (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
1750 victim
->__state
[0] |= kIOServiceInactiveState
;
1751 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
1752 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
1755 victim
->__state
[1] |= kIOServiceTermPhase1State
;
1757 victim
->_adjustBusy( 1 );
1759 } else if (victim
!= this) do {
1761 IOLockLock(gIOServiceBusyLock
);
1762 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
1764 TLOG("%s::waitPhase1(%s)\n", getName(), victim
->getName());
1765 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
1766 victim
->unlockForArbitration();
1767 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
1769 IOLockUnlock(gIOServiceBusyLock
);
1771 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
1772 TLOG("%s::did waitPhase1(%s)\n", getName(), victim
->getName());
1773 victim
->lockForArbitration();
1775 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
1777 victim
->unlockForArbitration();
1780 startPhase2
= didInactive
;
1783 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
1784 IOUserClient::destroyUserReferences( victim
);
1786 iter
= victim
->getClientIterator();
1788 while( (client
= (IOService
*) iter
->getNextObject())) {
1789 TLOG("%s::requestTerminate(%s, %08llx)\n",
1790 client
->getName(), victim
->getName(), (long long)options
);
1791 ok
= client
->requestTerminate( victim
, options
);
1792 TLOG("%s::requestTerminate(%s, ok = %d)\n",
1793 client
->getName(), victim
->getName(), ok
);
1795 uint64_t regID1
= client
->getRegistryEntryID();
1796 uint64_t regID2
= victim
->getRegistryEntryID();
1798 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
1799 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
1801 (uintptr_t) (regID1
>> 32),
1803 (uintptr_t) (regID2
>> 32));
1806 makeInactive
->setObject( client
);
1812 victim
= (IOService
*) makeInactive
->getObject(0);
1815 makeInactive
->removeObject(0);
1819 makeInactive
->release();
1823 lockForArbitration();
1824 __state
[1] &= ~kIOServiceTermPhase1State
;
1825 if (kIOServiceTerm1WaiterState
& __state
[1])
1827 __state
[1] &= ~kIOServiceTerm1WaiterState
;
1828 TLOG("%s::wakePhase1\n", getName());
1829 IOLockLock( gIOServiceBusyLock
);
1830 thread_wakeup( (event_t
) &__state
[1]);
1831 IOLockUnlock( gIOServiceBusyLock
);
1833 unlockForArbitration();
1835 scheduleTerminatePhase2( options
);
1840 void IOService::setTerminateDefer(IOService
* provider
, bool defer
)
1842 lockForArbitration();
1843 if (defer
) __state
[1] |= kIOServiceStartState
;
1844 else __state
[1] &= ~kIOServiceStartState
;
1845 unlockForArbitration();
1847 if (provider
&& !defer
)
1849 provider
->lockForArbitration();
1850 if (provider
->__state
[0] & kIOServiceInactiveState
)
1852 provider
->scheduleTerminatePhase2();
1854 provider
->unlockForArbitration();
1858 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
1860 AbsoluteTime deadline
;
1861 int waitResult
= THREAD_AWAKENED
;
1862 bool wait
, haveDeadline
= false;
1864 options
|= kIOServiceRequired
;
1868 IOLockLock( gJobsLock
);
1870 if( (options
& kIOServiceSynchronous
)
1871 && (current_thread() != gIOTerminateThread
)) {
1874 wait
= (gIOTerminateThread
!= 0);
1876 // wait to become the terminate thread
1877 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
1881 gIOTerminateThread
= current_thread();
1882 gIOTerminatePhase2List
->setObject( this );
1886 while( gIOTerminateWork
)
1887 terminateWorker( options
);
1888 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
1890 // wait for the victim to go non-busy
1891 if( !haveDeadline
) {
1892 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
1893 haveDeadline
= true;
1895 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
1896 deadline
, THREAD_UNINT
);
1897 if( waitResult
== THREAD_TIMED_OUT
) {
1898 IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName());
1901 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
1903 gIOTerminateThread
= 0;
1904 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1907 // ! kIOServiceSynchronous
1909 gIOTerminatePhase2List
->setObject( this );
1910 if( 0 == gIOTerminateWork
++) {
1911 if( !gIOTerminateThread
)
1912 kernel_thread_start(&terminateThread
, (void *)(uintptr_t) options
, &gIOTerminateThread
);
1914 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1918 IOLockUnlock( gJobsLock
);
1923 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
1925 IOLockLock( gJobsLock
);
1927 while (gIOTerminateWork
)
1928 terminateWorker( (uintptr_t) arg
);
1930 thread_deallocate(gIOTerminateThread
);
1931 gIOTerminateThread
= 0;
1932 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
1934 IOLockUnlock( gJobsLock
);
1937 void IOService::scheduleStop( IOService
* provider
)
1939 TLOG("%s::scheduleStop(%s)\n", getName(), provider
->getName());
1941 uint64_t regID1
= getRegistryEntryID();
1942 uint64_t regID2
= provider
->getRegistryEntryID();
1944 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
1946 (uintptr_t) (regID1
>> 32),
1948 (uintptr_t) (regID2
>> 32));
1950 IOLockLock( gJobsLock
);
1951 gIOStopList
->tailQ( this );
1952 gIOStopProviderList
->tailQ( provider
);
1954 if( 0 == gIOTerminateWork
++) {
1955 if( !gIOTerminateThread
)
1956 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1958 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1961 IOLockUnlock( gJobsLock
);
1964 void IOService::scheduleFinalize( void )
1966 TLOG("%s::scheduleFinalize\n", getName());
1968 uint64_t regID1
= getRegistryEntryID();
1970 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
1972 (uintptr_t) (regID1
>> 32),
1975 IOLockLock( gJobsLock
);
1976 gIOFinalizeList
->tailQ( this );
1978 if( 0 == gIOTerminateWork
++) {
1979 if( !gIOTerminateThread
)
1980 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
1982 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
1985 IOLockUnlock( gJobsLock
);
1988 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
1993 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
1995 if( false == *defer
) {
1997 if( lockForArbitration( true )) {
1998 if( false == provider
->handleIsOpen( this ))
1999 scheduleStop( provider
);
2002 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2003 if( false == provider
->handleIsOpen( this ))
2004 scheduleStop( provider
);
2007 unlockForArbitration();
2014 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2015 OSArray
* doPhase2List
,
2016 void *unused2 __unused
,
2017 void *unused3 __unused
)
2023 iter
= victim
->getClientIterator();
2025 while( (client
= (IOService
*) iter
->getNextObject())) {
2026 TLOG("%s::willTerminate(%s, %08llx)\n",
2027 client
->getName(), victim
->getName(), (long long)options
);
2029 uint64_t regID1
= client
->getRegistryEntryID();
2030 uint64_t regID2
= victim
->getRegistryEntryID();
2032 IOSERVICE_TERMINATE_WILL
,
2034 (uintptr_t) (regID1
>> 32),
2036 (uintptr_t) (regID2
>> 32));
2038 ok
= client
->willTerminate( victim
, options
);
2039 doPhase2List
->tailQ( client
);
2045 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2046 void *unused1 __unused
, void *unused2 __unused
,
2047 void *unused3 __unused
)
2053 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2055 iter
= victim
->getClientIterator();
2057 while( (client
= (IOService
*) iter
->getNextObject())) {
2058 TLOG("%s::didTerminate(%s, %08llx)\n",
2059 client
->getName(), victim
->getName(), (long long)options
);
2060 client
->didTerminate( victim
, options
, &defer
);
2062 uint64_t regID1
= client
->getRegistryEntryID();
2063 uint64_t regID2
= victim
->getRegistryEntryID();
2065 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2066 : IOSERVICE_TERMINATE_DID
),
2068 (uintptr_t) (regID1
>> 32),
2070 (uintptr_t) (regID2
>> 32));
2072 TLOG("%s::didTerminate(%s, defer %d)\n",
2073 client
->getName(), victim
->getName(), defer
);
2079 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2080 void *unused1 __unused
, void *unused2 __unused
,
2081 void *unused3 __unused
)
2083 TLOG("%s::finalize(%08llx)\n", victim
->getName(), (long long)options
);
2085 uint64_t regID1
= victim
->getRegistryEntryID();
2087 IOSERVICE_TERMINATE_FINALIZE
,
2089 (uintptr_t) (regID1
>> 32),
2092 victim
->finalize( options
);
2095 void IOService::actionStop( IOService
* provider
, IOService
* client
,
2096 void *unused1 __unused
, void *unused2 __unused
,
2097 void *unused3 __unused
)
2099 TLOG("%s::stop(%s)\n", client
->getName(), provider
->getName());
2101 uint64_t regID1
= provider
->getRegistryEntryID();
2102 uint64_t regID2
= client
->getRegistryEntryID();
2104 IOSERVICE_TERMINATE_STOP
,
2106 (uintptr_t) (regID1
>> 32),
2108 (uintptr_t) (regID2
>> 32));
2110 client
->stop( provider
);
2111 if( provider
->isOpen( client
))
2112 provider
->close( client
);
2113 TLOG("%s::detach(%s)\n", client
->getName(), provider
->getName());
2114 client
->detach( provider
);
2117 void IOService::terminateWorker( IOOptionBits options
)
2119 OSArray
* doPhase2List
;
2120 OSArray
* didPhase2List
;
2126 IOService
* provider
;
2132 options
|= kIOServiceRequired
;
2134 doPhase2List
= OSArray::withCapacity( 16 );
2135 didPhase2List
= OSArray::withCapacity( 16 );
2136 freeList
= OSSet::withCapacity( 16 );
2137 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2141 workDone
= gIOTerminateWork
;
2143 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2146 gIOTerminatePhase2List
->removeObject(0);
2147 IOLockUnlock( gJobsLock
);
2151 doPhase2
= victim
->lockForArbitration( true );
2153 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2155 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
2156 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
2158 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
2159 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
2160 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
2165 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2167 victim
->unlockForArbitration();
2170 if( 0 == victim
->getClient()) {
2171 // no clients - will go to finalize
2172 IOLockLock( gJobsLock
);
2173 gIOFinalizeList
->tailQ( victim
);
2174 IOLockUnlock( gJobsLock
);
2176 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2177 victim
, (void *)(uintptr_t) options
, (void *)(uintptr_t) doPhase2List
);
2179 didPhase2List
->headQ( victim
);
2182 victim
= (IOService
*) doPhase2List
->getObject(0);
2185 doPhase2List
->removeObject(0);
2189 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2191 if( victim
->lockForArbitration( true )) {
2192 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2193 victim
->unlockForArbitration();
2195 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2196 victim
, (void *)(uintptr_t) options
);
2197 didPhase2List
->removeObject(0);
2199 IOLockLock( gJobsLock
);
2206 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2208 IOLockUnlock( gJobsLock
);
2209 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2210 victim
, (void *)(uintptr_t) options
);
2211 IOLockLock( gJobsLock
);
2213 freeList
->setObject( victim
);
2214 // safe if finalize list is append only
2215 gIOFinalizeList
->removeObject(0);
2219 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2221 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2224 if( !provider
->isChild( client
, gIOServicePlane
)) {
2225 // may be multiply queued - nop it
2226 TLOG("%s::nop stop(%s)\n", client
->getName(), provider
->getName());
2228 uint64_t regID1
= provider
->getRegistryEntryID();
2229 uint64_t regID2
= client
->getRegistryEntryID();
2231 IOSERVICE_TERMINATE_STOP_NOP
,
2233 (uintptr_t) (regID1
>> 32),
2235 (uintptr_t) (regID2
>> 32));
2238 // a terminated client is not ready for stop if it has clients, skip it
2239 if( (kIOServiceInactiveState
& client
->__state
[0]) && client
->getClient()) {
2240 TLOG("%s::defer stop(%s)\n", client
->getName(), provider
->getName());
2242 uint64_t regID1
= provider
->getRegistryEntryID();
2243 uint64_t regID2
= client
->getRegistryEntryID();
2245 IOSERVICE_TERMINATE_STOP_DEFER
,
2247 (uintptr_t) (regID1
>> 32),
2249 (uintptr_t) (regID2
>> 32));
2255 IOLockUnlock( gJobsLock
);
2256 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2257 provider
, (void *) client
);
2258 IOLockLock( gJobsLock
);
2259 // check the finalize list now
2263 freeList
->setObject( client
);
2264 freeList
->setObject( provider
);
2266 // safe if stop list is append only
2267 gIOStopList
->removeObject( idx
);
2268 gIOStopProviderList
->removeObject( idx
);
2272 } while( doPhase3
);
2274 gIOTerminateWork
-= workDone
;
2275 moreToDo
= (gIOTerminateWork
!= 0);
2278 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2280 IOSERVICE_TERMINATE_DONE
,
2281 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2284 } while( moreToDo
);
2286 IOLockUnlock( gJobsLock
);
2288 freeList
->release();
2289 doPhase2List
->release();
2290 didPhase2List
->release();
2292 IOLockLock( gJobsLock
);
2295 bool IOService::finalize( IOOptionBits options
)
2298 IOService
* provider
;
2300 iter
= getProviderIterator();
2304 while( (provider
= (IOService
*) iter
->getNextObject())) {
2307 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2308 /* we come down here on programmatic terminate */
2310 if( provider
->isOpen( this ))
2311 provider
->close( this );
2315 if( provider
->lockForArbitration( true )) {
2316 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2317 scheduleStop( provider
);
2318 provider
->unlockForArbitration();
2335 void IOService::doServiceTerminate( IOOptionBits options
)
2339 // a method in case someone needs to override it
2340 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2344 if( client
->isParent( this, gIOServicePlane
, true))
2345 // we are the clients only provider
2346 ok
= client
->terminate( options
);
2353 bool IOService::terminate( IOOptionBits options
)
2355 options
|= kIOServiceTerminate
;
2357 return( terminatePhase1( options
));
2360 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2366 struct ServiceOpenMessageContext
2368 IOService
* service
;
2370 IOService
* excludeClient
;
2371 IOOptionBits options
;
2374 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2376 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2378 if( object
!= context
->excludeClient
)
2379 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
2382 bool IOService::open( IOService
* forClient
,
2383 IOOptionBits options
,
2387 ServiceOpenMessageContext context
;
2389 context
.service
= this;
2390 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2391 context
.excludeClient
= forClient
;
2392 context
.options
= options
;
2394 applyToInterested( gIOGeneralInterest
,
2395 &serviceOpenMessageApplier
, &context
);
2397 if( false == lockForArbitration(false) )
2400 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2402 ok
= handleOpen( forClient
, options
, arg
);
2404 unlockForArbitration();
2409 void IOService::close( IOService
* forClient
,
2410 IOOptionBits options
)
2415 lockForArbitration();
2417 wasClosed
= handleIsOpen( forClient
);
2419 handleClose( forClient
, options
);
2420 last
= (__state
[1] & kIOServiceTermPhase3State
);
2423 unlockForArbitration();
2426 forClient
->scheduleStop( this );
2428 else if( wasClosed
) {
2430 ServiceOpenMessageContext context
;
2432 context
.service
= this;
2433 context
.type
= kIOMessageServiceWasClosed
;
2434 context
.excludeClient
= forClient
;
2435 context
.options
= options
;
2437 applyToInterested( gIOGeneralInterest
,
2438 &serviceOpenMessageApplier
, &context
);
2442 bool IOService::isOpen( const IOService
* forClient
) const
2444 IOService
* self
= (IOService
*) this;
2447 self
->lockForArbitration();
2449 ok
= handleIsOpen( forClient
);
2451 self
->unlockForArbitration();
2456 bool IOService::handleOpen( IOService
* forClient
,
2457 IOOptionBits options
,
2462 ok
= (0 == __owner
);
2464 __owner
= forClient
;
2466 else if( options
& kIOServiceSeize
) {
2467 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2468 __owner
, (void *)(uintptr_t) options
));
2469 if( ok
&& (0 == __owner
))
2470 __owner
= forClient
;
2477 void IOService::handleClose( IOService
* forClient
,
2478 IOOptionBits options
)
2480 if( __owner
== forClient
)
2484 bool IOService::handleIsOpen( const IOService
* forClient
) const
2487 return( __owner
== forClient
);
2489 return( __owner
!= forClient
);
2493 * Probing & starting
2495 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2497 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2498 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2506 val1
= obj1
->priority
;
2509 val2
= obj2
->priority
;
2511 return ( val1
- val2
);
2514 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2516 OSDictionary
* dict
;
2517 IOService
* service
;
2518 _IOServiceNotifier
* notify
;
2519 OSSymbol
* key
= (OSSymbol
*) ref
;
2522 if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2523 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2524 else if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2525 return( notify
->priority
);
2527 else if( (service
= OSDynamicCast( IOService
, entry
)))
2528 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2535 return( (SInt32
) offset
->unsigned32BitValue());
2537 return( kIODefaultProbeScore
);
2540 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2542 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2543 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2551 val1
= IOServiceObjectOrder( obj1
, ref
);
2554 val2
= IOServiceObjectOrder( obj2
, ref
);
2556 return ( val1
- val2
);
2559 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
2561 IOService
* service
= 0;
2563 const OSSymbol
* nextCat
;
2565 iter
= getClientIterator();
2567 while( (service
= (IOService
*) iter
->getNextObject())) {
2568 if( kIOServiceInactiveState
& service
->__state
[0])
2570 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2571 service
->getProperty( gIOMatchCategoryKey
));
2572 if( category
== nextCat
)
2583 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
2586 service
= copyClientWithCategory(category
);
2592 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
2594 _IOServiceNotifierInvocation invocation
;
2598 invocation
.thread
= current_thread();
2601 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
2604 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
2605 _IOServiceNotifierInvocation
*, link
);
2611 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
2614 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
2615 _IOServiceNotifierInvocation
*, link
);
2616 if( kIOServiceNotifyWaiter
& notify
->state
) {
2617 notify
->state
&= ~kIOServiceNotifyWaiter
;
2618 WAKEUPNOTIFY( notify
);
2627 * Alloc and probe matching classes,
2628 * called on the provider instance
2631 void IOService::probeCandidates( OSOrderedSet
* matches
)
2633 OSDictionary
* match
= 0;
2636 IOService
* newInst
;
2637 OSDictionary
* props
;
2640 OSOrderedSet
* familyMatches
= 0;
2641 OSOrderedSet
* startList
;
2642 OSDictionary
* startDict
= 0;
2643 const OSSymbol
* category
;
2645 _IOServiceNotifier
* notify
;
2646 OSObject
* nextMatch
= 0;
2648 bool needReloc
= false;
2652 IOService
* client
= NULL
;
2656 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
2658 nextMatch
->retain();
2659 matches
->removeObject(nextMatch
);
2661 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
2663 lockForArbitration();
2664 if( 0 == (__state
[0] & kIOServiceInactiveState
))
2665 invokeNotifer( notify
);
2666 unlockForArbitration();
2667 nextMatch
->release();
2671 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
2672 nextMatch
->release();
2679 debugFlags
= getDebugFlags( match
);
2683 category
= OSDynamicCast( OSSymbol
,
2684 match
->getObject( gIOMatchCategoryKey
));
2686 category
= gIODefaultMatchCategoryKey
;
2688 if( (client
= copyClientWithCategory(category
)) ) {
2690 if( (debugFlags
& kIOLogMatch
) && (this != gIOResources
))
2691 LOG("%s: match category %s exists\n", getName(),
2692 category
->getCStringNoCopy());
2694 nextMatch
->release();
2703 // create a copy now in case its modified during matching
2704 props
= OSDictionary::withDictionary( match
, match
->getCount());
2707 props
->setCapacityIncrement(1);
2709 // check the nub matches
2710 if( false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
))
2713 // Check to see if driver reloc has been loaded.
2714 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
2717 if( debugFlags
& kIOLogCatalogue
)
2718 LOG("%s: stalling for module\n", getName());
2720 // If reloc hasn't been loaded, exit;
2721 // reprobing will occur after reloc has been loaded.
2725 // reorder on family matchPropertyTable score.
2726 if( 0 == familyMatches
)
2727 familyMatches
= OSOrderedSet::withCapacity( 1,
2728 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2730 familyMatches
->setObject( props
);
2735 nextMatch
->release();
2744 if( familyMatches
) {
2747 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
2750 familyMatches
->removeObject( props
);
2755 debugFlags
= getDebugFlags( props
);
2758 symbol
= OSDynamicCast( OSSymbol
,
2759 props
->getObject( gIOClassKey
));
2763 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props));
2765 // alloc the driver instance
2766 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
2769 IOLog("Couldn't alloc class \"%s\"\n",
2770 symbol
->getCStringNoCopy());
2774 // init driver instance
2775 if( !(inst
->init( props
))) {
2777 if( debugFlags
& kIOLogStart
)
2778 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
2782 if( __state
[1] & kIOServiceSynchronousState
)
2783 inst
->__state
[1] |= kIOServiceSynchronousState
;
2785 // give the driver the default match category if not specified
2786 category
= OSDynamicCast( OSSymbol
,
2787 props
->getObject( gIOMatchCategoryKey
));
2789 category
= gIODefaultMatchCategoryKey
;
2790 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
2791 // attach driver instance
2792 if( !(inst
->attach( this )))
2795 // pass in score from property table
2796 score
= familyMatches
->orderObject( props
);
2798 // & probe the new driver instance
2800 if( debugFlags
& kIOLogProbe
)
2801 LOG("%s::probe(%s)\n",
2802 inst
->getMetaClass()->getClassName(), getName());
2805 newInst
= inst
->probe( this, &score
);
2806 inst
->detach( this );
2809 if( debugFlags
& kIOLogProbe
)
2810 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
2816 newPri
= OSNumber::withNumber( score
, 32 );
2818 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
2822 // add to start list for the match category
2824 startDict
= OSDictionary::withCapacity( 1 );
2825 assert( startDict
);
2826 startList
= (OSOrderedSet
*)
2827 startDict
->getObject( category
);
2828 if( 0 == startList
) {
2829 startList
= OSOrderedSet::withCapacity( 1,
2830 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
2831 if( startDict
&& startList
) {
2832 startDict
->setObject( category
, startList
);
2833 startList
->release();
2836 assert( startList
);
2838 startList
->setObject( newInst
);
2846 familyMatches
->release();
2850 // start the best (until success) of each category
2852 iter
= OSCollectionIterator::withCollection( startDict
);
2854 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
2856 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
2857 assert( startList
);
2862 while( true // (!started)
2863 && (inst
= (IOService
*)startList
->getFirstObject())) {
2866 startList
->removeObject(inst
);
2869 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
2871 if( debugFlags
& kIOLogStart
) {
2873 LOG( "match category exists, skipping " );
2874 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
2875 getName(), inst
->getRetainCount());
2878 if( false == started
)
2879 started
= startCandidate( inst
);
2881 if( (debugFlags
& kIOLogStart
) && (false == started
))
2882 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
2883 inst
->getRetainCount());
2892 // adjust the busy count by +1 if matching is stalled for a module,
2893 // or -1 if a previously stalled matching is complete.
2894 lockForArbitration();
2896 uint64_t regID
= getRegistryEntryID();
2899 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
2903 IOSERVICE_MODULESTALL
,
2905 (uintptr_t) (regID
>> 32),
2909 __state
[1] |= kIOServiceModuleStallState
;
2912 } else if( __state
[1] & kIOServiceModuleStallState
) {
2915 IOSERVICE_MODULEUNSTALL
,
2917 (uintptr_t) (regID
>> 32),
2921 __state
[1] &= ~kIOServiceModuleStallState
;
2925 _adjustBusy( adjBusy
);
2926 unlockForArbitration();
2929 startDict
->release();
2933 * Start a previously attached & probed instance,
2934 * called on exporting object instance
2937 bool IOService::startCandidate( IOService
* service
)
2941 ok
= service
->attach( this );
2945 if (this != gIOResources
)
2947 // stall for any nub resources
2949 // stall for any driver resources
2950 service
->checkResources();
2953 AbsoluteTime startTime
;
2954 AbsoluteTime endTime
;
2957 if (kIOLogStart
& gIOKitDebug
)
2958 clock_get_uptime(&startTime
);
2960 ok
= service
->start(this);
2962 if (kIOLogStart
& gIOKitDebug
)
2964 clock_get_uptime(&endTime
);
2966 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
2968 SUB_ABSOLUTETIME(&endTime
, &startTime
);
2969 absolutetime_to_nanoseconds(endTime
, &nano
);
2970 if (nano
> 500000000ULL)
2971 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
2975 service
->detach( this );
2980 void IOService::publishResource( const char * key
, OSObject
* value
)
2982 const OSSymbol
* sym
;
2984 if( (sym
= OSSymbol::withCString( key
))) {
2985 publishResource( sym
, value
);
2990 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
2993 value
= (OSObject
*) gIOServiceKey
;
2995 gIOResources
->setProperty( key
, value
);
2997 if( IORecursiveLockHaveLock( gNotificationLock
))
3000 gIOResourceGenerationCount
++;
3001 gIOResources
->registerService();
3004 bool IOService::addNeededResource( const char * key
)
3006 OSObject
* resourcesProp
;
3011 resourcesProp
= getProperty( gIOResourceMatchKey
);
3013 newKey
= OSString::withCString( key
);
3014 if( (0 == resourcesProp
) || (0 == newKey
))
3017 set
= OSDynamicCast( OSSet
, resourcesProp
);
3019 set
= OSSet::withCapacity( 1 );
3021 set
->setObject( resourcesProp
);
3026 set
->setObject( newKey
);
3028 ret
= setProperty( gIOResourceMatchKey
, set
);
3034 bool IOService::checkResource( OSObject
* matching
)
3037 OSDictionary
* table
;
3039 if( (str
= OSDynamicCast( OSString
, matching
))) {
3040 if( gIOResources
->getProperty( str
))
3045 table
= resourceMatching( str
);
3046 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
3049 IOLog("%s: Can't match using: %s\n", getName(),
3050 matching
->getMetaClass()->getClassName());
3051 /* false would stall forever */
3055 if( gIOKitDebug
& kIOLogConfig
)
3056 LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName());
3058 waitForService( table
);
3060 if( gIOKitDebug
& kIOLogConfig
)
3061 LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) );
3066 bool IOService::checkResources( void )
3068 OSObject
* resourcesProp
;
3073 resourcesProp
= getProperty( gIOResourceMatchKey
);
3074 if( 0 == resourcesProp
)
3077 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
3079 iter
= OSCollectionIterator::withCollection( set
);
3081 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3082 ok
= checkResource( resourcesProp
);
3087 ok
= checkResource( resourcesProp
);
3093 void _IOConfigThread::configThread( void )
3095 _IOConfigThread
* inst
;
3098 if( !(inst
= new _IOConfigThread
))
3103 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3116 void _IOConfigThread::free( void )
3118 thread_deallocate(current_thread());
3122 void IOService::doServiceMatch( IOOptionBits options
)
3124 _IOServiceNotifier
* notify
;
3126 OSOrderedSet
* matches
;
3127 SInt32 catalogGeneration
;
3128 bool keepGuessing
= true;
3129 bool reRegistered
= true;
3132 // job->nub->deliverNotification( gIOPublishNotification,
3133 // kIOServiceRegisteredState, 0xffffffff );
3135 while( keepGuessing
) {
3137 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3138 // the matches list should always be created by findDrivers()
3141 lockForArbitration();
3142 if( 0 == (__state
[0] & kIOServiceFirstPublishState
)) {
3143 getMetaClass()->addInstance(this);
3144 deliverNotification( gIOFirstPublishNotification
,
3145 kIOServiceFirstPublishState
, 0xffffffff );
3148 __state
[1] &= ~kIOServiceNeedConfigState
;
3149 __state
[1] |= kIOServiceConfigState
;
3150 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
3151 __state
[0] |= kIOServiceRegisteredState
;
3153 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
3154 if (reRegistered
&& keepGuessing
) {
3155 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3156 gNotifications
->getObject( gIOPublishNotification
) );
3158 while((notify
= (_IOServiceNotifier
*)
3159 iter
->getNextObject())) {
3161 if( matchPassive(notify
->matching
, 0)
3162 && (kIOServiceNotifyEnable
& notify
->state
))
3163 matches
->setObject( notify
);
3170 unlockForArbitration();
3172 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources()))
3173 probeCandidates( matches
);
3178 lockForArbitration();
3179 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3181 (reRegistered
|| (catalogGeneration
!=
3182 gIOCatalogue
->getGenerationCount()))
3183 && (0 == (__state
[0] & kIOServiceInactiveState
));
3186 unlockForArbitration();
3189 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3190 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3191 deliverNotification( gIOMatchedNotification
,
3192 kIOServiceMatchedState
, 0xffffffff );
3193 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3194 deliverNotification( gIOFirstMatchNotification
,
3195 kIOServiceFirstMatchState
, 0xffffffff );
3198 __state
[1] &= ~kIOServiceConfigState
;
3199 if( __state
[0] & kIOServiceInactiveState
)
3200 scheduleTerminatePhase2();
3203 unlockForArbitration();
3206 UInt32
IOService::_adjustBusy( SInt32 delta
)
3211 bool wasQuiet
, nowQuiet
, needWake
;
3214 result
= __state
[1] & kIOServiceBusyStateMask
;
3218 next
->lockForArbitration();
3219 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3220 wasQuiet
= (0 == count
);
3221 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3222 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3225 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3226 nowQuiet
= (0 == count
);
3227 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3230 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3231 IOLockLock( gIOServiceBusyLock
);
3232 thread_wakeup( (event_t
) next
);
3233 IOLockUnlock( gIOServiceBusyLock
);
3236 next
->unlockForArbitration();
3238 if( (wasQuiet
|| nowQuiet
) ) {
3239 uint64_t regID
= next
->getRegistryEntryID();
3242 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3244 (uintptr_t) (regID
>> 32),
3250 next
->__timeBusy
= mach_absolute_time();
3254 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3255 next
->__timeBusy
= 0;
3258 MessageClientsContext context
;
3260 context
.service
= next
;
3261 context
.type
= kIOMessageServiceBusyStateChange
;
3262 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3263 context
.argSize
= 0;
3265 applyToInterestNotifiers( next
, gIOBusyInterest
,
3266 &messageClientsApplier
, &context
);
3269 if( nowQuiet
&& (next
== gIOServiceRoot
)) {
3270 OSKext::considerUnloads();
3271 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
3276 delta
= nowQuiet
? -1 : +1;
3278 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3283 void IOService::adjustBusy( SInt32 delta
)
3285 lockForArbitration();
3286 _adjustBusy( delta
);
3287 unlockForArbitration();
3290 uint64_t IOService::getAccumulatedBusyTime( void )
3292 uint64_t accumBusy
= __accumBusy
;
3293 uint64_t timeBusy
= __timeBusy
;
3298 accumBusy
= __accumBusy
;
3299 timeBusy
= __timeBusy
;
3301 accumBusy
+= mach_absolute_time() - timeBusy
;
3303 while (timeBusy
!= __timeBusy
);
3305 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3310 UInt32
IOService::getBusyState( void )
3312 return( __state
[1] & kIOServiceBusyStateMask
);
3315 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3316 mach_timespec_t
* timeout
)
3318 panic("waitForState");
3319 return (kIOReturnUnsupported
);
3322 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3326 int waitResult
= THREAD_AWAKENED
;
3327 bool computeDeadline
= true;
3328 AbsoluteTime abstime
;
3331 lockForArbitration();
3332 IOLockLock( gIOServiceBusyLock
);
3333 wait
= (value
!= (__state
[1] & mask
));
3335 __state
[1] |= kIOServiceBusyWaiterState
;
3336 unlockForArbitration();
3337 if( timeout
!= UINT64_MAX
) {
3338 if( computeDeadline
) {
3339 AbsoluteTime nsinterval
;
3340 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3341 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3342 computeDeadline
= false;
3344 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3347 assert_wait((event_t
)this, THREAD_UNINT
);
3349 unlockForArbitration();
3350 IOLockUnlock( gIOServiceBusyLock
);
3352 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3354 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3356 if( waitResult
== THREAD_TIMED_OUT
)
3357 return( kIOReturnTimeout
);
3359 return( kIOReturnSuccess
);
3362 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3365 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
3366 if ((kIOReturnTimeout
== ret
) && (timeout
>= 30000000000) && (kIOWaitQuietPanics
& gIOKitDebug
))
3368 panic("IOService 0x%llx (%s) busy timeout", getRegistryEntryID(), getName());
3373 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3379 timeoutNS
= timeout
->tv_sec
;
3380 timeoutNS
*= kSecondScale
;
3381 timeoutNS
+= timeout
->tv_nsec
;
3384 timeoutNS
= UINT64_MAX
;
3386 return (waitQuiet(timeoutNS
));
3389 bool IOService::serializeProperties( OSSerialize
* s
) const
3392 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3393 sizeof( __state
), "__state");
3395 return( super::serializeProperties(s
) );
3399 void _IOConfigThread::main(void * arg
, wait_result_t result
)
3401 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
3402 _IOServiceJob
* job
;
3406 thread_precedence_policy_data_t precedence
= { -1 };
3408 kr
= thread_policy_set(current_thread(),
3409 THREAD_PRECEDENCE_POLICY
,
3410 (thread_policy_t
) &precedence
,
3411 THREAD_PRECEDENCE_POLICY_COUNT
);
3412 if (KERN_SUCCESS
!= kr
)
3413 IOLog("thread_policy_set(%d)\n", kr
);
3419 semaphore_wait( gJobsSemaphore
);
3421 IOTakeLock( gJobsLock
);
3422 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3424 gJobs
->removeObject(job
);
3427 // gNumConfigThreads--; // we're out of service
3428 gNumWaitingThreads
--; // we're out of service
3430 IOUnlock( gJobsLock
);
3436 if( gIOKitDebug
& kIOLogConfig
)
3437 LOG("config(%p): starting on %s, %d\n",
3438 OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
3440 switch( job
->type
) {
3443 nub
->doServiceMatch( job
->options
);
3447 LOG("config(%p): strange type (%d)\n",
3448 OBFUSCATE(IOThreadSelf()), job
->type
);
3455 IOTakeLock( gJobsLock
);
3456 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3458 gNumWaitingThreads
++; // back in service
3459 // gNumConfigThreads++;
3461 if( 0 == --gNumConfigThreads
) {
3462 // IOLog("MATCH IDLE\n");
3463 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3466 IOUnlock( gJobsLock
);
3471 if( gIOKitDebug
& kIOLogConfig
)
3472 LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) );
3477 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3480 int waitResult
= THREAD_AWAKENED
;
3481 bool computeDeadline
= true;
3482 AbsoluteTime deadline
;
3484 IOLockLock( gJobsLock
);
3486 wait
= (0 != gNumConfigThreads
);
3489 if( computeDeadline
) {
3490 clock_interval_to_deadline(
3491 msToWait
, kMillisecondScale
, &deadline
);
3492 computeDeadline
= false;
3494 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
3495 deadline
, THREAD_UNINT
);
3497 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
3501 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3502 IOLockUnlock( gJobsLock
);
3504 if( waitResult
== THREAD_TIMED_OUT
)
3505 return( kIOReturnTimeout
);
3507 return( kIOReturnSuccess
);
3510 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
3517 IOTakeLock( gJobsLock
);
3520 gJobs
->setLastObject( job
);
3522 count
= gNumWaitingThreads
;
3523 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3525 create
= ( (gOutstandingJobs
> count
)
3526 && (gNumConfigThreads
< kMaxConfigThreads
) );
3528 gNumConfigThreads
++;
3529 gNumWaitingThreads
++;
3532 IOUnlock( gJobsLock
);
3537 if( gIOKitDebug
& kIOLogConfig
)
3538 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
3539 _IOConfigThread::configThread();
3542 semaphore_signal( gJobsSemaphore
);
3545 struct IOServiceMatchContext
3547 OSDictionary
* table
;
3555 bool IOService::instanceMatch(const OSObject
* entry
, void * context
)
3557 IOServiceMatchContext
* ctx
= (typeof(ctx
)) context
;
3558 IOService
* service
= (typeof(service
)) entry
;
3559 OSDictionary
* table
= ctx
->table
;
3560 uint32_t options
= ctx
->options
;
3561 uint32_t state
= ctx
->state
;
3568 match
= ((state
== (state
& service
->__state
[0]))
3569 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
3571 ctx
->count
+= table
->getCount();
3572 match
= service
->matchInternal(table
, options
, &done
);
3579 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
))
3582 ctx
->result
= service
;
3585 else if (!ctx
->result
)
3587 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
3591 ((OSSet
*)ctx
->result
)->setObject(service
);
3596 // internal - call with gNotificationLock
3597 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
3598 IOOptionBits inState
, IOOptionBits options
)
3600 OSObject
* current
= 0;
3602 IOService
* service
;
3610 OSSerialize
* s
= OSSerialize::withCapacity(128);
3611 matching
->serialize(s
);
3614 if((obj
= matching
->getObject(gIOProviderClassKey
))
3616 && gIOResourcesKey
->isEqualTo(obj
)
3617 && (service
= gIOResources
))
3619 if( (inState
== (service
->__state
[0] & inState
))
3620 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3621 && service
->matchPassive(matching
, options
))
3623 if( options
& kIONotifyOnce
)
3629 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
3634 IOServiceMatchContext ctx
;
3635 ctx
.table
= matching
;
3636 ctx
.state
= inState
;
3639 ctx
.options
= options
;
3642 if ((str
= OSDynamicCast(OSString
, obj
)))
3644 const OSSymbol
* sym
= OSSymbol::withString(str
);
3645 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
3650 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
3654 current
= ctx
.result
;
3656 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
3657 if (current
&& (ctx
.done
!= ctx
.count
))
3660 source
= OSDynamicCast(OSSet
, current
);
3662 while ((service
= (IOService
*) source
->getAnyObject()))
3664 if (service
->matchPassive(matching
, options
))
3666 if( options
& kIONotifyOnce
)
3674 ((OSSet
*)current
)->setObject( service
);
3678 current
= OSSet::withObjects(
3679 (const OSObject
**) &service
, 1, 1 );
3682 source
->removeObject(service
);
3690 OSObject
* _current
= 0;
3692 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
3693 kIORegistryIterateRecursively
);
3697 while( (service
= (IOService
*) iter
->getNextObject())) {
3698 if( (inState
== (service
->__state
[0] & inState
))
3699 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
3700 && service
->matchPassive(matching
, 0)) {
3702 if( options
& kIONotifyOnce
) {
3708 ((OSSet
*)_current
)->setObject( service
);
3710 _current
= OSSet::withObjects(
3711 (const OSObject
**) &service
, 1, 1 );
3714 } while( !service
&& !iter
->isValid());
3719 if ( ((current
!= 0) != (_current
!= 0))
3720 || (current
&& _current
&& !current
->isEqualTo(_current
)))
3722 OSSerialize
* s1
= OSSerialize::withCapacity(128);
3723 OSSerialize
* s2
= OSSerialize::withCapacity(128);
3724 current
->serialize(s1
);
3725 _current
->serialize(s2
);
3726 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current
),
3727 OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
3732 if (_current
) _current
->release();
3738 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
3739 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
3748 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
3752 // is a lock even needed?
3755 iter
= (OSIterator
*) copyExistingServices( matching
,
3756 kIOServiceMatchedState
);
3763 IOService
* IOService::copyMatchingService( OSDictionary
* matching
)
3765 IOService
* service
;
3767 // is a lock even needed?
3770 service
= (IOService
*) copyExistingServices( matching
,
3771 kIOServiceMatchedState
, kIONotifyOnce
);
3778 struct _IOServiceMatchingNotificationHandlerRef
3780 IOServiceNotificationHandler handler
;
3784 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
3785 IOService
* newService
,
3786 IONotifier
* notifier
)
3788 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
3791 // internal - call with gNotificationLock
3792 IONotifier
* IOService::setNotification(
3793 const OSSymbol
* type
, OSDictionary
* matching
,
3794 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
3797 _IOServiceNotifier
* notify
= 0;
3803 notify
= new _IOServiceNotifier
;
3804 if( notify
&& !notify
->init()) {
3810 notify
->handler
= handler
;
3811 notify
->target
= target
;
3812 notify
->matching
= matching
;
3814 if (handler
== &_IOServiceMatchingNotificationHandler
)
3816 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
3817 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
3821 notify
->priority
= priority
;
3822 notify
->state
= kIOServiceNotifyEnable
;
3823 queue_init( ¬ify
->handlerInvocations
);
3827 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
3828 set
= OSOrderedSet::withCapacity( 1,
3829 IONotifyOrdering
, 0 );
3831 gNotifications
->setObject( type
, set
);
3835 notify
->whence
= set
;
3837 set
->setObject( notify
);
3843 // internal - call with gNotificationLock
3844 IONotifier
* IOService::doInstallNotification(
3845 const OSSymbol
* type
, OSDictionary
* matching
,
3846 IOServiceMatchingNotificationHandler handler
,
3847 void * target
, void * ref
,
3848 SInt32 priority
, OSIterator
** existing
)
3851 IONotifier
* notify
;
3852 IOOptionBits inState
;
3857 if( type
== gIOPublishNotification
)
3858 inState
= kIOServiceRegisteredState
;
3860 else if( type
== gIOFirstPublishNotification
)
3861 inState
= kIOServiceFirstPublishState
;
3863 else if( (type
== gIOMatchedNotification
)
3864 || (type
== gIOFirstMatchNotification
))
3865 inState
= kIOServiceMatchedState
;
3866 else if( type
== gIOTerminatedNotification
)
3871 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
3874 // get the current set
3875 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
3884 #if !defined(__LP64__)
3885 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
3886 IOServiceNotificationHandler handler
,
3887 void * target
, void * refCon
,
3888 SInt32 priority
, OSIterator
** existing
)
3890 IONotifier
* result
;
3891 _IOServiceMatchingNotificationHandlerRef ref
;
3892 ref
.handler
= handler
;
3895 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3896 &_IOServiceMatchingNotificationHandler
,
3897 target
, &ref
, priority
, existing
);
3899 matching
->release();
3903 #endif /* !defined(__LP64__) */
3906 IONotifier
* IOService::installNotification(
3907 const OSSymbol
* type
, OSDictionary
* matching
,
3908 IOServiceMatchingNotificationHandler handler
,
3909 void * target
, void * ref
,
3910 SInt32 priority
, OSIterator
** existing
)
3912 IONotifier
* notify
;
3916 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
3917 priority
, existing
);
3924 IONotifier
* IOService::addNotification(
3925 const OSSymbol
* type
, OSDictionary
* matching
,
3926 IOServiceNotificationHandler handler
,
3927 void * target
, void * refCon
,
3930 IONotifier
* result
;
3931 _IOServiceMatchingNotificationHandlerRef ref
;
3933 ref
.handler
= handler
;
3936 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
3937 target
, &ref
, priority
);
3940 matching
->release();
3945 IONotifier
* IOService::addMatchingNotification(
3946 const OSSymbol
* type
, OSDictionary
* matching
,
3947 IOServiceMatchingNotificationHandler handler
,
3948 void * target
, void * ref
,
3951 OSIterator
* existing
= NULL
;
3952 _IOServiceNotifier
* notify
;
3955 notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
3956 handler
, target
, ref
, priority
, &existing
);
3958 // send notifications for existing set
3961 notify
->retain(); // in case handler remove()s
3962 while( (next
= (IOService
*) existing
->getNextObject())) {
3964 next
->lockForArbitration();
3965 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
3966 next
->invokeNotifer( notify
);
3967 next
->unlockForArbitration();
3970 existing
->release();
3976 bool IOService::syncNotificationHandler(
3977 void * /* target */, void * ref
,
3978 IOService
* newService
,
3979 IONotifier
* notifier
)
3983 if (!*((IOService
**) ref
))
3985 newService
->retain();
3986 (*(IOService
**) ref
) = newService
;
3994 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
3997 IONotifier
* notify
= 0;
3998 // priority doesn't help us much since we need a thread wakeup
3999 SInt32 priority
= 0;
4010 result
= (IOService
*) copyExistingServices( matching
,
4011 kIOServiceMatchedState
, kIONotifyOnce
);
4014 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
4015 &IOService::syncNotificationHandler
, (void *) 0,
4016 &result
, priority
);
4019 if (UINT64_MAX
!= timeout
)
4021 AbsoluteTime deadline
;
4022 nanoseconds_to_absolutetime(timeout
, &deadline
);
4023 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
4024 SLEEPNOTIFYTO(&result
, deadline
);
4028 SLEEPNOTIFY(&result
);
4036 notify
->remove(); // dequeues
4041 IOService
* IOService::waitForService( OSDictionary
* matching
,
4042 mach_timespec_t
* timeout
)
4049 timeoutNS
= timeout
->tv_sec
;
4050 timeoutNS
*= kSecondScale
;
4051 timeoutNS
+= timeout
->tv_nsec
;
4054 timeoutNS
= UINT64_MAX
;
4056 result
= waitForMatchingService(matching
, timeoutNS
);
4058 matching
->release();
4065 void IOService::deliverNotification( const OSSymbol
* type
,
4066 IOOptionBits orNewState
, IOOptionBits andNewState
)
4068 _IOServiceNotifier
* notify
;
4070 OSArray
* willSend
= 0;
4072 lockForArbitration();
4074 if( (0 == (__state
[0] & kIOServiceInactiveState
))
4075 || (type
== gIOTerminatedNotification
)) {
4079 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
4080 gNotifications
->getObject( type
) );
4083 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
4085 if( matchPassive(notify
->matching
, 0)
4086 && (kIOServiceNotifyEnable
& notify
->state
)) {
4088 willSend
= OSArray::withCapacity(8);
4090 willSend
->setObject( notify
);
4096 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
4102 for( unsigned int idx
= 0;
4103 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
4105 invokeNotifer( notify
);
4107 willSend
->release();
4109 unlockForArbitration();
4112 IOOptionBits
IOService::getState( void ) const
4114 return( __state
[0] );
4118 * Helpers to make matching objects for simple cases
4121 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
4122 OSDictionary
* table
)
4125 const OSString
* str
;
4127 str
= OSSymbol::withString(name
);
4132 table
= OSDictionary::withCapacity( 2 );
4134 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
4140 OSDictionary
* IOService::serviceMatching( const char * name
,
4141 OSDictionary
* table
)
4143 const OSString
* str
;
4145 str
= OSSymbol::withCString( name
);
4149 table
= serviceMatching( str
, table
);
4154 OSDictionary
* IOService::nameMatching( const OSString
* name
,
4155 OSDictionary
* table
)
4158 table
= OSDictionary::withCapacity( 2 );
4160 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
4165 OSDictionary
* IOService::nameMatching( const char * name
,
4166 OSDictionary
* table
)
4168 const OSString
* str
;
4170 str
= OSSymbol::withCString( name
);
4174 table
= nameMatching( str
, table
);
4179 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
4180 OSDictionary
* table
)
4182 table
= serviceMatching( gIOResourcesKey
, table
);
4184 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
4189 OSDictionary
* IOService::resourceMatching( const char * name
,
4190 OSDictionary
* table
)
4192 const OSSymbol
* str
;
4194 str
= OSSymbol::withCString( name
);
4198 table
= resourceMatching( str
, table
);
4204 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
4205 OSDictionary
* table
)
4207 OSDictionary
* properties
;
4209 properties
= OSDictionary::withCapacity( 2 );
4212 properties
->setObject( key
, value
);
4215 table
= OSDictionary::withCapacity( 2 );
4217 table
->setObject( gIOPropertyMatchKey
, properties
);
4219 properties
->release();
4224 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
4225 OSDictionary
* table
)
4229 num
= OSNumber::withNumber( entryID
, 64 );
4234 table
= OSDictionary::withCapacity( 2 );
4236 table
->setObject( gIORegistryEntryIDKey
, num
);
4246 * _IOServiceNotifier
4249 // wait for all threads, other than the current one,
4250 // to exit the handler
4252 void _IOServiceNotifier::wait()
4254 _IOServiceNotifierInvocation
* next
;
4259 queue_iterate( &handlerInvocations
, next
,
4260 _IOServiceNotifierInvocation
*, link
) {
4261 if( next
->thread
!= current_thread() ) {
4267 state
|= kIOServiceNotifyWaiter
;
4274 void _IOServiceNotifier::free()
4276 assert( queue_empty( &handlerInvocations
));
4280 void _IOServiceNotifier::remove()
4285 whence
->removeObject( (OSObject
*) this );
4289 matching
->release();
4293 state
&= ~kIOServiceNotifyEnable
;
4302 bool _IOServiceNotifier::disable()
4308 ret
= (0 != (kIOServiceNotifyEnable
& state
));
4309 state
&= ~kIOServiceNotifyEnable
;
4318 void _IOServiceNotifier::enable( bool was
)
4322 state
|= kIOServiceNotifyEnable
;
4324 state
&= ~kIOServiceNotifyEnable
;
4332 IOService
* IOResources::resources( void )
4336 inst
= new IOResources
;
4337 if( inst
&& !inst
->init()) {
4345 bool IOResources::init( OSDictionary
* dictionary
)
4347 // Do super init first
4348 if ( !super::init() )
4351 // Allow PAL layer to publish a value
4352 const char *property_name
;
4355 pal_get_resource_property( &property_name
, &property_value
);
4357 if( property_name
) {
4359 const OSSymbol
* sym
;
4361 if( (num
= OSNumber::withNumber(property_value
, 32)) != 0 ) {
4362 if( (sym
= OSSymbol::withCString( property_name
)) != 0 ) {
4363 this->setProperty( sym
, num
);
4373 IOWorkLoop
* IOResources::getWorkLoop() const
4375 // If we are the resource root
4376 // then use the platform's workloop
4377 if (this == (IOResources
*) gIOResources
)
4378 return getPlatform()->getWorkLoop();
4380 return IOService::getWorkLoop();
4383 bool IOResources::matchPropertyTable( OSDictionary
* table
)
4391 prop
= table
->getObject( gIOResourceMatchKey
);
4392 str
= OSDynamicCast( OSString
, prop
);
4394 ok
= (0 != getProperty( str
));
4396 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
4398 iter
= OSCollectionIterator::withCollection( set
);
4400 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
4401 ok
= (0 != getProperty( str
));
4410 void IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
4412 IOService::updateConsoleUsers(NULL
, 0);
4415 void IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
4417 IORegistryEntry
* regEntry
;
4418 OSObject
* locked
= kOSBooleanFalse
;
4421 OSDictionary
* user
;
4422 static IOMessage sSystemPower
;
4424 regEntry
= IORegistryEntry::getRegistryRoot();
4426 if (!gIOChosenEntry
)
4427 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
4429 IOLockLock(gIOConsoleUsersLock
);
4433 sSystemPower
= systemMessage
;
4435 if ((kIOMessageSystemHasPoweredOn
== systemMessage
) && IOHibernateWasScreenLocked())
4437 locked
= kOSBooleanTrue
;
4439 #endif /* HIBERNATION */
4445 gIOConsoleLoggedIn
= false;
4447 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
4450 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
4451 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
4454 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
4457 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
4460 if (!gIOConsoleLoggedIn
4461 || (kIOMessageSystemWillSleep
== sSystemPower
)
4462 || (kIOMessageSystemPagingOff
== sSystemPower
))
4464 locked
= kOSBooleanTrue
;
4466 else if (gIOConsoleLockTime
)
4469 clock_usec_t microsecs
;
4471 clock_get_calendar_microtime(&now
, µsecs
);
4472 if (gIOConsoleLockTime
> now
)
4474 AbsoluteTime deadline
;
4475 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
4476 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
4480 locked
= kOSBooleanTrue
;
4484 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
4487 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
4490 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
4492 OSIncrementAtomic( &gIOConsoleUsersSeed
);
4498 if (locked
== kOSBooleanTrue
) gIOScreenLockState
= kIOScreenLockLocked
;
4499 else if (gIOConsoleLockTime
) gIOScreenLockState
= kIOScreenLockUnlocked
;
4500 else gIOScreenLockState
= kIOScreenLockNoLock
;
4501 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
4503 #endif /* HIBERNATION */
4505 IOLockUnlock(gIOConsoleUsersLock
);
4509 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
4511 MessageClientsContext context
;
4513 context
.service
= getServiceRoot();
4514 context
.type
= kIOMessageConsoleSecurityChange
;
4515 context
.argument
= (void *) regEntry
;
4516 context
.argSize
= 0;
4518 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
4519 &messageClientsApplier
, &context
);
4523 IOReturn
IOResources::setProperties( OSObject
* properties
)
4526 const OSSymbol
* key
;
4527 OSDictionary
* dict
;
4528 OSCollectionIterator
* iter
;
4530 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
4531 if ( kIOReturnSuccess
!= err
)
4534 dict
= OSDynamicCast(OSDictionary
, properties
);
4536 return( kIOReturnBadArgument
);
4538 iter
= OSCollectionIterator::withCollection( dict
);
4540 return( kIOReturnBadArgument
);
4542 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4544 if (gIOConsoleUsersKey
== key
) do
4546 OSArray
* consoleUsers
;
4547 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
4550 IOService::updateConsoleUsers(consoleUsers
, 0);
4554 publishResource( key
, dict
->getObject(key
) );
4559 return( kIOReturnSuccess
);
4563 * Helpers for matching dictionaries.
4564 * Keys existing in matching are checked in properties.
4565 * Keys may be a string or OSCollection of IOStrings
4568 bool IOService::compareProperty( OSDictionary
* matching
,
4574 value
= matching
->getObject( key
);
4576 ok
= value
->isEqualTo( getProperty( key
));
4584 bool IOService::compareProperty( OSDictionary
* matching
,
4585 const OSString
* key
)
4590 value
= matching
->getObject( key
);
4592 ok
= value
->isEqualTo( getProperty( key
));
4599 bool IOService::compareProperties( OSDictionary
* matching
,
4600 OSCollection
* keys
)
4602 OSCollectionIterator
* iter
;
4603 const OSString
* key
;
4606 if( !matching
|| !keys
)
4609 iter
= OSCollectionIterator::withCollection( keys
);
4612 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
4613 ok
= compareProperty( matching
, key
);
4617 keys
->release(); // !! consume a ref !!
4622 /* Helper to add a location matching dict to the table */
4624 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
4626 OSDictionary
* dict
;
4631 dict
= OSDictionary::withCapacity( 1 );
4633 table
->setObject( gIOLocationMatchKey
, dict
);
4641 * Go looking for a provider to match a location dict.
4644 IOService
* IOService::matchLocation( IOService
* /* client */ )
4648 parent
= getProvider();
4651 parent
= parent
->matchLocation( this );
4656 bool IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
4661 IORegistryEntry
* entry
;
4664 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
4670 count
= table
->getCount();
4672 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
4675 match
= ((kIOServiceClassDone
& options
) || (0 != metaCast(str
)));
4677 match
= (0 != metaCast( str
));
4678 if ((kIOServiceClassDone
& options
) && !match
) panic("classDone");
4680 if ((!match
) || (done
== count
)) break;
4683 obj
= table
->getObject( gIONameMatchKey
);
4686 match
= compareNames( obj
, changesOK
? &matched
: 0 );
4688 if( changesOK
&& matched
) {
4689 // leave a hint as to which name matched
4690 table
->setObject( gIONameMatchedKey
, matched
);
4693 if (done
== count
) break;
4696 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
4699 const OSSymbol
* sym
;
4702 sym
= copyLocation();
4704 match
= sym
->isEqualTo( str
);
4707 if ((!match
) || (done
== count
)) break;
4710 obj
= table
->getObject( gIOPropertyMatchKey
);
4713 OSDictionary
* dict
;
4714 OSDictionary
* nextDict
;
4718 dict
= dictionaryWithProperties();
4720 nextDict
= OSDynamicCast( OSDictionary
, obj
);
4724 iter
= OSCollectionIterator::withCollection(
4725 OSDynamicCast(OSCollection
, obj
));
4728 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
4729 iter
->getNextObject()))))) {
4730 match
= dict
->isEqualTo( nextDict
, nextDict
);
4739 if ((!match
) || (done
== count
)) break;
4742 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
4745 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
4746 match
= (this == entry
);
4749 if ((!match
) || (done
== count
)) break;
4752 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
4755 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
4756 if ((!match
) || (done
== count
)) break;
4759 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
4763 IOService
* service
= 0;
4764 UInt32 serviceCount
= 0;
4767 iter
= getClientIterator();
4769 while( (service
= (IOService
*) iter
->getNextObject())) {
4770 if( kIOServiceInactiveState
& service
->__state
[0])
4772 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
4778 match
= (serviceCount
== num
->unsigned32BitValue());
4779 if ((!match
) || (done
== count
)) break;
4782 #define propMatch(key) \
4783 obj = table->getObject(key); \
4788 prop = copyProperty(key); \
4789 match = obj->isEqualTo(prop); \
4790 if (prop) prop->release(); \
4791 if ((!match) || (done == count)) break; \
4793 propMatch(kIOBSDNameKey
)
4794 propMatch(kIOBSDMajorKey
)
4795 propMatch(kIOBSDMinorKey
)
4796 propMatch(kIOBSDUnitKey
)
4801 if (did
) *did
= done
;
4805 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
4807 return (matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0));
4810 bool IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
4813 OSDictionary
* nextTable
;
4817 bool matchParent
= false;
4824 OSDictionary
* root
= table
;
4832 count
= table
->getCount();
4833 if (!(kIOServiceInternalDone
& options
))
4835 match
= where
->matchInternal(table
, options
, &done
);
4836 // don't call family if we've done all the entries in the table
4837 if ((!match
) || (done
== count
)) break;
4840 // pass in score from property table
4841 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
4843 // do family specific matching
4844 match
= where
->matchPropertyTable( table
, &score
);
4848 if( kIOLogMatch
& getDebugFlags( table
))
4849 LOG("%s: family specific matching fails\n", where
->getName());
4854 if (kIOServiceChangesOK
& options
) {
4856 newPri
= OSNumber::withNumber( score
, 32 );
4858 table
->setObject( gIOProbeScoreKey
, newPri
);
4864 matchParent
= false;
4866 nextTable
= OSDynamicCast(OSDictionary
,
4867 table
->getObject( gIOParentMatchKey
));
4869 // look for a matching entry anywhere up to root
4876 table
= OSDynamicCast(OSDictionary
,
4877 table
->getObject( gIOLocationMatchKey
));
4879 // look for a matching entry at matchLocation()
4881 where
= where
->getProvider();
4882 if (where
&& (where
= where
->matchLocation(where
))) continue;
4888 while( matchParent
&& (!match
) && (where
= where
->getProvider()) );
4893 OSSerialize
* s
= OSSerialize::withCapacity(128);
4895 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
4904 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4905 UInt32 type
, OSDictionary
* properties
,
4906 IOUserClient
** handler
)
4908 const OSSymbol
*userClientClass
= 0;
4909 IOUserClient
*client
;
4912 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
4913 return kIOReturnSuccess
;
4915 // First try my own properties for a user client class name
4916 temp
= getProperty(gIOUserClientClassKey
);
4918 if (OSDynamicCast(OSSymbol
, temp
))
4919 userClientClass
= (const OSSymbol
*) temp
;
4920 else if (OSDynamicCast(OSString
, temp
)) {
4921 userClientClass
= OSSymbol::withString((OSString
*) temp
);
4922 if (userClientClass
)
4923 setProperty(kIOUserClientClassKey
,
4924 (OSObject
*) userClientClass
);
4928 // Didn't find one so lets just bomb out now without further ado.
4929 if (!userClientClass
)
4930 return kIOReturnUnsupported
;
4932 // This reference is consumed by the IOServiceOpen call
4933 temp
= OSMetaClass::allocClassWithName(userClientClass
);
4935 return kIOReturnNoMemory
;
4937 if (OSDynamicCast(IOUserClient
, temp
))
4938 client
= (IOUserClient
*) temp
;
4941 return kIOReturnUnsupported
;
4944 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
4946 return kIOReturnBadArgument
;
4949 if ( !client
->attach(this) ) {
4951 return kIOReturnUnsupported
;
4954 if ( !client
->start(this) ) {
4955 client
->detach(this);
4957 return kIOReturnUnsupported
;
4961 return kIOReturnSuccess
;
4964 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
4965 UInt32 type
, IOUserClient
** handler
)
4967 return( kIOReturnUnsupported
);
4970 IOReturn
IOService::requestProbe( IOOptionBits options
)
4972 return( kIOReturnUnsupported
);
4976 * Convert an IOReturn to text. Subclasses which add additional
4977 * IOReturn's should override this method and call
4978 * super::stringFromReturn if the desired value is not found.
4981 const char * IOService::stringFromReturn( IOReturn rtn
)
4983 static const IONamedValue IOReturn_values
[] = {
4984 {kIOReturnSuccess
, "success" },
4985 {kIOReturnError
, "general error" },
4986 {kIOReturnNoMemory
, "memory allocation error" },
4987 {kIOReturnNoResources
, "resource shortage" },
4988 {kIOReturnIPCError
, "Mach IPC failure" },
4989 {kIOReturnNoDevice
, "no such device" },
4990 {kIOReturnNotPrivileged
, "privilege violation" },
4991 {kIOReturnBadArgument
, "invalid argument" },
4992 {kIOReturnLockedRead
, "device is read locked" },
4993 {kIOReturnLockedWrite
, "device is write locked" },
4994 {kIOReturnExclusiveAccess
, "device is exclusive access" },
4995 {kIOReturnBadMessageID
, "bad IPC message ID" },
4996 {kIOReturnUnsupported
, "unsupported function" },
4997 {kIOReturnVMError
, "virtual memory error" },
4998 {kIOReturnInternalError
, "internal driver error" },
4999 {kIOReturnIOError
, "I/O error" },
5000 {kIOReturnCannotLock
, "cannot acquire lock" },
5001 {kIOReturnNotOpen
, "device is not open" },
5002 {kIOReturnNotReadable
, "device is not readable" },
5003 {kIOReturnNotWritable
, "device is not writeable" },
5004 {kIOReturnNotAligned
, "alignment error" },
5005 {kIOReturnBadMedia
, "media error" },
5006 {kIOReturnStillOpen
, "device is still open" },
5007 {kIOReturnRLDError
, "rld failure" },
5008 {kIOReturnDMAError
, "DMA failure" },
5009 {kIOReturnBusy
, "device is busy" },
5010 {kIOReturnTimeout
, "I/O timeout" },
5011 {kIOReturnOffline
, "device is offline" },
5012 {kIOReturnNotReady
, "device is not ready" },
5013 {kIOReturnNotAttached
, "device/channel is not attached" },
5014 {kIOReturnNoChannels
, "no DMA channels available" },
5015 {kIOReturnNoSpace
, "no space for data" },
5016 {kIOReturnPortExists
, "device port already exists" },
5017 {kIOReturnCannotWire
, "cannot wire physical memory" },
5018 {kIOReturnNoInterrupt
, "no interrupt attached" },
5019 {kIOReturnNoFrames
, "no DMA frames enqueued" },
5020 {kIOReturnMessageTooLarge
, "message is too large" },
5021 {kIOReturnNotPermitted
, "operation is not permitted" },
5022 {kIOReturnNoPower
, "device is without power" },
5023 {kIOReturnNoMedia
, "media is not present" },
5024 {kIOReturnUnformattedMedia
, "media is not formatted" },
5025 {kIOReturnUnsupportedMode
, "unsupported mode" },
5026 {kIOReturnUnderrun
, "data underrun" },
5027 {kIOReturnOverrun
, "data overrun" },
5028 {kIOReturnDeviceError
, "device error" },
5029 {kIOReturnNoCompletion
, "no completion routine" },
5030 {kIOReturnAborted
, "operation was aborted" },
5031 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
5032 {kIOReturnNotResponding
, "device is not responding" },
5033 {kIOReturnInvalid
, "unanticipated driver error" },
5037 return IOFindNameForValue(rtn
, IOReturn_values
);
5041 * Convert an IOReturn to an errno.
5043 int IOService::errnoFromReturn( IOReturn rtn
)
5045 if (unix_err(err_get_code(rtn
)) == rtn
)
5046 return err_get_code(rtn
);
5050 case kIOReturnSuccess
:
5052 case kIOReturnNoMemory
:
5054 case kIOReturnNoDevice
:
5056 case kIOReturnVMError
:
5058 case kIOReturnNotPermitted
:
5060 case kIOReturnNotPrivileged
:
5062 case kIOReturnIOError
:
5064 case kIOReturnNotWritable
:
5066 case kIOReturnBadArgument
:
5068 case kIOReturnUnsupported
:
5072 case kIOReturnNoPower
:
5074 case kIOReturnDeviceError
:
5076 case kIOReturnTimeout
:
5078 case kIOReturnMessageTooLarge
:
5080 case kIOReturnNoSpace
:
5082 case kIOReturnCannotLock
:
5086 case kIOReturnBadMessageID
:
5087 case kIOReturnNoCompletion
:
5088 case kIOReturnNotAligned
:
5090 case kIOReturnNotReady
:
5092 case kIOReturnRLDError
:
5094 case kIOReturnPortExists
:
5095 case kIOReturnStillOpen
:
5097 case kIOReturnExclusiveAccess
:
5098 case kIOReturnLockedRead
:
5099 case kIOReturnLockedWrite
:
5100 case kIOReturnNotOpen
:
5101 case kIOReturnNotReadable
:
5103 case kIOReturnCannotWire
:
5104 case kIOReturnNoResources
:
5106 case kIOReturnAborted
:
5107 case kIOReturnOffline
:
5108 case kIOReturnNotResponding
:
5110 case kIOReturnBadMedia
:
5111 case kIOReturnNoMedia
:
5112 case kIOReturnNotAttached
:
5113 case kIOReturnUnformattedMedia
:
5114 return(ENXIO
); // (media error)
5115 case kIOReturnDMAError
:
5116 case kIOReturnOverrun
:
5117 case kIOReturnUnderrun
:
5118 return(EIO
); // (transfer error)
5119 case kIOReturnNoBandwidth
:
5120 case kIOReturnNoChannels
:
5121 case kIOReturnNoFrames
:
5122 case kIOReturnNoInterrupt
:
5123 return(EIO
); // (hardware error)
5124 case kIOReturnError
:
5125 case kIOReturnInternalError
:
5126 case kIOReturnInvalid
:
5127 return(EIO
); // (generic error)
5128 case kIOReturnIPCError
:
5129 return(EIO
); // (ipc error)
5131 return(EIO
); // (all other errors)
5135 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
5139 * Generic entry point for calls from the provider. A return value of
5140 * kIOReturnSuccess indicates that the message was received, and where
5141 * applicable, that it was successful.
5144 return kIOReturnUnsupported
;
5151 IOItemCount
IOService::getDeviceMemoryCount( void )
5156 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5158 count
= array
->getCount();
5165 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
5168 IODeviceMemory
* range
;
5170 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5172 range
= (IODeviceMemory
*) array
->getObject( index
);
5179 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
5180 IOOptionBits options
)
5182 IODeviceMemory
* range
;
5185 range
= getDeviceMemoryWithIndex( index
);
5187 map
= range
->map( options
);
5194 OSArray
* IOService::getDeviceMemory( void )
5196 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
5200 void IOService::setDeviceMemory( OSArray
* array
)
5202 setProperty( gIODeviceMemoryKey
, array
);
5206 * For machines where the transfers on an I/O bus can stall because
5207 * the CPU is in an idle mode, These APIs allow a driver to specify
5208 * the maximum bus stall that they can handle. 0 indicates no limit.
5211 setCPUSnoopDelay(UInt32 __unused ns
)
5213 #if defined(__i386__) || defined(__x86_64__)
5214 ml_set_maxsnoop(ns
);
5215 #endif /* defined(__i386__) || defined(__x86_64__) */
5221 #if defined(__i386__) || defined(__x86_64__)
5222 return ml_get_maxsnoop();
5225 #endif /* defined(__i386__) || defined(__x86_64__) */
5228 #if defined(__i386__) || defined(__x86_64__)
5230 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
5232 static const UInt kNoReplace
= -1U; // Must be an illegal index
5233 UInt replace
= kNoReplace
;
5234 bool setCpuDelay
= false;
5236 IORecursiveLockLock(sCpuDelayLock
);
5238 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5239 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5240 IOService
* holder
= NULL
;
5243 const CpuDelayEntry ne
= {service
, ns
, delayType
};
5245 // Set maximum delay.
5246 for (UInt i
= 0; i
< count
; i
++) {
5247 IOService
*thisService
= entries
[i
].fService
;
5248 bool sameType
= (delayType
== entries
[i
].fDelayType
);
5249 if ((service
== thisService
) && sameType
)
5251 else if (!thisService
) {
5252 if (kNoReplace
== replace
)
5255 else if (sameType
) {
5256 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
5260 holder
= thisService
;
5266 if (kNoReplace
== replace
)
5267 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
5269 entries
[replace
] = ne
;
5272 ns
= -1U; // Set to max unsigned, i.e. no restriction
5274 for (UInt i
= 0; i
< count
; i
++) {
5275 // Clear a maximum delay.
5276 IOService
*thisService
= entries
[i
].fService
;
5277 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
5278 UInt32 thisMax
= entries
[i
].fMaxDelay
;
5279 if (service
== thisService
)
5281 else if (thisMax
< ns
) {
5283 holder
= thisService
;
5288 // Check if entry found
5289 if (kNoReplace
!= replace
) {
5290 entries
[replace
].fService
= 0; // Null the entry
5297 // Must be safe to call from locked context
5298 if (delayType
== kCpuDelayBusStall
)
5300 ml_set_maxbusdelay(ns
);
5302 else if (delayType
== kCpuDelayInterrupt
)
5304 ml_set_maxintdelay(ns
);
5307 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
5309 if (handlers
) for (unsigned int idx
= 0;
5310 (target
= (IOService
*) handlers
->getObject(idx
));
5313 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5314 (void *) (uintptr_t) ns
, holder
,
5319 IORecursiveLockUnlock(sCpuDelayLock
);
5323 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
5325 IOReturn result
= kIOReturnNotFound
;
5329 IORecursiveLockLock(sCpuDelayLock
);
5333 if (enable
&& !sCpuLatencyHandlers
[delayType
])
5334 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
5335 array
= sCpuLatencyHandlers
[delayType
];
5338 idx
= array
->getNextIndexOfObject(target
, 0);
5343 array
->removeObject(idx
);
5344 result
= kIOReturnSuccess
;
5350 result
= kIOReturnExclusiveAccess
;
5353 array
->setObject(target
);
5355 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5356 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5357 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
5358 IOService
* holder
= NULL
;
5360 for (UInt i
= 0; i
< count
; i
++) {
5361 if (entries
[i
].fService
5362 && (delayType
== entries
[i
].fDelayType
)
5363 && (entries
[i
].fMaxDelay
< ns
)) {
5364 ns
= entries
[i
].fMaxDelay
;
5365 holder
= entries
[i
].fService
;
5368 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
5369 (void *) (uintptr_t) ns
, holder
,
5371 result
= kIOReturnSuccess
;
5376 IORecursiveLockUnlock(sCpuDelayLock
);
5381 #endif /* defined(__i386__) || defined(__x86_64__) */
5384 requireMaxBusStall(UInt32 __unused ns
)
5386 #if defined(__i386__) || defined(__x86_64__)
5387 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
5392 requireMaxInterruptDelay(uint32_t __unused ns
)
5394 #if defined(__i386__) || defined(__x86_64__)
5395 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
5403 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
5405 IOInterruptController
*interruptController
;
5408 OSSymbol
*interruptControllerName
;
5410 IOInterruptSource
*interruptSources
;
5412 // Get the parents list from the nub.
5413 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
5414 if (array
== 0) return kIOReturnNoResources
;
5416 // Allocate space for the IOInterruptSources if needed... then return early.
5417 if (nub
->_interruptSources
== 0) {
5418 numSources
= array
->getCount();
5419 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
5420 if (interruptSources
== 0) return kIOReturnNoMemory
;
5422 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
5424 nub
->_numInterruptSources
= numSources
;
5425 nub
->_interruptSources
= interruptSources
;
5426 return kIOReturnSuccess
;
5429 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
5430 if (interruptControllerName
== 0) return kIOReturnNoResources
;
5432 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
5433 if (interruptController
== 0) return kIOReturnNoResources
;
5435 // Get the interrupt numbers from the nub.
5436 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
5437 if (array
== 0) return kIOReturnNoResources
;
5438 data
= OSDynamicCast(OSData
, array
->getObject(source
));
5439 if (data
== 0) return kIOReturnNoResources
;
5441 // Set the interruptController and interruptSource in the nub's table.
5442 interruptSources
= nub
->_interruptSources
;
5443 interruptSources
[source
].interruptController
= interruptController
;
5444 interruptSources
[source
].vectorData
= data
;
5446 return kIOReturnSuccess
;
5449 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
5453 /* Make sure the _interruptSources are set */
5454 if (_interruptSources
== 0) {
5455 ret
= resolveInterrupt(this, source
);
5456 if (ret
!= kIOReturnSuccess
) return ret
;
5459 /* Make sure the local source number is valid */
5460 if ((source
< 0) || (source
>= _numInterruptSources
))
5461 return kIOReturnNoInterrupt
;
5463 /* Look up the contoller for the local source */
5464 *interruptController
= _interruptSources
[source
].interruptController
;
5466 if (*interruptController
== NULL
) {
5467 if (!resolve
) return kIOReturnNoInterrupt
;
5469 /* Try to reslove the interrupt */
5470 ret
= resolveInterrupt(this, source
);
5471 if (ret
!= kIOReturnSuccess
) return ret
;
5473 *interruptController
= _interruptSources
[source
].interruptController
;
5476 return kIOReturnSuccess
;
5479 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
5480 IOInterruptAction handler
,
5483 IOInterruptController
*interruptController
;
5486 ret
= lookupInterrupt(source
, true, &interruptController
);
5487 if (ret
!= kIOReturnSuccess
) return ret
;
5489 /* Register the source */
5490 return interruptController
->registerInterrupt(this, source
, target
,
5491 (IOInterruptHandler
)handler
,
5495 IOReturn
IOService::unregisterInterrupt(int source
)
5497 IOInterruptController
*interruptController
;
5500 ret
= lookupInterrupt(source
, false, &interruptController
);
5501 if (ret
!= kIOReturnSuccess
) return ret
;
5503 /* Unregister the source */
5504 return interruptController
->unregisterInterrupt(this, source
);
5507 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
5509 IOInterruptController
*interruptController
;
5512 ret
= lookupInterrupt(source
, true, &interruptController
);
5513 if (ret
!= kIOReturnSuccess
) return ret
;
5515 /* Return the type */
5516 return interruptController
->getInterruptType(this, source
, interruptType
);
5519 IOReturn
IOService::enableInterrupt(int source
)
5521 IOInterruptController
*interruptController
;
5524 ret
= lookupInterrupt(source
, false, &interruptController
);
5525 if (ret
!= kIOReturnSuccess
) return ret
;
5527 /* Enable the source */
5528 return interruptController
->enableInterrupt(this, source
);
5531 IOReturn
IOService::disableInterrupt(int source
)
5533 IOInterruptController
*interruptController
;
5536 ret
= lookupInterrupt(source
, false, &interruptController
);
5537 if (ret
!= kIOReturnSuccess
) return ret
;
5539 /* Disable the source */
5540 return interruptController
->disableInterrupt(this, source
);
5543 IOReturn
IOService::causeInterrupt(int source
)
5545 IOInterruptController
*interruptController
;
5548 ret
= lookupInterrupt(source
, false, &interruptController
);
5549 if (ret
!= kIOReturnSuccess
) return ret
;
5551 /* Cause an interrupt for the source */
5552 return interruptController
->causeInterrupt(this, source
);
5555 IOReturn
IOService::configureReport(IOReportChannelList
*channelList
,
5556 IOReportConfigureAction action
,
5562 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
5563 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
5564 if (pwrMgt
) configurePowerStatesReport(action
, result
);
5565 else return kIOReturnUnsupported
;
5567 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
5568 if (pwrMgt
) configureSimplePowerReport(action
, result
);
5569 else return kIOReturnUnsupported
;
5573 return kIOReturnSuccess
;
5576 IOReturn
IOService::updateReport(IOReportChannelList
*channelList
,
5577 IOReportUpdateAction action
,
5583 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
5584 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
5585 if (pwrMgt
) updatePowerStatesReport(action
, result
, destination
);
5586 else return kIOReturnUnsupported
;
5588 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
5589 if (pwrMgt
) updateSimplePowerReport(action
, result
, destination
);
5590 else return kIOReturnUnsupported
;
5594 return kIOReturnSuccess
;
5598 OSMetaClassDefineReservedUsed(IOService
, 0);
5599 OSMetaClassDefineReservedUsed(IOService
, 1);
5600 OSMetaClassDefineReservedUnused(IOService
, 2);
5601 OSMetaClassDefineReservedUnused(IOService
, 3);
5602 OSMetaClassDefineReservedUnused(IOService
, 4);
5603 OSMetaClassDefineReservedUnused(IOService
, 5);
5604 OSMetaClassDefineReservedUnused(IOService
, 6);
5605 OSMetaClassDefineReservedUnused(IOService
, 7);
5607 OSMetaClassDefineReservedUsed(IOService
, 0);
5608 OSMetaClassDefineReservedUsed(IOService
, 1);
5609 OSMetaClassDefineReservedUsed(IOService
, 2);
5610 OSMetaClassDefineReservedUsed(IOService
, 3);
5611 OSMetaClassDefineReservedUsed(IOService
, 4);
5612 OSMetaClassDefineReservedUsed(IOService
, 5);
5613 OSMetaClassDefineReservedUsed(IOService
, 6);
5614 OSMetaClassDefineReservedUsed(IOService
, 7);
5616 OSMetaClassDefineReservedUnused(IOService
, 8);
5617 OSMetaClassDefineReservedUnused(IOService
, 9);
5618 OSMetaClassDefineReservedUnused(IOService
, 10);
5619 OSMetaClassDefineReservedUnused(IOService
, 11);
5620 OSMetaClassDefineReservedUnused(IOService
, 12);
5621 OSMetaClassDefineReservedUnused(IOService
, 13);
5622 OSMetaClassDefineReservedUnused(IOService
, 14);
5623 OSMetaClassDefineReservedUnused(IOService
, 15);
5624 OSMetaClassDefineReservedUnused(IOService
, 16);
5625 OSMetaClassDefineReservedUnused(IOService
, 17);
5626 OSMetaClassDefineReservedUnused(IOService
, 18);
5627 OSMetaClassDefineReservedUnused(IOService
, 19);
5628 OSMetaClassDefineReservedUnused(IOService
, 20);
5629 OSMetaClassDefineReservedUnused(IOService
, 21);
5630 OSMetaClassDefineReservedUnused(IOService
, 22);
5631 OSMetaClassDefineReservedUnused(IOService
, 23);
5632 OSMetaClassDefineReservedUnused(IOService
, 24);
5633 OSMetaClassDefineReservedUnused(IOService
, 25);
5634 OSMetaClassDefineReservedUnused(IOService
, 26);
5635 OSMetaClassDefineReservedUnused(IOService
, 27);
5636 OSMetaClassDefineReservedUnused(IOService
, 28);
5637 OSMetaClassDefineReservedUnused(IOService
, 29);
5638 OSMetaClassDefineReservedUnused(IOService
, 30);
5639 OSMetaClassDefineReservedUnused(IOService
, 31);
5640 OSMetaClassDefineReservedUnused(IOService
, 32);
5641 OSMetaClassDefineReservedUnused(IOService
, 33);
5642 OSMetaClassDefineReservedUnused(IOService
, 34);
5643 OSMetaClassDefineReservedUnused(IOService
, 35);
5644 OSMetaClassDefineReservedUnused(IOService
, 36);
5645 OSMetaClassDefineReservedUnused(IOService
, 37);
5646 OSMetaClassDefineReservedUnused(IOService
, 38);
5647 OSMetaClassDefineReservedUnused(IOService
, 39);
5648 OSMetaClassDefineReservedUnused(IOService
, 40);
5649 OSMetaClassDefineReservedUnused(IOService
, 41);
5650 OSMetaClassDefineReservedUnused(IOService
, 42);
5651 OSMetaClassDefineReservedUnused(IOService
, 43);
5652 OSMetaClassDefineReservedUnused(IOService
, 44);
5653 OSMetaClassDefineReservedUnused(IOService
, 45);
5654 OSMetaClassDefineReservedUnused(IOService
, 46);
5655 OSMetaClassDefineReservedUnused(IOService
, 47);