2 * Copyright (c) 1998-2016 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 <IOKit/IOInterruptAccountingPrivate.h>
52 #include <IOKit/IOKernelReporters.h>
53 #include <IOKit/AppleKeyStoreInterface.h>
54 #include <IOKit/IOCPU.h>
55 #include <mach/sync_policy.h>
56 #include <IOKit/assert.h>
57 #include <sys/errno.h>
58 #include <sys/kdebug.h>
61 #include <machine/pal_routines.h>
66 #define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
68 #include "IOServicePrivate.h"
69 #include "IOKitKernelInternal.h"
71 // take lockForArbitration before LOCKNOTIFY
73 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
75 #define super IORegistryEntry
77 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
79 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
80 OSDefineMetaClassAndStructors(_IOServiceNullNotifier
, IONotifier
)
82 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
84 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
86 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
88 OSDefineMetaClassAndStructors(IOResources
, IOService
)
90 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
92 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
94 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
96 static IOPlatformExpert
* gIOPlatform
;
97 static class IOPMrootDomain
* gIOPMRootDomain
;
98 const IORegistryPlane
* gIOServicePlane
;
99 const IORegistryPlane
* gIOPowerPlane
;
100 const OSSymbol
* gIODeviceMemoryKey
;
101 const OSSymbol
* gIOInterruptControllersKey
;
102 const OSSymbol
* gIOInterruptSpecifiersKey
;
104 const OSSymbol
* gIOResourcesKey
;
105 const OSSymbol
* gIOResourceMatchKey
;
106 const OSSymbol
* gIOResourceMatchedKey
;
107 const OSSymbol
* gIOProviderClassKey
;
108 const OSSymbol
* gIONameMatchKey
;
109 const OSSymbol
* gIONameMatchedKey
;
110 const OSSymbol
* gIOPropertyMatchKey
;
111 const OSSymbol
* gIOPropertyExistsMatchKey
;
112 const OSSymbol
* gIOLocationMatchKey
;
113 const OSSymbol
* gIOParentMatchKey
;
114 const OSSymbol
* gIOPathMatchKey
;
115 const OSSymbol
* gIOMatchCategoryKey
;
116 const OSSymbol
* gIODefaultMatchCategoryKey
;
117 const OSSymbol
* gIOMatchedServiceCountKey
;
119 const OSSymbol
* gIOMapperIDKey
;
120 const OSSymbol
* gIOUserClientClassKey
;
121 const OSSymbol
* gIOKitDebugKey
;
123 const OSSymbol
* gIOCommandPoolSizeKey
;
125 const OSSymbol
* gIOConsoleLockedKey
;
126 const OSSymbol
* gIOConsoleUsersKey
;
127 const OSSymbol
* gIOConsoleSessionUIDKey
;
128 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
129 const OSSymbol
* gIOConsoleUsersSeedKey
;
130 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
131 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
132 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
133 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
134 const OSSymbol
* gIOConsoleSessionScreenIsLockedKey
;
135 clock_sec_t gIOConsoleLockTime
;
136 static bool gIOConsoleLoggedIn
;
138 static OSBoolean
* gIOConsoleBooterLockState
;
139 static uint32_t gIOScreenLockState
;
141 static IORegistryEntry
* gIOChosenEntry
;
143 static int gIOResourceGenerationCount
;
145 const OSSymbol
* gIOServiceKey
;
146 const OSSymbol
* gIOPublishNotification
;
147 const OSSymbol
* gIOFirstPublishNotification
;
148 const OSSymbol
* gIOMatchedNotification
;
149 const OSSymbol
* gIOFirstMatchNotification
;
150 const OSSymbol
* gIOTerminatedNotification
;
152 const OSSymbol
* gIOGeneralInterest
;
153 const OSSymbol
* gIOBusyInterest
;
154 const OSSymbol
* gIOAppPowerStateInterest
;
155 const OSSymbol
* gIOPriorityPowerStateInterest
;
156 const OSSymbol
* gIOConsoleSecurityInterest
;
158 const OSSymbol
* gIOBSDKey
;
159 const OSSymbol
* gIOBSDNameKey
;
160 const OSSymbol
* gIOBSDMajorKey
;
161 const OSSymbol
* gIOBSDMinorKey
;
162 const OSSymbol
* gIOBSDUnitKey
;
164 const OSSymbol
* gAKSGetKey
;
165 #if defined(__i386__) || defined(__x86_64__)
166 const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
169 static OSDictionary
* gNotifications
;
170 static IORecursiveLock
* gNotificationLock
;
172 static IOService
* gIOResources
;
173 static IOService
* gIOServiceRoot
;
175 static OSOrderedSet
* gJobs
;
176 static semaphore_port_t gJobsSemaphore
;
177 static IOLock
* gJobsLock
;
178 static int gOutstandingJobs
;
179 static int gNumConfigThreads
;
180 static int gNumWaitingThreads
;
181 static IOLock
* gIOServiceBusyLock
;
182 static bool gCPUsRunning
;
184 static thread_t gIOTerminateThread
;
185 static UInt32 gIOTerminateWork
;
186 static OSArray
* gIOTerminatePhase2List
;
187 static OSArray
* gIOStopList
;
188 static OSArray
* gIOStopProviderList
;
189 static OSArray
* gIOFinalizeList
;
191 static SInt32 gIOConsoleUsersSeed
;
192 static OSData
* gIOConsoleUsersSeedValue
;
194 extern const OSSymbol
* gIODTPHandleKey
;
196 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
198 static IOLock
* gIOConsoleUsersLock
;
199 static thread_call_t gIOConsoleLockCallout
;
200 static IONotifier
* gIOServiceNullNotifier
;
202 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
204 #define LOCKREADNOTIFY() \
205 IORecursiveLockLock( gNotificationLock )
206 #define LOCKWRITENOTIFY() \
207 IORecursiveLockLock( gNotificationLock )
208 #define LOCKWRITE2READNOTIFY()
209 #define UNLOCKNOTIFY() \
210 IORecursiveLockUnlock( gNotificationLock )
211 #define SLEEPNOTIFY(event) \
212 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
213 #define SLEEPNOTIFYTO(event, deadline) \
214 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
215 #define WAKEUPNOTIFY(event) \
216 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
218 #define randomDelay() \
219 int del = read_processor_clock(); \
220 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
223 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
225 #define queue_element(entry, element, type, field) do { \
226 vm_address_t __ele = (vm_address_t) (entry); \
227 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
228 (element) = (type) __ele; \
231 #define iterqueue(que, elt) \
232 for (queue_entry_t elt = queue_first(que); \
233 !queue_end(que, elt); \
234 elt = queue_next(elt))
236 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
238 struct IOInterruptAccountingReporter
{
239 IOSimpleReporter
* reporter
; /* Reporter responsible for communicating the statistics */
240 IOInterruptAccountingData
* statistics
; /* The live statistics values, if any */
243 struct ArbitrationLockQueueElement
{
252 static queue_head_t gArbitrationLockQueueActive
;
253 static queue_head_t gArbitrationLockQueueWaiting
;
254 static queue_head_t gArbitrationLockQueueFree
;
255 static IOLock
* gArbitrationLockQueueLock
;
257 bool IOService::isInactive( void ) const
258 { return( 0 != (kIOServiceInactiveState
& getState())); }
260 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
262 #if defined(__i386__) || defined(__x86_64__)
264 // Only used by the intel implementation of
265 // IOService::requireMaxBusStall(UInt32 ns)
266 // IOService::requireMaxInterruptDelay(uint32_t ns)
269 IOService
* fService
;
275 kCpuDelayBusStall
, kCpuDelayInterrupt
,
279 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
280 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
281 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
282 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
283 static OSNumber
* sCPULatencyHolder
[kCpuNumDelayTypes
];
284 static char sCPULatencyHolderName
[kCpuNumDelayTypes
][128];
285 static OSNumber
* sCPULatencySet
[kCpuNumDelayTypes
];
288 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
290 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
292 #endif /* defined(__i386__) || defined(__x86_64__) */
294 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
296 void IOService::initialize( void )
300 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
301 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
303 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
304 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
305 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
306 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
307 gIOPropertyExistsMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey
);
308 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
309 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
310 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
312 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
313 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
314 kIODefaultMatchCategoryKey
);
315 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
316 kIOMatchedServiceCountKey
);
318 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
320 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
321 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
322 gIOResourceMatchedKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchedKey
);
324 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
325 gIOInterruptControllersKey
326 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
327 gIOInterruptSpecifiersKey
328 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
330 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
332 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
334 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
336 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
337 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
338 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
339 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
340 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
342 gIOBSDKey
= OSSymbol::withCStringNoCopy(kIOBSDKey
);
343 gIOBSDNameKey
= OSSymbol::withCStringNoCopy(kIOBSDNameKey
);
344 gIOBSDMajorKey
= OSSymbol::withCStringNoCopy(kIOBSDMajorKey
);
345 gIOBSDMinorKey
= OSSymbol::withCStringNoCopy(kIOBSDMinorKey
);
346 gIOBSDUnitKey
= OSSymbol::withCStringNoCopy(kIOBSDUnitKey
);
348 gNotifications
= OSDictionary::withCapacity( 1 );
349 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
350 kIOPublishNotification
);
351 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
352 kIOFirstPublishNotification
);
353 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
354 kIOMatchedNotification
);
355 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
356 kIOFirstMatchNotification
);
357 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
358 kIOTerminatedNotification
);
359 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
361 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
362 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
363 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
364 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
366 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
367 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
368 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
369 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
370 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
371 gIOConsoleSessionScreenIsLockedKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey
);
373 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
375 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
376 #if defined(__i386__) || defined(__x86_64__)
377 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
378 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
380 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++)
382 sCPULatencySet
[idx
] = OSNumber::withNumber(-1U, 32);
383 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
384 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
386 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
388 gNotificationLock
= IORecursiveLockAlloc();
390 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
392 assert( gIOServicePlane
&& gIODeviceMemoryKey
393 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
394 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
395 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
396 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
397 && gIOPublishNotification
&& gIOMatchedNotification
398 && gIOTerminatedNotification
&& gIOServiceKey
399 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
400 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
401 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
403 gJobsLock
= IOLockAlloc();
404 gJobs
= OSOrderedSet::withCapacity( 10 );
406 gIOServiceBusyLock
= IOLockAlloc();
408 gIOConsoleUsersLock
= IOLockAlloc();
410 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
412 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
414 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
416 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
417 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
) );
419 gIOResources
= IOResources::resources();
420 assert( gIOResources
);
422 gIOServiceNullNotifier
= OSTypeAlloc(_IOServiceNullNotifier
);
423 assert(gIOServiceNullNotifier
);
425 gArbitrationLockQueueLock
= IOLockAlloc();
426 queue_init(&gArbitrationLockQueueActive
);
427 queue_init(&gArbitrationLockQueueWaiting
);
428 queue_init(&gArbitrationLockQueueFree
);
430 assert( gArbitrationLockQueueLock
);
432 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
433 gIOStopList
= OSArray::withCapacity( 16 );
434 gIOStopProviderList
= OSArray::withCapacity( 16 );
435 gIOFinalizeList
= OSArray::withCapacity( 16 );
436 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
439 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
441 #if defined(__i386__) || defined(__x86_64__)
444 const char *getCpuDelayBusStallHolderName(void);
445 const char *getCpuDelayBusStallHolderName(void) {
446 return sCPULatencyHolderName
[kCpuDelayBusStall
];
453 static UInt64
getDebugFlags( OSDictionary
* props
)
455 OSNumber
* debugProp
;
458 debugProp
= OSDynamicCast( OSNumber
,
459 props
->getObject( gIOKitDebugKey
));
461 debugFlags
= debugProp
->unsigned64BitValue();
463 debugFlags
= gIOKitDebug
;
465 return( debugFlags
);
469 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
471 // Probe a matched service and return an instance to be started.
472 // The default score is from the property table, & may be altered
473 // during probe to change the start order.
475 IOService
* IOService::probe( IOService
* provider
,
481 bool IOService::start( IOService
* provider
)
486 void IOService::stop( IOService
* provider
)
490 bool IOService::init( OSDictionary
* dictionary
)
494 ret
= super::init(dictionary
);
495 if (!ret
) return (false);
496 if (reserved
) return (true);
498 reserved
= IONew(ExpansionData
, 1);
499 if (!reserved
) return (false);
500 bzero(reserved
, sizeof(*reserved
));
503 * TODO: Improve on this. Previous efforts to more lazily allocate this
504 * lock based on the presence of specifiers ran into issues as some
505 * platforms set up the specifiers after IOService initialization.
507 * We may be able to get away with a global lock, as this should only be
508 * contended by IOReporting clients and driver start/stop (unless a
509 * driver wants to remove/add handlers in the course of normal operation,
510 * which should be unlikely).
512 reserved
->interruptStatisticsLock
= IOLockAlloc();
513 if (!reserved
->interruptStatisticsLock
) return (false);
518 bool IOService::init( IORegistryEntry
* from
,
519 const IORegistryPlane
* inPlane
)
523 ret
= super::init(from
, inPlane
);
524 if (!ret
) return (false);
525 if (reserved
) return (true);
527 reserved
= IONew(ExpansionData
, 1);
528 if (!reserved
) return (false);
529 bzero(reserved
, sizeof(*reserved
));
532 * TODO: Improve on this. Previous efforts to more lazily allocate this
533 * lock based on the presence of specifiers ran into issues as some
534 * platforms set up the specifiers after IOService initialization.
536 * We may be able to get away with a global lock, as this should only be
537 * contended by IOReporting clients and driver start/stop (unless a
538 * driver wants to remove/add handlers in the course of normal operation,
539 * which should be unlikely).
541 reserved
->interruptStatisticsLock
= IOLockAlloc();
542 if (!reserved
->interruptStatisticsLock
) return (false);
547 void IOService::free( void )
550 requireMaxBusStall(0);
551 requireMaxInterruptDelay(0);
552 if( getPropertyTable())
553 unregisterAllInterest();
557 if (reserved
->interruptStatisticsArray
) {
558 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
559 if (reserved
->interruptStatisticsArray
[i
].reporter
)
560 reserved
->interruptStatisticsArray
[i
].reporter
->release();
563 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
566 if (reserved
->interruptStatisticsLock
)
567 IOLockFree(reserved
->interruptStatisticsLock
);
568 IODelete(reserved
, ExpansionData
, 1);
571 if (_numInterruptSources
&& _interruptSources
)
573 IOFree(_interruptSources
, _numInterruptSources
* sizeof(IOInterruptSource
));
574 _interruptSources
= 0;
581 * Attach in service plane
583 bool IOService::attach( IOService
* provider
)
587 AbsoluteTime deadline
;
588 int waitResult
= THREAD_AWAKENED
;
589 bool wait
, computeDeadline
= true;
593 if( gIOKitDebug
& kIOLogAttach
)
594 LOG( "%s::attach(%s)\n", getName(),
595 provider
->getName());
601 provider
->lockForArbitration();
602 if (provider
->__state
[0] & kIOServiceInactiveState
) ok
= false;
605 count
= provider
->getChildCount(gIOServicePlane
);
606 wait
= (count
> (kIOServiceBusyMax
- 4));
607 if (!wait
) ok
= attachToParent(provider
, gIOServicePlane
);
610 IOLog("stalling for detach from %s\n", provider
->getName());
611 IOLockLock( gIOServiceBusyLock
);
612 provider
->__state
[1] |= kIOServiceWaitDetachState
;
615 provider
->unlockForArbitration();
620 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
621 computeDeadline
= false;
623 assert_wait_deadline((event_t
)&provider
->__provider
, THREAD_UNINT
, deadline
);
624 IOLockUnlock( gIOServiceBusyLock
);
625 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
626 wait
= (waitResult
!= THREAD_TIMED_OUT
);
632 gIOServiceRoot
= this;
633 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
636 if (ok
&& !__provider
) (void) getProvider();
641 IOService
* IOService::getServiceRoot( void )
643 return( gIOServiceRoot
);
646 void IOService::detach( IOService
* provider
)
648 IOService
* newProvider
= 0;
652 if( gIOKitDebug
& kIOLogAttach
)
653 LOG("%s::detach(%s)\n", getName(), provider
->getName());
655 lockForArbitration();
657 uint64_t regID1
= provider
->getRegistryEntryID();
658 uint64_t regID2
= getRegistryEntryID();
662 (uintptr_t) (regID1
>> 32),
664 (uintptr_t) (regID2
>> 32));
666 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
667 && (provider
== getProvider()));
669 detachFromParent( provider
, gIOServicePlane
);
672 newProvider
= getProvider();
673 if( busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (0 == newProvider
))
674 _adjustBusy( -busy
);
677 if (kIOServiceInactiveState
& __state
[0]) {
678 getMetaClass()->removeInstance(this);
679 IORemoveServicePlatformActions(this);
682 unlockForArbitration();
685 newProvider
->lockForArbitration();
686 newProvider
->_adjustBusy(1);
687 newProvider
->unlockForArbitration();
690 // check for last client detach from a terminated service
691 if( provider
->lockForArbitration( true ))
693 if (kIOServiceStartState
& __state
[1])
695 provider
->scheduleTerminatePhase2();
697 if( adjParent
) provider
->_adjustBusy( -1 );
698 if( (provider
->__state
[1] & kIOServiceTermPhase3State
)
699 && (0 == provider
->getClient())) {
700 provider
->scheduleFinalize(false);
703 IOLockLock( gIOServiceBusyLock
);
704 if (kIOServiceWaitDetachState
& provider
->__state
[1])
706 provider
->__state
[1] &= ~kIOServiceWaitDetachState
;
707 thread_wakeup(&provider
->__provider
);
709 IOLockUnlock( gIOServiceBusyLock
);
711 provider
->unlockForArbitration();
716 * Register instance - publish it for matching
719 void IOService::registerService( IOOptionBits options
)
725 enum { kMaxPathLen
= 256 };
726 enum { kMaxChars
= 63 };
728 IORegistryEntry
* parent
= this;
729 IORegistryEntry
* root
= getRegistryRoot();
730 while( parent
&& (parent
!= root
))
731 parent
= parent
->getParentEntry( gIOServicePlane
);
733 if( parent
!= root
) {
734 IOLog("%s: not registry member at registerService()\n", getName());
738 // Allow the Platform Expert to adjust this node.
739 if( gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this)))
742 IOInstallServicePlatformActions(this);
744 if( (this != gIOResources
)
745 && (kIOLogRegister
& gIOKitDebug
)) {
747 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
749 IOLog( "Registering: " );
752 if( pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
755 if( len
> kMaxChars
) {
759 if( (skip
= strchr( path
, '/')))
765 IOLog( "%s\n", path
);
768 IOFree( pathBuf
, kMaxPathLen
);
771 startMatching( options
);
774 void IOService::startMatching( IOOptionBits options
)
776 IOService
* provider
;
779 bool needWake
= false;
784 lockForArbitration();
786 sync
= (options
& kIOServiceSynchronous
)
787 || ((provider
= getProvider())
788 && (provider
->__state
[1] & kIOServiceSynchronousState
));
790 if ( options
& kIOServiceAsynchronous
)
793 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigState
)))
794 && (0 == (__state
[0] & kIOServiceInactiveState
));
796 __state
[1] |= kIOServiceNeedConfigState
;
798 // __state[0] &= ~kIOServiceInactiveState;
800 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
801 // OSKernelStackRemaining(), getName());
804 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
808 __state
[1] |= kIOServiceSynchronousState
;
810 __state
[1] &= ~kIOServiceSynchronousState
;
812 if( needConfig
) prevBusy
= _adjustBusy( 1 );
814 unlockForArbitration();
819 IOLockLock( gIOServiceBusyLock
);
820 thread_wakeup( (event_t
) this/*&__state[1]*/ );
821 IOLockUnlock( gIOServiceBusyLock
);
823 } else if( !sync
|| (kIOServiceAsynchronous
& options
)) {
825 ok
= (0 != _IOServiceJob::startJob( this, kMatchNubJob
, options
));
829 if( (__state
[1] & kIOServiceNeedConfigState
))
830 doServiceMatch( options
);
832 lockForArbitration();
833 IOLockLock( gIOServiceBusyLock
);
835 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
836 && (0 == (__state
[0] & kIOServiceInactiveState
)));
839 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
841 __state
[1] &= ~kIOServiceSyncPubState
;
843 unlockForArbitration();
846 assert_wait( (event_t
) this/*&__state[1]*/, THREAD_UNINT
);
848 IOLockUnlock( gIOServiceBusyLock
);
850 thread_block(THREAD_CONTINUE_NULL
);
852 } while( waitAgain
);
856 IOReturn
IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
858 OSDictionary
* table
;
868 while( (table
= (OSDictionary
*) newTables
->getFirstObject())) {
871 set
= (OSSet
*) copyExistingServices( table
,
872 kIOServiceRegisteredState
,
873 kIOServiceExistingSet
);
878 count
+= set
->getCount();
881 allSet
->merge((const OSSet
*) set
);
889 if( getDebugFlags( table
) & kIOLogMatch
)
890 LOG("Matching service count = %ld\n", (long)count
);
892 newTables
->removeObject(table
);
896 while( (service
= (IOService
*) allSet
->getAnyObject())) {
897 service
->startMatching(kIOServiceAsynchronous
);
898 allSet
->removeObject(service
);
903 newTables
->release();
905 return( kIOReturnSuccess
);
908 _IOServiceJob
* _IOServiceJob::startJob( IOService
* nub
, int type
,
909 IOOptionBits options
)
913 job
= new _IOServiceJob
;
914 if( job
&& !job
->init()) {
922 job
->options
= options
;
923 nub
->retain(); // thread will release()
931 * Called on a registered service to see if it matches
935 bool IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
937 return( matchPropertyTable(table
) );
940 bool IOService::matchPropertyTable( OSDictionary
* table
)
946 * Called on a matched service to allocate resources
947 * before first driver is attached.
950 IOReturn
IOService::getResources( void )
952 return( kIOReturnSuccess
);
956 * Client/provider accessors
959 IOService
* IOService::getProvider( void ) const
961 IOService
* self
= (IOService
*) this;
965 generation
= getRegistryEntryGenerationCount();
966 if( __providerGeneration
== generation
)
967 return( __provider
);
969 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
970 if( parent
== IORegistryEntry::getRegistryRoot())
971 /* root is not an IOService */
974 self
->__provider
= parent
;
976 // save the count from before call to getParentEntry()
977 self
->__providerGeneration
= generation
;
982 IOWorkLoop
* IOService::getWorkLoop() const
984 IOService
*provider
= getProvider();
987 return provider
->getWorkLoop();
992 OSIterator
* IOService::getProviderIterator( void ) const
994 return( getParentIterator( gIOServicePlane
));
997 IOService
* IOService::getClient( void ) const
999 return( (IOService
*) getChildEntry( gIOServicePlane
));
1002 OSIterator
* IOService::getClientIterator( void ) const
1004 return( getChildIterator( gIOServicePlane
));
1007 OSIterator
* _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
1008 const IOService
* client
,
1009 const IOService
* provider
)
1011 _IOOpenServiceIterator
* inst
;
1016 inst
= new _IOOpenServiceIterator
;
1018 if( inst
&& !inst
->init()) {
1024 inst
->client
= client
;
1025 inst
->provider
= provider
;
1031 void _IOOpenServiceIterator::free()
1035 last
->unlockForArbitration();
1039 OSObject
* _IOOpenServiceIterator::getNextObject()
1044 last
->unlockForArbitration();
1046 while( (next
= (IOService
*) iter
->getNextObject())) {
1048 next
->lockForArbitration();
1049 if( (client
&& (next
->isOpen( client
)))
1050 || (provider
&& (provider
->isOpen( next
))) )
1052 next
->unlockForArbitration();
1060 bool _IOOpenServiceIterator::isValid()
1062 return( iter
->isValid() );
1065 void _IOOpenServiceIterator::reset()
1068 last
->unlockForArbitration();
1074 OSIterator
* IOService::getOpenProviderIterator( void ) const
1076 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
1079 OSIterator
* IOService::getOpenClientIterator( void ) const
1081 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
1085 IOReturn
IOService::callPlatformFunction( const OSSymbol
* functionName
,
1086 bool waitForFunction
,
1087 void *param1
, void *param2
,
1088 void *param3
, void *param4
)
1090 IOReturn result
= kIOReturnUnsupported
;
1091 IOService
*provider
;
1093 if (gIOPlatformFunctionHandlerSet
== functionName
)
1095 #if defined(__i386__) || defined(__x86_64__)
1096 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1097 IOService
* target
= (IOService
*) param2
;
1098 bool enable
= (param3
!= 0);
1100 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
)
1101 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1102 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
)
1103 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1104 #endif /* defined(__i386__) || defined(__x86_64__) */
1107 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1108 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1109 param1
, param2
, param3
, param4
);
1115 IOReturn
IOService::callPlatformFunction( const char * functionName
,
1116 bool waitForFunction
,
1117 void *param1
, void *param2
,
1118 void *param3
, void *param4
)
1120 IOReturn result
= kIOReturnNoMemory
;
1121 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1123 if (functionSymbol
!= 0) {
1124 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1125 param1
, param2
, param3
, param4
);
1126 functionSymbol
->release();
1134 * Accessors for global services
1137 IOPlatformExpert
* IOService::getPlatform( void )
1139 return( gIOPlatform
);
1142 class IOPMrootDomain
* IOService::getPMRootDomain( void )
1144 return( gIOPMRootDomain
);
1147 IOService
* IOService::getResourceService( void )
1149 return( gIOResources
);
1152 void IOService::setPlatform( IOPlatformExpert
* platform
)
1154 gIOPlatform
= platform
;
1155 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1157 #if defined(__i386__) || defined(__x86_64__)
1159 static const char * keys
[kCpuNumDelayTypes
] = {
1160 kIOPlatformMaxBusDelay
, kIOPlatformMaxInterruptDelay
};
1161 const OSObject
* objs
[2];
1165 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++)
1167 objs
[0] = sCPULatencySet
[idx
];
1168 objs
[1] = sCPULatencyHolder
[idx
];
1169 array
= OSArray::withObjects(objs
, 2);
1171 platform
->setProperty(keys
[idx
], array
);
1174 #endif /* defined(__i386__) || defined(__x86_64__) */
1177 void IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1179 gIOPMRootDomain
= rootDomain
;
1180 publishResource("IOKit");
1187 bool IOService::lockForArbitration( bool isSuccessRequired
)
1191 ArbitrationLockQueueElement
* element
;
1192 ArbitrationLockQueueElement
* active
;
1193 ArbitrationLockQueueElement
* waiting
;
1195 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1197 // lock global access
1198 IOTakeLock( gArbitrationLockQueueLock
);
1200 // obtain an unused queue element
1201 if( !queue_empty( &gArbitrationLockQueueFree
)) {
1202 queue_remove_first( &gArbitrationLockQueueFree
,
1204 ArbitrationLockQueueElement
*,
1207 element
= IONew( ArbitrationLockQueueElement
, 1 );
1211 // prepare the queue element
1212 element
->thread
= IOThreadSelf();
1213 element
->service
= this;
1215 element
->required
= isSuccessRequired
;
1216 element
->aborted
= false;
1218 // determine whether this object is already locked (ie. on active queue)
1220 queue_iterate( &gArbitrationLockQueueActive
,
1222 ArbitrationLockQueueElement
*,
1225 if( active
->service
== element
->service
) {
1231 if( found
) { // this object is already locked
1233 // determine whether it is the same or a different thread trying to lock
1234 if( active
->thread
!= element
->thread
) { // it is a different thread
1236 ArbitrationLockQueueElement
* victim
= 0;
1238 // before placing this new thread on the waiting queue, we look for
1239 // a deadlock cycle...
1242 // determine whether the active thread holding the object we
1243 // want is waiting for another object to be unlocked
1245 queue_iterate( &gArbitrationLockQueueWaiting
,
1247 ArbitrationLockQueueElement
*,
1250 if( waiting
->thread
== active
->thread
) {
1251 assert( false == waiting
->aborted
);
1257 if( found
) { // yes, active thread waiting for another object
1259 // this may be a candidate for rejection if the required
1260 // flag is not set, should we detect a deadlock later on
1261 if( false == waiting
->required
)
1264 // find the thread that is holding this other object, that
1265 // is blocking the active thread from proceeding (fun :-)
1267 queue_iterate( &gArbitrationLockQueueActive
,
1268 active
, // (reuse active queue element)
1269 ArbitrationLockQueueElement
*,
1272 if( active
->service
== waiting
->service
) {
1278 // someone must be holding it or it wouldn't be waiting
1281 if( active
->thread
== element
->thread
) {
1283 // doh, it's waiting for the thread that originated
1284 // this whole lock (ie. current thread) -> deadlock
1285 if( false == element
->required
) { // willing to fail?
1287 // the originating thread doesn't have the required
1288 // flag, so it can fail
1289 success
= false; // (fail originating lock request)
1290 break; // (out of while)
1292 } else { // originating thread is not willing to fail
1294 // see if we came across a waiting thread that did
1295 // not have the 'required' flag set: we'll fail it
1298 // we do have a willing victim, fail it's lock
1299 victim
->aborted
= true;
1301 // take the victim off the waiting queue
1302 queue_remove( &gArbitrationLockQueueWaiting
,
1304 ArbitrationLockQueueElement
*,
1308 IOLockWakeup( gArbitrationLockQueueLock
,
1310 /* one thread */ true );
1312 // allow this thread to proceed (ie. wait)
1313 success
= true; // (put request on wait queue)
1314 break; // (out of while)
1317 // all the waiting threads we came across in
1318 // finding this loop had the 'required' flag
1319 // set, so we've got a deadlock we can't avoid
1320 panic("I/O Kit: Unrecoverable deadlock.");
1324 // repeat while loop, redefining active thread to be the
1325 // thread holding "this other object" (see above), and
1326 // looking for threads waiting on it; note the active
1327 // variable points to "this other object" already... so
1328 // there nothing to do in this else clause.
1330 } else { // no, active thread is not waiting for another object
1332 success
= true; // (put request on wait queue)
1333 break; // (out of while)
1337 if( success
) { // put the request on the waiting queue?
1338 kern_return_t wait_result
;
1340 // place this thread on the waiting queue and put it to sleep;
1341 // we place it at the tail of the queue...
1342 queue_enter( &gArbitrationLockQueueWaiting
,
1344 ArbitrationLockQueueElement
*,
1347 // declare that this thread will wait for a given event
1348 restart_sleep
: wait_result
= assert_wait( element
,
1349 element
->required
? THREAD_UNINT
1350 : THREAD_INTERRUPTIBLE
);
1352 // unlock global access
1353 IOUnlock( gArbitrationLockQueueLock
);
1355 // put thread to sleep, waiting for our event to fire...
1356 if (wait_result
== THREAD_WAITING
)
1357 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1360 // ...and we've been woken up; we might be in one of two states:
1361 // (a) we've been aborted and our queue element is not on
1362 // any of the three queues, but is floating around
1363 // (b) we're allowed to proceed with the lock and we have
1364 // already been moved from the waiting queue to the
1366 // ...plus a 3rd state, should the thread have been interrupted:
1367 // (c) we're still on the waiting queue
1369 // determine whether we were interrupted out of our sleep
1370 if( THREAD_INTERRUPTED
== wait_result
) {
1372 // re-lock global access
1373 IOTakeLock( gArbitrationLockQueueLock
);
1375 // determine whether we're still on the waiting queue
1377 queue_iterate( &gArbitrationLockQueueWaiting
,
1378 waiting
, // (reuse waiting queue element)
1379 ArbitrationLockQueueElement
*,
1382 if( waiting
== element
) {
1388 if( found
) { // yes, we're still on the waiting queue
1390 // determine whether we're willing to fail
1391 if( false == element
->required
) {
1393 // mark us as aborted
1394 element
->aborted
= true;
1396 // take us off the waiting queue
1397 queue_remove( &gArbitrationLockQueueWaiting
,
1399 ArbitrationLockQueueElement
*,
1401 } else { // we are not willing to fail
1403 // ignore interruption, go back to sleep
1408 // unlock global access
1409 IOUnlock( gArbitrationLockQueueLock
);
1411 // proceed as though this were a normal wake up
1412 wait_result
= THREAD_AWAKENED
;
1415 assert( THREAD_AWAKENED
== wait_result
);
1417 // determine whether we've been aborted while we were asleep
1418 if( element
->aborted
) {
1419 assert( false == element
->required
);
1421 // re-lock global access
1422 IOTakeLock( gArbitrationLockQueueLock
);
1424 action
= kPutOnFreeQueue
;
1426 } else { // we weren't aborted, so we must be ready to go :-)
1428 // we've already been moved from waiting to active queue
1432 } else { // the lock request is to be failed
1434 // return unused queue element to queue
1435 action
= kPutOnFreeQueue
;
1437 } else { // it is the same thread, recursive access is allowed
1439 // add one level of recursion
1442 // return unused queue element to queue
1443 action
= kPutOnFreeQueue
;
1446 } else { // this object is not already locked, so let this thread through
1447 action
= kPutOnActiveQueue
;
1451 // put the new element on a queue
1452 if( kPutOnActiveQueue
== action
) {
1453 queue_enter( &gArbitrationLockQueueActive
,
1455 ArbitrationLockQueueElement
*,
1457 } else if( kPutOnFreeQueue
== action
) {
1458 queue_enter( &gArbitrationLockQueueFree
,
1460 ArbitrationLockQueueElement
*,
1463 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1466 // unlock global access
1467 IOUnlock( gArbitrationLockQueueLock
);
1472 void IOService::unlockForArbitration( void )
1475 ArbitrationLockQueueElement
* element
;
1477 // lock global access
1478 IOTakeLock( gArbitrationLockQueueLock
);
1480 // find the lock element for this object (ie. on active queue)
1482 queue_iterate( &gArbitrationLockQueueActive
,
1484 ArbitrationLockQueueElement
*,
1487 if( element
->service
== this ) {
1495 // determine whether the lock has been taken recursively
1496 if( element
->count
> 1 ) {
1497 // undo one level of recursion
1502 // remove it from the active queue
1503 queue_remove( &gArbitrationLockQueueActive
,
1505 ArbitrationLockQueueElement
*,
1508 // put it on the free queue
1509 queue_enter( &gArbitrationLockQueueFree
,
1511 ArbitrationLockQueueElement
*,
1514 // determine whether a thread is waiting for object (head to tail scan)
1516 queue_iterate( &gArbitrationLockQueueWaiting
,
1518 ArbitrationLockQueueElement
*,
1521 if( element
->service
== this ) {
1527 if ( found
) { // we found an interested thread on waiting queue
1529 // remove it from the waiting queue
1530 queue_remove( &gArbitrationLockQueueWaiting
,
1532 ArbitrationLockQueueElement
*,
1535 // put it on the active queue
1536 queue_enter( &gArbitrationLockQueueActive
,
1538 ArbitrationLockQueueElement
*,
1541 // wake the waiting thread
1542 IOLockWakeup( gArbitrationLockQueueLock
,
1544 /* one thread */ true );
1548 // unlock global access
1549 IOUnlock( gArbitrationLockQueueLock
);
1552 void IOService::applyToProviders( IOServiceApplierFunction applier
,
1555 applyToParents( (IORegistryEntryApplierFunction
) applier
,
1556 context
, gIOServicePlane
);
1559 void IOService::applyToClients( IOServiceApplierFunction applier
,
1562 applyToChildren( (IORegistryEntryApplierFunction
) applier
,
1563 context
, gIOServicePlane
);
1572 // send a message to a client or interested party of this service
1573 IOReturn
IOService::messageClient( UInt32 type
, OSObject
* client
,
1574 void * argument
, vm_size_t argSize
)
1577 IOService
* service
;
1578 _IOServiceInterestNotifier
* notify
;
1580 if( (service
= OSDynamicCast( IOService
, client
)))
1581 ret
= service
->message( type
, this, argument
);
1583 else if( (notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1585 _IOServiceNotifierInvocation invocation
;
1588 invocation
.thread
= current_thread();
1591 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1594 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1595 _IOServiceNotifierInvocation
*, link
);
1601 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1602 type
, this, argument
, argSize
);
1605 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1606 _IOServiceNotifierInvocation
*, link
);
1607 if( kIOServiceNotifyWaiter
& notify
->state
) {
1608 notify
->state
&= ~kIOServiceNotifyWaiter
;
1609 WAKEUPNOTIFY( notify
);
1614 ret
= kIOReturnSuccess
;
1617 ret
= kIOReturnBadArgument
;
1623 applyToInterestNotifiers(const IORegistryEntry
*target
,
1624 const OSSymbol
* typeOfInterest
,
1625 OSObjectApplierFunction applier
,
1628 OSArray
* copyArray
= 0;
1632 IOCommand
*notifyList
=
1633 OSDynamicCast( IOCommand
, target
->getProperty( typeOfInterest
));
1636 copyArray
= OSArray::withCapacity(1);
1638 // iterate over queue, entry is set to each element in the list
1639 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1640 _IOServiceInterestNotifier
* notify
;
1642 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1643 copyArray
->setObject(notify
);
1652 for( index
= 0; (next
= copyArray
->getObject( index
)); index
++)
1653 (*applier
)(next
, context
);
1654 copyArray
->release();
1658 void IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1659 OSObjectApplierFunction applier
,
1662 if (gIOGeneralInterest
== typeOfInterest
)
1663 applyToClients( (IOServiceApplierFunction
) applier
, context
);
1664 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1667 struct MessageClientsContext
{
1668 IOService
* service
;
1675 static void messageClientsApplier( OSObject
* object
, void * ctx
)
1678 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
1680 ret
= context
->service
->messageClient( context
->type
,
1681 object
, context
->argument
, context
->argSize
);
1682 if( kIOReturnSuccess
!= ret
)
1686 // send a message to all clients
1687 IOReturn
IOService::messageClients( UInt32 type
,
1688 void * argument
, vm_size_t argSize
)
1690 MessageClientsContext context
;
1692 context
.service
= this;
1693 context
.type
= type
;
1694 context
.argument
= argument
;
1695 context
.argSize
= argSize
;
1696 context
.ret
= kIOReturnSuccess
;
1698 applyToInterested( gIOGeneralInterest
,
1699 &messageClientsApplier
, &context
);
1701 return( context
.ret
);
1704 IOReturn
IOService::acknowledgeNotification( IONotificationRef notification
,
1705 IOOptionBits response
)
1707 return( kIOReturnUnsupported
);
1710 IONotifier
* IOService::registerInterest( const OSSymbol
* typeOfInterest
,
1711 IOServiceInterestHandler handler
, void * target
, void * ref
)
1713 _IOServiceInterestNotifier
* notify
= 0;
1714 IOReturn rc
= kIOReturnError
;
1716 notify
= new _IOServiceInterestNotifier
;
1717 if (!notify
) return NULL
;
1719 if(notify
->init()) {
1720 rc
= registerInterestForNotifer(notify
, typeOfInterest
,
1721 handler
, target
, ref
);
1724 if (rc
!= kIOReturnSuccess
) {
1732 IOReturn
IOService::registerInterestForNotifer( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
1733 IOServiceInterestHandler handler
, void * target
, void * ref
)
1735 IOReturn rc
= kIOReturnSuccess
;
1736 _IOServiceInterestNotifier
*notify
= 0;
1738 if( (typeOfInterest
!= gIOGeneralInterest
)
1739 && (typeOfInterest
!= gIOBusyInterest
)
1740 && (typeOfInterest
!= gIOAppPowerStateInterest
)
1741 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
1742 && (typeOfInterest
!= gIOPriorityPowerStateInterest
))
1743 return( kIOReturnBadArgument
);
1745 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
)))
1746 return( kIOReturnBadArgument
);
1748 lockForArbitration();
1749 if( 0 == (__state
[0] & kIOServiceInactiveState
)) {
1751 notify
->handler
= handler
;
1752 notify
->target
= target
;
1754 notify
->state
= kIOServiceNotifyEnable
;
1760 // Get the head of the notifier linked list
1761 IOCommand
* notifyList
;
1762 OSObject
* obj
= copyProperty( typeOfInterest
);
1763 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
1764 notifyList
= OSTypeAlloc(IOCommand
);
1767 bool ok
= setProperty( typeOfInterest
, notifyList
);
1768 notifyList
->release();
1769 if (!ok
) notifyList
= 0;
1772 if (obj
) obj
->release();
1775 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
1776 notify
->retain(); // ref'ed while in list
1782 rc
= kIOReturnNotReady
;
1784 unlockForArbitration();
1789 static void cleanInterestList( OSObject
* head
)
1791 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
1796 while ( queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
) ) {
1797 queue_next(entry
) = queue_prev(entry
) = 0;
1799 _IOServiceInterestNotifier
* notify
;
1801 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1807 void IOService::unregisterAllInterest( void )
1809 cleanInterestList( getProperty( gIOGeneralInterest
));
1810 cleanInterestList( getProperty( gIOBusyInterest
));
1811 cleanInterestList( getProperty( gIOAppPowerStateInterest
));
1812 cleanInterestList( getProperty( gIOPriorityPowerStateInterest
));
1813 cleanInterestList( getProperty( gIOConsoleSecurityInterest
));
1817 * _IOServiceInterestNotifier
1820 // wait for all threads, other than the current one,
1821 // to exit the handler
1823 void _IOServiceInterestNotifier::wait()
1825 _IOServiceNotifierInvocation
* next
;
1830 queue_iterate( &handlerInvocations
, next
,
1831 _IOServiceNotifierInvocation
*, link
) {
1832 if( next
->thread
!= current_thread() ) {
1838 state
|= kIOServiceNotifyWaiter
;
1845 void _IOServiceInterestNotifier::free()
1847 assert( queue_empty( &handlerInvocations
));
1851 void _IOServiceInterestNotifier::remove()
1855 if( queue_next( &chain
)) {
1857 queue_next( &chain
) = queue_prev( &chain
) = 0;
1861 state
&= ~kIOServiceNotifyEnable
;
1870 bool _IOServiceInterestNotifier::disable()
1876 ret
= (0 != (kIOServiceNotifyEnable
& state
));
1877 state
&= ~kIOServiceNotifyEnable
;
1886 void _IOServiceInterestNotifier::enable( bool was
)
1890 state
|= kIOServiceNotifyEnable
;
1892 state
&= ~kIOServiceNotifyEnable
;
1896 bool _IOServiceInterestNotifier::init()
1898 queue_init( &handlerInvocations
);
1899 return (OSObject::init());
1901 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1907 #define tailQ(o) setObject(o)
1908 #define headQ(o) setObject(0, o)
1909 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1911 static void _workLoopAction( IOWorkLoop::Action action
,
1912 IOService
* service
,
1913 void * p0
= 0, void * p1
= 0,
1914 void * p2
= 0, void * p3
= 0 )
1918 if( (wl
= service
->getWorkLoop())) {
1920 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
1923 (*action
)( service
, p0
, p1
, p2
, p3
);
1926 bool IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
1930 // if its our only provider
1931 ok
= isParent( provider
, gIOServicePlane
, true);
1935 provider
->terminateClient( this, options
| kIOServiceRecursing
);
1936 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
1943 bool IOService::terminatePhase1( IOOptionBits options
)
1948 OSArray
* makeInactive
;
1949 OSArray
* waitingInactive
;
1950 int waitResult
= THREAD_AWAKENED
;
1954 bool startPhase2
= false;
1956 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
1958 uint64_t regID
= getRegistryEntryID();
1960 IOSERVICE_TERMINATE_PHASE1
,
1962 (uintptr_t) (regID
>> 32),
1964 (uintptr_t) options
);
1967 if( options
& kIOServiceRecursing
) {
1968 lockForArbitration();
1969 if (0 == (kIOServiceInactiveState
& __state
[0]))
1971 __state
[0] |= kIOServiceInactiveState
;
1972 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
1974 unlockForArbitration();
1980 makeInactive
= OSArray::withCapacity( 16 );
1981 waitingInactive
= OSArray::withCapacity( 16 );
1982 if(!makeInactive
|| !waitingInactive
) return( false );
1989 didInactive
= victim
->lockForArbitration( true );
1992 uint64_t regID1
= victim
->getRegistryEntryID();
1993 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
1995 (uintptr_t) (regID1
>> 32),
1996 (uintptr_t) victim
->__state
[1],
1999 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
2000 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
2001 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
2005 // a multiply attached IOService can be visited twice
2006 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) do
2008 IOLockLock(gIOServiceBusyLock
);
2009 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
2011 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2012 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2013 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
2014 victim
->unlockForArbitration();
2015 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
2017 IOLockUnlock(gIOServiceBusyLock
);
2019 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2020 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2021 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2022 victim
->lockForArbitration();
2025 while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2029 victim
->__state
[0] |= kIOServiceInactiveState
;
2030 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
2031 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
2032 victim
->__state
[1] &= ~kIOServiceRecursing
;
2033 victim
->__state
[1] |= kIOServiceTermPhase1State
;
2034 waitingInactive
->headQ(victim
);
2037 if (kIOServiceTerminateNeedWillTerminate
& options
)
2039 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
2042 victim
->_adjustBusy( 1 );
2044 victim
->unlockForArbitration();
2046 if( victim
== this) startPhase2
= didInactive
;
2049 victim
->deliverNotification( gIOTerminatedNotification
, 0, 0xffffffff );
2050 IOUserClient::destroyUserReferences( victim
);
2052 iter
= victim
->getClientIterator();
2054 while( (client
= (IOService
*) iter
->getNextObject())) {
2055 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2056 client
->getName(), client
->getRegistryEntryID(),
2057 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
2058 ok
= client
->requestTerminate( victim
, options
);
2059 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2060 client
->getName(), client
->getRegistryEntryID(),
2061 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2063 uint64_t regID1
= client
->getRegistryEntryID();
2064 uint64_t regID2
= victim
->getRegistryEntryID();
2066 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2067 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2069 (uintptr_t) (regID1
>> 32),
2071 (uintptr_t) (regID2
>> 32));
2074 makeInactive
->setObject( client
);
2080 victim
= (IOService
*) makeInactive
->getObject(0);
2083 makeInactive
->removeObject(0);
2086 makeInactive
->release();
2088 while ((victim
= (IOService
*) waitingInactive
->getObject(0)))
2091 waitingInactive
->removeObject(0);
2093 victim
->lockForArbitration();
2094 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2095 if (kIOServiceTerm1WaiterState
& victim
->__state
[1])
2097 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2098 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2099 IOLockLock( gIOServiceBusyLock
);
2100 thread_wakeup( (event_t
) &victim
->__state
[1]);
2101 IOLockUnlock( gIOServiceBusyLock
);
2103 victim
->unlockForArbitration();
2106 waitingInactive
->release();
2111 lockForArbitration();
2112 scheduleTerminatePhase2(options
);
2113 unlockForArbitration();
2120 void IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2122 lockForArbitration();
2123 if (defer
) __state
[1] |= kIOServiceStartState
;
2124 else __state
[1] &= ~kIOServiceStartState
;
2125 unlockForArbitration();
2127 if (provider
&& !defer
)
2129 provider
->lockForArbitration();
2130 provider
->scheduleTerminatePhase2();
2131 provider
->unlockForArbitration();
2135 // call with lockForArbitration
2136 void IOService::scheduleTerminatePhase2( IOOptionBits options
)
2138 AbsoluteTime deadline
;
2140 int waitResult
= THREAD_AWAKENED
;
2141 bool wait
, haveDeadline
= false;
2143 if (!(__state
[0] & kIOServiceInactiveState
)) return;
2145 regID1
= getRegistryEntryID();
2147 IOSERVICE_TERM_SCHED_PHASE2
,
2149 (uintptr_t) (regID1
>> 32),
2150 (uintptr_t) __state
[1],
2151 (uintptr_t) options
);
2153 if (__state
[1] & kIOServiceTermPhase1State
) return;
2156 unlockForArbitration();
2157 options
|= kIOServiceRequired
;
2158 IOLockLock( gJobsLock
);
2160 if( (options
& kIOServiceSynchronous
)
2161 && (current_thread() != gIOTerminateThread
)) {
2164 wait
= (gIOTerminateThread
!= 0);
2166 // wait to become the terminate thread
2167 IOLockSleep( gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2171 gIOTerminateThread
= current_thread();
2172 gIOTerminatePhase2List
->setObject( this );
2176 while( gIOTerminateWork
)
2177 terminateWorker( options
);
2178 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2180 // wait for the victim to go non-busy
2181 if( !haveDeadline
) {
2182 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2183 haveDeadline
= true;
2185 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2186 deadline
, THREAD_UNINT
);
2187 if( waitResult
== THREAD_TIMED_OUT
) {
2188 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
2191 } while(gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2193 gIOTerminateThread
= 0;
2194 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2197 // ! kIOServiceSynchronous
2199 gIOTerminatePhase2List
->setObject( this );
2200 if( 0 == gIOTerminateWork
++) {
2201 if( !gIOTerminateThread
)
2202 kernel_thread_start(&terminateThread
, (void *)(uintptr_t) options
, &gIOTerminateThread
);
2204 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
2208 IOLockUnlock( gJobsLock
);
2209 lockForArbitration();
2213 void IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2215 IOLockLock( gJobsLock
);
2217 while (gIOTerminateWork
)
2218 terminateWorker( (uintptr_t) arg
);
2220 thread_deallocate(gIOTerminateThread
);
2221 gIOTerminateThread
= 0;
2222 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2224 IOLockUnlock( gJobsLock
);
2227 void IOService::scheduleStop( IOService
* provider
)
2229 uint64_t regID1
= getRegistryEntryID();
2230 uint64_t regID2
= provider
->getRegistryEntryID();
2232 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2234 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2236 (uintptr_t) (regID1
>> 32),
2238 (uintptr_t) (regID2
>> 32));
2240 IOLockLock( gJobsLock
);
2241 gIOStopList
->tailQ( this );
2242 gIOStopProviderList
->tailQ( provider
);
2244 if( 0 == gIOTerminateWork
++) {
2245 if( !gIOTerminateThread
)
2246 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
2248 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
2251 IOLockUnlock( gJobsLock
);
2254 void IOService::scheduleFinalize(bool now
)
2256 uint64_t regID1
= getRegistryEntryID();
2258 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2260 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2262 (uintptr_t) (regID1
>> 32),
2265 if (now
|| IOUserClient::finalizeUserReferences(this))
2267 IOLockLock( gJobsLock
);
2268 gIOFinalizeList
->tailQ(this);
2269 if( 0 == gIOTerminateWork
++)
2271 if( !gIOTerminateThread
)
2272 kernel_thread_start(&terminateThread
, (void *) 0, &gIOTerminateThread
);
2274 IOLockWakeup(gJobsLock
, (event_t
) &gIOTerminateWork
, /* one-thread */ false );
2276 IOLockUnlock( gJobsLock
);
2280 bool IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2285 bool IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2287 if( false == *defer
) {
2289 if( lockForArbitration( true )) {
2290 if( false == provider
->handleIsOpen( this ))
2291 scheduleStop( provider
);
2294 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2295 if( false == provider
->handleIsOpen( this ))
2296 scheduleStop( provider
);
2299 unlockForArbitration();
2306 void IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2307 OSArray
* doPhase2List
,
2308 void *unused2 __unused
,
2309 void *unused3 __unused
)
2314 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2316 iter
= victim
->getClientIterator();
2318 while( (client
= (IOService
*) iter
->getNextObject())) {
2320 regID1
= client
->getRegistryEntryID();
2321 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2322 client
->getName(), regID1
,
2323 victim
->getName(), regID2
, (long long)options
);
2325 IOSERVICE_TERMINATE_WILL
,
2327 (uintptr_t) (regID1
>> 32),
2329 (uintptr_t) (regID2
>> 32));
2331 ok
= client
->willTerminate( victim
, options
);
2332 doPhase2List
->tailQ( client
);
2338 void IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2339 void *unused1 __unused
, void *unused2 __unused
,
2340 void *unused3 __unused
)
2345 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2347 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2349 iter
= victim
->getClientIterator();
2351 while( (client
= (IOService
*) iter
->getNextObject())) {
2353 regID1
= client
->getRegistryEntryID();
2354 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2355 client
->getName(), regID1
,
2356 victim
->getName(), regID2
, (long long)options
);
2358 client
->didTerminate( victim
, options
, &defer
);
2361 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2362 : IOSERVICE_TERMINATE_DID
),
2364 (uintptr_t) (regID1
>> 32),
2366 (uintptr_t) (regID2
>> 32));
2368 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2369 client
->getName(), regID1
,
2370 victim
->getName(), regID2
, defer
);
2377 void IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2378 void *unused1 __unused
, void *unused2 __unused
,
2379 void *unused3 __unused
)
2382 IOService
* provider
;
2384 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2386 iter
= victim
->getProviderIterator();
2388 while( (provider
= (IOService
*) iter
->getNextObject())) {
2390 regID1
= provider
->getRegistryEntryID();
2391 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2392 victim
->getName(), regID2
,
2393 provider
->getName(), regID1
, (long long)options
);
2395 IOSERVICE_TERMINATE_WILL
,
2397 (uintptr_t) (regID2
>> 32),
2399 (uintptr_t) (regID1
>> 32));
2401 ok
= victim
->willTerminate( provider
, options
);
2407 void IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2408 void *unused1 __unused
, void *unused2 __unused
,
2409 void *unused3 __unused
)
2412 IOService
* provider
;
2414 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2416 iter
= victim
->getProviderIterator();
2418 while( (provider
= (IOService
*) iter
->getNextObject())) {
2420 regID1
= provider
->getRegistryEntryID();
2421 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2422 victim
->getName(), regID2
,
2423 provider
->getName(), regID1
, (long long)options
);
2424 victim
->didTerminate( provider
, options
, &defer
);
2427 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2428 : IOSERVICE_TERMINATE_DID
),
2430 (uintptr_t) (regID2
>> 32),
2432 (uintptr_t) (regID1
>> 32));
2434 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2435 victim
->getName(), regID2
,
2436 provider
->getName(), regID1
, defer
);
2443 void IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2444 void *unused1 __unused
, void *unused2 __unused
,
2445 void *unused3 __unused
)
2447 uint64_t regID1
= victim
->getRegistryEntryID();
2448 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2450 IOSERVICE_TERMINATE_FINALIZE
,
2452 (uintptr_t) (regID1
>> 32),
2455 victim
->finalize( options
);
2458 void IOService::actionStop( IOService
* provider
, IOService
* client
,
2459 void *unused1 __unused
, void *unused2 __unused
,
2460 void *unused3 __unused
)
2462 uint64_t regID1
= provider
->getRegistryEntryID();
2463 uint64_t regID2
= client
->getRegistryEntryID();
2465 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2467 IOSERVICE_TERMINATE_STOP
,
2469 (uintptr_t) (regID1
>> 32),
2471 (uintptr_t) (regID2
>> 32));
2473 client
->stop( provider
);
2474 if( provider
->isOpen( client
))
2475 provider
->close( client
);
2477 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2478 client
->detach( provider
);
2481 void IOService::terminateWorker( IOOptionBits options
)
2483 OSArray
* doPhase2List
;
2484 OSArray
* didPhase2List
;
2490 IOService
* provider
;
2496 options
|= kIOServiceRequired
;
2498 doPhase2List
= OSArray::withCapacity( 16 );
2499 didPhase2List
= OSArray::withCapacity( 16 );
2500 freeList
= OSSet::withCapacity( 16 );
2501 if( (0 == doPhase2List
) || (0 == didPhase2List
) || (0 == freeList
))
2505 workDone
= gIOTerminateWork
;
2507 while( (victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0) )) {
2510 gIOTerminatePhase2List
->removeObject(0);
2511 IOLockUnlock( gJobsLock
);
2513 uint64_t regID1
= victim
->getRegistryEntryID();
2515 IOSERVICE_TERM_START_PHASE2
,
2517 (uintptr_t) (regID1
>> 32),
2523 doPhase2
= victim
->lockForArbitration( true );
2525 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2528 uint64_t regID1
= victim
->getRegistryEntryID();
2530 IOSERVICE_TERM_TRY_PHASE2
,
2532 (uintptr_t) (regID1
>> 32),
2533 (uintptr_t) victim
->__state
[1],
2536 doPhase2
= (0 == (victim
->__state
[1] & kIOServiceTermPhase2State
))
2537 && (0 == (victim
->__state
[1] & kIOServiceConfigState
));
2539 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
2540 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
2541 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
2544 uint64_t regID1
= client
->getRegistryEntryID();
2546 IOSERVICE_TERM_UC_DEFER
,
2548 (uintptr_t) (regID1
>> 32),
2549 (uintptr_t) client
->__state
[1],
2551 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
2552 victim
->getName(), victim
->getRegistryEntryID(),
2553 client
->getName(), client
->getRegistryEntryID());
2559 victim
->__state
[1] |= kIOServiceTermPhase2State
;
2561 victim
->unlockForArbitration();
2565 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
2566 _workLoopAction( (IOWorkLoop::Action
) &actionWillStop
,
2567 victim
, (void *)(uintptr_t) options
, NULL
);
2570 if( 0 == victim
->getClient()) {
2572 // no clients - will go to finalize
2573 victim
->scheduleFinalize(false);
2576 _workLoopAction( (IOWorkLoop::Action
) &actionWillTerminate
,
2577 victim
, (void *)(uintptr_t) options
, (void *)(uintptr_t) doPhase2List
);
2579 didPhase2List
->headQ( victim
);
2582 victim
= (IOService
*) doPhase2List
->getObject(0);
2585 doPhase2List
->removeObject(0);
2589 while( (victim
= (IOService
*) didPhase2List
->getObject(0)) ) {
2591 if( victim
->lockForArbitration( true )) {
2592 victim
->__state
[1] |= kIOServiceTermPhase3State
;
2593 victim
->unlockForArbitration();
2595 _workLoopAction( (IOWorkLoop::Action
) &actionDidTerminate
,
2596 victim
, (void *)(uintptr_t) options
);
2597 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
2598 _workLoopAction( (IOWorkLoop::Action
) &actionDidStop
,
2599 victim
, (void *)(uintptr_t) options
, NULL
);
2601 didPhase2List
->removeObject(0);
2603 IOLockLock( gJobsLock
);
2610 while( (victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
2612 IOLockUnlock( gJobsLock
);
2613 _workLoopAction( (IOWorkLoop::Action
) &actionFinalize
,
2614 victim
, (void *)(uintptr_t) options
);
2615 IOLockLock( gJobsLock
);
2617 freeList
->setObject( victim
);
2618 // safe if finalize list is append only
2619 gIOFinalizeList
->removeObject(0);
2623 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
)); ) {
2625 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
2628 uint64_t regID1
= provider
->getRegistryEntryID();
2629 uint64_t regID2
= client
->getRegistryEntryID();
2631 if( !provider
->isChild( client
, gIOServicePlane
)) {
2632 // may be multiply queued - nop it
2633 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2635 IOSERVICE_TERMINATE_STOP_NOP
,
2637 (uintptr_t) (regID1
>> 32),
2639 (uintptr_t) (regID2
>> 32));
2642 // a terminated client is not ready for stop if it has clients, skip it
2643 if( (kIOServiceInactiveState
& client
->__state
[0]) && client
->getClient()) {
2644 TLOG("%s[0x%qx]::defer stop(%s[0x%qx])\n",
2645 client
->getName(), regID2
,
2646 client
->getClient()->getName(), client
->getClient()->getRegistryEntryID());
2648 IOSERVICE_TERMINATE_STOP_DEFER
,
2650 (uintptr_t) (regID1
>> 32),
2652 (uintptr_t) (regID2
>> 32));
2658 IOLockUnlock( gJobsLock
);
2659 _workLoopAction( (IOWorkLoop::Action
) &actionStop
,
2660 provider
, (void *) client
);
2661 IOLockLock( gJobsLock
);
2662 // check the finalize list now
2666 freeList
->setObject( client
);
2667 freeList
->setObject( provider
);
2669 // safe if stop list is append only
2670 gIOStopList
->removeObject( idx
);
2671 gIOStopProviderList
->removeObject( idx
);
2675 } while( doPhase3
);
2677 gIOTerminateWork
-= workDone
;
2678 moreToDo
= (gIOTerminateWork
!= 0);
2681 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
2683 IOSERVICE_TERMINATE_DONE
,
2684 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
2687 } while( moreToDo
);
2689 IOLockUnlock( gJobsLock
);
2691 freeList
->release();
2692 doPhase2List
->release();
2693 didPhase2List
->release();
2695 IOLockLock( gJobsLock
);
2698 bool IOService::finalize( IOOptionBits options
)
2701 IOService
* provider
;
2702 uint64_t regID1
, regID2
= getRegistryEntryID();
2704 iter
= getProviderIterator();
2708 while( (provider
= (IOService
*) iter
->getNextObject())) {
2711 if( 0 == (__state
[1] & kIOServiceTermPhase3State
)) {
2712 /* we come down here on programmatic terminate */
2714 regID1
= provider
->getRegistryEntryID();
2715 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
2717 IOSERVICE_TERMINATE_STOP
,
2719 (uintptr_t) (regID1
>> 32),
2721 (uintptr_t) (regID2
>> 32));
2724 if( provider
->isOpen( this ))
2725 provider
->close( this );
2729 if( provider
->lockForArbitration( true )) {
2730 if( 0 == (provider
->__state
[1] & kIOServiceTermPhase3State
))
2731 scheduleStop( provider
);
2732 provider
->unlockForArbitration();
2749 void IOService::doServiceTerminate( IOOptionBits options
)
2753 // a method in case someone needs to override it
2754 bool IOService::terminateClient( IOService
* client
, IOOptionBits options
)
2758 if( client
->isParent( this, gIOServicePlane
, true))
2759 // we are the clients only provider
2760 ok
= client
->terminate( options
);
2767 bool IOService::terminate( IOOptionBits options
)
2769 options
|= kIOServiceTerminate
;
2771 return( terminatePhase1( options
));
2774 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2780 struct ServiceOpenMessageContext
2782 IOService
* service
;
2784 IOService
* excludeClient
;
2785 IOOptionBits options
;
2788 static void serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
2790 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
2792 if( object
!= context
->excludeClient
)
2793 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
2796 bool IOService::open( IOService
* forClient
,
2797 IOOptionBits options
,
2801 ServiceOpenMessageContext context
;
2803 context
.service
= this;
2804 context
.type
= kIOMessageServiceIsAttemptingOpen
;
2805 context
.excludeClient
= forClient
;
2806 context
.options
= options
;
2808 applyToInterested( gIOGeneralInterest
,
2809 &serviceOpenMessageApplier
, &context
);
2811 if( false == lockForArbitration(false) )
2814 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
2816 ok
= handleOpen( forClient
, options
, arg
);
2818 unlockForArbitration();
2823 void IOService::close( IOService
* forClient
,
2824 IOOptionBits options
)
2829 lockForArbitration();
2831 wasClosed
= handleIsOpen( forClient
);
2833 handleClose( forClient
, options
);
2834 last
= (__state
[1] & kIOServiceTermPhase3State
);
2837 unlockForArbitration();
2840 forClient
->scheduleStop( this );
2842 else if( wasClosed
) {
2844 ServiceOpenMessageContext context
;
2846 context
.service
= this;
2847 context
.type
= kIOMessageServiceWasClosed
;
2848 context
.excludeClient
= forClient
;
2849 context
.options
= options
;
2851 applyToInterested( gIOGeneralInterest
,
2852 &serviceOpenMessageApplier
, &context
);
2856 bool IOService::isOpen( const IOService
* forClient
) const
2858 IOService
* self
= (IOService
*) this;
2861 self
->lockForArbitration();
2863 ok
= handleIsOpen( forClient
);
2865 self
->unlockForArbitration();
2870 bool IOService::handleOpen( IOService
* forClient
,
2871 IOOptionBits options
,
2876 ok
= (0 == __owner
);
2878 __owner
= forClient
;
2880 else if( options
& kIOServiceSeize
) {
2881 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
2882 __owner
, (void *)(uintptr_t) options
));
2883 if( ok
&& (0 == __owner
))
2884 __owner
= forClient
;
2891 void IOService::handleClose( IOService
* forClient
,
2892 IOOptionBits options
)
2894 if( __owner
== forClient
)
2898 bool IOService::handleIsOpen( const IOService
* forClient
) const
2901 return( __owner
== forClient
);
2903 return( __owner
!= forClient
);
2907 * Probing & starting
2909 static SInt32
IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2911 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
2912 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
2920 val1
= obj1
->priority
;
2923 val2
= obj2
->priority
;
2925 return ( val1
- val2
);
2928 static SInt32
IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
2930 OSDictionary
* dict
;
2931 IOService
* service
;
2932 _IOServiceNotifier
* notify
;
2933 OSSymbol
* key
= (OSSymbol
*) ref
;
2936 if( (dict
= OSDynamicCast( OSDictionary
, entry
)))
2937 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
2938 else if( (notify
= OSDynamicCast( _IOServiceNotifier
, entry
)))
2939 return( notify
->priority
);
2941 else if( (service
= OSDynamicCast( IOService
, entry
)))
2942 offset
= OSDynamicCast(OSNumber
, service
->getProperty( key
));
2949 return( (SInt32
) offset
->unsigned32BitValue());
2951 return( kIODefaultProbeScore
);
2954 SInt32
IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
2956 const OSObject
* obj1
= (const OSObject
*) inObj1
;
2957 const OSObject
* obj2
= (const OSObject
*) inObj2
;
2965 val1
= IOServiceObjectOrder( obj1
, ref
);
2968 val2
= IOServiceObjectOrder( obj2
, ref
);
2970 return ( val1
- val2
);
2973 IOService
* IOService::copyClientWithCategory( const OSSymbol
* category
)
2975 IOService
* service
= 0;
2977 const OSSymbol
* nextCat
;
2979 iter
= getClientIterator();
2981 while( (service
= (IOService
*) iter
->getNextObject())) {
2982 if( kIOServiceInactiveState
& service
->__state
[0])
2984 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
2985 service
->getProperty( gIOMatchCategoryKey
));
2986 if( category
== nextCat
)
2997 IOService
* IOService::getClientWithCategory( const OSSymbol
* category
)
3000 service
= copyClientWithCategory(category
);
3006 bool IOService::invokeNotifer( _IOServiceNotifier
* notify
)
3008 _IOServiceNotifierInvocation invocation
;
3012 invocation
.thread
= current_thread();
3015 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3018 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3019 _IOServiceNotifierInvocation
*, link
);
3025 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3028 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3029 _IOServiceNotifierInvocation
*, link
);
3030 if( kIOServiceNotifyWaiter
& notify
->state
) {
3031 notify
->state
&= ~kIOServiceNotifyWaiter
;
3032 WAKEUPNOTIFY( notify
);
3041 * Alloc and probe matching classes,
3042 * called on the provider instance
3045 void IOService::probeCandidates( OSOrderedSet
* matches
)
3047 OSDictionary
* match
= 0;
3050 IOService
* newInst
;
3051 OSDictionary
* props
;
3054 OSOrderedSet
* familyMatches
= 0;
3055 OSOrderedSet
* startList
;
3056 OSDictionary
* startDict
= 0;
3057 const OSSymbol
* category
;
3059 _IOServiceNotifier
* notify
;
3060 OSObject
* nextMatch
= 0;
3062 bool needReloc
= false;
3066 IOService
* client
= NULL
;
3070 while( !needReloc
&& (nextMatch
= matches
->getFirstObject())) {
3072 nextMatch
->retain();
3073 matches
->removeObject(nextMatch
);
3075 if( (notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3077 lockForArbitration();
3078 if( 0 == (__state
[0] & kIOServiceInactiveState
))
3079 invokeNotifer( notify
);
3080 unlockForArbitration();
3081 nextMatch
->release();
3085 } else if( !(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3086 nextMatch
->release();
3093 debugFlags
= getDebugFlags( match
);
3097 category
= OSDynamicCast( OSSymbol
,
3098 match
->getObject( gIOMatchCategoryKey
));
3100 category
= gIODefaultMatchCategoryKey
;
3102 if( (client
= copyClientWithCategory(category
)) ) {
3104 if( (debugFlags
& kIOLogMatch
) && (this != gIOResources
))
3105 LOG("%s: match category %s exists\n", getName(),
3106 category
->getCStringNoCopy());
3108 nextMatch
->release();
3117 // create a copy now in case its modified during matching
3118 props
= OSDictionary::withDictionary( match
, match
->getCount());
3121 props
->setCapacityIncrement(1);
3123 // check the nub matches
3124 if( false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
))
3127 // Check to see if driver reloc has been loaded.
3128 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
));
3131 if( debugFlags
& kIOLogCatalogue
)
3132 LOG("%s: stalling for module\n", getName());
3134 // If reloc hasn't been loaded, exit;
3135 // reprobing will occur after reloc has been loaded.
3139 // reorder on family matchPropertyTable score.
3140 if( 0 == familyMatches
)
3141 familyMatches
= OSOrderedSet::withCapacity( 1,
3142 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3144 familyMatches
->setObject( props
);
3149 nextMatch
->release();
3158 if( familyMatches
) {
3161 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3164 familyMatches
->removeObject( props
);
3169 debugFlags
= getDebugFlags( props
);
3172 symbol
= OSDynamicCast( OSSymbol
,
3173 props
->getObject( gIOClassKey
));
3177 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props));
3179 // alloc the driver instance
3180 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3182 if( !inst
|| !OSDynamicCast(IOService
, inst
)) {
3183 IOLog("Couldn't alloc class \"%s\"\n",
3184 symbol
->getCStringNoCopy());
3188 // init driver instance
3189 if( !(inst
->init( props
))) {
3191 if( debugFlags
& kIOLogStart
)
3192 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3196 if( __state
[1] & kIOServiceSynchronousState
)
3197 inst
->__state
[1] |= kIOServiceSynchronousState
;
3199 // give the driver the default match category if not specified
3200 category
= OSDynamicCast( OSSymbol
,
3201 props
->getObject( gIOMatchCategoryKey
));
3203 category
= gIODefaultMatchCategoryKey
;
3204 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3205 // attach driver instance
3206 if( !(inst
->attach( this )))
3209 // pass in score from property table
3210 score
= familyMatches
->orderObject( props
);
3212 // & probe the new driver instance
3214 if( debugFlags
& kIOLogProbe
)
3215 LOG("%s::probe(%s)\n",
3216 inst
->getMetaClass()->getClassName(), getName());
3219 newInst
= inst
->probe( this, &score
);
3220 inst
->detach( this );
3223 if( debugFlags
& kIOLogProbe
)
3224 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3230 newPri
= OSNumber::withNumber( score
, 32 );
3232 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3236 // add to start list for the match category
3238 startDict
= OSDictionary::withCapacity( 1 );
3239 assert( startDict
);
3240 startList
= (OSOrderedSet
*)
3241 startDict
->getObject( category
);
3242 if( 0 == startList
) {
3243 startList
= OSOrderedSet::withCapacity( 1,
3244 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3245 if( startDict
&& startList
) {
3246 startDict
->setObject( category
, startList
);
3247 startList
->release();
3250 assert( startList
);
3252 startList
->setObject( newInst
);
3260 familyMatches
->release();
3264 // start the best (until success) of each category
3266 iter
= OSCollectionIterator::withCollection( startDict
);
3268 while( (category
= (const OSSymbol
*) iter
->getNextObject())) {
3270 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3271 assert( startList
);
3276 while( true // (!started)
3277 && (inst
= (IOService
*)startList
->getFirstObject())) {
3280 startList
->removeObject(inst
);
3283 debugFlags
= getDebugFlags( inst
->getPropertyTable() );
3285 if( debugFlags
& kIOLogStart
) {
3287 LOG( "match category exists, skipping " );
3288 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3289 getName(), inst
->getRetainCount());
3292 if( false == started
)
3293 started
= startCandidate( inst
);
3295 if( (debugFlags
& kIOLogStart
) && (false == started
))
3296 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3297 inst
->getRetainCount());
3306 // adjust the busy count by +1 if matching is stalled for a module,
3307 // or -1 if a previously stalled matching is complete.
3308 lockForArbitration();
3310 uint64_t regID
= getRegistryEntryID();
3313 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
3317 IOSERVICE_MODULESTALL
,
3319 (uintptr_t) (regID
>> 32),
3323 __state
[1] |= kIOServiceModuleStallState
;
3326 } else if( __state
[1] & kIOServiceModuleStallState
) {
3329 IOSERVICE_MODULEUNSTALL
,
3331 (uintptr_t) (regID
>> 32),
3335 __state
[1] &= ~kIOServiceModuleStallState
;
3339 _adjustBusy( adjBusy
);
3340 unlockForArbitration();
3343 startDict
->release();
3347 * Start a previously attached & probed instance,
3348 * called on exporting object instance
3351 bool IOService::startCandidate( IOService
* service
)
3355 ok
= service
->attach( this );
3359 if (this != gIOResources
)
3361 // stall for any nub resources
3363 // stall for any driver resources
3364 service
->checkResources();
3367 AbsoluteTime startTime
;
3368 AbsoluteTime endTime
;
3371 if (kIOLogStart
& gIOKitDebug
)
3372 clock_get_uptime(&startTime
);
3374 ok
= service
->start(this);
3376 if (kIOLogStart
& gIOKitDebug
)
3378 clock_get_uptime(&endTime
);
3380 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
3382 SUB_ABSOLUTETIME(&endTime
, &startTime
);
3383 absolutetime_to_nanoseconds(endTime
, &nano
);
3384 if (nano
> 500000000ULL)
3385 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
3389 service
->detach( this );
3394 void IOService::publishResource( const char * key
, OSObject
* value
)
3396 const OSSymbol
* sym
;
3398 if( (sym
= OSSymbol::withCString( key
))) {
3399 publishResource( sym
, value
);
3404 void IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
3407 value
= (OSObject
*) gIOServiceKey
;
3409 gIOResources
->setProperty( key
, value
);
3411 if( IORecursiveLockHaveLock( gNotificationLock
))
3414 gIOResourceGenerationCount
++;
3415 gIOResources
->registerService();
3418 bool IOService::addNeededResource( const char * key
)
3420 OSObject
* resourcesProp
;
3425 resourcesProp
= getProperty( gIOResourceMatchKey
);
3427 newKey
= OSString::withCString( key
);
3428 if( (0 == resourcesProp
) || (0 == newKey
))
3431 set
= OSDynamicCast( OSSet
, resourcesProp
);
3433 set
= OSSet::withCapacity( 1 );
3435 set
->setObject( resourcesProp
);
3440 set
->setObject( newKey
);
3442 ret
= setProperty( gIOResourceMatchKey
, set
);
3448 bool IOService::checkResource( OSObject
* matching
)
3451 OSDictionary
* table
;
3453 if( (str
= OSDynamicCast( OSString
, matching
))) {
3454 if( gIOResources
->getProperty( str
))
3459 table
= resourceMatching( str
);
3460 else if( (table
= OSDynamicCast( OSDictionary
, matching
)))
3463 IOLog("%s: Can't match using: %s\n", getName(),
3464 matching
->getMetaClass()->getClassName());
3465 /* false would stall forever */
3469 if( gIOKitDebug
& kIOLogConfig
)
3470 LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName());
3472 waitForService( table
);
3474 if( gIOKitDebug
& kIOLogConfig
)
3475 LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) );
3480 bool IOService::checkResources( void )
3482 OSObject
* resourcesProp
;
3487 resourcesProp
= getProperty( gIOResourceMatchKey
);
3488 if( 0 == resourcesProp
)
3491 if( (set
= OSDynamicCast( OSSet
, resourcesProp
))) {
3493 iter
= OSCollectionIterator::withCollection( set
);
3495 while( ok
&& (resourcesProp
= iter
->getNextObject()) )
3496 ok
= checkResource( resourcesProp
);
3501 ok
= checkResource( resourcesProp
);
3507 void _IOConfigThread::configThread( void )
3509 _IOConfigThread
* inst
;
3512 if( !(inst
= new _IOConfigThread
))
3517 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &unused
))
3530 void _IOConfigThread::free( void )
3532 thread_deallocate(current_thread());
3536 void IOService::doServiceMatch( IOOptionBits options
)
3538 _IOServiceNotifier
* notify
;
3540 OSOrderedSet
* matches
;
3541 OSArray
* resourceKeys
= 0;
3542 SInt32 catalogGeneration
;
3543 bool keepGuessing
= true;
3544 bool reRegistered
= true;
3547 // job->nub->deliverNotification( gIOPublishNotification,
3548 // kIOServiceRegisteredState, 0xffffffff );
3550 while( keepGuessing
) {
3552 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
3553 // the matches list should always be created by findDrivers()
3556 lockForArbitration();
3557 if( 0 == (__state
[0] & kIOServiceFirstPublishState
)) {
3558 getMetaClass()->addInstance(this);
3559 deliverNotification( gIOFirstPublishNotification
,
3560 kIOServiceFirstPublishState
, 0xffffffff );
3563 __state
[1] &= ~kIOServiceNeedConfigState
;
3564 __state
[1] |= kIOServiceConfigState
;
3565 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
3566 __state
[0] |= kIOServiceRegisteredState
;
3568 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
3569 if (reRegistered
&& keepGuessing
) {
3570 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
3571 gNotifications
->getObject( gIOPublishNotification
) );
3573 while((notify
= (_IOServiceNotifier
*)
3574 iter
->getNextObject())) {
3576 if( matchPassive(notify
->matching
, 0)
3577 && (kIOServiceNotifyEnable
& notify
->state
))
3578 matches
->setObject( notify
);
3585 unlockForArbitration();
3587 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources()))
3589 if (this == gIOResources
)
3591 if (resourceKeys
) resourceKeys
->release();
3592 resourceKeys
= copyPropertyKeys();
3594 probeCandidates( matches
);
3600 lockForArbitration();
3601 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
3603 (reRegistered
|| (catalogGeneration
!=
3604 gIOCatalogue
->getGenerationCount()))
3605 && (0 == (__state
[0] & kIOServiceInactiveState
));
3608 unlockForArbitration();
3611 if( (0 == (__state
[0] & kIOServiceInactiveState
))
3612 && (0 == (__state
[1] & kIOServiceModuleStallState
)) ) {
3614 if (resourceKeys
) setProperty(gIOResourceMatchedKey
, resourceKeys
);
3616 deliverNotification( gIOMatchedNotification
,
3617 kIOServiceMatchedState
, 0xffffffff );
3618 if( 0 == (__state
[0] & kIOServiceFirstMatchState
))
3619 deliverNotification( gIOFirstMatchNotification
,
3620 kIOServiceFirstMatchState
, 0xffffffff );
3623 if (resourceKeys
) resourceKeys
->release();
3625 __state
[1] &= ~kIOServiceConfigState
;
3626 scheduleTerminatePhase2();
3629 unlockForArbitration();
3632 UInt32
IOService::_adjustBusy( SInt32 delta
)
3637 bool wasQuiet
, nowQuiet
, needWake
;
3640 result
= __state
[1] & kIOServiceBusyStateMask
;
3644 next
->lockForArbitration();
3645 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
3646 wasQuiet
= (0 == count
);
3647 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
)))
3648 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
3651 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
3652 nowQuiet
= (0 == count
);
3653 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
3656 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
3657 IOLockLock( gIOServiceBusyLock
);
3658 thread_wakeup( (event_t
) next
);
3659 IOLockUnlock( gIOServiceBusyLock
);
3662 next
->unlockForArbitration();
3664 if( (wasQuiet
|| nowQuiet
) ) {
3666 uint64_t regID
= next
->getRegistryEntryID();
3668 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
3670 (uintptr_t) (regID
>> 32),
3676 next
->__timeBusy
= mach_absolute_time();
3680 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
3681 next
->__timeBusy
= 0;
3684 MessageClientsContext context
;
3686 context
.service
= next
;
3687 context
.type
= kIOMessageServiceBusyStateChange
;
3688 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
3689 context
.argSize
= 0;
3691 applyToInterestNotifiers( next
, gIOBusyInterest
,
3692 &messageClientsApplier
, &context
);
3695 if( nowQuiet
&& (next
== gIOServiceRoot
)) {
3696 OSKext::considerUnloads();
3697 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
3702 delta
= nowQuiet
? -1 : +1;
3704 } while( (wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
3709 void IOService::adjustBusy( SInt32 delta
)
3711 lockForArbitration();
3712 _adjustBusy( delta
);
3713 unlockForArbitration();
3716 uint64_t IOService::getAccumulatedBusyTime( void )
3718 uint64_t accumBusy
= __accumBusy
;
3719 uint64_t timeBusy
= __timeBusy
;
3724 accumBusy
= __accumBusy
;
3725 timeBusy
= __timeBusy
;
3727 accumBusy
+= mach_absolute_time() - timeBusy
;
3729 while (timeBusy
!= __timeBusy
);
3731 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
3736 UInt32
IOService::getBusyState( void )
3738 return( __state
[1] & kIOServiceBusyStateMask
);
3741 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3742 mach_timespec_t
* timeout
)
3744 panic("waitForState");
3745 return (kIOReturnUnsupported
);
3748 IOReturn
IOService::waitForState( UInt32 mask
, UInt32 value
,
3752 int waitResult
= THREAD_AWAKENED
;
3753 bool computeDeadline
= true;
3754 AbsoluteTime abstime
;
3757 lockForArbitration();
3758 IOLockLock( gIOServiceBusyLock
);
3759 wait
= (value
!= (__state
[1] & mask
));
3761 __state
[1] |= kIOServiceBusyWaiterState
;
3762 unlockForArbitration();
3763 if( timeout
!= UINT64_MAX
) {
3764 if( computeDeadline
) {
3765 AbsoluteTime nsinterval
;
3766 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
3767 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
3768 computeDeadline
= false;
3770 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
3773 assert_wait((event_t
)this, THREAD_UNINT
);
3775 unlockForArbitration();
3776 IOLockUnlock( gIOServiceBusyLock
);
3778 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
3780 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
3782 if( waitResult
== THREAD_TIMED_OUT
)
3783 return( kIOReturnTimeout
);
3785 return( kIOReturnSuccess
);
3789 #define WAITING_KEXTD false
3791 extern bool gIOKextdClearedBusy
;
3792 #define WAITING_KEXTD (false == gIOKextdClearedBusy)
3795 IOReturn
IOService::waitQuiet( uint64_t timeout
)
3799 char * string
= NULL
;
3804 time
= mach_absolute_time();
3805 for (loops
= 0; loops
< 2; loops
++)
3807 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
3809 if (loops
&& (kIOReturnSuccess
== ret
))
3811 time
= mach_absolute_time() - time
;
3812 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
3813 IOLog("busy extended ok[%d], (%llds, %llds), kextd wait(%d): %s\n",
3814 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL, WAITING_KEXTD
,
3815 string
? string
: "");
3818 else if (kIOReturnTimeout
!= ret
) break;
3819 else if (timeout
< 41000000000) break;
3823 IORegistryIterator
* iter
;
3825 OSOrderedSet
* leaves
;
3827 IOService
* nextParent
;
3832 string
= IONew(char, len
);
3834 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
3835 leaves
= OSOrderedSet::withCapacity(4);
3836 if (iter
) set
= iter
->iterateAll();
3837 if (string
&& leaves
&& set
)
3839 while ((next
= (IOService
*) set
->getLastObject()))
3841 if (next
->getBusyState())
3843 leaves
->setObject(next
);
3845 while ((nextParent
= nextParent
->getProvider()))
3847 set
->removeObject(nextParent
);
3848 leaves
->removeObject(nextParent
);
3851 set
->removeObject(next
);
3854 while ((next
= (IOService
*) leaves
->getLastObject()))
3856 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
3857 if (l
>= len
) break;
3860 leaves
->removeObject(next
);
3863 OSSafeReleaseNULL(leaves
);
3864 OSSafeReleaseNULL(set
);
3865 OSSafeReleaseNULL(iter
);
3867 if (loops
&& (kIOWaitQuietPanics
& gIOKitDebug
))
3869 panic("busy timeout[%d], (%llds), kextd wait(%d): %s",
3870 loops
, timeout
/ 1000000000ULL, WAITING_KEXTD
,
3871 string
? string
: "");
3875 IOLog("busy timeout[%d], (%llds), kextd wait(%d): %s\n",
3876 loops
, timeout
/ 1000000000ULL, WAITING_KEXTD
,
3877 string
? string
: "");
3881 if (string
) IODelete(string
, char, 256);
3886 IOReturn
IOService::waitQuiet( mach_timespec_t
* timeout
)
3892 timeoutNS
= timeout
->tv_sec
;
3893 timeoutNS
*= kSecondScale
;
3894 timeoutNS
+= timeout
->tv_nsec
;
3897 timeoutNS
= UINT64_MAX
;
3899 return (waitQuiet(timeoutNS
));
3902 bool IOService::serializeProperties( OSSerialize
* s
) const
3905 ((IOService
*)this)->setProperty( ((IOService
*)this)->__state
,
3906 sizeof( __state
), "__state");
3908 return( super::serializeProperties(s
) );
3912 void _IOConfigThread::main(void * arg
, wait_result_t result
)
3914 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
3915 _IOServiceJob
* job
;
3919 thread_precedence_policy_data_t precedence
= { -1 };
3921 kr
= thread_policy_set(current_thread(),
3922 THREAD_PRECEDENCE_POLICY
,
3923 (thread_policy_t
) &precedence
,
3924 THREAD_PRECEDENCE_POLICY_COUNT
);
3925 if (KERN_SUCCESS
!= kr
)
3926 IOLog("thread_policy_set(%d)\n", kr
);
3932 semaphore_wait( gJobsSemaphore
);
3934 IOTakeLock( gJobsLock
);
3935 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
3937 gJobs
->removeObject(job
);
3940 // gNumConfigThreads--; // we're out of service
3941 gNumWaitingThreads
--; // we're out of service
3943 IOUnlock( gJobsLock
);
3949 if( gIOKitDebug
& kIOLogConfig
)
3950 LOG("config(%p): starting on %s, %d\n",
3951 OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
3953 switch( job
->type
) {
3956 nub
->doServiceMatch( job
->options
);
3960 LOG("config(%p): strange type (%d)\n",
3961 OBFUSCATE(IOThreadSelf()), job
->type
);
3968 IOTakeLock( gJobsLock
);
3969 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
3971 gNumWaitingThreads
++; // back in service
3972 // gNumConfigThreads++;
3974 if( 0 == --gNumConfigThreads
) {
3975 // IOLog("MATCH IDLE\n");
3976 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
3979 IOUnlock( gJobsLock
);
3984 if( gIOKitDebug
& kIOLogConfig
)
3985 LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) );
3990 IOReturn
IOService::waitMatchIdle( UInt32 msToWait
)
3993 int waitResult
= THREAD_AWAKENED
;
3994 bool computeDeadline
= true;
3995 AbsoluteTime deadline
;
3997 IOLockLock( gJobsLock
);
3999 wait
= (0 != gNumConfigThreads
);
4002 if( computeDeadline
) {
4003 clock_interval_to_deadline(
4004 msToWait
, kMillisecondScale
, &deadline
);
4005 computeDeadline
= false;
4007 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
4008 deadline
, THREAD_UNINT
);
4010 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
4014 } while( wait
&& (waitResult
!= THREAD_TIMED_OUT
));
4015 IOLockUnlock( gJobsLock
);
4017 if( waitResult
== THREAD_TIMED_OUT
)
4018 return( kIOReturnTimeout
);
4020 return( kIOReturnSuccess
);
4023 void IOService::cpusRunning(void)
4025 gCPUsRunning
= true;
4028 void _IOServiceJob::pingConfig( _IOServiceJob
* job
)
4035 IOTakeLock( gJobsLock
);
4038 gJobs
->setLastObject( job
);
4040 count
= gNumWaitingThreads
;
4041 // if( gNumConfigThreads) count++;// assume we're called from a config thread
4043 create
= ( (gOutstandingJobs
> count
)
4044 && ((gNumConfigThreads
< kMaxConfigThreads
)
4045 || (job
->nub
== gIOResources
)
4048 gNumConfigThreads
++;
4049 gNumWaitingThreads
++;
4052 IOUnlock( gJobsLock
);
4057 if( gIOKitDebug
& kIOLogConfig
)
4058 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
4059 _IOConfigThread::configThread();
4062 semaphore_signal( gJobsSemaphore
);
4065 struct IOServiceMatchContext
4067 OSDictionary
* table
;
4075 bool IOService::instanceMatch(const OSObject
* entry
, void * context
)
4077 IOServiceMatchContext
* ctx
= (typeof(ctx
)) context
;
4078 IOService
* service
= (typeof(service
)) entry
;
4079 OSDictionary
* table
= ctx
->table
;
4080 uint32_t options
= ctx
->options
;
4081 uint32_t state
= ctx
->state
;
4088 match
= ((state
== (state
& service
->__state
[0]))
4089 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
4091 ctx
->count
+= table
->getCount();
4092 match
= service
->matchInternal(table
, options
, &done
);
4099 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
))
4102 ctx
->result
= service
;
4105 else if (!ctx
->result
)
4107 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
4111 ((OSSet
*)ctx
->result
)->setObject(service
);
4116 // internal - call with gNotificationLock
4117 OSObject
* IOService::copyExistingServices( OSDictionary
* matching
,
4118 IOOptionBits inState
, IOOptionBits options
)
4120 OSObject
* current
= 0;
4122 IOService
* service
;
4130 OSSerialize
* s
= OSSerialize::withCapacity(128);
4131 matching
->serialize(s
);
4134 if((obj
= matching
->getObject(gIOProviderClassKey
))
4136 && gIOResourcesKey
->isEqualTo(obj
)
4137 && (service
= gIOResources
))
4139 if( (inState
== (service
->__state
[0] & inState
))
4140 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
4141 && service
->matchPassive(matching
, options
))
4143 if( options
& kIONotifyOnce
)
4149 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
4154 IOServiceMatchContext ctx
;
4155 ctx
.table
= matching
;
4156 ctx
.state
= inState
;
4159 ctx
.options
= options
;
4162 if ((str
= OSDynamicCast(OSString
, obj
)))
4164 const OSSymbol
* sym
= OSSymbol::withString(str
);
4165 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
4170 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
4174 current
= ctx
.result
;
4176 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
4177 if (current
&& (ctx
.done
!= ctx
.count
))
4180 source
= OSDynamicCast(OSSet
, current
);
4182 while ((service
= (IOService
*) source
->getAnyObject()))
4184 if (service
->matchPassive(matching
, options
))
4186 if( options
& kIONotifyOnce
)
4194 ((OSSet
*)current
)->setObject( service
);
4198 current
= OSSet::withObjects(
4199 (const OSObject
**) &service
, 1, 1 );
4202 source
->removeObject(service
);
4210 OSObject
* _current
= 0;
4212 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
4213 kIORegistryIterateRecursively
);
4217 while( (service
= (IOService
*) iter
->getNextObject())) {
4218 if( (inState
== (service
->__state
[0] & inState
))
4219 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
4220 && service
->matchPassive(matching
, 0)) {
4222 if( options
& kIONotifyOnce
) {
4228 ((OSSet
*)_current
)->setObject( service
);
4230 _current
= OSSet::withObjects(
4231 (const OSObject
**) &service
, 1, 1 );
4234 } while( !service
&& !iter
->isValid());
4239 if ( ((current
!= 0) != (_current
!= 0))
4240 || (current
&& _current
&& !current
->isEqualTo(_current
)))
4242 OSSerialize
* s1
= OSSerialize::withCapacity(128);
4243 OSSerialize
* s2
= OSSerialize::withCapacity(128);
4244 current
->serialize(s1
);
4245 _current
->serialize(s2
);
4246 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current
),
4247 OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
4252 if (_current
) _current
->release();
4258 if( current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
4259 iter
= OSCollectionIterator::withCollection( (OSSet
*)current
);
4268 OSIterator
* IOService::getMatchingServices( OSDictionary
* matching
)
4272 // is a lock even needed?
4275 iter
= (OSIterator
*) copyExistingServices( matching
,
4276 kIOServiceMatchedState
);
4283 IOService
* IOService::copyMatchingService( OSDictionary
* matching
)
4285 IOService
* service
;
4287 // is a lock even needed?
4290 service
= (IOService
*) copyExistingServices( matching
,
4291 kIOServiceMatchedState
, kIONotifyOnce
);
4298 struct _IOServiceMatchingNotificationHandlerRef
4300 IOServiceNotificationHandler handler
;
4304 static bool _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
4305 IOService
* newService
,
4306 IONotifier
* notifier
)
4308 return ((*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
));
4311 // internal - call with gNotificationLock
4312 IONotifier
* IOService::setNotification(
4313 const OSSymbol
* type
, OSDictionary
* matching
,
4314 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
4317 _IOServiceNotifier
* notify
= 0;
4323 notify
= new _IOServiceNotifier
;
4324 if( notify
&& !notify
->init()) {
4330 notify
->handler
= handler
;
4331 notify
->target
= target
;
4332 notify
->matching
= matching
;
4334 if (handler
== &_IOServiceMatchingNotificationHandler
)
4336 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
4337 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
4341 notify
->priority
= priority
;
4342 notify
->state
= kIOServiceNotifyEnable
;
4343 queue_init( ¬ify
->handlerInvocations
);
4347 if( 0 == (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
4348 set
= OSOrderedSet::withCapacity( 1,
4349 IONotifyOrdering
, 0 );
4351 gNotifications
->setObject( type
, set
);
4355 notify
->whence
= set
;
4357 set
->setObject( notify
);
4363 // internal - call with gNotificationLock
4364 IONotifier
* IOService::doInstallNotification(
4365 const OSSymbol
* type
, OSDictionary
* matching
,
4366 IOServiceMatchingNotificationHandler handler
,
4367 void * target
, void * ref
,
4368 SInt32 priority
, OSIterator
** existing
)
4371 IONotifier
* notify
;
4372 IOOptionBits inState
;
4377 if( type
== gIOPublishNotification
)
4378 inState
= kIOServiceRegisteredState
;
4380 else if( type
== gIOFirstPublishNotification
)
4381 inState
= kIOServiceFirstPublishState
;
4383 else if (type
== gIOMatchedNotification
)
4384 inState
= kIOServiceMatchedState
;
4386 else if (type
== gIOFirstMatchNotification
)
4387 inState
= kIOServiceFirstMatchState
;
4389 else if( type
== gIOTerminatedNotification
)
4394 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
4397 // get the current set
4398 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
4407 #if !defined(__LP64__)
4408 IONotifier
* IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
4409 IOServiceNotificationHandler handler
,
4410 void * target
, void * refCon
,
4411 SInt32 priority
, OSIterator
** existing
)
4413 IONotifier
* result
;
4414 _IOServiceMatchingNotificationHandlerRef ref
;
4415 ref
.handler
= handler
;
4418 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
4419 &_IOServiceMatchingNotificationHandler
,
4420 target
, &ref
, priority
, existing
);
4422 matching
->release();
4426 #endif /* !defined(__LP64__) */
4429 IONotifier
* IOService::installNotification(
4430 const OSSymbol
* type
, OSDictionary
* matching
,
4431 IOServiceMatchingNotificationHandler handler
,
4432 void * target
, void * ref
,
4433 SInt32 priority
, OSIterator
** existing
)
4435 IONotifier
* notify
;
4439 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
4440 priority
, existing
);
4442 // in case handler remove()s
4443 if (notify
) notify
->retain();
4450 IONotifier
* IOService::addNotification(
4451 const OSSymbol
* type
, OSDictionary
* matching
,
4452 IOServiceNotificationHandler handler
,
4453 void * target
, void * refCon
,
4456 IONotifier
* result
;
4457 _IOServiceMatchingNotificationHandlerRef ref
;
4459 ref
.handler
= handler
;
4462 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
4463 target
, &ref
, priority
);
4466 matching
->release();
4471 IONotifier
* IOService::addMatchingNotification(
4472 const OSSymbol
* type
, OSDictionary
* matching
,
4473 IOServiceMatchingNotificationHandler handler
,
4474 void * target
, void * ref
,
4477 OSIterator
* existing
= NULL
;
4479 _IOServiceNotifier
* notify
;
4482 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
4483 handler
, target
, ref
, priority
, &existing
);
4484 if (!ret
) return (0);
4486 // send notifications for existing set
4489 while( (next
= (IOService
*) existing
->getNextObject())) {
4491 next
->lockForArbitration();
4492 if( 0 == (next
->__state
[0] & kIOServiceInactiveState
))
4493 next
->invokeNotifer( notify
);
4494 next
->unlockForArbitration();
4496 existing
->release();
4500 bool removed
= (0 == notify
->whence
);
4502 if (removed
) ret
= gIOServiceNullNotifier
;
4508 bool IOService::syncNotificationHandler(
4509 void * /* target */, void * ref
,
4510 IOService
* newService
,
4511 IONotifier
* notifier
)
4515 if (!*((IOService
**) ref
))
4517 newService
->retain();
4518 (*(IOService
**) ref
) = newService
;
4526 IOService
* IOService::waitForMatchingService( OSDictionary
* matching
,
4529 IONotifier
* notify
= 0;
4530 // priority doesn't help us much since we need a thread wakeup
4531 SInt32 priority
= 0;
4542 result
= (IOService
*) copyExistingServices( matching
,
4543 kIOServiceMatchedState
, kIONotifyOnce
);
4546 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
4547 &IOService::syncNotificationHandler
, (void *) 0,
4548 &result
, priority
);
4551 if (UINT64_MAX
!= timeout
)
4553 AbsoluteTime deadline
;
4554 nanoseconds_to_absolutetime(timeout
, &deadline
);
4555 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
4556 SLEEPNOTIFYTO(&result
, deadline
);
4560 SLEEPNOTIFY(&result
);
4568 notify
->remove(); // dequeues
4573 IOService
* IOService::waitForService( OSDictionary
* matching
,
4574 mach_timespec_t
* timeout
)
4581 timeoutNS
= timeout
->tv_sec
;
4582 timeoutNS
*= kSecondScale
;
4583 timeoutNS
+= timeout
->tv_nsec
;
4586 timeoutNS
= UINT64_MAX
;
4588 result
= waitForMatchingService(matching
, timeoutNS
);
4590 matching
->release();
4597 void IOService::deliverNotification( const OSSymbol
* type
,
4598 IOOptionBits orNewState
, IOOptionBits andNewState
)
4600 _IOServiceNotifier
* notify
;
4602 OSArray
* willSend
= 0;
4604 lockForArbitration();
4606 if( (0 == (__state
[0] & kIOServiceInactiveState
))
4607 || (type
== gIOTerminatedNotification
)) {
4611 iter
= OSCollectionIterator::withCollection( (OSOrderedSet
*)
4612 gNotifications
->getObject( type
) );
4615 while( (notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
4617 if( matchPassive(notify
->matching
, 0)
4618 && (kIOServiceNotifyEnable
& notify
->state
)) {
4620 willSend
= OSArray::withCapacity(8);
4622 willSend
->setObject( notify
);
4628 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
4634 for( unsigned int idx
= 0;
4635 (notify
= (_IOServiceNotifier
*) willSend
->getObject(idx
));
4637 invokeNotifer( notify
);
4639 willSend
->release();
4641 unlockForArbitration();
4644 IOOptionBits
IOService::getState( void ) const
4646 return( __state
[0] );
4650 * Helpers to make matching objects for simple cases
4653 OSDictionary
* IOService::serviceMatching( const OSString
* name
,
4654 OSDictionary
* table
)
4657 const OSString
* str
;
4659 str
= OSSymbol::withString(name
);
4664 table
= OSDictionary::withCapacity( 2 );
4666 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
4672 OSDictionary
* IOService::serviceMatching( const char * name
,
4673 OSDictionary
* table
)
4675 const OSString
* str
;
4677 str
= OSSymbol::withCString( name
);
4681 table
= serviceMatching( str
, table
);
4686 OSDictionary
* IOService::nameMatching( const OSString
* name
,
4687 OSDictionary
* table
)
4690 table
= OSDictionary::withCapacity( 2 );
4692 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
4697 OSDictionary
* IOService::nameMatching( const char * name
,
4698 OSDictionary
* table
)
4700 const OSString
* str
;
4702 str
= OSSymbol::withCString( name
);
4706 table
= nameMatching( str
, table
);
4711 OSDictionary
* IOService::resourceMatching( const OSString
* str
,
4712 OSDictionary
* table
)
4714 table
= serviceMatching( gIOResourcesKey
, table
);
4716 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
4721 OSDictionary
* IOService::resourceMatching( const char * name
,
4722 OSDictionary
* table
)
4724 const OSSymbol
* str
;
4726 str
= OSSymbol::withCString( name
);
4730 table
= resourceMatching( str
, table
);
4736 OSDictionary
* IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
4737 OSDictionary
* table
)
4739 OSDictionary
* properties
;
4741 properties
= OSDictionary::withCapacity( 2 );
4744 properties
->setObject( key
, value
);
4747 table
= OSDictionary::withCapacity( 2 );
4749 table
->setObject( gIOPropertyMatchKey
, properties
);
4751 properties
->release();
4756 OSDictionary
* IOService::registryEntryIDMatching( uint64_t entryID
,
4757 OSDictionary
* table
)
4761 num
= OSNumber::withNumber( entryID
, 64 );
4766 table
= OSDictionary::withCapacity( 2 );
4768 table
->setObject( gIORegistryEntryIDKey
, num
);
4778 * _IOServiceNotifier
4781 // wait for all threads, other than the current one,
4782 // to exit the handler
4784 void _IOServiceNotifier::wait()
4786 _IOServiceNotifierInvocation
* next
;
4791 queue_iterate( &handlerInvocations
, next
,
4792 _IOServiceNotifierInvocation
*, link
) {
4793 if( next
->thread
!= current_thread() ) {
4799 state
|= kIOServiceNotifyWaiter
;
4806 void _IOServiceNotifier::free()
4808 assert( queue_empty( &handlerInvocations
));
4812 void _IOServiceNotifier::remove()
4817 whence
->removeObject( (OSObject
*) this );
4821 matching
->release();
4825 state
&= ~kIOServiceNotifyEnable
;
4834 bool _IOServiceNotifier::disable()
4840 ret
= (0 != (kIOServiceNotifyEnable
& state
));
4841 state
&= ~kIOServiceNotifyEnable
;
4850 void _IOServiceNotifier::enable( bool was
)
4854 state
|= kIOServiceNotifyEnable
;
4856 state
&= ~kIOServiceNotifyEnable
;
4862 * _IOServiceNullNotifier
4865 void _IOServiceNullNotifier::taggedRetain(const void *tag
) const {}
4866 void _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const {}
4867 void _IOServiceNullNotifier::free() {}
4868 void _IOServiceNullNotifier::wait() {}
4869 void _IOServiceNullNotifier::remove() {}
4870 void _IOServiceNullNotifier::enable(bool was
) {}
4871 bool _IOServiceNullNotifier::disable() { return(false); }
4877 IOService
* IOResources::resources( void )
4881 inst
= new IOResources
;
4882 if( inst
&& !inst
->init()) {
4890 bool IOResources::init( OSDictionary
* dictionary
)
4892 // Do super init first
4893 if ( !IOService::init() )
4896 // Allow PAL layer to publish a value
4897 const char *property_name
;
4900 pal_get_resource_property( &property_name
, &property_value
);
4902 if( property_name
) {
4904 const OSSymbol
* sym
;
4906 if( (num
= OSNumber::withNumber(property_value
, 32)) != 0 ) {
4907 if( (sym
= OSSymbol::withCString( property_name
)) != 0 ) {
4908 this->setProperty( sym
, num
);
4918 IOReturn
IOResources::newUserClient(task_t owningTask
, void * securityID
,
4919 UInt32 type
, OSDictionary
* properties
,
4920 IOUserClient
** handler
)
4922 return( kIOReturnUnsupported
);
4925 IOWorkLoop
* IOResources::getWorkLoop() const
4927 // If we are the resource root
4928 // then use the platform's workloop
4929 if (this == (IOResources
*) gIOResources
)
4930 return getPlatform()->getWorkLoop();
4932 return IOService::getWorkLoop();
4935 bool IOResources::matchPropertyTable( OSDictionary
* table
)
4944 prop
= table
->getObject( gIOResourceMatchKey
);
4945 str
= OSDynamicCast( OSString
, prop
);
4947 ok
= (0 != getProperty( str
));
4949 else if( (set
= OSDynamicCast( OSSet
, prop
))) {
4951 iter
= OSCollectionIterator::withCollection( set
);
4953 while( ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()) ))
4954 ok
= (0 != getProperty( str
));
4959 else if ((prop
= table
->getObject(gIOResourceMatchedKey
)))
4961 keys
= (OSArray
*) copyProperty(gIOResourceMatchedKey
);
4965 // assuming OSSymbol
4966 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
4974 void IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
4976 IOService::updateConsoleUsers(NULL
, 0);
4979 void IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
4981 IORegistryEntry
* regEntry
;
4982 OSObject
* locked
= kOSBooleanFalse
;
4985 OSDictionary
* user
;
4986 static IOMessage sSystemPower
;
4987 clock_sec_t now
= 0;
4988 clock_usec_t microsecs
;
4990 regEntry
= IORegistryEntry::getRegistryRoot();
4992 if (!gIOChosenEntry
)
4993 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
4995 IOLockLock(gIOConsoleUsersLock
);
4999 sSystemPower
= systemMessage
;
5001 if (kIOMessageSystemHasPoweredOn
== systemMessage
)
5003 uint32_t lockState
= IOHibernateWasScreenLocked();
5008 case kIOScreenLockLocked
:
5009 case kIOScreenLockFileVaultDialog
:
5010 gIOConsoleBooterLockState
= kOSBooleanTrue
;
5012 case kIOScreenLockNoLock
:
5013 gIOConsoleBooterLockState
= 0;
5015 case kIOScreenLockUnlocked
:
5017 gIOConsoleBooterLockState
= kOSBooleanFalse
;
5021 #endif /* HIBERNATION */
5027 bool loginLocked
= true;
5029 gIOConsoleLoggedIn
= false;
5031 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
5034 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
5035 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
5037 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
5040 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
5044 if (!loginLocked
) gIOConsoleBooterLockState
= 0;
5045 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
5046 (num
!= 0), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
5047 gIOConsoleLoggedIn
, loginLocked
);
5048 #endif /* HIBERNATION */
5049 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
5052 if (!gIOConsoleLoggedIn
5053 || (kIOMessageSystemWillSleep
== sSystemPower
)
5054 || (kIOMessageSystemPagingOff
== sSystemPower
))
5056 locked
= kOSBooleanTrue
;
5059 else if (gIOConsoleBooterLockState
)
5061 locked
= gIOConsoleBooterLockState
;
5063 #endif /* HIBERNATION */
5064 else if (gIOConsoleLockTime
)
5066 clock_get_calendar_microtime(&now
, µsecs
);
5067 if (gIOConsoleLockTime
> now
)
5069 AbsoluteTime deadline
;
5070 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
5071 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
5075 locked
= kOSBooleanTrue
;
5079 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
5082 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
5085 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
5087 OSIncrementAtomic( &gIOConsoleUsersSeed
);
5093 if (locked
== kOSBooleanTrue
) gIOScreenLockState
= kIOScreenLockLocked
;
5094 else if (gIOConsoleLockTime
) gIOScreenLockState
= kIOScreenLockUnlocked
;
5095 else gIOScreenLockState
= kIOScreenLockNoLock
;
5096 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
5098 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
5099 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= 0), now
, systemMessage
);
5101 #endif /* HIBERNATION */
5103 IOLockUnlock(gIOConsoleUsersLock
);
5107 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
5109 MessageClientsContext context
;
5111 context
.service
= getServiceRoot();
5112 context
.type
= kIOMessageConsoleSecurityChange
;
5113 context
.argument
= (void *) regEntry
;
5114 context
.argSize
= 0;
5116 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
5117 &messageClientsApplier
, &context
);
5121 IOReturn
IOResources::setProperties( OSObject
* properties
)
5124 const OSSymbol
* key
;
5125 OSDictionary
* dict
;
5126 OSCollectionIterator
* iter
;
5128 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
5129 if ( kIOReturnSuccess
!= err
)
5132 dict
= OSDynamicCast(OSDictionary
, properties
);
5134 return( kIOReturnBadArgument
);
5136 iter
= OSCollectionIterator::withCollection( dict
);
5138 return( kIOReturnBadArgument
);
5140 while( (key
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
5142 if (gIOConsoleUsersKey
== key
) do
5144 OSArray
* consoleUsers
;
5145 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
5148 IOService::updateConsoleUsers(consoleUsers
, 0);
5152 publishResource( key
, dict
->getObject(key
) );
5157 return( kIOReturnSuccess
);
5161 * Helpers for matching dictionaries.
5162 * Keys existing in matching are checked in properties.
5163 * Keys may be a string or OSCollection of IOStrings
5166 bool IOService::compareProperty( OSDictionary
* matching
,
5173 value
= matching
->getObject( key
);
5176 prop
= copyProperty(key
);
5177 ok
= value
->isEqualTo(prop
);
5178 if (prop
) prop
->release();
5187 bool IOService::compareProperty( OSDictionary
* matching
,
5188 const OSString
* key
)
5194 value
= matching
->getObject( key
);
5197 prop
= copyProperty(key
);
5198 ok
= value
->isEqualTo(prop
);
5199 if (prop
) prop
->release();
5207 bool IOService::compareProperties( OSDictionary
* matching
,
5208 OSCollection
* keys
)
5210 OSCollectionIterator
* iter
;
5211 const OSString
* key
;
5214 if( !matching
|| !keys
)
5217 iter
= OSCollectionIterator::withCollection( keys
);
5220 while( ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject())))
5221 ok
= compareProperty( matching
, key
);
5225 keys
->release(); // !! consume a ref !!
5230 /* Helper to add a location matching dict to the table */
5232 OSDictionary
* IOService::addLocation( OSDictionary
* table
)
5234 OSDictionary
* dict
;
5239 dict
= OSDictionary::withCapacity( 1 );
5241 table
->setObject( gIOLocationMatchKey
, dict
);
5249 * Go looking for a provider to match a location dict.
5252 IOService
* IOService::matchLocation( IOService
* /* client */ )
5256 parent
= getProvider();
5259 parent
= parent
->matchLocation( this );
5264 bool IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
5269 IORegistryEntry
* entry
;
5272 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
5278 count
= table
->getCount();
5281 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
5284 match
= ((kIOServiceClassDone
& options
) || (0 != metaCast(str
)));
5286 match
= (0 != metaCast( str
));
5287 if ((kIOServiceClassDone
& options
) && !match
) panic("classDone");
5289 if ((!match
) || (done
== count
)) break;
5292 obj
= table
->getObject( gIONameMatchKey
);
5295 match
= compareNames( obj
, changesOK
? &matched
: 0 );
5297 if( changesOK
&& matched
) {
5298 // leave a hint as to which name matched
5299 table
->setObject( gIONameMatchedKey
, matched
);
5302 if (done
== count
) break;
5305 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
5308 const OSSymbol
* sym
;
5311 sym
= copyLocation();
5313 match
= sym
->isEqualTo( str
);
5316 if ((!match
) || (done
== count
)) break;
5319 obj
= table
->getObject( gIOPropertyMatchKey
);
5322 OSDictionary
* dict
;
5323 OSDictionary
* nextDict
;
5327 dict
= dictionaryWithProperties();
5329 nextDict
= OSDynamicCast( OSDictionary
, obj
);
5333 iter
= OSCollectionIterator::withCollection(
5334 OSDynamicCast(OSCollection
, obj
));
5337 || (iter
&& (0 != (nextDict
= OSDynamicCast(OSDictionary
,
5338 iter
->getNextObject()))))) {
5339 match
= dict
->isEqualTo( nextDict
, nextDict
);
5348 if ((!match
) || (done
== count
)) break;
5351 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
5354 OSDictionary
* dict
;
5359 dict
= dictionaryWithProperties();
5361 nextKey
= OSDynamicCast( OSString
, obj
);
5365 iter
= OSCollectionIterator::withCollection(
5366 OSDynamicCast(OSCollection
, obj
));
5369 || (iter
&& (0 != (nextKey
= OSDynamicCast(OSString
,
5370 iter
->getNextObject()))))) {
5371 match
= (0 != dict
->getObject(nextKey
));
5380 if ((!match
) || (done
== count
)) break;
5383 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
5386 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy() );
5387 match
= (this == entry
);
5390 if ((!match
) || (done
== count
)) break;
5393 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
5396 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
5397 if ((!match
) || (done
== count
)) break;
5400 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
5404 IOService
* service
= 0;
5405 UInt32 serviceCount
= 0;
5408 iter
= getClientIterator();
5410 while( (service
= (IOService
*) iter
->getNextObject())) {
5411 if( kIOServiceInactiveState
& service
->__state
[0])
5413 if( 0 == service
->getProperty( gIOMatchCategoryKey
))
5419 match
= (serviceCount
== num
->unsigned32BitValue());
5420 if ((!match
) || (done
== count
)) break;
5423 #define propMatch(key) \
5424 obj = table->getObject(key); \
5429 prop = copyProperty(key); \
5430 match = obj->isEqualTo(prop); \
5431 if (prop) prop->release(); \
5432 if ((!match) || (done == count)) break; \
5434 propMatch(gIOBSDNameKey
)
5435 propMatch(gIOBSDMajorKey
)
5436 propMatch(gIOBSDMinorKey
)
5437 propMatch(gIOBSDUnitKey
)
5442 if (did
) *did
= done
;
5446 bool IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
5448 return (matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0));
5451 bool IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
5454 OSDictionary
* nextTable
;
5458 bool matchParent
= false;
5464 OSArray
* aliasServiceRegIds
= NULL
;
5465 IOService
* foundAlternateService
= NULL
;
5468 OSDictionary
* root
= table
;
5476 count
= table
->getCount();
5477 if (!(kIOServiceInternalDone
& options
))
5479 match
= where
->matchInternal(table
, options
, &done
);
5480 // don't call family if we've done all the entries in the table
5481 if ((!match
) || (done
== count
)) break;
5484 // pass in score from property table
5485 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
5487 // do family specific matching
5488 match
= where
->matchPropertyTable( table
, &score
);
5492 if( kIOLogMatch
& getDebugFlags( table
))
5493 LOG("%s: family specific matching fails\n", where
->getName());
5498 if (kIOServiceChangesOK
& options
) {
5500 newPri
= OSNumber::withNumber( score
, 32 );
5502 table
->setObject( gIOProbeScoreKey
, newPri
);
5508 matchParent
= false;
5510 nextTable
= OSDynamicCast(OSDictionary
,
5511 table
->getObject( gIOParentMatchKey
));
5513 // look for a matching entry anywhere up to root
5520 table
= OSDynamicCast(OSDictionary
,
5521 table
->getObject( gIOLocationMatchKey
));
5523 // look for a matching entry at matchLocation()
5525 where
= where
->getProvider();
5526 if (where
&& (where
= where
->matchLocation(where
))) continue;
5536 if(matchParent
== true) {
5537 // check if service has an alias to search its other "parents" if a parent match isn't found
5538 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, where
->getProperty(kIOServiceLegacyMatchingRegistryIDKey
));
5539 if(alternateRegistryID
!= NULL
) {
5540 if(aliasServiceRegIds
== NULL
)
5542 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
5544 aliasServiceRegIds
->setObject(alternateRegistryID
);
5551 where
= where
->getProvider();
5553 // there were no matching parent services, check to see if there are aliased services that have a matching parent
5554 if(aliasServiceRegIds
!= NULL
) {
5555 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
5556 if(numAliasedServices
!= 0) {
5557 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
5558 if(alternateRegistryID
!= NULL
) {
5559 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
5560 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
5561 if(alternateMatchingDict
!= NULL
) {
5562 OSSafeReleaseNULL(foundAlternateService
);
5563 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
5564 alternateMatchingDict
->release();
5565 if(foundAlternateService
!= NULL
) {
5566 where
= foundAlternateService
;
5574 while( where
!= NULL
);
5576 OSSafeReleaseNULL(foundAlternateService
);
5577 OSSafeReleaseNULL(aliasServiceRegIds
);
5582 OSSerialize
* s
= OSSerialize::withCapacity(128);
5584 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
5593 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
5594 UInt32 type
, OSDictionary
* properties
,
5595 IOUserClient
** handler
)
5597 const OSSymbol
*userClientClass
= 0;
5598 IOUserClient
*client
;
5601 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
))
5602 return kIOReturnSuccess
;
5604 // First try my own properties for a user client class name
5605 temp
= getProperty(gIOUserClientClassKey
);
5607 if (OSDynamicCast(OSSymbol
, temp
))
5608 userClientClass
= (const OSSymbol
*) temp
;
5609 else if (OSDynamicCast(OSString
, temp
)) {
5610 userClientClass
= OSSymbol::withString((OSString
*) temp
);
5611 if (userClientClass
)
5612 setProperty(kIOUserClientClassKey
,
5613 (OSObject
*) userClientClass
);
5617 // Didn't find one so lets just bomb out now without further ado.
5618 if (!userClientClass
)
5619 return kIOReturnUnsupported
;
5621 // This reference is consumed by the IOServiceOpen call
5622 temp
= OSMetaClass::allocClassWithName(userClientClass
);
5624 return kIOReturnNoMemory
;
5626 if (OSDynamicCast(IOUserClient
, temp
))
5627 client
= (IOUserClient
*) temp
;
5630 return kIOReturnUnsupported
;
5633 if ( !client
->initWithTask(owningTask
, securityID
, type
, properties
) ) {
5635 return kIOReturnBadArgument
;
5638 if ( !client
->attach(this) ) {
5640 return kIOReturnUnsupported
;
5643 if ( !client
->start(this) ) {
5644 client
->detach(this);
5646 return kIOReturnUnsupported
;
5650 return kIOReturnSuccess
;
5653 IOReturn
IOService::newUserClient( task_t owningTask
, void * securityID
,
5654 UInt32 type
, IOUserClient
** handler
)
5656 return( kIOReturnUnsupported
);
5659 IOReturn
IOService::requestProbe( IOOptionBits options
)
5661 return( kIOReturnUnsupported
);
5665 * Convert an IOReturn to text. Subclasses which add additional
5666 * IOReturn's should override this method and call
5667 * super::stringFromReturn if the desired value is not found.
5670 const char * IOService::stringFromReturn( IOReturn rtn
)
5672 static const IONamedValue IOReturn_values
[] = {
5673 {kIOReturnSuccess
, "success" },
5674 {kIOReturnError
, "general error" },
5675 {kIOReturnNoMemory
, "memory allocation error" },
5676 {kIOReturnNoResources
, "resource shortage" },
5677 {kIOReturnIPCError
, "Mach IPC failure" },
5678 {kIOReturnNoDevice
, "no such device" },
5679 {kIOReturnNotPrivileged
, "privilege violation" },
5680 {kIOReturnBadArgument
, "invalid argument" },
5681 {kIOReturnLockedRead
, "device is read locked" },
5682 {kIOReturnLockedWrite
, "device is write locked" },
5683 {kIOReturnExclusiveAccess
, "device is exclusive access" },
5684 {kIOReturnBadMessageID
, "bad IPC message ID" },
5685 {kIOReturnUnsupported
, "unsupported function" },
5686 {kIOReturnVMError
, "virtual memory error" },
5687 {kIOReturnInternalError
, "internal driver error" },
5688 {kIOReturnIOError
, "I/O error" },
5689 {kIOReturnCannotLock
, "cannot acquire lock" },
5690 {kIOReturnNotOpen
, "device is not open" },
5691 {kIOReturnNotReadable
, "device is not readable" },
5692 {kIOReturnNotWritable
, "device is not writeable" },
5693 {kIOReturnNotAligned
, "alignment error" },
5694 {kIOReturnBadMedia
, "media error" },
5695 {kIOReturnStillOpen
, "device is still open" },
5696 {kIOReturnRLDError
, "rld failure" },
5697 {kIOReturnDMAError
, "DMA failure" },
5698 {kIOReturnBusy
, "device is busy" },
5699 {kIOReturnTimeout
, "I/O timeout" },
5700 {kIOReturnOffline
, "device is offline" },
5701 {kIOReturnNotReady
, "device is not ready" },
5702 {kIOReturnNotAttached
, "device/channel is not attached" },
5703 {kIOReturnNoChannels
, "no DMA channels available" },
5704 {kIOReturnNoSpace
, "no space for data" },
5705 {kIOReturnPortExists
, "device port already exists" },
5706 {kIOReturnCannotWire
, "cannot wire physical memory" },
5707 {kIOReturnNoInterrupt
, "no interrupt attached" },
5708 {kIOReturnNoFrames
, "no DMA frames enqueued" },
5709 {kIOReturnMessageTooLarge
, "message is too large" },
5710 {kIOReturnNotPermitted
, "operation is not permitted" },
5711 {kIOReturnNoPower
, "device is without power" },
5712 {kIOReturnNoMedia
, "media is not present" },
5713 {kIOReturnUnformattedMedia
, "media is not formatted" },
5714 {kIOReturnUnsupportedMode
, "unsupported mode" },
5715 {kIOReturnUnderrun
, "data underrun" },
5716 {kIOReturnOverrun
, "data overrun" },
5717 {kIOReturnDeviceError
, "device error" },
5718 {kIOReturnNoCompletion
, "no completion routine" },
5719 {kIOReturnAborted
, "operation was aborted" },
5720 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
5721 {kIOReturnNotResponding
, "device is not responding" },
5722 {kIOReturnInvalid
, "unanticipated driver error" },
5726 return IOFindNameForValue(rtn
, IOReturn_values
);
5730 * Convert an IOReturn to an errno.
5732 int IOService::errnoFromReturn( IOReturn rtn
)
5734 if (unix_err(err_get_code(rtn
)) == rtn
)
5735 return err_get_code(rtn
);
5739 case kIOReturnSuccess
:
5741 case kIOReturnNoMemory
:
5743 case kIOReturnNoDevice
:
5745 case kIOReturnVMError
:
5747 case kIOReturnNotPermitted
:
5749 case kIOReturnNotPrivileged
:
5751 case kIOReturnIOError
:
5753 case kIOReturnNotWritable
:
5755 case kIOReturnBadArgument
:
5757 case kIOReturnUnsupported
:
5761 case kIOReturnNoPower
:
5763 case kIOReturnDeviceError
:
5765 case kIOReturnTimeout
:
5767 case kIOReturnMessageTooLarge
:
5769 case kIOReturnNoSpace
:
5771 case kIOReturnCannotLock
:
5775 case kIOReturnBadMessageID
:
5776 case kIOReturnNoCompletion
:
5777 case kIOReturnNotAligned
:
5779 case kIOReturnNotReady
:
5781 case kIOReturnRLDError
:
5783 case kIOReturnPortExists
:
5784 case kIOReturnStillOpen
:
5786 case kIOReturnExclusiveAccess
:
5787 case kIOReturnLockedRead
:
5788 case kIOReturnLockedWrite
:
5789 case kIOReturnNotOpen
:
5790 case kIOReturnNotReadable
:
5792 case kIOReturnCannotWire
:
5793 case kIOReturnNoResources
:
5795 case kIOReturnAborted
:
5796 case kIOReturnOffline
:
5797 case kIOReturnNotResponding
:
5799 case kIOReturnBadMedia
:
5800 case kIOReturnNoMedia
:
5801 case kIOReturnNotAttached
:
5802 case kIOReturnUnformattedMedia
:
5803 return(ENXIO
); // (media error)
5804 case kIOReturnDMAError
:
5805 case kIOReturnOverrun
:
5806 case kIOReturnUnderrun
:
5807 return(EIO
); // (transfer error)
5808 case kIOReturnNoBandwidth
:
5809 case kIOReturnNoChannels
:
5810 case kIOReturnNoFrames
:
5811 case kIOReturnNoInterrupt
:
5812 return(EIO
); // (hardware error)
5813 case kIOReturnError
:
5814 case kIOReturnInternalError
:
5815 case kIOReturnInvalid
:
5816 return(EIO
); // (generic error)
5817 case kIOReturnIPCError
:
5818 return(EIO
); // (ipc error)
5820 return(EIO
); // (all other errors)
5824 IOReturn
IOService::message( UInt32 type
, IOService
* provider
,
5828 * Generic entry point for calls from the provider. A return value of
5829 * kIOReturnSuccess indicates that the message was received, and where
5830 * applicable, that it was successful.
5833 return kIOReturnUnsupported
;
5840 IOItemCount
IOService::getDeviceMemoryCount( void )
5845 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5847 count
= array
->getCount();
5854 IODeviceMemory
* IOService::getDeviceMemoryWithIndex( unsigned int index
)
5857 IODeviceMemory
* range
;
5859 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
5861 range
= (IODeviceMemory
*) array
->getObject( index
);
5868 IOMemoryMap
* IOService::mapDeviceMemoryWithIndex( unsigned int index
,
5869 IOOptionBits options
)
5871 IODeviceMemory
* range
;
5874 range
= getDeviceMemoryWithIndex( index
);
5876 map
= range
->map( options
);
5883 OSArray
* IOService::getDeviceMemory( void )
5885 return( OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
)));
5889 void IOService::setDeviceMemory( OSArray
* array
)
5891 setProperty( gIODeviceMemoryKey
, array
);
5895 * For machines where the transfers on an I/O bus can stall because
5896 * the CPU is in an idle mode, These APIs allow a driver to specify
5897 * the maximum bus stall that they can handle. 0 indicates no limit.
5900 setCPUSnoopDelay(UInt32 __unused ns
)
5902 #if defined(__i386__) || defined(__x86_64__)
5903 ml_set_maxsnoop(ns
);
5904 #endif /* defined(__i386__) || defined(__x86_64__) */
5910 #if defined(__i386__) || defined(__x86_64__)
5911 return ml_get_maxsnoop();
5914 #endif /* defined(__i386__) || defined(__x86_64__) */
5917 #if defined(__i386__) || defined(__x86_64__)
5919 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
5921 static const UInt kNoReplace
= -1U; // Must be an illegal index
5922 UInt replace
= kNoReplace
;
5923 bool setCpuDelay
= false;
5925 IORecursiveLockLock(sCpuDelayLock
);
5927 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
5928 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
5929 IOService
* holder
= NULL
;
5932 const CpuDelayEntry ne
= {service
, ns
, delayType
};
5934 // Set maximum delay.
5935 for (UInt i
= 0; i
< count
; i
++) {
5936 IOService
*thisService
= entries
[i
].fService
;
5937 bool sameType
= (delayType
== entries
[i
].fDelayType
);
5938 if ((service
== thisService
) && sameType
)
5940 else if (!thisService
) {
5941 if (kNoReplace
== replace
)
5944 else if (sameType
) {
5945 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
5949 holder
= thisService
;
5955 if (kNoReplace
== replace
)
5956 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
5958 entries
[replace
] = ne
;
5961 ns
= -1U; // Set to max unsigned, i.e. no restriction
5963 for (UInt i
= 0; i
< count
; i
++) {
5964 // Clear a maximum delay.
5965 IOService
*thisService
= entries
[i
].fService
;
5966 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
5967 UInt32 thisMax
= entries
[i
].fMaxDelay
;
5968 if (service
== thisService
)
5970 else if (thisMax
< ns
) {
5972 holder
= thisService
;
5977 // Check if entry found
5978 if (kNoReplace
!= replace
) {
5979 entries
[replace
].fService
= 0; // Null the entry
5986 if (holder
&& debug_boot_arg
) {
5987 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
5990 // Must be safe to call from locked context
5991 if (delayType
== kCpuDelayBusStall
)
5993 ml_set_maxbusdelay(ns
);
5995 else if (delayType
== kCpuDelayInterrupt
)
5997 ml_set_maxintdelay(ns
);
5999 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
6000 sCPULatencySet
[delayType
]->setValue(ns
);
6002 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
6004 if (handlers
) for (unsigned int idx
= 0;
6005 (target
= (IOService
*) handlers
->getObject(idx
));
6008 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
6009 (void *) (uintptr_t) ns
, holder
,
6014 IORecursiveLockUnlock(sCpuDelayLock
);
6018 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
6020 IOReturn result
= kIOReturnNotFound
;
6024 IORecursiveLockLock(sCpuDelayLock
);
6028 if (enable
&& !sCpuLatencyHandlers
[delayType
])
6029 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
6030 array
= sCpuLatencyHandlers
[delayType
];
6033 idx
= array
->getNextIndexOfObject(target
, 0);
6038 array
->removeObject(idx
);
6039 result
= kIOReturnSuccess
;
6045 result
= kIOReturnExclusiveAccess
;
6048 array
->setObject(target
);
6050 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
6051 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
6052 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
6053 IOService
* holder
= NULL
;
6055 for (UInt i
= 0; i
< count
; i
++) {
6056 if (entries
[i
].fService
6057 && (delayType
== entries
[i
].fDelayType
)
6058 && (entries
[i
].fMaxDelay
< ns
)) {
6059 ns
= entries
[i
].fMaxDelay
;
6060 holder
= entries
[i
].fService
;
6063 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
6064 (void *) (uintptr_t) ns
, holder
,
6066 result
= kIOReturnSuccess
;
6071 IORecursiveLockUnlock(sCpuDelayLock
);
6076 #endif /* defined(__i386__) || defined(__x86_64__) */
6079 requireMaxBusStall(UInt32 __unused ns
)
6081 #if defined(__i386__) || defined(__x86_64__)
6082 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
6087 requireMaxInterruptDelay(uint32_t __unused ns
)
6089 #if defined(__i386__) || defined(__x86_64__)
6090 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
6098 IOReturn
IOService::resolveInterrupt(IOService
*nub
, int source
)
6100 IOInterruptController
*interruptController
;
6103 OSSymbol
*interruptControllerName
;
6105 IOInterruptSource
*interruptSources
;
6107 // Get the parents list from the nub.
6108 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
6109 if (array
== 0) return kIOReturnNoResources
;
6111 // Allocate space for the IOInterruptSources if needed... then return early.
6112 if (nub
->_interruptSources
== 0) {
6113 numSources
= array
->getCount();
6114 interruptSources
= (IOInterruptSource
*)IOMalloc(numSources
* sizeof(IOInterruptSource
));
6115 if (interruptSources
== 0) return kIOReturnNoMemory
;
6117 bzero(interruptSources
, numSources
* sizeof(IOInterruptSource
));
6119 nub
->_numInterruptSources
= numSources
;
6120 nub
->_interruptSources
= interruptSources
;
6121 return kIOReturnSuccess
;
6124 interruptControllerName
= OSDynamicCast(OSSymbol
,array
->getObject(source
));
6125 if (interruptControllerName
== 0) return kIOReturnNoResources
;
6127 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
6128 if (interruptController
== 0) return kIOReturnNoResources
;
6130 // Get the interrupt numbers from the nub.
6131 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
6132 if (array
== 0) return kIOReturnNoResources
;
6133 data
= OSDynamicCast(OSData
, array
->getObject(source
));
6134 if (data
== 0) return kIOReturnNoResources
;
6136 // Set the interruptController and interruptSource in the nub's table.
6137 interruptSources
= nub
->_interruptSources
;
6138 interruptSources
[source
].interruptController
= interruptController
;
6139 interruptSources
[source
].vectorData
= data
;
6141 return kIOReturnSuccess
;
6144 IOReturn
IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
6148 /* Make sure the _interruptSources are set */
6149 if (_interruptSources
== 0) {
6150 ret
= resolveInterrupt(this, source
);
6151 if (ret
!= kIOReturnSuccess
) return ret
;
6154 /* Make sure the local source number is valid */
6155 if ((source
< 0) || (source
>= _numInterruptSources
))
6156 return kIOReturnNoInterrupt
;
6158 /* Look up the contoller for the local source */
6159 *interruptController
= _interruptSources
[source
].interruptController
;
6161 if (*interruptController
== NULL
) {
6162 if (!resolve
) return kIOReturnNoInterrupt
;
6164 /* Try to reslove the interrupt */
6165 ret
= resolveInterrupt(this, source
);
6166 if (ret
!= kIOReturnSuccess
) return ret
;
6168 *interruptController
= _interruptSources
[source
].interruptController
;
6171 return kIOReturnSuccess
;
6174 IOReturn
IOService::registerInterrupt(int source
, OSObject
*target
,
6175 IOInterruptAction handler
,
6178 IOInterruptController
*interruptController
;
6181 ret
= lookupInterrupt(source
, true, &interruptController
);
6182 if (ret
!= kIOReturnSuccess
) return ret
;
6184 /* Register the source */
6185 return interruptController
->registerInterrupt(this, source
, target
,
6186 (IOInterruptHandler
)handler
,
6190 IOReturn
IOService::unregisterInterrupt(int source
)
6192 IOInterruptController
*interruptController
;
6195 ret
= lookupInterrupt(source
, false, &interruptController
);
6196 if (ret
!= kIOReturnSuccess
) return ret
;
6198 /* Unregister the source */
6199 return interruptController
->unregisterInterrupt(this, source
);
6202 IOReturn
IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
6204 IOReportLegend
* legend
= NULL
;
6205 IOInterruptAccountingData
* oldValue
= NULL
;
6206 IOInterruptAccountingReporter
* newArray
= NULL
;
6207 char subgroupName
[64];
6208 int newArraySize
= 0;
6212 return kIOReturnBadArgument
;
6216 * We support statistics on a maximum of 256 interrupts per nub; if a nub
6217 * has more than 256 interrupt specifiers associated with it, and tries
6218 * to register a high interrupt index with interrupt accounting, panic.
6219 * Having more than 256 interrupts associated with a single nub is
6220 * probably a sign that something fishy is going on.
6222 if (source
> IA_INDEX_MAX
) {
6223 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
6227 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
6228 * leaving it as is because the likelihood of contention where we are
6229 * actually growing the array is minimal (we would realistically need
6230 * to be starting a driver for the first time, with an IOReporting
6231 * client already in place). Nonetheless, cleanup that can be done
6232 * to adhere to best practices; it'll make the code more complicated,
6235 IOLockLock(reserved
->interruptStatisticsLock
);
6238 * Lazily allocate the statistics array.
6240 if (!reserved
->interruptStatisticsArray
) {
6241 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
6242 assert(reserved
->interruptStatisticsArray
);
6243 reserved
->interruptStatisticsArrayCount
= 1;
6244 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
6247 if (source
>= reserved
->interruptStatisticsArrayCount
) {
6249 * We're still within the range of supported indices, but we are out
6250 * of space in the current array. Do a nasty realloc (because
6251 * IORealloc isn't a thing) here. We'll double the size with each
6254 * Yes, the "next power of 2" could be more efficient; but this will
6255 * be invoked incredibly rarely. Who cares.
6257 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
6259 while (newArraySize
<= source
)
6260 newArraySize
= (newArraySize
<< 1);
6261 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
6266 * TODO: This even zeroes the memory it is about to overwrite.
6267 * Shameful; fix it. Not particularly high impact, however.
6269 bzero(newArray
, newArraySize
* sizeof(*newArray
));
6270 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
6271 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
6272 reserved
->interruptStatisticsArray
= newArray
;
6273 reserved
->interruptStatisticsArrayCount
= newArraySize
;
6276 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
6278 * We don't have a reporter associated with this index yet, so we
6279 * need to create one.
6282 * TODO: Some statistics do in fact have common units (time); should this be
6283 * split into separate reporters to communicate this?
6285 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
6288 * Each statistic is given an identifier based on the interrupt index (which
6289 * should be unique relative to any single nub) and the statistic involved.
6290 * We should now have a sane (small and positive) index, so start
6291 * constructing the channels for statistics.
6293 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
6295 * TODO: Currently, this does not add channels for disabled statistics.
6296 * Will this be confusing for clients? If so, we should just add the
6297 * channels; we can avoid updating the channels even if they exist.
6299 if (IA_GET_STATISTIC_ENABLED(i
))
6300 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
6304 * We now need to add the legend for this reporter to the registry.
6306 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, getProperty(kIOReportLegendKey
)));
6309 * Note that while we compose the subgroup name, we do not need to
6310 * manage its lifecycle (the reporter will handle this).
6312 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
6313 subgroupName
[sizeof(subgroupName
) - 1] = 0;
6314 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
6315 setProperty(kIOReportLegendKey
, legend
->getLegend());
6319 * TODO: Is this a good idea? Probably not; my assumption is it opts
6320 * all entities who register interrupts into public disclosure of all
6321 * IOReporting channels. Unfortunately, this appears to be as fine
6324 setProperty(kIOReportLegendPublicKey
, true);
6328 * Don't stomp existing entries. If we are about to, panic; this
6329 * probably means we failed to tear down our old interrupt source
6332 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
6335 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
6338 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
6341 * Inherit the reporter values for each statistic. The target may
6342 * be torn down as part of the runtime of the service (especially
6343 * for sleep/wake), so we inherit in order to avoid having values
6344 * reset for no apparent reason. Our statistics are ultimately
6345 * tied to the index and the sevice, not to an individual target,
6346 * so we should maintain them accordingly.
6348 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
6350 IOLockUnlock(reserved
->interruptStatisticsLock
);
6352 return kIOReturnSuccess
;
6355 IOReturn
IOService::removeInterruptStatistics(int source
)
6357 IOInterruptAccountingData
* value
= NULL
;
6360 return kIOReturnBadArgument
;
6363 IOLockLock(reserved
->interruptStatisticsLock
);
6366 * We dynamically grow the statistics array, so an excessively
6367 * large index value has NEVER been registered. This either
6368 * means our cap on the array size is too small (unlikely), or
6369 * that we have been passed a corrupt index (this must be passed
6370 * the plain index into the interrupt specifier list).
6372 if (source
>= reserved
->interruptStatisticsArrayCount
) {
6373 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
6376 assert(reserved
->interruptStatisticsArray
);
6379 * If there is no existing entry, we are most likely trying to
6380 * free an interrupt owner twice, or we have corrupted the
6383 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
6386 panic("removeInterruptStatistics called for empty index %d", source
);
6390 * We update the statistics, so that any delta with the reporter
6391 * state is not lost.
6393 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
6394 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
6395 IOLockUnlock(reserved
->interruptStatisticsLock
);
6397 return kIOReturnSuccess
;
6400 IOReturn
IOService::getInterruptType(int source
, int *interruptType
)
6402 IOInterruptController
*interruptController
;
6405 ret
= lookupInterrupt(source
, true, &interruptController
);
6406 if (ret
!= kIOReturnSuccess
) return ret
;
6408 /* Return the type */
6409 return interruptController
->getInterruptType(this, source
, interruptType
);
6412 IOReturn
IOService::enableInterrupt(int source
)
6414 IOInterruptController
*interruptController
;
6417 ret
= lookupInterrupt(source
, false, &interruptController
);
6418 if (ret
!= kIOReturnSuccess
) return ret
;
6420 /* Enable the source */
6421 return interruptController
->enableInterrupt(this, source
);
6424 IOReturn
IOService::disableInterrupt(int source
)
6426 IOInterruptController
*interruptController
;
6429 ret
= lookupInterrupt(source
, false, &interruptController
);
6430 if (ret
!= kIOReturnSuccess
) return ret
;
6432 /* Disable the source */
6433 return interruptController
->disableInterrupt(this, source
);
6436 IOReturn
IOService::causeInterrupt(int source
)
6438 IOInterruptController
*interruptController
;
6441 ret
= lookupInterrupt(source
, false, &interruptController
);
6442 if (ret
!= kIOReturnSuccess
) return ret
;
6444 /* Cause an interrupt for the source */
6445 return interruptController
->causeInterrupt(this, source
);
6448 IOReturn
IOService::configureReport(IOReportChannelList
*channelList
,
6449 IOReportConfigureAction action
,
6455 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
6456 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
6457 if (pwrMgt
) configurePowerStatesReport(action
, result
);
6458 else return kIOReturnUnsupported
;
6460 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
6461 if (pwrMgt
) configureSimplePowerReport(action
, result
);
6462 else return kIOReturnUnsupported
;
6466 IOLockLock(reserved
->interruptStatisticsLock
);
6468 /* The array count is signed (because the interrupt indices are signed), hence the cast */
6469 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
6470 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
6472 * If the reporter is currently associated with the statistics
6473 * for an event source, we may need to update the reporter.
6475 if (reserved
->interruptStatisticsArray
[cnt
].statistics
)
6476 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
6478 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
6482 IOLockUnlock(reserved
->interruptStatisticsLock
);
6484 return kIOReturnSuccess
;
6487 IOReturn
IOService::updateReport(IOReportChannelList
*channelList
,
6488 IOReportUpdateAction action
,
6494 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
6495 if ( channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
6496 if (pwrMgt
) updatePowerStatesReport(action
, result
, destination
);
6497 else return kIOReturnUnsupported
;
6499 else if ( channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
6500 if (pwrMgt
) updateSimplePowerReport(action
, result
, destination
);
6501 else return kIOReturnUnsupported
;
6505 IOLockLock(reserved
->interruptStatisticsLock
);
6507 /* The array count is signed (because the interrupt indices are signed), hence the cast */
6508 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
6509 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
6511 * If the reporter is currently associated with the statistics
6512 * for an event source, we need to update the reporter.
6514 if (reserved
->interruptStatisticsArray
[cnt
].statistics
)
6515 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
6517 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
6521 IOLockUnlock(reserved
->interruptStatisticsLock
);
6523 return kIOReturnSuccess
;
6526 uint64_t IOService::getAuthorizationID( void )
6528 return reserved
->authorizationID
;
6531 IOReturn
IOService::setAuthorizationID( uint64_t authorizationID
)
6533 OSObject
* entitlement
;
6536 entitlement
= IOUserClient::copyClientEntitlement( current_task( ), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
6540 if ( entitlement
== kOSBooleanTrue
)
6542 reserved
->authorizationID
= authorizationID
;
6544 status
= kIOReturnSuccess
;
6548 status
= kIOReturnNotPrivileged
;
6551 entitlement
->release( );
6555 status
= kIOReturnNotPrivileged
;
6562 OSMetaClassDefineReservedUsed(IOService
, 0);
6563 OSMetaClassDefineReservedUsed(IOService
, 1);
6564 OSMetaClassDefineReservedUnused(IOService
, 2);
6565 OSMetaClassDefineReservedUnused(IOService
, 3);
6566 OSMetaClassDefineReservedUnused(IOService
, 4);
6567 OSMetaClassDefineReservedUnused(IOService
, 5);
6568 OSMetaClassDefineReservedUnused(IOService
, 6);
6569 OSMetaClassDefineReservedUnused(IOService
, 7);
6571 OSMetaClassDefineReservedUsed(IOService
, 0);
6572 OSMetaClassDefineReservedUsed(IOService
, 1);
6573 OSMetaClassDefineReservedUsed(IOService
, 2);
6574 OSMetaClassDefineReservedUsed(IOService
, 3);
6575 OSMetaClassDefineReservedUsed(IOService
, 4);
6576 OSMetaClassDefineReservedUsed(IOService
, 5);
6577 OSMetaClassDefineReservedUsed(IOService
, 6);
6578 OSMetaClassDefineReservedUsed(IOService
, 7);
6580 OSMetaClassDefineReservedUnused(IOService
, 8);
6581 OSMetaClassDefineReservedUnused(IOService
, 9);
6582 OSMetaClassDefineReservedUnused(IOService
, 10);
6583 OSMetaClassDefineReservedUnused(IOService
, 11);
6584 OSMetaClassDefineReservedUnused(IOService
, 12);
6585 OSMetaClassDefineReservedUnused(IOService
, 13);
6586 OSMetaClassDefineReservedUnused(IOService
, 14);
6587 OSMetaClassDefineReservedUnused(IOService
, 15);
6588 OSMetaClassDefineReservedUnused(IOService
, 16);
6589 OSMetaClassDefineReservedUnused(IOService
, 17);
6590 OSMetaClassDefineReservedUnused(IOService
, 18);
6591 OSMetaClassDefineReservedUnused(IOService
, 19);
6592 OSMetaClassDefineReservedUnused(IOService
, 20);
6593 OSMetaClassDefineReservedUnused(IOService
, 21);
6594 OSMetaClassDefineReservedUnused(IOService
, 22);
6595 OSMetaClassDefineReservedUnused(IOService
, 23);
6596 OSMetaClassDefineReservedUnused(IOService
, 24);
6597 OSMetaClassDefineReservedUnused(IOService
, 25);
6598 OSMetaClassDefineReservedUnused(IOService
, 26);
6599 OSMetaClassDefineReservedUnused(IOService
, 27);
6600 OSMetaClassDefineReservedUnused(IOService
, 28);
6601 OSMetaClassDefineReservedUnused(IOService
, 29);
6602 OSMetaClassDefineReservedUnused(IOService
, 30);
6603 OSMetaClassDefineReservedUnused(IOService
, 31);
6604 OSMetaClassDefineReservedUnused(IOService
, 32);
6605 OSMetaClassDefineReservedUnused(IOService
, 33);
6606 OSMetaClassDefineReservedUnused(IOService
, 34);
6607 OSMetaClassDefineReservedUnused(IOService
, 35);
6608 OSMetaClassDefineReservedUnused(IOService
, 36);
6609 OSMetaClassDefineReservedUnused(IOService
, 37);
6610 OSMetaClassDefineReservedUnused(IOService
, 38);
6611 OSMetaClassDefineReservedUnused(IOService
, 39);
6612 OSMetaClassDefineReservedUnused(IOService
, 40);
6613 OSMetaClassDefineReservedUnused(IOService
, 41);
6614 OSMetaClassDefineReservedUnused(IOService
, 42);
6615 OSMetaClassDefineReservedUnused(IOService
, 43);
6616 OSMetaClassDefineReservedUnused(IOService
, 44);
6617 OSMetaClassDefineReservedUnused(IOService
, 45);
6618 OSMetaClassDefineReservedUnused(IOService
, 46);
6619 OSMetaClassDefineReservedUnused(IOService
, 47);