1/*
2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <IOKit/system.h>
30
31#include <IOKit/IOService.h>
32#include <libkern/OSDebug.h>
33#include <libkern/c++/OSContainers.h>
34#include <libkern/c++/OSKext.h>
35#include <libkern/c++/OSUnserialize.h>
36#include <IOKit/IOCatalogue.h>
37#include <IOKit/IOCommand.h>
38#include <IOKit/IODeviceTreeSupport.h>
39#include <IOKit/IODeviceMemory.h>
40#include <IOKit/IOInterrupts.h>
41#include <IOKit/IOInterruptController.h>
42#include <IOKit/IOPlatformExpert.h>
43#include <IOKit/IOMessage.h>
44#include <IOKit/IOLib.h>
45#include <IOKit/IOKitKeysPrivate.h>
46#include <IOKit/IOBSD.h>
47#include <IOKit/IOUserClient.h>
48#include <IOKit/IOWorkLoop.h>
49#include <IOKit/IOTimeStamp.h>
50#include <IOKit/IOHibernatePrivate.h>
51#include <mach/sync_policy.h>
52#include <IOKit/assert.h>
53#include <sys/errno.h>
54
55#include <machine/pal_routines.h>
56
57#define LOG kprintf
58//#define LOG IOLog
59#define MATCH_DEBUG	0
60#define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
61
62#include "IOServicePrivate.h"
63#include "IOKitKernelInternal.h"
64
65// take lockForArbitration before LOCKNOTIFY
66
67/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
68
69#define super IORegistryEntry
70
71OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
72
73OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
74
75OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
76
77OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
78
79OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
80
81OSDefineMetaClassAndStructors(IOResources, IOService)
82
83OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
84
85OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject)
86
87/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88
89static IOPlatformExpert *	gIOPlatform;
90static class IOPMrootDomain *	gIOPMRootDomain;
91const IORegistryPlane *		gIOServicePlane;
92const IORegistryPlane *		gIOPowerPlane;
93const OSSymbol *		gIODeviceMemoryKey;
94const OSSymbol *		gIOInterruptControllersKey;
95const OSSymbol *		gIOInterruptSpecifiersKey;
96
97const OSSymbol *		gIOResourcesKey;
98const OSSymbol *		gIOResourceMatchKey;
99const OSSymbol *		gIOProviderClassKey;
100const OSSymbol * 		gIONameMatchKey;
101const OSSymbol *		gIONameMatchedKey;
102const OSSymbol *		gIOPropertyMatchKey;
103const OSSymbol *		gIOLocationMatchKey;
104const OSSymbol *		gIOParentMatchKey;
105const OSSymbol *		gIOPathMatchKey;
106const OSSymbol *		gIOMatchCategoryKey;
107const OSSymbol *		gIODefaultMatchCategoryKey;
108const OSSymbol *		gIOMatchedServiceCountKey;
109
110const OSSymbol *		gIOMapperIDKey;
111const OSSymbol *		gIOUserClientClassKey;
112const OSSymbol *		gIOKitDebugKey;
113
114const OSSymbol *		gIOCommandPoolSizeKey;
115
116const OSSymbol *		gIOConsoleLockedKey;
117const OSSymbol *		gIOConsoleUsersKey;
118const OSSymbol *		gIOConsoleSessionUIDKey;
119const OSSymbol *		gIOConsoleSessionAuditIDKey;
120const OSSymbol *		gIOConsoleUsersSeedKey;
121const OSSymbol *		gIOConsoleSessionOnConsoleKey;
122const OSSymbol *		gIOConsoleSessionLoginDoneKey;
123const OSSymbol *		gIOConsoleSessionSecureInputPIDKey;
124const OSSymbol *		gIOConsoleSessionScreenLockedTimeKey;
125
126clock_sec_t			gIOConsoleLockTime;
127static bool			gIOConsoleLoggedIn;
128#if HIBERNATION
129static uint32_t			gIOScreenLockState;
130#endif
131static IORegistryEntry *        gIOChosenEntry;
132
133static int			gIOResourceGenerationCount;
134
135const OSSymbol *		gIOServiceKey;
136const OSSymbol *		gIOPublishNotification;
137const OSSymbol *		gIOFirstPublishNotification;
138const OSSymbol *		gIOMatchedNotification;
139const OSSymbol *		gIOFirstMatchNotification;
140const OSSymbol *		gIOTerminatedNotification;
141
142const OSSymbol *		gIOGeneralInterest;
143const OSSymbol *		gIOBusyInterest;
144const OSSymbol *		gIOAppPowerStateInterest;
145const OSSymbol *		gIOPriorityPowerStateInterest;
146const OSSymbol *		gIOConsoleSecurityInterest;
147
148static OSDictionary * 		gNotifications;
149static IORecursiveLock *	gNotificationLock;
150
151static IOService *		gIOResources;
152static IOService * 		gIOServiceRoot;
153
154static OSOrderedSet *		gJobs;
155static semaphore_port_t		gJobsSemaphore;
156static IOLock *			gJobsLock;
157static int			gOutstandingJobs;
158static int			gNumConfigThreads;
159static int			gNumWaitingThreads;
160static IOLock *			gIOServiceBusyLock;
161
162static thread_t			gIOTerminateThread;
163static UInt32			gIOTerminateWork;
164static OSArray *		gIOTerminatePhase2List;
165static OSArray *		gIOStopList;
166static OSArray *		gIOStopProviderList;
167static OSArray *		gIOFinalizeList;
168
169static SInt32			gIOConsoleUsersSeed;
170static OSData *			gIOConsoleUsersSeedValue;
171
172extern const OSSymbol *		gIODTPHandleKey;
173
174const OSSymbol *		gIOPlatformSleepActionKey;
175const OSSymbol *		gIOPlatformWakeActionKey;
176const OSSymbol *		gIOPlatformQuiesceActionKey;
177const OSSymbol *		gIOPlatformActiveActionKey;
178
179const OSSymbol *		gIOPlatformFunctionHandlerSet;
180
181static IOLock *			gIOConsoleUsersLock;
182static thread_call_t		gIOConsoleLockCallout;
183
184/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185
186#define LOCKREADNOTIFY()	\
187    IORecursiveLockLock( gNotificationLock )
188#define LOCKWRITENOTIFY()	\
189    IORecursiveLockLock( gNotificationLock )
190#define LOCKWRITE2READNOTIFY()
191#define UNLOCKNOTIFY()		\
192    IORecursiveLockUnlock( gNotificationLock )
193#define SLEEPNOTIFY(event) \
194    IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
195#define SLEEPNOTIFYTO(event, deadline) \
196    IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
197#define WAKEUPNOTIFY(event) \
198	IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
199
200#define randomDelay()	\
201        int del = read_processor_clock();				\
202        del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff;	\
203        IOSleep( del );
204
205/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
206
207#define queue_element(entry, element, type, field) do {	\
208	vm_address_t __ele = (vm_address_t) (entry);	\
209	__ele -= -4 + ((size_t)(&((type) 4)->field));	\
210	(element) = (type) __ele;			\
211    } while(0)
212
213#define iterqueue(que, elt)				\
214	for (queue_entry_t elt = queue_first(que);	\
215	     !queue_end(que, elt);			\
216	     elt = queue_next(elt))
217
218/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
219
220struct ArbitrationLockQueueElement {
221    queue_chain_t link;
222    IOThread      thread;
223    IOService *   service;
224    unsigned      count;
225    bool          required;
226    bool          aborted;
227};
228
229static queue_head_t gArbitrationLockQueueActive;
230static queue_head_t gArbitrationLockQueueWaiting;
231static queue_head_t gArbitrationLockQueueFree;
232static IOLock *     gArbitrationLockQueueLock;
233
234bool IOService::isInactive( void ) const
235    { return( 0 != (kIOServiceInactiveState & getState())); }
236
237/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
238
239#if defined(__i386__) || defined(__x86_64__)
240
241// Only used by the intel implementation of
242//     IOService::requireMaxBusStall(UInt32 ns)
243//     IOService::requireMaxInterruptDelay(uint32_t ns)
244struct CpuDelayEntry
245{
246    IOService * fService;
247    UInt32      fMaxDelay;
248    UInt32      fDelayType;
249};
250
251enum {
252    kCpuDelayBusStall, kCpuDelayInterrupt,
253    kCpuNumDelayTypes
254};
255
256static OSData          *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry));
257static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc();
258static OSArray         *sCpuLatencyHandlers[kCpuNumDelayTypes];
259const OSSymbol         *sCPULatencyFunctionName[kCpuNumDelayTypes];
260
261static void
262requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType);
263static IOReturn
264setLatencyHandler(UInt32 delayType, IOService * target, bool enable);
265
266#endif /* defined(__i386__) || defined(__x86_64__) */
267
268/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
269
270void IOService::initialize( void )
271{
272    kern_return_t	err;
273
274    gIOServicePlane	= IORegistryEntry::makePlane( kIOServicePlane );
275    gIOPowerPlane 	= IORegistryEntry::makePlane( kIOPowerPlane );
276
277    gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey );
278    gIONameMatchKey	= OSSymbol::withCStringNoCopy( kIONameMatchKey );
279    gIONameMatchedKey	= OSSymbol::withCStringNoCopy( kIONameMatchedKey );
280    gIOPropertyMatchKey	= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey );
281    gIOPathMatchKey 	= OSSymbol::withCStringNoCopy( kIOPathMatchKey );
282    gIOLocationMatchKey	= OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
283    gIOParentMatchKey	= OSSymbol::withCStringNoCopy( kIOParentMatchKey );
284
285    gIOMatchCategoryKey	= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey );
286    gIODefaultMatchCategoryKey	= OSSymbol::withCStringNoCopy(
287					kIODefaultMatchCategoryKey );
288    gIOMatchedServiceCountKey	= OSSymbol::withCStringNoCopy(
289					kIOMatchedServiceCountKey );
290
291    gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey );
292
293    gIOResourcesKey	= OSSymbol::withCStringNoCopy( kIOResourcesClass );
294    gIOResourceMatchKey	= OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
295
296    gIODeviceMemoryKey	= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
297    gIOInterruptControllersKey
298	= OSSymbol::withCStringNoCopy("IOInterruptControllers");
299    gIOInterruptSpecifiersKey
300	= OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
301
302    gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey);
303
304    gIOKitDebugKey	= OSSymbol::withCStringNoCopy( kIOKitDebugKey );
305
306    gIOCommandPoolSizeKey	= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey );
307
308    gIOGeneralInterest 		= OSSymbol::withCStringNoCopy( kIOGeneralInterest );
309    gIOBusyInterest   		= OSSymbol::withCStringNoCopy( kIOBusyInterest );
310    gIOAppPowerStateInterest   	= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest );
311    gIOPriorityPowerStateInterest   	= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
312    gIOConsoleSecurityInterest 	= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
313
314    gNotifications		= OSDictionary::withCapacity( 1 );
315    gIOPublishNotification	= OSSymbol::withCStringNoCopy(
316						 kIOPublishNotification );
317    gIOFirstPublishNotification	= OSSymbol::withCStringNoCopy(
318                                                 kIOFirstPublishNotification );
319    gIOMatchedNotification	= OSSymbol::withCStringNoCopy(
320						 kIOMatchedNotification );
321    gIOFirstMatchNotification	= OSSymbol::withCStringNoCopy(
322						 kIOFirstMatchNotification );
323    gIOTerminatedNotification	= OSSymbol::withCStringNoCopy(
324						 kIOTerminatedNotification );
325    gIOServiceKey		= OSSymbol::withCStringNoCopy( kIOServiceClass);
326
327    gIOConsoleLockedKey		= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey);
328    gIOConsoleUsersKey		= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
329    gIOConsoleSessionUIDKey	= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
330    gIOConsoleSessionAuditIDKey	= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey);
331
332    gIOConsoleUsersSeedKey	         = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey);
333    gIOConsoleSessionOnConsoleKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey);
334    gIOConsoleSessionLoginDoneKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey);
335    gIOConsoleSessionSecureInputPIDKey   = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey);
336    gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey);
337
338    gIOConsoleUsersSeedValue	       = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
339
340    gIOPlatformSleepActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey);
341    gIOPlatformWakeActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey);
342    gIOPlatformQuiesceActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey);
343    gIOPlatformActiveActionKey	= OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey);
344
345    gIOPlatformFunctionHandlerSet		= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet);
346#if defined(__i386__) || defined(__x86_64__)
347    sCPULatencyFunctionName[kCpuDelayBusStall]	= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay);
348    sCPULatencyFunctionName[kCpuDelayInterrupt]	= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay);
349#endif
350    gNotificationLock	 	= IORecursiveLockAlloc();
351
352    assert( gIOServicePlane && gIODeviceMemoryKey
353        && gIOInterruptControllersKey && gIOInterruptSpecifiersKey
354        && gIOResourcesKey && gNotifications && gNotificationLock
355        && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey
356	&& gIOMatchCategoryKey && gIODefaultMatchCategoryKey
357        && gIOPublishNotification && gIOMatchedNotification
358        && gIOTerminatedNotification && gIOServiceKey
359	&& gIOConsoleUsersKey && gIOConsoleSessionUIDKey
360    && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey
361	&& gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue);
362
363    gJobsLock	= IOLockAlloc();
364    gJobs 	= OSOrderedSet::withCapacity( 10 );
365
366    gIOServiceBusyLock = IOLockAlloc();
367
368    gIOConsoleUsersLock = IOLockAlloc();
369
370    err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
371
372    gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL);
373
374    IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue);
375
376    assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock
377    		&& gIOConsoleLockCallout && (err == KERN_SUCCESS) );
378
379    gIOResources = IOResources::resources();
380    assert( gIOResources );
381
382    gArbitrationLockQueueLock = IOLockAlloc();
383    queue_init(&gArbitrationLockQueueActive);
384    queue_init(&gArbitrationLockQueueWaiting);
385    queue_init(&gArbitrationLockQueueFree);
386
387    assert( gArbitrationLockQueueLock );
388
389    gIOTerminatePhase2List = OSArray::withCapacity( 2 );
390    gIOStopList            = OSArray::withCapacity( 16 );
391    gIOStopProviderList    = OSArray::withCapacity( 16 );
392    gIOFinalizeList	   = OSArray::withCapacity( 16 );
393    assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
394}
395
396/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
397
398#if IOMATCHDEBUG
399static UInt64 getDebugFlags( OSDictionary * props )
400{
401    OSNumber *	debugProp;
402    UInt64	debugFlags;
403
404    debugProp = OSDynamicCast( OSNumber,
405		props->getObject( gIOKitDebugKey ));
406    if( debugProp)
407	debugFlags = debugProp->unsigned64BitValue();
408    else
409	debugFlags = gIOKitDebug;
410
411    return( debugFlags );
412}
413#endif
414
415/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
416
417// Probe a matched service and return an instance to be started.
418// The default score is from the property table, & may be altered
419// during probe to change the start order.
420
421IOService * IOService::probe(	IOService * provider,
422				SInt32	  * score )
423{
424    return( this );
425}
426
427bool IOService::start( IOService * provider )
428{
429    return( true );
430}
431
432void IOService::stop( IOService * provider )
433{
434}
435
436void IOService::free( void )
437{
438    requireMaxBusStall(0);
439    requireMaxInterruptDelay(0);
440    if( getPropertyTable())
441        unregisterAllInterest();
442    PMfree();
443    super::free();
444}
445
446/*
447 * Attach in service plane
448 */
449bool IOService::attach( IOService * provider )
450{
451    bool	ok;
452
453    if( provider) {
454
455	if( gIOKitDebug & kIOLogAttach)
456            LOG( "%s::attach(%s)\n", getName(),
457                    provider->getName());
458
459        provider->lockForArbitration();
460        if( provider->__state[0] & kIOServiceInactiveState)
461            ok = false;
462        else
463            ok = attachToParent( provider, gIOServicePlane);
464        provider->unlockForArbitration();
465
466    } else {
467	gIOServiceRoot = this;
468	ok = attachToParent( getRegistryRoot(), gIOServicePlane);
469    }
470
471    if (ok && !__provider) (void) getProvider();
472
473    return( ok );
474}
475
476IOService * IOService::getServiceRoot( void )
477{
478    return( gIOServiceRoot );
479}
480
481void IOService::detach( IOService * provider )
482{
483    IOService * newProvider = 0;
484    SInt32	busy;
485    bool	adjParent;
486
487    if( gIOKitDebug & kIOLogAttach)
488        LOG("%s::detach(%s)\n", getName(), provider->getName());
489
490    lockForArbitration();
491
492    adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask))
493               && (provider == getProvider()));
494
495    detachFromParent( provider, gIOServicePlane );
496
497    if( busy) {
498        newProvider = getProvider();
499        if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider))
500            _adjustBusy( -busy );
501    }
502
503    if (kIOServiceInactiveState & __state[0]) {
504	getMetaClass()->removeInstance(this);
505    }
506
507    unlockForArbitration();
508
509    if( newProvider) {
510        newProvider->lockForArbitration();
511        newProvider->_adjustBusy(1);
512        newProvider->unlockForArbitration();
513    }
514
515    // check for last client detach from a terminated service
516    if( provider->lockForArbitration( true )) {
517        if( adjParent)
518            provider->_adjustBusy( -1 );
519        if( (provider->__state[1] & kIOServiceTermPhase3State)
520         && (0 == provider->getClient())) {
521            provider->scheduleFinalize();
522        }
523        provider->unlockForArbitration();
524    }
525}
526
527/*
528 * Register instance - publish it for matching
529 */
530
531void IOService::registerService( IOOptionBits options )
532{
533    char *		pathBuf;
534    const char *	path;
535    char *		skip;
536    int			len;
537    enum { kMaxPathLen	= 256 };
538    enum { kMaxChars	= 63 };
539
540    IORegistryEntry * parent = this;
541    IORegistryEntry * root = getRegistryRoot();
542    while( parent && (parent != root))
543        parent = parent->getParentEntry( gIOServicePlane);
544
545    if( parent != root) {
546        IOLog("%s: not registry member at registerService()\n", getName());
547        return;
548    }
549
550    // Allow the Platform Expert to adjust this node.
551    if( gIOPlatform && (!gIOPlatform->platformAdjustService(this)))
552	return;
553
554    if( (this != gIOResources)
555     && (kIOLogRegister & gIOKitDebug)) {
556
557        pathBuf = (char *) IOMalloc( kMaxPathLen );
558
559        IOLog( "Registering: " );
560
561        len = kMaxPathLen;
562        if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) {
563
564            path = pathBuf;
565            if( len > kMaxChars) {
566                IOLog("..");
567                len -= kMaxChars;
568                path += len;
569                if( (skip = strchr( path, '/')))
570                    path = skip;
571            }
572        } else
573            path = getName();
574
575        IOLog( "%s\n", path );
576
577	if( pathBuf)
578	    IOFree( pathBuf, kMaxPathLen );
579    }
580
581    startMatching( options );
582}
583
584void IOService::startMatching( IOOptionBits options )
585{
586    IOService *	provider;
587    UInt32	prevBusy = 0;
588    bool	needConfig;
589    bool	needWake = false;
590    bool	ok;
591    bool	sync;
592    bool	waitAgain;
593
594    lockForArbitration();
595
596    sync = (options & kIOServiceSynchronous)
597	|| ((provider = getProvider())
598		&& (provider->__state[1] & kIOServiceSynchronousState));
599
600	if ( options & kIOServiceAsynchronous )
601		sync = false;
602
603    needConfig =  (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState)))
604	       && (0 == (__state[0] & kIOServiceInactiveState));
605
606    __state[1] |= kIOServiceNeedConfigState;
607
608//    __state[0] &= ~kIOServiceInactiveState;
609
610//    if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
611//			OSKernelStackRemaining(), getName());
612
613    if( needConfig) {
614        needWake = (0 != (kIOServiceSyncPubState & __state[1]));
615    }
616
617    if( sync)
618	__state[1] |= kIOServiceSynchronousState;
619    else
620	__state[1] &= ~kIOServiceSynchronousState;
621
622    if( needConfig) prevBusy = _adjustBusy( 1 );
623
624    unlockForArbitration();
625
626    if( needConfig) {
627
628        if( needWake) {
629            IOLockLock( gIOServiceBusyLock );
630            thread_wakeup( (event_t) this/*&__state[1]*/ );
631            IOLockUnlock( gIOServiceBusyLock );
632
633        } else if( !sync || (kIOServiceAsynchronous & options)) {
634
635            ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options ));
636
637        } else do {
638
639            if( (__state[1] & kIOServiceNeedConfigState))
640                doServiceMatch( options );
641
642            lockForArbitration();
643            IOLockLock( gIOServiceBusyLock );
644
645            waitAgain = ((prevBusy < (__state[1] & kIOServiceBusyStateMask))
646				       && (0 == (__state[0] & kIOServiceInactiveState)));
647
648            if( waitAgain)
649                __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState;
650            else
651                __state[1] &= ~kIOServiceSyncPubState;
652
653            unlockForArbitration();
654
655            if( waitAgain)
656                assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT);
657
658            IOLockUnlock( gIOServiceBusyLock );
659            if( waitAgain)
660                thread_block(THREAD_CONTINUE_NULL);
661
662        } while( waitAgain );
663    }
664}
665
666IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables )
667{
668    OSDictionary *	table;
669    OSSet *	        set;
670    OSSet *	        allSet = 0;
671    IOService *		service;
672#if IOMATCHDEBUG
673    SInt32		count = 0;
674#endif
675
676    newTables->retain();
677
678    while( (table = (OSDictionary *) newTables->getFirstObject())) {
679
680        LOCKWRITENOTIFY();
681        set = (OSSet *) copyExistingServices( table,
682						kIOServiceRegisteredState,
683						kIOServiceExistingSet);
684        UNLOCKNOTIFY();
685        if( set) {
686
687#if IOMATCHDEBUG
688            count += set->getCount();
689#endif
690            if (allSet) {
691                allSet->merge((const OSSet *) set);
692                set->release();
693            }
694            else
695                allSet = set;
696        }
697
698#if IOMATCHDEBUG
699        if( getDebugFlags( table ) & kIOLogMatch)
700            LOG("Matching service count = %ld\n", (long)count);
701#endif
702        newTables->removeObject(table);
703    }
704
705    if (allSet) {
706        while( (service = (IOService *) allSet->getAnyObject())) {
707            service->startMatching(kIOServiceAsynchronous);
708            allSet->removeObject(service);
709        }
710        allSet->release();
711    }
712
713    newTables->release();
714
715    return( kIOReturnSuccess );
716}
717
718 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type,
719						IOOptionBits options )
720{
721    _IOServiceJob *	job;
722
723    job = new _IOServiceJob;
724    if( job && !job->init()) {
725        job->release();
726        job = 0;
727    }
728
729    if( job) {
730        job->type	= type;
731        job->nub	= nub;
732	job->options	= options;
733        nub->retain();			// thread will release()
734        pingConfig( job );
735    }
736
737    return( job );
738}
739
740/*
741 * Called on a registered service to see if it matches
742 * a property table.
743 */
744
745bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score )
746{
747    return( matchPropertyTable(table) );
748}
749
750bool IOService::matchPropertyTable( OSDictionary * table )
751{
752    return( true );
753}
754
755/*
756 * Called on a matched service to allocate resources
757 * before first driver is attached.
758 */
759
760IOReturn IOService::getResources( void )
761{
762    return( kIOReturnSuccess);
763}
764
765/*
766 * Client/provider accessors
767 */
768
769IOService * IOService::getProvider( void ) const
770{
771    IOService *	self = (IOService *) this;
772    IOService *	parent;
773    SInt32	generation;
774
775    generation = getGenerationCount();
776    if( __providerGeneration == generation)
777	return( __provider );
778
779    parent = (IOService *) getParentEntry( gIOServicePlane);
780    if( parent == IORegistryEntry::getRegistryRoot())
781	/* root is not an IOService */
782	parent = 0;
783
784    self->__provider = parent;
785    OSMemoryBarrier();
786    // save the count from before call to getParentEntry()
787    self->__providerGeneration = generation;
788
789    return( parent );
790}
791
792IOWorkLoop * IOService::getWorkLoop() const
793{
794    IOService *provider = getProvider();
795
796    if (provider)
797	return provider->getWorkLoop();
798    else
799	return 0;
800}
801
802OSIterator * IOService::getProviderIterator( void ) const
803{
804    return( getParentIterator( gIOServicePlane));
805}
806
807IOService * IOService::getClient( void ) const
808{
809    return( (IOService *) getChildEntry( gIOServicePlane));
810}
811
812OSIterator * IOService::getClientIterator( void ) const
813{
814    return( getChildIterator( gIOServicePlane));
815}
816
817OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter,
818						const IOService * client,
819						const IOService * provider )
820{
821    _IOOpenServiceIterator * inst;
822
823    if( !_iter)
824	return( 0 );
825
826    inst = new _IOOpenServiceIterator;
827
828    if( inst && !inst->init()) {
829	inst->release();
830	inst = 0;
831    }
832    if( inst) {
833	inst->iter = _iter;
834	inst->client = client;
835	inst->provider = provider;
836    }
837
838    return( inst );
839}
840
841void _IOOpenServiceIterator::free()
842{
843    iter->release();
844    if( last)
845	last->unlockForArbitration();
846    OSIterator::free();
847}
848
849OSObject * _IOOpenServiceIterator::getNextObject()
850{
851    IOService * next;
852
853    if( last)
854	last->unlockForArbitration();
855
856    while( (next = (IOService *) iter->getNextObject())) {
857
858	next->lockForArbitration();
859	if( (client && (next->isOpen( client )))
860	 || (provider && (provider->isOpen( next ))) )
861            break;
862	next->unlockForArbitration();
863    }
864
865    last = next;
866
867    return( next );
868}
869
870bool _IOOpenServiceIterator::isValid()
871{
872    return( iter->isValid() );
873}
874
875void _IOOpenServiceIterator::reset()
876{
877    if( last) {
878	last->unlockForArbitration();
879	last = 0;
880    }
881    iter->reset();
882}
883
884OSIterator * IOService::getOpenProviderIterator( void ) const
885{
886    return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
887}
888
889OSIterator * IOService::getOpenClientIterator( void ) const
890{
891    return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
892}
893
894
895IOReturn IOService::callPlatformFunction( const OSSymbol * functionName,
896					  bool waitForFunction,
897					  void *param1, void *param2,
898					  void *param3, void *param4 )
899{
900  IOReturn  result = kIOReturnUnsupported;
901  IOService *provider;
902
903  if (gIOPlatformFunctionHandlerSet == functionName)
904  {
905#if defined(__i386__) || defined(__x86_64__)
906    const OSSymbol * functionHandlerName = (const OSSymbol *) param1;
907    IOService *	     target		 = (IOService *) param2;
908    bool	     enable		 = (param3 != 0);
909
910    if (sCPULatencyFunctionName[kCpuDelayBusStall] == functionHandlerName)
911	result = setLatencyHandler(kCpuDelayBusStall, target, enable);
912    else if (sCPULatencyFunctionName[kCpuDelayInterrupt] == param1)
913	result = setLatencyHandler(kCpuDelayInterrupt, target, enable);
914#endif /* defined(__i386__) || defined(__x86_64__) */
915  }
916
917  if ((kIOReturnUnsupported == result) && (provider = getProvider())) {
918    result = provider->callPlatformFunction(functionName, waitForFunction,
919					    param1, param2, param3, param4);
920  }
921
922  return result;
923}
924
925IOReturn IOService::callPlatformFunction( const char * functionName,
926					  bool waitForFunction,
927					  void *param1, void *param2,
928					  void *param3, void *param4 )
929{
930  IOReturn result = kIOReturnNoMemory;
931  const OSSymbol *functionSymbol = OSSymbol::withCString(functionName);
932
933  if (functionSymbol != 0) {
934    result = callPlatformFunction(functionSymbol, waitForFunction,
935				  param1, param2, param3, param4);
936    functionSymbol->release();
937  }
938
939  return result;
940}
941
942
943/*
944 * Accessors for global services
945 */
946
947IOPlatformExpert * IOService::getPlatform( void )
948{
949    return( gIOPlatform);
950}
951
952class IOPMrootDomain * IOService::getPMRootDomain( void )
953{
954    return( gIOPMRootDomain);
955}
956
957IOService * IOService::getResourceService( void )
958{
959    return( gIOResources );
960}
961
962void IOService::setPlatform( IOPlatformExpert * platform)
963{
964    gIOPlatform = platform;
965    gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
966}
967
968void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
969{
970    gIOPMRootDomain = rootDomain;
971    publishResource("IOKit");
972}
973
974/*
975 * Stacking change
976 */
977
978bool IOService::lockForArbitration( bool isSuccessRequired )
979{
980    bool                          found;
981    bool                          success;
982    ArbitrationLockQueueElement * element;
983    ArbitrationLockQueueElement * active;
984    ArbitrationLockQueueElement * waiting;
985
986    enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action;
987
988    // lock global access
989    IOTakeLock( gArbitrationLockQueueLock );
990
991    // obtain an unused queue element
992    if( !queue_empty( &gArbitrationLockQueueFree )) {
993        queue_remove_first( &gArbitrationLockQueueFree,
994                            element,
995                            ArbitrationLockQueueElement *,
996                            link );
997    } else {
998        element = IONew( ArbitrationLockQueueElement, 1 );
999        assert( element );
1000    }
1001
1002    // prepare the queue element
1003    element->thread   = IOThreadSelf();
1004    element->service  = this;
1005    element->count    = 1;
1006    element->required = isSuccessRequired;
1007    element->aborted  = false;
1008
1009    // determine whether this object is already locked (ie. on active queue)
1010    found = false;
1011    queue_iterate( &gArbitrationLockQueueActive,
1012                    active,
1013                    ArbitrationLockQueueElement *,
1014                    link )
1015    {
1016        if( active->service == element->service ) {
1017            found = true;
1018            break;
1019        }
1020    }
1021
1022    if( found ) { // this object is already locked
1023
1024        // determine whether it is the same or a different thread trying to lock
1025        if( active->thread != element->thread ) { // it is a different thread
1026
1027            ArbitrationLockQueueElement * victim = 0;
1028
1029            // before placing this new thread on the waiting queue, we look for
1030            // a deadlock cycle...
1031
1032            while( 1 ) {
1033                // determine whether the active thread holding the object we
1034                // want is waiting for another object to be unlocked
1035                found = false;
1036                queue_iterate( &gArbitrationLockQueueWaiting,
1037                               waiting,
1038                               ArbitrationLockQueueElement *,
1039                               link )
1040                {
1041                    if( waiting->thread == active->thread ) {
1042                        assert( false == waiting->aborted );
1043                        found = true;
1044                        break;
1045                    }
1046                }
1047
1048                if( found ) { // yes, active thread waiting for another object
1049
1050                    // this may be a candidate for rejection if the required
1051                    // flag is not set, should we detect a deadlock later on
1052                    if( false == waiting->required )
1053                        victim = waiting;
1054
1055                    // find the thread that is holding this other object, that
1056                    // is blocking the active thread from proceeding (fun :-)
1057                    found = false;
1058                    queue_iterate( &gArbitrationLockQueueActive,
1059                                   active,      // (reuse active queue element)
1060                                   ArbitrationLockQueueElement *,
1061                                   link )
1062                    {
1063                        if( active->service == waiting->service ) {
1064                            found = true;
1065                            break;
1066                        }
1067                    }
1068
1069                    // someone must be holding it or it wouldn't be waiting
1070                    assert( found );
1071
1072                    if( active->thread == element->thread ) {
1073
1074                        // doh, it's waiting for the thread that originated
1075                        // this whole lock (ie. current thread) -> deadlock
1076                        if( false == element->required ) { // willing to fail?
1077
1078                            // the originating thread doesn't have the required
1079                            // flag, so it can fail
1080                            success = false; // (fail originating lock request)
1081                            break; // (out of while)
1082
1083                        } else { // originating thread is not willing to fail
1084
1085                            // see if we came across a waiting thread that did
1086                            // not have the 'required' flag set: we'll fail it
1087                            if( victim ) {
1088
1089                                // we do have a willing victim, fail it's lock
1090                                victim->aborted = true;
1091
1092                                // take the victim off the waiting queue
1093                                queue_remove( &gArbitrationLockQueueWaiting,
1094                                              victim,
1095                                              ArbitrationLockQueueElement *,
1096                                              link );
1097
1098                                // wake the victim
1099                                IOLockWakeup( gArbitrationLockQueueLock,
1100                                              victim,
1101                                              /* one thread */ true );
1102
1103                                // allow this thread to proceed (ie. wait)
1104                                success = true; // (put request on wait queue)
1105                                break; // (out of while)
1106                            } else {
1107
1108                                // all the waiting threads we came across in
1109                                // finding this loop had the 'required' flag
1110                                // set, so we've got a deadlock we can't avoid
1111                                panic("I/O Kit: Unrecoverable deadlock.");
1112                            }
1113                        }
1114                    } else {
1115                        // repeat while loop, redefining active thread to be the
1116                        // thread holding "this other object" (see above), and
1117                        // looking for threads waiting on it; note the active
1118                        // variable points to "this other object" already... so
1119                        // there nothing to do in this else clause.
1120                    }
1121                } else { // no, active thread is not waiting for another object
1122
1123                    success = true; // (put request on wait queue)
1124                    break; // (out of while)
1125                }
1126            } // while forever
1127
1128            if( success ) { // put the request on the waiting queue?
1129                kern_return_t wait_result;
1130
1131                // place this thread on the waiting queue and put it to sleep;
1132                // we place it at the tail of the queue...
1133                queue_enter( &gArbitrationLockQueueWaiting,
1134                             element,
1135                             ArbitrationLockQueueElement *,
1136                             link );
1137
1138                // declare that this thread will wait for a given event
1139restart_sleep:  wait_result = assert_wait( element,
1140					   element->required ? THREAD_UNINT
1141					   : THREAD_INTERRUPTIBLE );
1142
1143                // unlock global access
1144                IOUnlock( gArbitrationLockQueueLock );
1145
1146                // put thread to sleep, waiting for our event to fire...
1147		if (wait_result == THREAD_WAITING)
1148		    wait_result = thread_block(THREAD_CONTINUE_NULL);
1149
1150
1151                // ...and we've been woken up; we might be in one of two states:
1152                // (a) we've been aborted and our queue element is not on
1153                //     any of the three queues, but is floating around
1154                // (b) we're allowed to proceed with the lock and we have
1155                //     already been moved from the waiting queue to the
1156                //     active queue.
1157                // ...plus a 3rd state, should the thread have been interrupted:
1158                // (c) we're still on the waiting queue
1159
1160                // determine whether we were interrupted out of our sleep
1161                if( THREAD_INTERRUPTED == wait_result ) {
1162
1163                    // re-lock global access
1164                    IOTakeLock( gArbitrationLockQueueLock );
1165
1166                    // determine whether we're still on the waiting queue
1167                    found = false;
1168                    queue_iterate( &gArbitrationLockQueueWaiting,
1169                                   waiting,     // (reuse waiting queue element)
1170                                   ArbitrationLockQueueElement *,
1171                                   link )
1172                    {
1173                        if( waiting == element ) {
1174                            found = true;
1175                            break;
1176                        }
1177                    }
1178
1179                    if( found ) { // yes, we're still on the waiting queue
1180
1181                        // determine whether we're willing to fail
1182                        if( false == element->required ) {
1183
1184                            // mark us as aborted
1185                            element->aborted = true;
1186
1187                            // take us off the waiting queue
1188                            queue_remove( &gArbitrationLockQueueWaiting,
1189                                          element,
1190                                          ArbitrationLockQueueElement *,
1191                                          link );
1192                        } else { // we are not willing to fail
1193
1194                            // ignore interruption, go back to sleep
1195                            goto restart_sleep;
1196                        }
1197                    }
1198
1199                    // unlock global access
1200                    IOUnlock( gArbitrationLockQueueLock );
1201
1202                    // proceed as though this were a normal wake up
1203                    wait_result = THREAD_AWAKENED;
1204                }
1205
1206                assert( THREAD_AWAKENED == wait_result );
1207
1208                // determine whether we've been aborted while we were asleep
1209                if( element->aborted ) {
1210                    assert( false == element->required );
1211
1212                    // re-lock global access
1213                    IOTakeLock( gArbitrationLockQueueLock );
1214
1215                    action = kPutOnFreeQueue;
1216                    success = false;
1217                } else { // we weren't aborted, so we must be ready to go :-)
1218
1219                    // we've already been moved from waiting to active queue
1220                    return true;
1221                }
1222
1223            } else { // the lock request is to be failed
1224
1225                // return unused queue element to queue
1226                action = kPutOnFreeQueue;
1227            }
1228        } else { // it is the same thread, recursive access is allowed
1229
1230            // add one level of recursion
1231            active->count++;
1232
1233            // return unused queue element to queue
1234            action = kPutOnFreeQueue;
1235            success = true;
1236        }
1237    } else { // this object is not already locked, so let this thread through
1238        action = kPutOnActiveQueue;
1239        success = true;
1240    }
1241
1242    // put the new element on a queue
1243    if( kPutOnActiveQueue == action ) {
1244        queue_enter( &gArbitrationLockQueueActive,
1245                     element,
1246                     ArbitrationLockQueueElement *,
1247                     link );
1248    } else if( kPutOnFreeQueue == action ) {
1249        queue_enter( &gArbitrationLockQueueFree,
1250                     element,
1251                     ArbitrationLockQueueElement *,
1252                     link );
1253    } else {
1254        assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1255    }
1256
1257    // unlock global access
1258    IOUnlock( gArbitrationLockQueueLock );
1259
1260    return( success );
1261}
1262
1263void IOService::unlockForArbitration( void )
1264{
1265    bool                          found;
1266    ArbitrationLockQueueElement * element;
1267
1268    // lock global access
1269    IOTakeLock( gArbitrationLockQueueLock );
1270
1271    // find the lock element for this object (ie. on active queue)
1272    found = false;
1273    queue_iterate( &gArbitrationLockQueueActive,
1274                    element,
1275                    ArbitrationLockQueueElement *,
1276                    link )
1277    {
1278        if( element->service == this ) {
1279            found = true;
1280            break;
1281        }
1282    }
1283
1284    assert( found );
1285
1286    // determine whether the lock has been taken recursively
1287    if( element->count > 1 ) {
1288        // undo one level of recursion
1289        element->count--;
1290
1291    } else {
1292
1293        // remove it from the active queue
1294        queue_remove( &gArbitrationLockQueueActive,
1295                      element,
1296                      ArbitrationLockQueueElement *,
1297                      link );
1298
1299        // put it on the free queue
1300        queue_enter( &gArbitrationLockQueueFree,
1301                     element,
1302                     ArbitrationLockQueueElement *,
1303                     link );
1304
1305        // determine whether a thread is waiting for object (head to tail scan)
1306        found = false;
1307        queue_iterate( &gArbitrationLockQueueWaiting,
1308                       element,
1309                       ArbitrationLockQueueElement *,
1310                       link )
1311        {
1312            if( element->service == this ) {
1313                found = true;
1314                break;
1315            }
1316        }
1317
1318        if ( found ) { // we found an interested thread on waiting queue
1319
1320            // remove it from the waiting queue
1321            queue_remove( &gArbitrationLockQueueWaiting,
1322                          element,
1323                          ArbitrationLockQueueElement *,
1324                          link );
1325
1326            // put it on the active queue
1327            queue_enter( &gArbitrationLockQueueActive,
1328                         element,
1329                         ArbitrationLockQueueElement *,
1330                         link );
1331
1332            // wake the waiting thread
1333            IOLockWakeup( gArbitrationLockQueueLock,
1334                          element,
1335                          /* one thread */ true );
1336        }
1337    }
1338
1339    // unlock global access
1340    IOUnlock( gArbitrationLockQueueLock );
1341}
1342
1343void IOService::applyToProviders( IOServiceApplierFunction applier,
1344                                  void * context )
1345{
1346    applyToParents( (IORegistryEntryApplierFunction) applier,
1347                    context, gIOServicePlane );
1348}
1349
1350void IOService::applyToClients( IOServiceApplierFunction applier,
1351                                void * context )
1352{
1353    applyToChildren( (IORegistryEntryApplierFunction) applier,
1354                     context, gIOServicePlane );
1355}
1356
1357
1358/*
1359 * Client messages
1360 */
1361
1362
1363// send a message to a client or interested party of this service
1364IOReturn IOService::messageClient( UInt32 type, OSObject * client,
1365                                   void * argument, vm_size_t argSize )
1366{
1367    IOReturn 				ret;
1368    IOService * 			service;
1369    _IOServiceInterestNotifier *	notify;
1370
1371    if( (service = OSDynamicCast( IOService, client)))
1372        ret = service->message( type, this, argument );
1373
1374    else if( (notify = OSDynamicCast( _IOServiceInterestNotifier, client))) {
1375
1376        _IOServiceNotifierInvocation invocation;
1377        bool			 willNotify;
1378
1379        invocation.thread = current_thread();
1380
1381        LOCKWRITENOTIFY();
1382        willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
1383
1384        if( willNotify) {
1385            queue_enter( &notify->handlerInvocations, &invocation,
1386                            _IOServiceNotifierInvocation *, link );
1387        }
1388        UNLOCKNOTIFY();
1389
1390        if( willNotify) {
1391
1392            ret = (*notify->handler)( notify->target, notify->ref,
1393                                          type, this, argument, argSize );
1394
1395            LOCKWRITENOTIFY();
1396            queue_remove( &notify->handlerInvocations, &invocation,
1397                            _IOServiceNotifierInvocation *, link );
1398            if( kIOServiceNotifyWaiter & notify->state) {
1399                notify->state &= ~kIOServiceNotifyWaiter;
1400                WAKEUPNOTIFY( notify );
1401            }
1402            UNLOCKNOTIFY();
1403
1404        } else
1405            ret = kIOReturnSuccess;
1406
1407    } else
1408        ret = kIOReturnBadArgument;
1409
1410    return( ret );
1411}
1412
1413static void
1414applyToInterestNotifiers(const IORegistryEntry *target,
1415			 const OSSymbol * typeOfInterest,
1416			 OSObjectApplierFunction applier,
1417			 void * context )
1418{
1419    OSArray *		copyArray = 0;
1420
1421    LOCKREADNOTIFY();
1422
1423    IOCommand *notifyList =
1424	OSDynamicCast( IOCommand, target->getProperty( typeOfInterest ));
1425
1426    if( notifyList) {
1427        copyArray = OSArray::withCapacity(1);
1428
1429	// iterate over queue, entry is set to each element in the list
1430	iterqueue(&notifyList->fCommandChain, entry) {
1431	    _IOServiceInterestNotifier * notify;
1432
1433	    queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
1434	    copyArray->setObject(notify);
1435	}
1436    }
1437    UNLOCKNOTIFY();
1438
1439    if( copyArray) {
1440	unsigned int	index;
1441	OSObject *	next;
1442
1443	for( index = 0; (next = copyArray->getObject( index )); index++)
1444	    (*applier)(next, context);
1445	copyArray->release();
1446    }
1447}
1448
1449void IOService::applyToInterested( const OSSymbol * typeOfInterest,
1450                                   OSObjectApplierFunction applier,
1451                                   void * context )
1452{
1453    if (gIOGeneralInterest == typeOfInterest)
1454	applyToClients( (IOServiceApplierFunction) applier, context );
1455    applyToInterestNotifiers(this, typeOfInterest, applier, context);
1456}
1457
1458struct MessageClientsContext {
1459    IOService *	service;
1460    UInt32	type;
1461    void *	argument;
1462    vm_size_t	argSize;
1463    IOReturn	ret;
1464};
1465
1466static void messageClientsApplier( OSObject * object, void * ctx )
1467{
1468    IOReturn		    ret;
1469    MessageClientsContext * context = (MessageClientsContext *) ctx;
1470
1471    ret = context->service->messageClient( context->type,
1472                                           object, context->argument, context->argSize );
1473    if( kIOReturnSuccess != ret)
1474        context->ret = ret;
1475}
1476
1477// send a message to all clients
1478IOReturn IOService::messageClients( UInt32 type,
1479                                    void * argument, vm_size_t argSize )
1480{
1481    MessageClientsContext	context;
1482
1483    context.service	= this;
1484    context.type	= type;
1485    context.argument	= argument;
1486    context.argSize	= argSize;
1487    context.ret		= kIOReturnSuccess;
1488
1489    applyToInterested( gIOGeneralInterest,
1490                       &messageClientsApplier, &context );
1491
1492    return( context.ret );
1493}
1494
1495IOReturn IOService::acknowledgeNotification( IONotificationRef notification,
1496                                              IOOptionBits response )
1497{
1498    return( kIOReturnUnsupported );
1499}
1500
1501IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest,
1502                  IOServiceInterestHandler handler, void * target, void * ref )
1503{
1504    _IOServiceInterestNotifier * notify = 0;
1505
1506    if( (typeOfInterest != gIOGeneralInterest)
1507     && (typeOfInterest != gIOBusyInterest)
1508     && (typeOfInterest != gIOAppPowerStateInterest)
1509     && (typeOfInterest != gIOConsoleSecurityInterest)
1510     && (typeOfInterest != gIOPriorityPowerStateInterest))
1511        return( 0 );
1512
1513    lockForArbitration();
1514    if( 0 == (__state[0] & kIOServiceInactiveState)) {
1515
1516        notify = new _IOServiceInterestNotifier;
1517        if( notify && !notify->init()) {
1518            notify->release();
1519            notify = 0;
1520        }
1521
1522        if( notify) {
1523            notify->handler = handler;
1524            notify->target = target;
1525            notify->ref = ref;
1526            notify->state = kIOServiceNotifyEnable;
1527            queue_init( &notify->handlerInvocations );
1528
1529            ////// queue
1530
1531            LOCKWRITENOTIFY();
1532
1533	    // Get the head of the notifier linked list
1534	    IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest );
1535	    if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) {
1536		notifyList = OSTypeAlloc(IOCommand);
1537		if (notifyList) {
1538		    notifyList->init();
1539		    setProperty( typeOfInterest, notifyList);
1540		    notifyList->release();
1541		}
1542	    }
1543
1544	    if (notifyList) {
1545		enqueue(&notifyList->fCommandChain, &notify->chain);
1546		notify->retain();	// ref'ed while in list
1547	    }
1548
1549            UNLOCKNOTIFY();
1550        }
1551    }
1552    unlockForArbitration();
1553
1554    return( notify );
1555}
1556
1557static void cleanInterestList( OSObject * head )
1558{
1559    IOCommand *notifyHead = OSDynamicCast(IOCommand, head);
1560    if (!notifyHead)
1561	return;
1562
1563    LOCKWRITENOTIFY();
1564    while ( queue_entry_t entry = dequeue(&notifyHead->fCommandChain) ) {
1565	queue_next(entry) = queue_prev(entry) = 0;
1566
1567	_IOServiceInterestNotifier * notify;
1568
1569	queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
1570	notify->release();
1571    }
1572    UNLOCKNOTIFY();
1573}
1574
1575void IOService::unregisterAllInterest( void )
1576{
1577    cleanInterestList( getProperty( gIOGeneralInterest ));
1578    cleanInterestList( getProperty( gIOBusyInterest ));
1579    cleanInterestList( getProperty( gIOAppPowerStateInterest ));
1580    cleanInterestList( getProperty( gIOPriorityPowerStateInterest ));
1581    cleanInterestList( getProperty( gIOConsoleSecurityInterest ));
1582}
1583
1584/*
1585 * _IOServiceInterestNotifier
1586 */
1587
1588// wait for all threads, other than the current one,
1589//  to exit the handler
1590
1591void _IOServiceInterestNotifier::wait()
1592{
1593    _IOServiceNotifierInvocation * next;
1594    bool doWait;
1595
1596    do {
1597        doWait = false;
1598        queue_iterate( &handlerInvocations, next,
1599                        _IOServiceNotifierInvocation *, link) {
1600            if( next->thread != current_thread() ) {
1601                doWait = true;
1602                break;
1603            }
1604        }
1605        if( doWait) {
1606            state |= kIOServiceNotifyWaiter;
1607	       SLEEPNOTIFY(this);
1608        }
1609
1610    } while( doWait );
1611}
1612
1613void _IOServiceInterestNotifier::free()
1614{
1615    assert( queue_empty( &handlerInvocations ));
1616    OSObject::free();
1617}
1618
1619void _IOServiceInterestNotifier::remove()
1620{
1621    LOCKWRITENOTIFY();
1622
1623    if( queue_next( &chain )) {
1624	remqueue(&chain);
1625	queue_next( &chain) = queue_prev( &chain) = 0;
1626	release();
1627    }
1628
1629    state &= ~kIOServiceNotifyEnable;
1630
1631    wait();
1632
1633    UNLOCKNOTIFY();
1634
1635    release();
1636}
1637
1638bool _IOServiceInterestNotifier::disable()
1639{
1640    bool	ret;
1641
1642    LOCKWRITENOTIFY();
1643
1644    ret = (0 != (kIOServiceNotifyEnable & state));
1645    state &= ~kIOServiceNotifyEnable;
1646    if( ret)
1647        wait();
1648
1649    UNLOCKNOTIFY();
1650
1651    return( ret );
1652}
1653
1654void _IOServiceInterestNotifier::enable( bool was )
1655{
1656    LOCKWRITENOTIFY();
1657    if( was)
1658        state |= kIOServiceNotifyEnable;
1659    else
1660        state &= ~kIOServiceNotifyEnable;
1661    UNLOCKNOTIFY();
1662}
1663
1664/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1665
1666/*
1667 * Termination
1668 */
1669
1670#define tailQ(o)		setObject(o)
1671#define headQ(o)		setObject(0, o)
1672#define TLOG(fmt, args...)  	{ if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
1673
1674static void _workLoopAction( IOWorkLoop::Action action,
1675                             IOService * service,
1676                             void * p0 = 0, void * p1 = 0,
1677                             void * p2 = 0, void * p3 = 0 )
1678{
1679    IOWorkLoop * wl;
1680
1681    if( (wl = service->getWorkLoop())) {
1682        wl->retain();
1683        wl->runAction( action, service, p0, p1, p2, p3 );
1684        wl->release();
1685    } else
1686        (*action)( service, p0, p1, p2, p3 );
1687}
1688
1689bool IOService::requestTerminate( IOService * provider, IOOptionBits options )
1690{
1691    bool ok;
1692
1693    // if its our only provider
1694    ok = isParent( provider, gIOServicePlane, true);
1695
1696    // -- compat
1697    if( ok) {
1698        provider->terminateClient( this, options | kIOServiceRecursing );
1699        ok = (0 != (__state[1] & kIOServiceRecursing));
1700    }
1701    // --
1702
1703    return( ok );
1704}
1705
1706bool IOService::terminatePhase1( IOOptionBits options )
1707{
1708    IOService *	 victim;
1709    IOService *	 client;
1710    OSIterator * iter;
1711    OSArray *	 makeInactive;
1712	int          waitResult = THREAD_AWAKENED;
1713	bool         wait;
1714    bool		 ok;
1715    bool		 didInactive;
1716    bool		 startPhase2 = false;
1717
1718    TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options);
1719
1720    uint64_t regID = getRegistryEntryID();
1721    IOServiceTrace(
1722	IOSERVICE_TERMINATE_PHASE1,
1723	(uintptr_t) regID,
1724	(uintptr_t) (regID >> 32),
1725	(uintptr_t) this,
1726	(uintptr_t) options);
1727
1728    // -- compat
1729    if( options & kIOServiceRecursing) {
1730        lockForArbitration();
1731        __state[1] |= kIOServiceRecursing;
1732        unlockForArbitration();
1733        return( true );
1734    }
1735    // --
1736
1737    makeInactive = OSArray::withCapacity( 16 );
1738    if( !makeInactive)
1739        return( false );
1740
1741    victim = this;
1742    victim->retain();
1743
1744    while( victim ) {
1745
1746		didInactive = victim->lockForArbitration( true );
1747        if( didInactive) {
1748            didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState));
1749            if( didInactive) {
1750                victim->__state[0] |= kIOServiceInactiveState;
1751                victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState
1752                                        | kIOServiceFirstPublishState | kIOServiceFirstMatchState);
1753
1754				if (victim == this)
1755					victim->__state[1] |= kIOServiceTermPhase1State;
1756
1757                victim->_adjustBusy( 1 );
1758
1759            } else if (victim != this) do {
1760
1761				IOLockLock(gIOServiceBusyLock);
1762				wait = (victim->__state[1] & kIOServiceTermPhase1State);
1763				if( wait) {
1764				    TLOG("%s::waitPhase1(%s)\n", getName(), victim->getName());
1765					victim->__state[1] |= kIOServiceTerm1WaiterState;
1766					victim->unlockForArbitration();
1767					assert_wait((event_t)&victim->__state[1], THREAD_UNINT);
1768				}
1769				IOLockUnlock(gIOServiceBusyLock);
1770				if( wait) {
1771					waitResult = thread_block(THREAD_CONTINUE_NULL);
1772				    TLOG("%s::did waitPhase1(%s)\n", getName(), victim->getName());
1773					victim->lockForArbitration();
1774				}
1775			} while( wait && (waitResult != THREAD_TIMED_OUT));
1776
1777			victim->unlockForArbitration();
1778        }
1779        if( victim == this)
1780            startPhase2 = didInactive;
1781        if( didInactive) {
1782
1783            victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff );
1784            IOUserClient::destroyUserReferences( victim );
1785
1786            iter = victim->getClientIterator();
1787            if( iter) {
1788                while( (client = (IOService *) iter->getNextObject())) {
1789                    TLOG("%s::requestTerminate(%s, %08llx)\n",
1790                            client->getName(), victim->getName(), (long long)options);
1791                    ok = client->requestTerminate( victim, options );
1792                    TLOG("%s::requestTerminate(%s, ok = %d)\n",
1793                            client->getName(), victim->getName(), ok);
1794
1795		    uint64_t regID1 = client->getRegistryEntryID();
1796		    uint64_t regID2 = victim->getRegistryEntryID();
1797		    IOServiceTrace(
1798			(ok ? IOSERVICE_TERMINATE_REQUEST_OK
1799			   : IOSERVICE_TERMINATE_REQUEST_FAIL),
1800			(uintptr_t) regID1,
1801			(uintptr_t) (regID1 >> 32),
1802			(uintptr_t) regID2,
1803			(uintptr_t) (regID2 >> 32));
1804
1805                    if( ok)
1806                        makeInactive->setObject( client );
1807                }
1808                iter->release();
1809            }
1810        }
1811        victim->release();
1812        victim = (IOService *) makeInactive->getObject(0);
1813        if( victim) {
1814            victim->retain();
1815            makeInactive->removeObject(0);
1816        }
1817    }
1818
1819    makeInactive->release();
1820
1821    if( startPhase2)
1822    {
1823		lockForArbitration();
1824		__state[1] &= ~kIOServiceTermPhase1State;
1825		if (kIOServiceTerm1WaiterState & __state[1])
1826		{
1827			__state[1] &= ~kIOServiceTerm1WaiterState;
1828			TLOG("%s::wakePhase1\n", getName());
1829			IOLockLock( gIOServiceBusyLock );
1830			thread_wakeup( (event_t) &__state[1]);
1831			IOLockUnlock( gIOServiceBusyLock );
1832		}
1833		unlockForArbitration();
1834
1835        scheduleTerminatePhase2( options );
1836    }
1837    return( true );
1838}
1839
1840void IOService::setTerminateDefer(IOService * provider, bool defer)
1841{
1842    lockForArbitration();
1843    if (defer)	__state[1] |= kIOServiceStartState;
1844    else	__state[1] &= ~kIOServiceStartState;
1845    unlockForArbitration();
1846
1847    if (provider && !defer)
1848    {
1849    	provider->lockForArbitration();
1850	if (provider->__state[0] & kIOServiceInactiveState)
1851	{
1852	    provider->scheduleTerminatePhase2();
1853	}
1854        provider->unlockForArbitration();
1855    }
1856}
1857
1858void IOService::scheduleTerminatePhase2( IOOptionBits options )
1859{
1860    AbsoluteTime	deadline;
1861    int			waitResult = THREAD_AWAKENED;
1862    bool		wait, haveDeadline = false;
1863
1864    options |= kIOServiceRequired;
1865
1866    retain();
1867
1868    IOLockLock( gJobsLock );
1869
1870    if( (options & kIOServiceSynchronous)
1871        && (current_thread() != gIOTerminateThread)) {
1872
1873        do {
1874            wait = (gIOTerminateThread != 0);
1875            if( wait) {
1876                // wait to become the terminate thread
1877                IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT);
1878            }
1879        } while( wait );
1880
1881        gIOTerminateThread = current_thread();
1882        gIOTerminatePhase2List->setObject( this );
1883        gIOTerminateWork++;
1884
1885        do {
1886	    while( gIOTerminateWork )
1887		terminateWorker( options );
1888            wait = (0 != (__state[1] & kIOServiceBusyStateMask));
1889            if( wait) {
1890                // wait for the victim to go non-busy
1891                if( !haveDeadline) {
1892                    clock_interval_to_deadline( 15, kSecondScale, &deadline );
1893                    haveDeadline = true;
1894                }
1895                waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
1896                                                  deadline, THREAD_UNINT );
1897                if( waitResult == THREAD_TIMED_OUT) {
1898                    IOLog("%s::terminate(kIOServiceSynchronous) timeout\n", getName());
1899		}
1900            }
1901        } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
1902
1903	gIOTerminateThread = 0;
1904	IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
1905
1906    } else {
1907        // ! kIOServiceSynchronous
1908
1909        gIOTerminatePhase2List->setObject( this );
1910        if( 0 == gIOTerminateWork++) {
1911	    if( !gIOTerminateThread)
1912		kernel_thread_start(&terminateThread, (void *)(uintptr_t) options, &gIOTerminateThread);
1913	    else
1914		IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1915	}
1916    }
1917
1918    IOLockUnlock( gJobsLock );
1919
1920    release();
1921}
1922
1923void IOService::terminateThread( void * arg, wait_result_t waitResult )
1924{
1925    IOLockLock( gJobsLock );
1926
1927    while (gIOTerminateWork)
1928	terminateWorker( (uintptr_t) arg );
1929
1930    thread_deallocate(gIOTerminateThread);
1931    gIOTerminateThread = 0;
1932    IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
1933
1934    IOLockUnlock( gJobsLock );
1935}
1936
1937void IOService::scheduleStop( IOService * provider )
1938{
1939    TLOG("%s::scheduleStop(%s)\n", getName(), provider->getName());
1940
1941    uint64_t regID1 = getRegistryEntryID();
1942    uint64_t regID2 = provider->getRegistryEntryID();
1943    IOServiceTrace(
1944	IOSERVICE_TERMINATE_SCHEDULE_STOP,
1945	(uintptr_t) regID1,
1946	(uintptr_t) (regID1 >> 32),
1947	(uintptr_t) regID2,
1948	(uintptr_t) (regID2 >> 32));
1949
1950    IOLockLock( gJobsLock );
1951    gIOStopList->tailQ( this );
1952    gIOStopProviderList->tailQ( provider );
1953
1954    if( 0 == gIOTerminateWork++) {
1955        if( !gIOTerminateThread)
1956	    kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
1957        else
1958            IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1959    }
1960
1961    IOLockUnlock( gJobsLock );
1962}
1963
1964void IOService::scheduleFinalize( void )
1965{
1966    TLOG("%s::scheduleFinalize\n", getName());
1967
1968    uint64_t regID1 = getRegistryEntryID();
1969    IOServiceTrace(
1970	IOSERVICE_TERMINATE_SCHEDULE_FINALIZE,
1971	(uintptr_t) regID1,
1972	(uintptr_t) (regID1 >> 32),
1973	0, 0);
1974
1975    IOLockLock( gJobsLock );
1976    gIOFinalizeList->tailQ( this );
1977
1978    if( 0 == gIOTerminateWork++) {
1979        if( !gIOTerminateThread)
1980	    kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread);
1981        else
1982            IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false );
1983    }
1984
1985    IOLockUnlock( gJobsLock );
1986}
1987
1988bool IOService::willTerminate( IOService * provider, IOOptionBits options )
1989{
1990    return( true );
1991}
1992
1993bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
1994{
1995    if( false == *defer) {
1996
1997        if( lockForArbitration( true )) {
1998            if( false == provider->handleIsOpen( this ))
1999                scheduleStop( provider );
2000            // -- compat
2001            else {
2002                message( kIOMessageServiceIsRequestingClose, provider, (void *)(uintptr_t) options );
2003                if( false == provider->handleIsOpen( this ))
2004                    scheduleStop( provider );
2005            }
2006            // --
2007            unlockForArbitration();
2008        }
2009    }
2010
2011    return( true );
2012}
2013
2014void IOService::actionWillTerminate( IOService * victim, IOOptionBits options,
2015				     OSArray * doPhase2List,
2016				     void *unused2 __unused,
2017				     void *unused3 __unused  )
2018{
2019    OSIterator * iter;
2020    IOService *	 client;
2021    bool	 ok;
2022
2023    iter = victim->getClientIterator();
2024    if( iter) {
2025        while( (client = (IOService *) iter->getNextObject())) {
2026            TLOG("%s::willTerminate(%s, %08llx)\n",
2027                    client->getName(), victim->getName(), (long long)options);
2028
2029	    uint64_t regID1 = client->getRegistryEntryID();
2030	    uint64_t regID2 = victim->getRegistryEntryID();
2031	    IOServiceTrace(
2032		IOSERVICE_TERMINATE_WILL,
2033		(uintptr_t) regID1,
2034		(uintptr_t) (regID1 >> 32),
2035		(uintptr_t) regID2,
2036		(uintptr_t) (regID2 >> 32));
2037
2038            ok = client->willTerminate( victim, options );
2039            doPhase2List->tailQ( client );
2040        }
2041        iter->release();
2042    }
2043}
2044
2045void IOService::actionDidTerminate( IOService * victim, IOOptionBits options,
2046			    void *unused1 __unused, void *unused2 __unused,
2047			    void *unused3 __unused )
2048{
2049    OSIterator * iter;
2050    IOService *	 client;
2051    bool defer = false;
2052
2053    victim->messageClients( kIOMessageServiceIsTerminated, (void *)(uintptr_t) options );
2054
2055    iter = victim->getClientIterator();
2056    if( iter) {
2057        while( (client = (IOService *) iter->getNextObject())) {
2058            TLOG("%s::didTerminate(%s, %08llx)\n",
2059                    client->getName(), victim->getName(), (long long)options);
2060            client->didTerminate( victim, options, &defer );
2061
2062	    uint64_t regID1 = client->getRegistryEntryID();
2063	    uint64_t regID2 = victim->getRegistryEntryID();
2064	    IOServiceTrace(
2065		(defer ? IOSERVICE_TERMINATE_DID_DEFER
2066		       : IOSERVICE_TERMINATE_DID),
2067		(uintptr_t) regID1,
2068		(uintptr_t) (regID1 >> 32),
2069		(uintptr_t) regID2,
2070		(uintptr_t) (regID2 >> 32));
2071
2072            TLOG("%s::didTerminate(%s, defer %d)\n",
2073                    client->getName(), victim->getName(), defer);
2074        }
2075        iter->release();
2076    }
2077}
2078
2079void IOService::actionFinalize( IOService * victim, IOOptionBits options,
2080			    void *unused1 __unused, void *unused2 __unused,
2081			    void *unused3 __unused )
2082{
2083    TLOG("%s::finalize(%08llx)\n", victim->getName(), (long long)options);
2084
2085    uint64_t regID1 = victim->getRegistryEntryID();
2086    IOServiceTrace(
2087	IOSERVICE_TERMINATE_FINALIZE,
2088	(uintptr_t) regID1,
2089	(uintptr_t) (regID1 >> 32),
2090	0, 0);
2091
2092    victim->finalize( options );
2093}
2094
2095void IOService::actionStop( IOService * provider, IOService * client,
2096			    void *unused1 __unused, void *unused2 __unused,
2097			    void *unused3 __unused )
2098{
2099    TLOG("%s::stop(%s)\n", client->getName(), provider->getName());
2100
2101    uint64_t regID1 = provider->getRegistryEntryID();
2102    uint64_t regID2 = client->getRegistryEntryID();
2103    IOServiceTrace(
2104	IOSERVICE_TERMINATE_STOP,
2105	(uintptr_t) regID1,
2106	(uintptr_t) (regID1 >> 32),
2107	(uintptr_t) regID2,
2108	(uintptr_t) (regID2 >> 32));
2109
2110    client->stop( provider );
2111    if( provider->isOpen( client ))
2112        provider->close( client );
2113    TLOG("%s::detach(%s)\n", client->getName(), provider->getName());
2114    client->detach( provider );
2115}
2116
2117void IOService::terminateWorker( IOOptionBits options )
2118{
2119    OSArray *		doPhase2List;
2120    OSArray *		didPhase2List;
2121    OSSet *		freeList;
2122    OSIterator *        iter;
2123    UInt32		workDone;
2124    IOService * 	victim;
2125    IOService * 	client;
2126    IOService * 	provider;
2127    unsigned int	idx;
2128    bool		moreToDo;
2129    bool		doPhase2;
2130    bool		doPhase3;
2131
2132    options |= kIOServiceRequired;
2133
2134    doPhase2List  = OSArray::withCapacity( 16 );
2135    didPhase2List = OSArray::withCapacity( 16 );
2136    freeList	  = OSSet::withCapacity( 16 );
2137    if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList))
2138        return;
2139
2140    do {
2141        workDone = gIOTerminateWork;
2142
2143        while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) {
2144
2145            victim->retain();
2146            gIOTerminatePhase2List->removeObject(0);
2147            IOLockUnlock( gJobsLock );
2148
2149            while( victim ) {
2150
2151                doPhase2 = victim->lockForArbitration( true );
2152                if( doPhase2) {
2153                    doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0]));
2154                    if( doPhase2) {
2155                        doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State))
2156                                && (0 == (victim->__state[1] & kIOServiceConfigState));
2157
2158			if (doPhase2 && (iter = victim->getClientIterator())) {
2159			    while (doPhase2 && (client = (IOService *) iter->getNextObject())) {
2160				doPhase2 = (0 == (client->__state[1] & kIOServiceStartState));
2161			    }
2162			    iter->release();
2163			}
2164                        if( doPhase2)
2165                            victim->__state[1] |= kIOServiceTermPhase2State;
2166                    }
2167                    victim->unlockForArbitration();
2168                }
2169                if( doPhase2) {
2170                    if( 0 == victim->getClient()) {
2171                        // no clients - will go to finalize
2172                        IOLockLock( gJobsLock );
2173                        gIOFinalizeList->tailQ( victim );
2174                        IOLockUnlock( gJobsLock );
2175                    } else {
2176                        _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate,
2177                                            victim, (void *)(uintptr_t) options, (void *)(uintptr_t) doPhase2List );
2178                    }
2179                    didPhase2List->headQ( victim );
2180                }
2181                victim->release();
2182                victim = (IOService *) doPhase2List->getObject(0);
2183                if( victim) {
2184                    victim->retain();
2185                    doPhase2List->removeObject(0);
2186                }
2187            }
2188
2189            while( (victim = (IOService *) didPhase2List->getObject(0)) ) {
2190
2191                if( victim->lockForArbitration( true )) {
2192                    victim->__state[1] |= kIOServiceTermPhase3State;
2193                    victim->unlockForArbitration();
2194                }
2195                _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate,
2196                                    victim, (void *)(uintptr_t) options );
2197                didPhase2List->removeObject(0);
2198            }
2199            IOLockLock( gJobsLock );
2200        }
2201
2202        // phase 3
2203        do {
2204            doPhase3 = false;
2205            // finalize leaves
2206            while( (victim = (IOService *) gIOFinalizeList->getObject(0))) {
2207
2208                IOLockUnlock( gJobsLock );
2209                _workLoopAction( (IOWorkLoop::Action) &actionFinalize,
2210                                    victim, (void *)(uintptr_t) options );
2211                IOLockLock( gJobsLock );
2212                // hold off free
2213                freeList->setObject( victim );
2214                // safe if finalize list is append only
2215                gIOFinalizeList->removeObject(0);
2216            }
2217
2218            for( idx = 0;
2219                 (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) {
2220
2221                provider = (IOService *) gIOStopProviderList->getObject(idx);
2222                assert( provider );
2223
2224                if( !provider->isChild( client, gIOServicePlane )) {
2225                    // may be multiply queued - nop it
2226                    TLOG("%s::nop stop(%s)\n", client->getName(), provider->getName());
2227
2228		    uint64_t regID1 = provider->getRegistryEntryID();
2229		    uint64_t regID2 = client->getRegistryEntryID();
2230		    IOServiceTrace(
2231			IOSERVICE_TERMINATE_STOP_NOP,
2232			(uintptr_t) regID1,
2233			(uintptr_t) (regID1 >> 32),
2234			(uintptr_t) regID2,
2235			(uintptr_t) (regID2 >> 32));
2236
2237                } else {
2238                    // a terminated client is not ready for stop if it has clients, skip it
2239                    if( (kIOServiceInactiveState & client->__state[0]) && client->getClient()) {
2240                        TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName());
2241
2242			uint64_t regID1 = provider->getRegistryEntryID();
2243			uint64_t regID2 = client->getRegistryEntryID();
2244			IOServiceTrace(
2245			    IOSERVICE_TERMINATE_STOP_DEFER,
2246			    (uintptr_t) regID1,
2247			    (uintptr_t) (regID1 >> 32),
2248			    (uintptr_t) regID2,
2249			    (uintptr_t) (regID2 >> 32));
2250
2251                        idx++;
2252                        continue;
2253                    }
2254
2255                    IOLockUnlock( gJobsLock );
2256                    _workLoopAction( (IOWorkLoop::Action) &actionStop,
2257                                     provider, (void *) client );
2258                    IOLockLock( gJobsLock );
2259                    // check the finalize list now
2260                    doPhase3 = true;
2261                }
2262                // hold off free
2263                freeList->setObject( client );
2264                freeList->setObject( provider );
2265
2266                // safe if stop list is append only
2267                gIOStopList->removeObject( idx );
2268                gIOStopProviderList->removeObject( idx );
2269                idx = 0;
2270            }
2271
2272        } while( doPhase3 );
2273
2274        gIOTerminateWork -= workDone;
2275        moreToDo = (gIOTerminateWork != 0);
2276
2277        if( !moreToDo) {
2278            TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount());
2279	    IOServiceTrace(
2280		IOSERVICE_TERMINATE_DONE,
2281		(uintptr_t) gIOStopList->getCount(), 0, 0, 0);
2282        }
2283
2284    } while( moreToDo );
2285
2286    IOLockUnlock( gJobsLock );
2287
2288    freeList->release();
2289    doPhase2List->release();
2290    didPhase2List->release();
2291
2292    IOLockLock( gJobsLock );
2293}
2294
2295bool IOService::finalize( IOOptionBits options )
2296{
2297    OSIterator *	iter;
2298    IOService *		provider;
2299
2300    iter = getProviderIterator();
2301    assert( iter );
2302
2303    if( iter) {
2304        while( (provider = (IOService *) iter->getNextObject())) {
2305
2306            // -- compat
2307            if( 0 == (__state[1] & kIOServiceTermPhase3State)) {
2308                /* we come down here on programmatic terminate */
2309                stop( provider );
2310                if( provider->isOpen( this ))
2311                    provider->close( this );
2312                detach( provider );
2313            } else {
2314            //--
2315                if( provider->lockForArbitration( true )) {
2316                    if( 0 == (provider->__state[1] & kIOServiceTermPhase3State))
2317                        scheduleStop( provider );
2318                    provider->unlockForArbitration();
2319                }
2320            }
2321        }
2322        iter->release();
2323    }
2324
2325    return( true );
2326}
2327
2328#undef tailQ
2329#undef headQ
2330
2331/*
2332 * Terminate
2333 */
2334
2335void IOService::doServiceTerminate( IOOptionBits options )
2336{
2337}
2338
2339// a method in case someone needs to override it
2340bool IOService::terminateClient( IOService * client, IOOptionBits options )
2341{
2342    bool ok;
2343
2344    if( client->isParent( this, gIOServicePlane, true))
2345        // we are the clients only provider
2346        ok = client->terminate( options );
2347    else
2348	ok = true;
2349
2350    return( ok );
2351}
2352
2353bool IOService::terminate( IOOptionBits options )
2354{
2355    options |= kIOServiceTerminate;
2356
2357    return( terminatePhase1( options ));
2358}
2359
2360/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2361
2362/*
2363 * Open & close
2364 */
2365
2366struct ServiceOpenMessageContext
2367{
2368    IOService *	 service;
2369    UInt32	 type;
2370    IOService *  excludeClient;
2371    IOOptionBits options;
2372};
2373
2374static void serviceOpenMessageApplier( OSObject * object, void * ctx )
2375{
2376    ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx;
2377
2378    if( object != context->excludeClient)
2379        context->service->messageClient( context->type, object, (void *)(uintptr_t) context->options );
2380}
2381
2382bool IOService::open( 	IOService *	forClient,
2383                        IOOptionBits	options,
2384                        void *		arg )
2385{
2386    bool			ok;
2387    ServiceOpenMessageContext	context;
2388
2389    context.service		= this;
2390    context.type		= kIOMessageServiceIsAttemptingOpen;
2391    context.excludeClient	= forClient;
2392    context.options		= options;
2393
2394    applyToInterested( gIOGeneralInterest,
2395                        &serviceOpenMessageApplier, &context );
2396
2397    if( false == lockForArbitration(false) )
2398        return false;
2399
2400    ok = (0 == (__state[0] & kIOServiceInactiveState));
2401    if( ok)
2402        ok = handleOpen( forClient, options, arg );
2403
2404    unlockForArbitration();
2405
2406    return( ok );
2407}
2408
2409void IOService::close( 	IOService *	forClient,
2410                        IOOptionBits	options )
2411{
2412    bool		wasClosed;
2413    bool		last = false;
2414
2415    lockForArbitration();
2416
2417    wasClosed = handleIsOpen( forClient );
2418    if( wasClosed) {
2419        handleClose( forClient, options );
2420	last = (__state[1] & kIOServiceTermPhase3State);
2421    }
2422
2423    unlockForArbitration();
2424
2425    if( last)
2426        forClient->scheduleStop( this );
2427
2428    else if( wasClosed) {
2429
2430        ServiceOpenMessageContext context;
2431
2432        context.service		= this;
2433        context.type		= kIOMessageServiceWasClosed;
2434        context.excludeClient	= forClient;
2435        context.options		= options;
2436
2437        applyToInterested( gIOGeneralInterest,
2438                            &serviceOpenMessageApplier, &context );
2439    }
2440}
2441
2442bool IOService::isOpen( const IOService * forClient ) const
2443{
2444    IOService *	self = (IOService *) this;
2445    bool ok;
2446
2447    self->lockForArbitration();
2448
2449    ok = handleIsOpen( forClient );
2450
2451    self->unlockForArbitration();
2452
2453    return( ok );
2454}
2455
2456bool IOService::handleOpen( 	IOService *	forClient,
2457                                IOOptionBits	options,
2458                                void *		arg )
2459{
2460    bool	ok;
2461
2462    ok = (0 == __owner);
2463    if( ok )
2464        __owner = forClient;
2465
2466    else if( options & kIOServiceSeize ) {
2467        ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose,
2468                                __owner, (void *)(uintptr_t) options ));
2469        if( ok && (0 == __owner ))
2470            __owner = forClient;
2471        else
2472            ok = false;
2473    }
2474    return( ok );
2475}
2476
2477void IOService::handleClose( 	IOService *	forClient,
2478                                IOOptionBits	options )
2479{
2480    if( __owner == forClient)
2481        __owner = 0;
2482}
2483
2484bool IOService::handleIsOpen( 	const IOService * forClient ) const
2485{
2486    if( forClient)
2487	return( __owner == forClient );
2488    else
2489	return( __owner != forClient );
2490}
2491
2492/*
2493 * Probing & starting
2494 */
2495static SInt32 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
2496{
2497    const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1;
2498    const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2;
2499    SInt32             val1;
2500    SInt32             val2;
2501
2502    val1 = 0;
2503    val2 = 0;
2504
2505    if ( obj1 )
2506        val1 = obj1->priority;
2507
2508    if ( obj2 )
2509        val2 = obj2->priority;
2510
2511    return ( val1 - val2 );
2512}
2513
2514static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref)
2515{
2516    OSDictionary *	dict;
2517    IOService *		service;
2518    _IOServiceNotifier * notify;
2519    OSSymbol *		key = (OSSymbol *) ref;
2520    OSNumber *		offset;
2521
2522    if( (dict = OSDynamicCast( OSDictionary, entry)))
2523        offset = OSDynamicCast(OSNumber, dict->getObject( key ));
2524    else if( (notify = OSDynamicCast( _IOServiceNotifier, entry)))
2525	return( notify->priority );
2526
2527    else if( (service = OSDynamicCast( IOService, entry)))
2528        offset = OSDynamicCast(OSNumber, service->getProperty( key ));
2529    else {
2530	assert( false );
2531	offset = 0;
2532    }
2533
2534    if( offset)
2535        return( (SInt32) offset->unsigned32BitValue());
2536    else
2537        return( kIODefaultProbeScore );
2538}
2539
2540SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
2541{
2542    const OSObject *	obj1 = (const OSObject *) inObj1;
2543    const OSObject *	obj2 = (const OSObject *) inObj2;
2544    SInt32               val1;
2545    SInt32               val2;
2546
2547    val1 = 0;
2548    val2 = 0;
2549
2550    if ( obj1 )
2551        val1 = IOServiceObjectOrder( obj1, ref );
2552
2553    if ( obj2 )
2554        val2 = IOServiceObjectOrder( obj2, ref );
2555
2556    return ( val1 - val2 );
2557}
2558
2559IOService * IOService::copyClientWithCategory( const OSSymbol * category )
2560{
2561    IOService *		service = 0;
2562    OSIterator *	iter;
2563    const OSSymbol *	nextCat;
2564
2565    iter = getClientIterator();
2566    if( iter) {
2567	while( (service = (IOService *) iter->getNextObject())) {
2568	    if( kIOServiceInactiveState & service->__state[0])
2569		continue;
2570            nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol,
2571			service->getProperty( gIOMatchCategoryKey ));
2572	    if( category == nextCat)
2573	    {
2574		service->retain();
2575		break;
2576	    }
2577	}
2578	iter->release();
2579    }
2580    return( service );
2581}
2582
2583IOService * IOService::getClientWithCategory( const OSSymbol * category )
2584{
2585    IOService *
2586    service = copyClientWithCategory(category);
2587    if (service)
2588	service->release();
2589    return (service);
2590}
2591
2592bool IOService::invokeNotifer( _IOServiceNotifier * notify )
2593{
2594    _IOServiceNotifierInvocation invocation;
2595    bool			 willNotify;
2596    bool			 ret = true;
2597
2598    invocation.thread = current_thread();
2599
2600    LOCKWRITENOTIFY();
2601    willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
2602
2603    if( willNotify) {
2604        queue_enter( &notify->handlerInvocations, &invocation,
2605                        _IOServiceNotifierInvocation *, link );
2606    }
2607    UNLOCKNOTIFY();
2608
2609    if( willNotify) {
2610
2611	ret = (*notify->handler)(notify->target, notify->ref, this, notify);
2612
2613        LOCKWRITENOTIFY();
2614        queue_remove( &notify->handlerInvocations, &invocation,
2615                        _IOServiceNotifierInvocation *, link );
2616        if( kIOServiceNotifyWaiter & notify->state) {
2617            notify->state &= ~kIOServiceNotifyWaiter;
2618            WAKEUPNOTIFY( notify );
2619        }
2620        UNLOCKNOTIFY();
2621    }
2622
2623    return( ret );
2624}
2625
2626/*
2627 * Alloc and probe matching classes,
2628 * called on the provider instance
2629 */
2630
2631void IOService::probeCandidates( OSOrderedSet * matches )
2632{
2633    OSDictionary 	*	match = 0;
2634    OSSymbol 		*	symbol;
2635    IOService 		*	inst;
2636    IOService 		*	newInst;
2637    OSDictionary 	*	props;
2638    SInt32			score;
2639    OSNumber 		*	newPri;
2640    OSOrderedSet 	*	familyMatches = 0;
2641    OSOrderedSet 	*	startList;
2642    OSDictionary	*	startDict = 0;
2643    const OSSymbol	* 	category;
2644    OSIterator		*	iter;
2645    _IOServiceNotifier 	*		notify;
2646    OSObject 		*	nextMatch = 0;
2647    bool			started;
2648    bool			needReloc = false;
2649#if IOMATCHDEBUG
2650    SInt64			debugFlags;
2651#endif
2652    IOService * client = NULL;
2653
2654
2655    assert( matches );
2656    while( !needReloc && (nextMatch = matches->getFirstObject())) {
2657
2658        nextMatch->retain();
2659        matches->removeObject(nextMatch);
2660
2661        if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) {
2662
2663            lockForArbitration();
2664            if( 0 == (__state[0] & kIOServiceInactiveState))
2665                invokeNotifer( notify );
2666            unlockForArbitration();
2667            nextMatch->release();
2668            nextMatch = 0;
2669            continue;
2670
2671        } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) {
2672            nextMatch->release();
2673            nextMatch = 0;
2674            continue;
2675	}
2676
2677	props = 0;
2678#if IOMATCHDEBUG
2679        debugFlags = getDebugFlags( match );
2680#endif
2681
2682        do {
2683            category = OSDynamicCast( OSSymbol,
2684			match->getObject( gIOMatchCategoryKey ));
2685	    if( 0 == category)
2686		category = gIODefaultMatchCategoryKey;
2687
2688	    if( (client = copyClientWithCategory(category)) ) {
2689#if IOMATCHDEBUG
2690		if( (debugFlags & kIOLogMatch) && (this != gIOResources))
2691		    LOG("%s: match category %s exists\n", getName(),
2692				category->getCStringNoCopy());
2693#endif
2694                nextMatch->release();
2695                nextMatch = 0;
2696
2697		client->release();
2698		client = NULL;
2699
2700                continue;
2701	    }
2702
2703            // create a copy now in case its modified during matching
2704            props = OSDictionary::withDictionary( match, match->getCount());
2705            if( 0 == props)
2706                continue;
2707	    props->setCapacityIncrement(1);
2708
2709	    // check the nub matches
2710	    if( false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone))
2711		continue;
2712
2713            // Check to see if driver reloc has been loaded.
2714            needReloc = (false == gIOCatalogue->isModuleLoaded( match ));
2715            if( needReloc) {
2716#if IOMATCHDEBUG
2717		if( debugFlags & kIOLogCatalogue)
2718		    LOG("%s: stalling for module\n", getName());
2719#endif
2720                // If reloc hasn't been loaded, exit;
2721                // reprobing will occur after reloc has been loaded.
2722                continue;
2723	    }
2724
2725            // reorder on family matchPropertyTable score.
2726            if( 0 == familyMatches)
2727                familyMatches = OSOrderedSet::withCapacity( 1,
2728                        IOServiceOrdering, (void *) gIOProbeScoreKey );
2729            if( familyMatches)
2730                familyMatches->setObject( props );
2731
2732        } while( false );
2733
2734        if (nextMatch) {
2735            nextMatch->release();
2736            nextMatch = 0;
2737        }
2738        if( props)
2739            props->release();
2740    }
2741    matches->release();
2742    matches = 0;
2743
2744    if( familyMatches) {
2745
2746        while( !needReloc
2747             && (props = (OSDictionary *) familyMatches->getFirstObject())) {
2748
2749            props->retain();
2750            familyMatches->removeObject( props );
2751
2752            inst = 0;
2753            newInst = 0;
2754#if IOMATCHDEBUG
2755            debugFlags = getDebugFlags( props );
2756#endif
2757            do {
2758                symbol = OSDynamicCast( OSSymbol,
2759                                props->getObject( gIOClassKey));
2760                if( !symbol)
2761                    continue;
2762
2763                //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props));
2764
2765                // alloc the driver instance
2766                inst = (IOService *) OSMetaClass::allocClassWithName( symbol);
2767
2768                if( !inst) {
2769                    IOLog("Couldn't alloc class \"%s\"\n",
2770                        symbol->getCStringNoCopy());
2771                    continue;
2772                }
2773
2774                // init driver instance
2775                if( !(inst->init( props ))) {
2776#if IOMATCHDEBUG
2777                    if( debugFlags & kIOLogStart)
2778                        IOLog("%s::init fails\n", symbol->getCStringNoCopy());
2779#endif
2780                    continue;
2781                }
2782                if( __state[1] & kIOServiceSynchronousState)
2783                    inst->__state[1] |= kIOServiceSynchronousState;
2784
2785                // give the driver the default match category if not specified
2786                category = OSDynamicCast( OSSymbol,
2787                            props->getObject( gIOMatchCategoryKey ));
2788                if( 0 == category)
2789                    category = gIODefaultMatchCategoryKey;
2790                inst->setProperty( gIOMatchCategoryKey, (OSObject *) category );
2791                // attach driver instance
2792                if( !(inst->attach( this )))
2793                        continue;
2794
2795                // pass in score from property table
2796                score = familyMatches->orderObject( props );
2797
2798                // & probe the new driver instance
2799#if IOMATCHDEBUG
2800                if( debugFlags & kIOLogProbe)
2801                    LOG("%s::probe(%s)\n",
2802                        inst->getMetaClass()->getClassName(), getName());
2803#endif
2804
2805                newInst = inst->probe( this, &score );
2806                inst->detach( this );
2807                if( 0 == newInst) {
2808#if IOMATCHDEBUG
2809                    if( debugFlags & kIOLogProbe)
2810                        IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
2811#endif
2812                    continue;
2813                }
2814
2815                // save the score
2816                newPri = OSNumber::withNumber( score, 32 );
2817                if( newPri) {
2818                    newInst->setProperty( gIOProbeScoreKey, newPri );
2819                    newPri->release();
2820                }
2821
2822                // add to start list for the match category
2823                if( 0 == startDict)
2824                    startDict = OSDictionary::withCapacity( 1 );
2825                assert( startDict );
2826                startList = (OSOrderedSet *)
2827                                startDict->getObject( category );
2828                if( 0 == startList) {
2829                    startList = OSOrderedSet::withCapacity( 1,
2830                            IOServiceOrdering, (void *) gIOProbeScoreKey );
2831                    if( startDict && startList) {
2832                        startDict->setObject( category, startList );
2833                        startList->release();
2834                    }
2835                }
2836                assert( startList );
2837                if( startList)
2838                    startList->setObject( newInst );
2839
2840            } while( false );
2841
2842            props->release();
2843            if( inst)
2844                inst->release();
2845        }
2846        familyMatches->release();
2847        familyMatches = 0;
2848    }
2849
2850    // start the best (until success) of each category
2851
2852    iter = OSCollectionIterator::withCollection( startDict );
2853    if( iter) {
2854	while( (category = (const OSSymbol *) iter->getNextObject())) {
2855
2856	    startList = (OSOrderedSet *) startDict->getObject( category );
2857	    assert( startList );
2858	    if( !startList)
2859		continue;
2860
2861            started = false;
2862            while( true // (!started)
2863		   && (inst = (IOService *)startList->getFirstObject())) {
2864
2865		inst->retain();
2866		startList->removeObject(inst);
2867
2868#if IOMATCHDEBUG
2869        	debugFlags = getDebugFlags( inst->getPropertyTable() );
2870
2871                if( debugFlags & kIOLogStart) {
2872                    if( started)
2873                        LOG( "match category exists, skipping " );
2874                    LOG( "%s::start(%s) <%d>\n", inst->getName(),
2875                         getName(), inst->getRetainCount());
2876                }
2877#endif
2878                if( false == started)
2879                    started = startCandidate( inst );
2880#if IOMATCHDEBUG
2881                if( (debugFlags & kIOLogStart) && (false == started))
2882                    LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
2883                         inst->getRetainCount());
2884#endif
2885		inst->release();
2886            }
2887        }
2888	iter->release();
2889    }
2890
2891
2892    // adjust the busy count by +1 if matching is stalled for a module,
2893    // or -1 if a previously stalled matching is complete.
2894    lockForArbitration();
2895    SInt32 adjBusy = 0;
2896    uint64_t regID = getRegistryEntryID();
2897
2898    if( needReloc) {
2899        adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1;
2900        if( adjBusy) {
2901
2902	    IOServiceTrace(
2903		IOSERVICE_MODULESTALL,
2904		(uintptr_t) regID,
2905		(uintptr_t) (regID >> 32),
2906		(uintptr_t) this,
2907		0);
2908
2909            __state[1] |= kIOServiceModuleStallState;
2910	}
2911
2912    } else if( __state[1] & kIOServiceModuleStallState) {
2913
2914	    IOServiceTrace(
2915	    IOSERVICE_MODULEUNSTALL,
2916	    (uintptr_t) regID,
2917	    (uintptr_t) (regID >> 32),
2918	    (uintptr_t) this,
2919	    0);
2920
2921        __state[1] &= ~kIOServiceModuleStallState;
2922        adjBusy = -1;
2923    }
2924    if( adjBusy)
2925        _adjustBusy( adjBusy );
2926    unlockForArbitration();
2927
2928    if( startDict)
2929	startDict->release();
2930}
2931
2932/*
2933 * Start a previously attached & probed instance,
2934 * called on exporting object instance
2935 */
2936
2937bool IOService::startCandidate( IOService * service )
2938{
2939    bool		ok;
2940
2941    ok = service->attach( this );
2942
2943    if( ok)
2944    {
2945	if (this != gIOResources)
2946	{
2947	    // stall for any nub resources
2948	    checkResources();
2949	    // stall for any driver resources
2950	    service->checkResources();
2951	}
2952
2953	AbsoluteTime startTime;
2954	AbsoluteTime endTime;
2955	UInt64       nano;
2956
2957	if (kIOLogStart & gIOKitDebug)
2958	    clock_get_uptime(&startTime);
2959
2960        ok = service->start(this);
2961
2962	if (kIOLogStart & gIOKitDebug)
2963	{
2964	    clock_get_uptime(&endTime);
2965
2966	    if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
2967	    {
2968		SUB_ABSOLUTETIME(&endTime, &startTime);
2969		absolutetime_to_nanoseconds(endTime, &nano);
2970		if (nano > 500000000ULL)
2971		    IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
2972	    }
2973	}
2974        if( !ok)
2975            service->detach( this );
2976    }
2977    return( ok );
2978}
2979
2980void IOService::publishResource( const char * key, OSObject * value )
2981{
2982    const OSSymbol *	sym;
2983
2984    if( (sym = OSSymbol::withCString( key))) {
2985        publishResource( sym, value);
2986	sym->release();
2987    }
2988}
2989
2990void IOService::publishResource( const OSSymbol * key, OSObject * value )
2991{
2992    if( 0 == value)
2993	value = (OSObject *) gIOServiceKey;
2994
2995    gIOResources->setProperty( key, value);
2996
2997    if( IORecursiveLockHaveLock( gNotificationLock))
2998	return;
2999
3000    gIOResourceGenerationCount++;
3001    gIOResources->registerService();
3002}
3003
3004bool IOService::addNeededResource( const char * key )
3005{
3006    OSObject *	resourcesProp;
3007    OSSet *	set;
3008    OSString *	newKey;
3009    bool ret;
3010
3011    resourcesProp = getProperty( gIOResourceMatchKey );
3012
3013    newKey = OSString::withCString( key );
3014    if( (0 == resourcesProp) || (0 == newKey))
3015	return( false);
3016
3017    set = OSDynamicCast( OSSet, resourcesProp );
3018    if( !set) {
3019	set = OSSet::withCapacity( 1 );
3020	if( set)
3021            set->setObject( resourcesProp );
3022    }
3023    else
3024        set->retain();
3025
3026    set->setObject( newKey );
3027    newKey->release();
3028    ret = setProperty( gIOResourceMatchKey, set );
3029    set->release();
3030
3031    return( ret );
3032}
3033
3034bool IOService::checkResource( OSObject * matching )
3035{
3036    OSString *		str;
3037    OSDictionary *	table;
3038
3039    if( (str = OSDynamicCast( OSString, matching ))) {
3040	if( gIOResources->getProperty( str ))
3041	    return( true );
3042    }
3043
3044    if( str)
3045	table = resourceMatching( str );
3046    else if( (table = OSDynamicCast( OSDictionary, matching )))
3047	table->retain();
3048    else {
3049	IOLog("%s: Can't match using: %s\n", getName(),
3050		matching->getMetaClass()->getClassName());
3051	/* false would stall forever */
3052	return( true );
3053    }
3054
3055    if( gIOKitDebug & kIOLogConfig)
3056        LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName());
3057
3058    waitForService( table );
3059
3060    if( gIOKitDebug & kIOLogConfig)
3061        LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) );
3062
3063    return( true );
3064}
3065
3066bool IOService::checkResources( void )
3067{
3068    OSObject * 		resourcesProp;
3069    OSSet *		set;
3070    OSIterator *	iter;
3071    bool		ok;
3072
3073    resourcesProp = getProperty( gIOResourceMatchKey );
3074    if( 0 == resourcesProp)
3075        return( true );
3076
3077    if( (set = OSDynamicCast( OSSet, resourcesProp ))) {
3078
3079	iter = OSCollectionIterator::withCollection( set );
3080	ok = (0 != iter);
3081        while( ok && (resourcesProp = iter->getNextObject()) )
3082            ok = checkResource( resourcesProp );
3083	if( iter)
3084	    iter->release();
3085
3086    } else
3087	ok = checkResource( resourcesProp );
3088
3089    return( ok );
3090}
3091
3092
3093void _IOConfigThread::configThread( void )
3094{
3095    _IOConfigThread * 	inst;
3096
3097    do {
3098	if( !(inst = new _IOConfigThread))
3099	    continue;
3100	if( !inst->init())
3101	    continue;
3102	thread_t unused;
3103	if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &unused))
3104	    continue;
3105
3106	return;
3107
3108    } while( false);
3109
3110    if( inst)
3111	inst->release();
3112
3113    return;
3114}
3115
3116void _IOConfigThread::free( void )
3117{
3118    thread_deallocate(current_thread());
3119    OSObject::free();
3120}
3121
3122void IOService::doServiceMatch( IOOptionBits options )
3123{
3124    _IOServiceNotifier * notify;
3125    OSIterator *	iter;
3126    OSOrderedSet *	matches;
3127    SInt32		catalogGeneration;
3128    bool		keepGuessing = true;
3129    bool		reRegistered = true;
3130    bool		didRegister;
3131
3132//    job->nub->deliverNotification( gIOPublishNotification,
3133//  				kIOServiceRegisteredState, 0xffffffff );
3134
3135    while( keepGuessing ) {
3136
3137        matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
3138	// the matches list should always be created by findDrivers()
3139        if( matches) {
3140
3141            lockForArbitration();
3142            if( 0 == (__state[0] & kIOServiceFirstPublishState)) {
3143		getMetaClass()->addInstance(this);
3144                deliverNotification( gIOFirstPublishNotification,
3145                                     kIOServiceFirstPublishState, 0xffffffff );
3146            }
3147	    LOCKREADNOTIFY();
3148            __state[1] &= ~kIOServiceNeedConfigState;
3149            __state[1] |= kIOServiceConfigState;
3150            didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
3151            __state[0] |= kIOServiceRegisteredState;
3152
3153	    keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
3154            if (reRegistered && keepGuessing) {
3155                iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
3156                        gNotifications->getObject( gIOPublishNotification ) );
3157                if( iter) {
3158                    while((notify = (_IOServiceNotifier *)
3159                           iter->getNextObject())) {
3160
3161                        if( matchPassive(notify->matching, 0)
3162                         && (kIOServiceNotifyEnable & notify->state))
3163                            matches->setObject( notify );
3164                    }
3165                    iter->release();
3166                }
3167            }
3168
3169	    UNLOCKNOTIFY();
3170            unlockForArbitration();
3171
3172            if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources()))
3173                probeCandidates( matches );
3174            else
3175                matches->release();
3176        }
3177
3178        lockForArbitration();
3179	reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
3180	keepGuessing =
3181		   (reRegistered || (catalogGeneration !=
3182					gIOCatalogue->getGenerationCount()))
3183                && (0 == (__state[0] & kIOServiceInactiveState));
3184
3185	if( keepGuessing)
3186            unlockForArbitration();
3187    }
3188
3189    if( (0 == (__state[0] & kIOServiceInactiveState))
3190     && (0 == (__state[1] & kIOServiceModuleStallState)) ) {
3191        deliverNotification( gIOMatchedNotification,
3192		kIOServiceMatchedState, 0xffffffff );
3193	if( 0 == (__state[0] & kIOServiceFirstMatchState))
3194	    deliverNotification( gIOFirstMatchNotification,
3195		kIOServiceFirstMatchState, 0xffffffff );
3196    }
3197
3198    __state[1] &= ~kIOServiceConfigState;
3199    if( __state[0] & kIOServiceInactiveState)
3200        scheduleTerminatePhase2();
3201
3202    _adjustBusy( -1 );
3203    unlockForArbitration();
3204}
3205
3206UInt32 IOService::_adjustBusy( SInt32 delta )
3207{
3208    IOService * next;
3209    UInt32	count;
3210    UInt32	result;
3211    bool	wasQuiet, nowQuiet, needWake;
3212
3213    next = this;
3214    result = __state[1] & kIOServiceBusyStateMask;
3215
3216    if( delta) do {
3217        if( next != this)
3218            next->lockForArbitration();
3219        count = next->__state[1] & kIOServiceBusyStateMask;
3220        wasQuiet = (0 == count);
3221	if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count)))
3222	    OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), count, delta);
3223	else
3224	    count += delta;
3225	next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count;
3226        nowQuiet = (0 == count);
3227	needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
3228
3229        if( needWake) {
3230            next->__state[1] &= ~kIOServiceBusyWaiterState;
3231            IOLockLock( gIOServiceBusyLock );
3232	    thread_wakeup( (event_t) next);
3233            IOLockUnlock( gIOServiceBusyLock );
3234        }
3235        if( next != this)
3236            next->unlockForArbitration();
3237
3238        if( (wasQuiet || nowQuiet) ) {
3239	    uint64_t regID = next->getRegistryEntryID();
3240
3241		IOServiceTrace(
3242		((wasQuiet/*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY),
3243		(uintptr_t) regID,
3244		(uintptr_t) (regID >> 32),
3245		(uintptr_t) next,
3246		0);
3247
3248	    if (wasQuiet)
3249	    {
3250		next->__timeBusy = mach_absolute_time();
3251	    }
3252	    else
3253	    {
3254		next->__accumBusy += mach_absolute_time() - next->__timeBusy;
3255		next->__timeBusy = 0;
3256	    }
3257
3258	    MessageClientsContext context;
3259
3260	    context.service  = next;
3261	    context.type     = kIOMessageServiceBusyStateChange;
3262	    context.argument = (void *) wasQuiet;	/*nowBusy*/
3263	    context.argSize  = 0;
3264
3265	    applyToInterestNotifiers( next, gIOBusyInterest,
3266				     &messageClientsApplier, &context );
3267
3268#if !NO_KEXTD
3269            if( nowQuiet && (next == gIOServiceRoot)) {
3270                OSKext::considerUnloads();
3271                IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
3272            }
3273#endif
3274        }
3275
3276        delta = nowQuiet ? -1 : +1;
3277
3278    } while( (wasQuiet || nowQuiet) && (next = next->getProvider()));
3279
3280    return( result );
3281}
3282
3283void IOService::adjustBusy( SInt32 delta )
3284{
3285    lockForArbitration();
3286    _adjustBusy( delta );
3287    unlockForArbitration();
3288}
3289
3290uint64_t IOService::getAccumulatedBusyTime( void )
3291{
3292    uint64_t accumBusy = __accumBusy;
3293    uint64_t timeBusy = __timeBusy;
3294    uint64_t nano;
3295
3296    do
3297    {
3298	accumBusy = __accumBusy;
3299	timeBusy  = __timeBusy;
3300	if (timeBusy)
3301	    accumBusy += mach_absolute_time() - timeBusy;
3302    }
3303    while (timeBusy != __timeBusy);
3304
3305    absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano);
3306
3307    return (nano);
3308}
3309
3310UInt32 IOService::getBusyState( void )
3311{
3312    return( __state[1] & kIOServiceBusyStateMask );
3313}
3314
3315IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3316				  mach_timespec_t * timeout )
3317{
3318    panic("waitForState");
3319    return (kIOReturnUnsupported);
3320}
3321
3322IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3323				   uint64_t timeout )
3324{
3325    bool            wait;
3326    int             waitResult = THREAD_AWAKENED;
3327    bool            computeDeadline = true;
3328    AbsoluteTime    abstime;
3329
3330    do {
3331        lockForArbitration();
3332        IOLockLock( gIOServiceBusyLock );
3333        wait = (value != (__state[1] & mask));
3334        if( wait) {
3335            __state[1] |= kIOServiceBusyWaiterState;
3336            unlockForArbitration();
3337            if( timeout != UINT64_MAX ) {
3338                if( computeDeadline ) {
3339                    AbsoluteTime  nsinterval;
3340                    nanoseconds_to_absolutetime(timeout, &nsinterval );
3341                    clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
3342                    computeDeadline = false;
3343                }
3344                assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
3345            }
3346            else
3347                assert_wait((event_t)this, THREAD_UNINT );
3348        } else
3349            unlockForArbitration();
3350        IOLockUnlock( gIOServiceBusyLock );
3351        if( wait)
3352            waitResult = thread_block(THREAD_CONTINUE_NULL);
3353
3354    } while( wait && (waitResult != THREAD_TIMED_OUT));
3355
3356    if( waitResult == THREAD_TIMED_OUT)
3357        return( kIOReturnTimeout );
3358    else
3359        return( kIOReturnSuccess );
3360}
3361
3362IOReturn IOService::waitQuiet( uint64_t timeout )
3363{
3364	IOReturn ret;
3365    ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
3366	if ((kIOReturnTimeout == ret) && (timeout >= 30000000000) && (kIOWaitQuietPanics & gIOKitDebug))
3367	{
3368		panic("IOService 0x%llx (%s) busy timeout", getRegistryEntryID(), getName());
3369	}
3370	return (ret);
3371}
3372
3373IOReturn IOService::waitQuiet( mach_timespec_t * timeout )
3374{
3375    uint64_t    timeoutNS;
3376
3377    if (timeout)
3378    {
3379	timeoutNS = timeout->tv_sec;
3380	timeoutNS *= kSecondScale;
3381	timeoutNS += timeout->tv_nsec;
3382    }
3383    else
3384	timeoutNS = UINT64_MAX;
3385
3386    return (waitQuiet(timeoutNS));
3387}
3388
3389bool IOService::serializeProperties( OSSerialize * s ) const
3390{
3391#if 0
3392    ((IOService *)this)->setProperty( ((IOService *)this)->__state,
3393		sizeof( __state), "__state");
3394#endif
3395    return( super::serializeProperties(s) );
3396}
3397
3398
3399void _IOConfigThread::main(void * arg, wait_result_t result)
3400{
3401    _IOConfigThread * self = (_IOConfigThread *) arg;
3402    _IOServiceJob * job;
3403    IOService 	*   nub;
3404    bool	    alive = true;
3405    kern_return_t   kr;
3406    thread_precedence_policy_data_t precedence = { -1 };
3407
3408    kr = thread_policy_set(current_thread(),
3409			    THREAD_PRECEDENCE_POLICY,
3410			    (thread_policy_t) &precedence,
3411			    THREAD_PRECEDENCE_POLICY_COUNT);
3412    if (KERN_SUCCESS != kr)
3413	IOLog("thread_policy_set(%d)\n", kr);
3414
3415    do {
3416
3417//	randomDelay();
3418
3419        semaphore_wait( gJobsSemaphore );
3420
3421	IOTakeLock( gJobsLock );
3422	job = (_IOServiceJob *) gJobs->getFirstObject();
3423        job->retain();
3424        gJobs->removeObject(job);
3425	if( job) {
3426	    gOutstandingJobs--;
3427//	    gNumConfigThreads--;	// we're out of service
3428	    gNumWaitingThreads--;	// we're out of service
3429	}
3430	IOUnlock( gJobsLock );
3431
3432	if( job) {
3433
3434	  nub = job->nub;
3435
3436          if( gIOKitDebug & kIOLogConfig)
3437            LOG("config(%p): starting on %s, %d\n",
3438                        OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type);
3439
3440	  switch( job->type) {
3441
3442	    case kMatchNubJob:
3443		nub->doServiceMatch( job->options );
3444		break;
3445
3446            default:
3447                LOG("config(%p): strange type (%d)\n",
3448			OBFUSCATE(IOThreadSelf()), job->type );
3449		break;
3450            }
3451
3452	    nub->release();
3453            job->release();
3454
3455            IOTakeLock( gJobsLock );
3456	    alive = (gOutstandingJobs > gNumWaitingThreads);
3457	    if( alive)
3458		gNumWaitingThreads++;	// back in service
3459//		gNumConfigThreads++;
3460	    else {
3461                if( 0 == --gNumConfigThreads) {
3462//                    IOLog("MATCH IDLE\n");
3463                    IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
3464                }
3465            }
3466            IOUnlock( gJobsLock );
3467	}
3468
3469    } while( alive );
3470
3471    if( gIOKitDebug & kIOLogConfig)
3472        LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) );
3473
3474    self->release();
3475}
3476
3477IOReturn IOService::waitMatchIdle( UInt32 msToWait )
3478{
3479    bool            wait;
3480    int             waitResult = THREAD_AWAKENED;
3481    bool            computeDeadline = true;
3482    AbsoluteTime    deadline;
3483
3484    IOLockLock( gJobsLock );
3485    do {
3486        wait = (0 != gNumConfigThreads);
3487        if( wait) {
3488            if( msToWait) {
3489                if( computeDeadline ) {
3490                    clock_interval_to_deadline(
3491                          msToWait, kMillisecondScale, &deadline );
3492                    computeDeadline = false;
3493                }
3494			  waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
3495								deadline, THREAD_UNINT );
3496	    	   } else {
3497			  waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
3498								THREAD_UNINT );
3499	        }
3500        }
3501    } while( wait && (waitResult != THREAD_TIMED_OUT));
3502	IOLockUnlock( gJobsLock );
3503
3504    if( waitResult == THREAD_TIMED_OUT)
3505        return( kIOReturnTimeout );
3506    else
3507        return( kIOReturnSuccess );
3508}
3509
3510void _IOServiceJob::pingConfig( _IOServiceJob * job )
3511{
3512    int		count;
3513    bool	create;
3514
3515    assert( job );
3516
3517    IOTakeLock( gJobsLock );
3518
3519    gOutstandingJobs++;
3520    gJobs->setLastObject( job );
3521
3522    count = gNumWaitingThreads;
3523//    if( gNumConfigThreads) count++;// assume we're called from a config thread
3524
3525    create = (  (gOutstandingJobs > count)
3526		&& (gNumConfigThreads < kMaxConfigThreads) );
3527    if( create) {
3528	gNumConfigThreads++;
3529	gNumWaitingThreads++;
3530    }
3531
3532    IOUnlock( gJobsLock );
3533
3534    job->release();
3535
3536    if( create) {
3537        if( gIOKitDebug & kIOLogConfig)
3538            LOG("config(%d): creating\n", gNumConfigThreads - 1);
3539        _IOConfigThread::configThread();
3540    }
3541
3542    semaphore_signal( gJobsSemaphore );
3543}
3544
3545struct IOServiceMatchContext
3546{
3547    OSDictionary * table;
3548    OSObject *     result;
3549    uint32_t	   options;
3550    uint32_t	   state;
3551    uint32_t	   count;
3552    uint32_t       done;
3553};
3554
3555bool IOService::instanceMatch(const OSObject * entry, void * context)
3556{
3557    IOServiceMatchContext * ctx = (typeof(ctx)) context;
3558    IOService *    service = (typeof(service)) entry;
3559    OSDictionary * table   = ctx->table;
3560    uint32_t	   options = ctx->options;
3561    uint32_t	   state   = ctx->state;
3562    uint32_t       done;
3563    bool           match;
3564
3565    done = 0;
3566    do
3567    {
3568	match = ((state == (state & service->__state[0]))
3569		&& (0 == (service->__state[0] & kIOServiceInactiveState)));
3570	if (!match) break;
3571	ctx->count += table->getCount();
3572        match = service->matchInternal(table, options, &done);
3573	ctx->done += done;
3574    }
3575    while (false);
3576    if (!match)
3577    	return (false);
3578
3579    if ((kIONotifyOnce & options) && (ctx->done == ctx->count))
3580    {
3581	service->retain();
3582	ctx->result = service;
3583	return (true);
3584    }
3585    else if (!ctx->result)
3586    {
3587	ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1);
3588    }
3589    else
3590    {
3591    	((OSSet *)ctx->result)->setObject(service);
3592    }
3593    return (false);
3594}
3595
3596// internal - call with gNotificationLock
3597OSObject * IOService::copyExistingServices( OSDictionary * matching,
3598		 IOOptionBits inState, IOOptionBits options )
3599{
3600    OSObject *	 current = 0;
3601    OSIterator * iter;
3602    IOService *	 service;
3603    OSObject *	 obj;
3604    OSString *   str;
3605
3606    if( !matching)
3607	return( 0 );
3608
3609#if MATCH_DEBUG
3610    OSSerialize * s = OSSerialize::withCapacity(128);
3611    matching->serialize(s);
3612#endif
3613
3614    if((obj = matching->getObject(gIOProviderClassKey))
3615      && gIOResourcesKey
3616      && gIOResourcesKey->isEqualTo(obj)
3617      && (service = gIOResources))
3618    {
3619	if( (inState == (service->__state[0] & inState))
3620	  && (0 == (service->__state[0] & kIOServiceInactiveState))
3621	  &&  service->matchPassive(matching, options))
3622	{
3623	    if( options & kIONotifyOnce)
3624	    {
3625		service->retain();
3626		current = service;
3627	    }
3628	    else
3629		current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
3630	}
3631    }
3632    else
3633    {
3634    	IOServiceMatchContext ctx;
3635	ctx.table   = matching;
3636	ctx.state   = inState;
3637	ctx.count   = 0;
3638	ctx.done    = 0;
3639	ctx.options = options;
3640	ctx.result  = 0;
3641
3642	if ((str = OSDynamicCast(OSString, obj)))
3643	{
3644	    const OSSymbol * sym = OSSymbol::withString(str);
3645	    OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx);
3646	    sym->release();
3647	}
3648	else
3649	{
3650	    IOService::gMetaClass.applyToInstances(instanceMatch, &ctx);
3651	}
3652
3653
3654	current = ctx.result;
3655
3656	options |= kIOServiceInternalDone | kIOServiceClassDone;
3657	if (current && (ctx.done != ctx.count))
3658	{
3659	    OSSet *
3660	    source = OSDynamicCast(OSSet, current);
3661	    current = 0;
3662	    while ((service = (IOService *) source->getAnyObject()))
3663	    {
3664		if (service->matchPassive(matching, options))
3665		{
3666		    if( options & kIONotifyOnce)
3667		    {
3668			service->retain();
3669			current = service;
3670			break;
3671		    }
3672		    if( current)
3673		    {
3674			((OSSet *)current)->setObject( service );
3675		    }
3676		    else
3677		    {
3678			current = OSSet::withObjects(
3679					(const OSObject **) &service, 1, 1 );
3680		    }
3681		}
3682		source->removeObject(service);
3683	    }
3684	    source->release();
3685	}
3686    }
3687
3688#if MATCH_DEBUG
3689    {
3690	OSObject * _current = 0;
3691
3692	iter = IORegistryIterator::iterateOver( gIOServicePlane,
3693					    kIORegistryIterateRecursively );
3694	if( iter) {
3695	    do {
3696		iter->reset();
3697		while( (service = (IOService *) iter->getNextObject())) {
3698		    if( (inState == (service->__state[0] & inState))
3699		    && (0 == (service->__state[0] & kIOServiceInactiveState))
3700		    &&  service->matchPassive(matching, 0)) {
3701
3702			if( options & kIONotifyOnce) {
3703			    service->retain();
3704			    _current = service;
3705			    break;
3706			}
3707			if( _current)
3708			    ((OSSet *)_current)->setObject( service );
3709			else
3710			    _current = OSSet::withObjects(
3711					    (const OSObject **) &service, 1, 1 );
3712		    }
3713		}
3714	    } while( !service && !iter->isValid());
3715	    iter->release();
3716	}
3717
3718
3719	if ( ((current != 0) != (_current != 0))
3720	|| (current && _current && !current->isEqualTo(_current)))
3721	{
3722	    OSSerialize * s1 = OSSerialize::withCapacity(128);
3723	    OSSerialize * s2 = OSSerialize::withCapacity(128);
3724	    current->serialize(s1);
3725	    _current->serialize(s2);
3726	    kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current),
3727                OBFUSCATE(_current), s->text(), s1->text(), s2->text());
3728	    s1->release();
3729	    s2->release();
3730	}
3731
3732	if (_current) _current->release();
3733    }
3734
3735    s->release();
3736#endif
3737
3738    if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
3739	iter = OSCollectionIterator::withCollection( (OSSet *)current );
3740	current->release();
3741	current = iter;
3742    }
3743
3744    return( current );
3745}
3746
3747// public version
3748OSIterator * IOService::getMatchingServices( OSDictionary * matching )
3749{
3750    OSIterator *	iter;
3751
3752    // is a lock even needed?
3753    LOCKWRITENOTIFY();
3754
3755    iter = (OSIterator *) copyExistingServices( matching,
3756						kIOServiceMatchedState );
3757
3758    UNLOCKNOTIFY();
3759
3760    return( iter );
3761}
3762
3763IOService * IOService::copyMatchingService( OSDictionary * matching )
3764{
3765    IOService *	service;
3766
3767    // is a lock even needed?
3768    LOCKWRITENOTIFY();
3769
3770    service = (IOService *) copyExistingServices( matching,
3771						kIOServiceMatchedState, kIONotifyOnce );
3772
3773    UNLOCKNOTIFY();
3774
3775    return( service );
3776}
3777
3778struct _IOServiceMatchingNotificationHandlerRef
3779{
3780    IOServiceNotificationHandler handler;
3781    void * ref;
3782};
3783
3784static bool _IOServiceMatchingNotificationHandler( void * target, void * refCon,
3785						   IOService * newService,
3786						   IONotifier * notifier )
3787{
3788    return ((*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService));
3789}
3790
3791// internal - call with gNotificationLock
3792IONotifier * IOService::setNotification(
3793	    const OSSymbol * type, OSDictionary * matching,
3794            IOServiceMatchingNotificationHandler handler, void * target, void * ref,
3795            SInt32 priority )
3796{
3797    _IOServiceNotifier * notify = 0;
3798    OSOrderedSet *	set;
3799
3800    if( !matching)
3801	return( 0 );
3802
3803    notify = new _IOServiceNotifier;
3804    if( notify && !notify->init()) {
3805        notify->release();
3806        notify = 0;
3807    }
3808
3809    if( notify) {
3810	notify->handler = handler;
3811        notify->target = target;
3812        notify->matching = matching;
3813	matching->retain();
3814	if (handler == &_IOServiceMatchingNotificationHandler)
3815	{
3816	    notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler;
3817	    notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref;
3818	}
3819	else
3820	    notify->ref = ref;
3821        notify->priority = priority;
3822	notify->state = kIOServiceNotifyEnable;
3823        queue_init( &notify->handlerInvocations );
3824
3825        ////// queue
3826
3827        if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
3828            set = OSOrderedSet::withCapacity( 1,
3829			IONotifyOrdering, 0 );
3830            if( set) {
3831                gNotifications->setObject( type, set );
3832                set->release();
3833            }
3834        }
3835        notify->whence = set;
3836        if( set)
3837            set->setObject( notify );
3838    }
3839
3840    return( notify );
3841}
3842
3843// internal - call with gNotificationLock
3844IONotifier * IOService::doInstallNotification(
3845			const OSSymbol * type, OSDictionary * matching,
3846			IOServiceMatchingNotificationHandler handler,
3847			void * target, void * ref,
3848			SInt32 priority, OSIterator ** existing )
3849{
3850    OSIterator *	exist;
3851    IONotifier *	notify;
3852    IOOptionBits	inState;
3853
3854    if( !matching)
3855	return( 0 );
3856
3857    if( type == gIOPublishNotification)
3858	inState = kIOServiceRegisteredState;
3859
3860    else if( type == gIOFirstPublishNotification)
3861	inState = kIOServiceFirstPublishState;
3862
3863    else if( (type == gIOMatchedNotification)
3864	  || (type == gIOFirstMatchNotification))
3865	inState = kIOServiceMatchedState;
3866    else if( type == gIOTerminatedNotification)
3867	inState = 0;
3868    else
3869        return( 0 );
3870
3871    notify = setNotification( type, matching, handler, target, ref, priority );
3872
3873    if( inState)
3874        // get the current set
3875        exist = (OSIterator *) copyExistingServices( matching, inState );
3876    else
3877	exist = 0;
3878
3879    *existing = exist;
3880
3881    return( notify );
3882}
3883
3884#if !defined(__LP64__)
3885IONotifier * IOService::installNotification(const OSSymbol * type, OSDictionary * matching,
3886					IOServiceNotificationHandler handler,
3887					void * target, void * refCon,
3888					SInt32 priority, OSIterator ** existing )
3889{
3890    IONotifier * result;
3891    _IOServiceMatchingNotificationHandlerRef ref;
3892    ref.handler = handler;
3893    ref.ref     = refCon;
3894
3895    result = (_IOServiceNotifier *) installNotification( type, matching,
3896			 &_IOServiceMatchingNotificationHandler,
3897			target, &ref, priority, existing );
3898    if (result)
3899	matching->release();
3900
3901    return (result);
3902}
3903#endif /* !defined(__LP64__) */
3904
3905
3906IONotifier * IOService::installNotification(
3907			const OSSymbol * type, OSDictionary * matching,
3908			IOServiceMatchingNotificationHandler handler,
3909			void * target, void * ref,
3910			SInt32 priority, OSIterator ** existing )
3911{
3912    IONotifier * notify;
3913
3914    LOCKWRITENOTIFY();
3915
3916    notify = doInstallNotification( type, matching, handler, target, ref,
3917		priority, existing );
3918
3919    UNLOCKNOTIFY();
3920
3921    return( notify );
3922}
3923
3924IONotifier * IOService::addNotification(
3925			const OSSymbol * type, OSDictionary * matching,
3926			IOServiceNotificationHandler handler,
3927			void * target, void * refCon,
3928			SInt32 priority )
3929{
3930    IONotifier * result;
3931    _IOServiceMatchingNotificationHandlerRef ref;
3932
3933    ref.handler = handler;
3934    ref.ref     = refCon;
3935
3936    result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler,
3937			    target, &ref, priority);
3938
3939    if (result)
3940	matching->release();
3941
3942    return (result);
3943}
3944
3945IONotifier * IOService::addMatchingNotification(
3946			const OSSymbol * type, OSDictionary * matching,
3947			IOServiceMatchingNotificationHandler handler,
3948			void * target, void * ref,
3949			SInt32 priority )
3950{
3951    OSIterator *		existing = NULL;
3952    _IOServiceNotifier *	notify;
3953    IOService *			next;
3954
3955    notify = (_IOServiceNotifier *) installNotification( type, matching,
3956		handler, target, ref, priority, &existing );
3957
3958    // send notifications for existing set
3959    if( existing) {
3960
3961        notify->retain();		// in case handler remove()s
3962        while( (next = (IOService *) existing->getNextObject())) {
3963
3964	    next->lockForArbitration();
3965	    if( 0 == (next->__state[0] & kIOServiceInactiveState))
3966                next->invokeNotifer( notify );
3967	    next->unlockForArbitration();
3968	}
3969        notify->release();
3970	existing->release();
3971    }
3972
3973    return( notify );
3974}
3975
3976bool IOService::syncNotificationHandler(
3977			void * /* target */, void * ref,
3978			IOService * newService,
3979			IONotifier * notifier )
3980{
3981
3982    LOCKWRITENOTIFY();
3983    if (!*((IOService **) ref))
3984    {
3985	newService->retain();
3986	(*(IOService **) ref) = newService;
3987	WAKEUPNOTIFY(ref);
3988    }
3989    UNLOCKNOTIFY();
3990
3991    return( false );
3992}
3993
3994IOService * IOService::waitForMatchingService( OSDictionary * matching,
3995						uint64_t timeout)
3996{
3997    IONotifier *	notify = 0;
3998    // priority doesn't help us much since we need a thread wakeup
3999    SInt32		priority = 0;
4000    IOService *  	result;
4001
4002    if (!matching)
4003        return( 0 );
4004
4005    result = NULL;
4006
4007    LOCKWRITENOTIFY();
4008    do
4009    {
4010        result = (IOService *) copyExistingServices( matching,
4011                            kIOServiceMatchedState, kIONotifyOnce );
4012	if (result)
4013	    break;
4014        notify = IOService::setNotification( gIOMatchedNotification, matching,
4015                    &IOService::syncNotificationHandler, (void *) 0,
4016                    &result, priority );
4017	 if (!notify)
4018	    break;
4019        if (UINT64_MAX != timeout)
4020	{
4021	    AbsoluteTime deadline;
4022	    nanoseconds_to_absolutetime(timeout, &deadline);
4023	    clock_absolutetime_interval_to_deadline(deadline, &deadline);
4024	    SLEEPNOTIFYTO(&result, deadline);
4025	}
4026        else
4027	{
4028	    SLEEPNOTIFY(&result);
4029	}
4030    }
4031    while( false );
4032
4033    UNLOCKNOTIFY();
4034
4035    if (notify)
4036        notify->remove();	// dequeues
4037
4038    return( result );
4039}
4040
4041IOService * IOService::waitForService( OSDictionary * matching,
4042					mach_timespec_t * timeout )
4043{
4044    IOService * result;
4045    uint64_t    timeoutNS;
4046
4047    if (timeout)
4048    {
4049	timeoutNS = timeout->tv_sec;
4050	timeoutNS *= kSecondScale;
4051	timeoutNS += timeout->tv_nsec;
4052    }
4053    else
4054	timeoutNS = UINT64_MAX;
4055
4056    result = waitForMatchingService(matching, timeoutNS);
4057
4058    matching->release();
4059    if (result)
4060	result->release();
4061
4062    return (result);
4063}
4064
4065void IOService::deliverNotification( const OSSymbol * type,
4066                            IOOptionBits orNewState, IOOptionBits andNewState )
4067{
4068    _IOServiceNotifier * notify;
4069    OSIterator *	 iter;
4070    OSArray *		 willSend = 0;
4071
4072    lockForArbitration();
4073
4074    if( (0 == (__state[0] & kIOServiceInactiveState))
4075     ||	(type == gIOTerminatedNotification)) {
4076
4077	LOCKREADNOTIFY();
4078
4079        iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
4080                    gNotifications->getObject( type ) );
4081
4082        if( iter) {
4083            while( (notify = (_IOServiceNotifier *) iter->getNextObject())) {
4084
4085                if( matchPassive(notify->matching, 0)
4086                  && (kIOServiceNotifyEnable & notify->state)) {
4087                    if( 0 == willSend)
4088                        willSend = OSArray::withCapacity(8);
4089                    if( willSend)
4090                        willSend->setObject( notify );
4091                }
4092            }
4093            iter->release();
4094        }
4095
4096        __state[0] = (__state[0] | orNewState) & andNewState;
4097
4098        UNLOCKNOTIFY();
4099    }
4100
4101    if( willSend) {
4102        for( unsigned int idx = 0;
4103             (notify = (_IOServiceNotifier *) willSend->getObject(idx));
4104             idx++) {
4105            invokeNotifer( notify );
4106        }
4107        willSend->release();
4108    }
4109    unlockForArbitration();
4110}
4111
4112IOOptionBits IOService::getState( void ) const
4113{
4114    return( __state[0] );
4115}
4116
4117/*
4118 * Helpers to make matching objects for simple cases
4119 */
4120
4121OSDictionary * IOService::serviceMatching( const OSString * name,
4122			OSDictionary * table )
4123{
4124
4125    const OSString *	str;
4126
4127    str = OSSymbol::withString(name);
4128    if( !str)
4129	return( 0 );
4130
4131    if( !table)
4132	table = OSDictionary::withCapacity( 2 );
4133    if( table)
4134        table->setObject(gIOProviderClassKey, (OSObject *)str );
4135    str->release();
4136
4137    return( table );
4138}
4139
4140OSDictionary * IOService::serviceMatching( const char * name,
4141			OSDictionary * table )
4142{
4143    const OSString *	str;
4144
4145    str = OSSymbol::withCString( name );
4146    if( !str)
4147	return( 0 );
4148
4149    table = serviceMatching( str, table );
4150    str->release();
4151    return( table );
4152}
4153
4154OSDictionary * IOService::nameMatching( const OSString * name,
4155			OSDictionary * table )
4156{
4157    if( !table)
4158	table = OSDictionary::withCapacity( 2 );
4159    if( table)
4160        table->setObject( gIONameMatchKey, (OSObject *)name );
4161
4162    return( table );
4163}
4164
4165OSDictionary * IOService::nameMatching( const char * name,
4166			OSDictionary * table )
4167{
4168    const OSString *	str;
4169
4170    str = OSSymbol::withCString( name );
4171    if( !str)
4172	return( 0 );
4173
4174    table = nameMatching( str, table );
4175    str->release();
4176    return( table );
4177}
4178
4179OSDictionary * IOService::resourceMatching( const OSString * str,
4180			OSDictionary * table )
4181{
4182    table = serviceMatching( gIOResourcesKey, table );
4183    if( table)
4184        table->setObject( gIOResourceMatchKey, (OSObject *) str );
4185
4186    return( table );
4187}
4188
4189OSDictionary * IOService::resourceMatching( const char * name,
4190			OSDictionary * table )
4191{
4192    const OSSymbol *	str;
4193
4194    str = OSSymbol::withCString( name );
4195    if( !str)
4196	return( 0 );
4197
4198    table = resourceMatching( str, table );
4199    str->release();
4200
4201    return( table );
4202}
4203
4204OSDictionary * IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
4205			OSDictionary * table )
4206{
4207    OSDictionary * properties;
4208
4209    properties = OSDictionary::withCapacity( 2 );
4210    if( !properties)
4211	return( 0 );
4212    properties->setObject( key, value );
4213
4214    if( !table)
4215	table = OSDictionary::withCapacity( 2 );
4216    if( table)
4217        table->setObject( gIOPropertyMatchKey, properties );
4218
4219    properties->release();
4220
4221    return( table );
4222}
4223
4224OSDictionary * IOService::registryEntryIDMatching( uint64_t entryID,
4225			OSDictionary * table )
4226{
4227    OSNumber *     num;
4228
4229    num = OSNumber::withNumber( entryID, 64 );
4230    if( !num)
4231	return( 0 );
4232
4233    if( !table)
4234	table = OSDictionary::withCapacity( 2 );
4235    if( table)
4236        table->setObject( gIORegistryEntryIDKey, num );
4237
4238    if (num)
4239	num->release();
4240
4241    return( table );
4242}
4243
4244
4245/*
4246 * _IOServiceNotifier
4247 */
4248
4249// wait for all threads, other than the current one,
4250//  to exit the handler
4251
4252void _IOServiceNotifier::wait()
4253{
4254    _IOServiceNotifierInvocation * next;
4255    bool doWait;
4256
4257    do {
4258        doWait = false;
4259        queue_iterate( &handlerInvocations, next,
4260                        _IOServiceNotifierInvocation *, link) {
4261            if( next->thread != current_thread() ) {
4262                doWait = true;
4263                break;
4264            }
4265        }
4266        if( doWait) {
4267            state |= kIOServiceNotifyWaiter;
4268            SLEEPNOTIFY(this);
4269        }
4270
4271    } while( doWait );
4272}
4273
4274void _IOServiceNotifier::free()
4275{
4276    assert( queue_empty( &handlerInvocations ));
4277    OSObject::free();
4278}
4279
4280void _IOServiceNotifier::remove()
4281{
4282    LOCKWRITENOTIFY();
4283
4284    if( whence) {
4285        whence->removeObject( (OSObject *) this );
4286        whence = 0;
4287    }
4288    if( matching) {
4289        matching->release();
4290        matching = 0;
4291    }
4292
4293    state &= ~kIOServiceNotifyEnable;
4294
4295    wait();
4296
4297    UNLOCKNOTIFY();
4298
4299    release();
4300}
4301
4302bool _IOServiceNotifier::disable()
4303{
4304    bool	ret;
4305
4306    LOCKWRITENOTIFY();
4307
4308    ret = (0 != (kIOServiceNotifyEnable & state));
4309    state &= ~kIOServiceNotifyEnable;
4310    if( ret)
4311        wait();
4312
4313    UNLOCKNOTIFY();
4314
4315    return( ret );
4316}
4317
4318void _IOServiceNotifier::enable( bool was )
4319{
4320    LOCKWRITENOTIFY();
4321    if( was)
4322        state |= kIOServiceNotifyEnable;
4323    else
4324        state &= ~kIOServiceNotifyEnable;
4325    UNLOCKNOTIFY();
4326}
4327
4328/*
4329 * IOResources
4330 */
4331
4332IOService * IOResources::resources( void )
4333{
4334    IOResources *	inst;
4335
4336    inst = new IOResources;
4337    if( inst && !inst->init()) {
4338	inst->release();
4339	inst = 0;
4340    }
4341
4342    return( inst );
4343}
4344
4345bool IOResources::init( OSDictionary * dictionary )
4346{
4347    // Do super init first
4348    if ( !super::init() )
4349        return false;
4350
4351    // Allow PAL layer to publish a value
4352    const char *property_name;
4353    int property_value;
4354
4355    pal_get_resource_property( &property_name, &property_value );
4356
4357    if( property_name ) {
4358	OSNumber *num;
4359	const OSSymbol *	sym;
4360
4361	if( (num = OSNumber::withNumber(property_value, 32)) != 0 ) {
4362	    if( (sym = OSSymbol::withCString( property_name)) != 0 ) {
4363		this->setProperty( sym, num );
4364		sym->release();
4365	    }
4366	    num->release();
4367	}
4368    }
4369
4370    return true;
4371}
4372
4373IOWorkLoop * IOResources::getWorkLoop() const
4374{
4375    // If we are the resource root
4376    // then use the platform's workloop
4377    if (this == (IOResources *) gIOResources)
4378	return getPlatform()->getWorkLoop();
4379    else
4380	return IOService::getWorkLoop();
4381}
4382
4383bool IOResources::matchPropertyTable( OSDictionary * table )
4384{
4385    OSObject *		prop;
4386    OSString *		str;
4387    OSSet *		set;
4388    OSIterator *	iter;
4389    bool		ok = true;
4390
4391    prop = table->getObject( gIOResourceMatchKey );
4392    str = OSDynamicCast( OSString, prop );
4393    if( str)
4394	ok = (0 != getProperty( str ));
4395
4396    else if( (set = OSDynamicCast( OSSet, prop))) {
4397
4398	iter = OSCollectionIterator::withCollection( set );
4399	ok = (iter != 0);
4400        while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) ))
4401            ok = (0 != getProperty( str ));
4402
4403        if( iter)
4404	    iter->release();
4405    }
4406
4407    return( ok );
4408}
4409
4410void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
4411{
4412    IOService::updateConsoleUsers(NULL, 0);
4413}
4414
4415void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage)
4416{
4417    IORegistryEntry * regEntry;
4418    OSObject *        locked = kOSBooleanFalse;
4419    uint32_t          idx;
4420    bool              publish;
4421    OSDictionary *    user;
4422    static IOMessage  sSystemPower;
4423
4424    regEntry = IORegistryEntry::getRegistryRoot();
4425
4426    if (!gIOChosenEntry)
4427	gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
4428
4429    IOLockLock(gIOConsoleUsersLock);
4430
4431    if (systemMessage)
4432    {
4433        sSystemPower = systemMessage;
4434#if HIBERNATION
4435	if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked())
4436	{
4437	    locked = kOSBooleanTrue;
4438	}
4439#endif /* HIBERNATION */
4440    }
4441
4442    if (consoleUsers)
4443    {
4444        OSNumber * num = 0;
4445	gIOConsoleLoggedIn = false;
4446	for (idx = 0;
4447	      (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
4448	      idx++)
4449	{
4450	    gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
4451	      		&& (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
4452	    if (!num)
4453	    {
4454   	        num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
4455	    }
4456	}
4457        gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
4458    }
4459
4460    if (!gIOConsoleLoggedIn
4461     || (kIOMessageSystemWillSleep == sSystemPower)
4462     || (kIOMessageSystemPagingOff == sSystemPower))
4463    {
4464	locked = kOSBooleanTrue;
4465    }
4466    else if (gIOConsoleLockTime)
4467    {
4468	clock_sec_t  now;
4469	clock_usec_t microsecs;
4470
4471	clock_get_calendar_microtime(&now, &microsecs);
4472	if (gIOConsoleLockTime > now)
4473	{
4474	    AbsoluteTime deadline;
4475	    clock_interval_to_deadline(gIOConsoleLockTime - now, kSecondScale, &deadline);
4476	    thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
4477	}
4478	else
4479	{
4480	    locked = kOSBooleanTrue;
4481	}
4482    }
4483
4484    publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
4485    if (publish)
4486    {
4487	regEntry->setProperty(gIOConsoleLockedKey, locked);
4488	if (consoleUsers)
4489	{
4490	    regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
4491	}
4492	OSIncrementAtomic( &gIOConsoleUsersSeed );
4493    }
4494
4495#if HIBERNATION
4496    if (gIOChosenEntry)
4497    {
4498	if (locked == kOSBooleanTrue) gIOScreenLockState = kIOScreenLockLocked;
4499	else if (gIOConsoleLockTime)  gIOScreenLockState = kIOScreenLockUnlocked;
4500	else                          gIOScreenLockState = kIOScreenLockNoLock;
4501	gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState));
4502    }
4503#endif /* HIBERNATION */
4504
4505    IOLockUnlock(gIOConsoleUsersLock);
4506
4507    if (publish)
4508    {
4509	publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
4510
4511	MessageClientsContext context;
4512
4513	context.service  = getServiceRoot();
4514	context.type     = kIOMessageConsoleSecurityChange;
4515	context.argument = (void *) regEntry;
4516	context.argSize  = 0;
4517
4518	applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
4519				 &messageClientsApplier, &context );
4520    }
4521}
4522
4523IOReturn IOResources::setProperties( OSObject * properties )
4524{
4525    IOReturn			err;
4526    const OSSymbol *		key;
4527    OSDictionary *		dict;
4528    OSCollectionIterator *	iter;
4529
4530    err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
4531    if ( kIOReturnSuccess != err)
4532	return( err );
4533
4534    dict = OSDynamicCast(OSDictionary, properties);
4535    if( 0 == dict)
4536	return( kIOReturnBadArgument);
4537
4538    iter = OSCollectionIterator::withCollection( dict);
4539    if( 0 == iter)
4540	return( kIOReturnBadArgument);
4541
4542    while( (key = OSDynamicCast(OSSymbol, iter->getNextObject())))
4543    {
4544	if (gIOConsoleUsersKey == key) do
4545	{
4546	    OSArray * consoleUsers;
4547	    consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
4548	    if (!consoleUsers)
4549		continue;
4550	    IOService::updateConsoleUsers(consoleUsers, 0);
4551	}
4552	while (false);
4553
4554	publishResource( key, dict->getObject(key) );
4555    }
4556
4557    iter->release();
4558
4559    return( kIOReturnSuccess );
4560}
4561
4562/*
4563 * Helpers for matching dictionaries.
4564 * Keys existing in matching are checked in properties.
4565 * Keys may be a string or OSCollection of IOStrings
4566 */
4567
4568bool IOService::compareProperty( OSDictionary * matching,
4569                                 const char * 	key )
4570{
4571    OSObject *	value;
4572    bool	ok;
4573
4574    value = matching->getObject( key );
4575    if( value)
4576        ok = value->isEqualTo( getProperty( key ));
4577    else
4578	ok = true;
4579
4580    return( ok );
4581}
4582
4583
4584bool IOService::compareProperty( OSDictionary *   matching,
4585                                 const OSString * key )
4586{
4587    OSObject *	value;
4588    bool	ok;
4589
4590    value = matching->getObject( key );
4591    if( value)
4592        ok = value->isEqualTo( getProperty( key ));
4593    else
4594	ok = true;
4595
4596    return( ok );
4597}
4598
4599bool IOService::compareProperties( OSDictionary * matching,
4600                                   OSCollection * keys )
4601{
4602    OSCollectionIterator *	iter;
4603    const OSString *		key;
4604    bool			ok = true;
4605
4606    if( !matching || !keys)
4607	return( false );
4608
4609    iter = OSCollectionIterator::withCollection( keys );
4610
4611    if( iter) {
4612	while( ok && (key = OSDynamicCast( OSString, iter->getNextObject())))
4613	    ok = compareProperty( matching, key );
4614
4615	iter->release();
4616    }
4617    keys->release();	// !! consume a ref !!
4618
4619    return( ok );
4620}
4621
4622/* Helper to add a location matching dict to the table */
4623
4624OSDictionary * IOService::addLocation( OSDictionary * table )
4625{
4626    OSDictionary * 	dict;
4627
4628    if( !table)
4629	return( 0 );
4630
4631    dict = OSDictionary::withCapacity( 1 );
4632    if( dict) {
4633        table->setObject( gIOLocationMatchKey, dict );
4634        dict->release();
4635    }
4636
4637    return( dict );
4638}
4639
4640/*
4641 * Go looking for a provider to match a location dict.
4642 */
4643
4644IOService * IOService::matchLocation( IOService * /* client */ )
4645{
4646    IOService *	parent;
4647
4648    parent = getProvider();
4649
4650    if( parent)
4651        parent = parent->matchLocation( this );
4652
4653    return( parent );
4654}
4655
4656bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
4657{
4658    OSString *		matched;
4659    OSObject *		obj;
4660    OSString *		str;
4661    IORegistryEntry *	entry;
4662    OSNumber *		num;
4663    bool		match = true;
4664    bool                changesOK = (0 != (kIOServiceChangesOK & options));
4665    uint32_t            count;
4666    uint32_t            done;
4667
4668    do
4669    {
4670	count = table->getCount();
4671	done = 0;
4672	str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
4673	if (str) {
4674	    done++;
4675	    match = ((kIOServiceClassDone & options) || (0 != metaCast(str)));
4676#if MATCH_DEBUG
4677	    match = (0 != metaCast( str ));
4678	    if ((kIOServiceClassDone & options) && !match) panic("classDone");
4679#endif
4680	    if ((!match) || (done == count)) break;
4681	}
4682
4683	obj = table->getObject( gIONameMatchKey );
4684	if( obj) {
4685	    done++;
4686	    match = compareNames( obj, changesOK ? &matched : 0 );
4687	    if (!match)	break;
4688	    if( changesOK && matched) {
4689		// leave a hint as to which name matched
4690		table->setObject( gIONameMatchedKey, matched );
4691		matched->release();
4692	    }
4693	    if (done == count) break;
4694	}
4695
4696	str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
4697	if (str)
4698	{
4699    	    const OSSymbol * sym;
4700	    done++;
4701	    match = false;
4702	    sym = copyLocation();
4703	    if (sym) {
4704		match = sym->isEqualTo( str );
4705		sym->release();
4706	    }
4707	    if ((!match) || (done == count)) break;
4708	}
4709
4710	obj = table->getObject( gIOPropertyMatchKey );
4711	if( obj)
4712	{
4713	    OSDictionary * dict;
4714	    OSDictionary * nextDict;
4715	    OSIterator *   iter;
4716	    done++;
4717	    match = false;
4718	    dict = dictionaryWithProperties();
4719	    if( dict) {
4720		nextDict = OSDynamicCast( OSDictionary, obj);
4721		if( nextDict)
4722		    iter = 0;
4723		else
4724		    iter = OSCollectionIterator::withCollection(
4725				OSDynamicCast(OSCollection, obj));
4726
4727		while( nextDict
4728		    || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary,
4729					    iter->getNextObject()))))) {
4730		    match = dict->isEqualTo( nextDict, nextDict);
4731		    if( match)
4732			break;
4733		    nextDict = 0;
4734		}
4735		dict->release();
4736		if( iter)
4737		    iter->release();
4738	    }
4739	    if ((!match) || (done == count)) break;
4740	}
4741
4742	str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
4743	if( str) {
4744	    done++;
4745	    entry = IORegistryEntry::fromPath( str->getCStringNoCopy() );
4746	    match = (this == entry);
4747	    if( entry)
4748		entry->release();
4749	    if ((!match) || (done == count)) break;
4750	}
4751
4752	num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
4753	if (num) {
4754	    done++;
4755	    match = (getRegistryEntryID() == num->unsigned64BitValue());
4756	    if ((!match) || (done == count)) break;
4757	}
4758
4759	num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
4760	if( num)
4761	{
4762	    OSIterator *	iter;
4763	    IOService *		service = 0;
4764	    UInt32		serviceCount = 0;
4765
4766	    done++;
4767	    iter = getClientIterator();
4768	    if( iter) {
4769		while( (service = (IOService *) iter->getNextObject())) {
4770		    if( kIOServiceInactiveState & service->__state[0])
4771			continue;
4772		    if( 0 == service->getProperty( gIOMatchCategoryKey ))
4773			continue;
4774		    ++serviceCount;
4775		}
4776		iter->release();
4777	    }
4778	    match = (serviceCount == num->unsigned32BitValue());
4779	    if ((!match) || (done == count)) break;
4780	}
4781
4782#define propMatch(key)					\
4783	obj = table->getObject(key);			\
4784	if (obj)					\
4785	{						\
4786	    OSObject * prop;				\
4787	    done++;					\
4788	    prop = copyProperty(key);			\
4789	    match = obj->isEqualTo(prop);		\
4790            if (prop) prop->release();			\
4791	    if ((!match) || (done == count)) break;	\
4792	}
4793	propMatch(kIOBSDNameKey)
4794	propMatch(kIOBSDMajorKey)
4795	propMatch(kIOBSDMinorKey)
4796	propMatch(kIOBSDUnitKey)
4797#undef propMatch
4798    }
4799    while (false);
4800
4801    if (did) *did = done;
4802    return (match);
4803}
4804
4805bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
4806{
4807    return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0));
4808}
4809
4810bool IOService::matchPassive(OSDictionary * table, uint32_t options)
4811{
4812    IOService *		where;
4813    OSDictionary *      nextTable;
4814    SInt32		score;
4815    OSNumber *		newPri;
4816    bool		match = true;
4817    bool		matchParent = false;
4818    uint32_t		count;
4819    uint32_t		done;
4820
4821    assert( table );
4822
4823#if MATCH_DEBUG
4824    OSDictionary * root = table;
4825#endif
4826
4827    where = this;
4828    do
4829    {
4830        do
4831        {
4832	    count = table->getCount();
4833	    if (!(kIOServiceInternalDone & options))
4834	    {
4835		match = where->matchInternal(table, options, &done);
4836		// don't call family if we've done all the entries in the table
4837		if ((!match) || (done == count)) break;
4838            }
4839
4840            // pass in score from property table
4841            score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
4842
4843            // do family specific matching
4844            match = where->matchPropertyTable( table, &score );
4845
4846            if( !match) {
4847#if IOMATCHDEBUG
4848                if( kIOLogMatch & getDebugFlags( table ))
4849                    LOG("%s: family specific matching fails\n", where->getName());
4850#endif
4851                break;
4852            }
4853
4854            if (kIOServiceChangesOK & options) {
4855                // save the score
4856                newPri = OSNumber::withNumber( score, 32 );
4857                if( newPri) {
4858                    table->setObject( gIOProbeScoreKey, newPri );
4859                    newPri->release();
4860                }
4861            }
4862
4863	    options = 0;
4864            matchParent = false;
4865
4866            nextTable = OSDynamicCast(OSDictionary,
4867                  table->getObject( gIOParentMatchKey ));
4868            if( nextTable) {
4869		// look for a matching entry anywhere up to root
4870                match = false;
4871                matchParent = true;
4872		table = nextTable;
4873                break;
4874            }
4875
4876            table = OSDynamicCast(OSDictionary,
4877                    table->getObject( gIOLocationMatchKey ));
4878            if (table) {
4879		// look for a matching entry at matchLocation()
4880                match = false;
4881                where = where->getProvider();
4882                if (where && (where = where->matchLocation(where))) continue;
4883            }
4884            break;
4885        }
4886        while (true);
4887    }
4888    while( matchParent && (!match) && (where = where->getProvider()) );
4889
4890#if MATCH_DEBUG
4891    if (where != this)
4892    {
4893	OSSerialize * s = OSSerialize::withCapacity(128);
4894	root->serialize(s);
4895	kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text());
4896	s->release();
4897    }
4898#endif
4899
4900    return( match );
4901}
4902
4903
4904IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4905                                    UInt32 type,  OSDictionary * properties,
4906                                    IOUserClient ** handler )
4907{
4908    const OSSymbol *userClientClass = 0;
4909    IOUserClient *client;
4910    OSObject *temp;
4911
4912    if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler ))
4913	return kIOReturnSuccess;
4914
4915    // First try my own properties for a user client class name
4916    temp = getProperty(gIOUserClientClassKey);
4917    if (temp) {
4918	if (OSDynamicCast(OSSymbol, temp))
4919	    userClientClass = (const OSSymbol *) temp;
4920	else if (OSDynamicCast(OSString, temp)) {
4921	    userClientClass = OSSymbol::withString((OSString *) temp);
4922	    if (userClientClass)
4923		setProperty(kIOUserClientClassKey,
4924			    (OSObject *) userClientClass);
4925	}
4926    }
4927
4928    // Didn't find one so lets just bomb out now without further ado.
4929    if (!userClientClass)
4930        return kIOReturnUnsupported;
4931
4932    // This reference is consumed by the IOServiceOpen call
4933    temp = OSMetaClass::allocClassWithName(userClientClass);
4934    if (!temp)
4935        return kIOReturnNoMemory;
4936
4937    if (OSDynamicCast(IOUserClient, temp))
4938        client = (IOUserClient *) temp;
4939    else {
4940        temp->release();
4941        return kIOReturnUnsupported;
4942    }
4943
4944    if ( !client->initWithTask(owningTask, securityID, type, properties) ) {
4945        client->release();
4946        return kIOReturnBadArgument;
4947    }
4948
4949    if ( !client->attach(this) ) {
4950        client->release();
4951        return kIOReturnUnsupported;
4952    }
4953
4954    if ( !client->start(this) ) {
4955        client->detach(this);
4956        client->release();
4957        return kIOReturnUnsupported;
4958    }
4959
4960    *handler = client;
4961    return kIOReturnSuccess;
4962}
4963
4964IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4965                                    UInt32 type, IOUserClient ** handler )
4966{
4967    return( kIOReturnUnsupported );
4968}
4969
4970IOReturn IOService::requestProbe( IOOptionBits options )
4971{
4972    return( kIOReturnUnsupported);
4973}
4974
4975/*
4976 * Convert an IOReturn to text. Subclasses which add additional
4977 * IOReturn's should override this method and call
4978 * super::stringFromReturn if the desired value is not found.
4979 */
4980
4981const char * IOService::stringFromReturn( IOReturn rtn )
4982{
4983    static const IONamedValue IOReturn_values[] = {
4984        {kIOReturnSuccess,          "success"                           },
4985        {kIOReturnError,            "general error"                     },
4986        {kIOReturnNoMemory,         "memory allocation error"           },
4987        {kIOReturnNoResources,      "resource shortage"                 },
4988        {kIOReturnIPCError,         "Mach IPC failure"                  },
4989        {kIOReturnNoDevice,         "no such device"                    },
4990        {kIOReturnNotPrivileged,    "privilege violation"               },
4991        {kIOReturnBadArgument,      "invalid argument"                  },
4992        {kIOReturnLockedRead,       "device is read locked"             },
4993        {kIOReturnLockedWrite,      "device is write locked"            },
4994        {kIOReturnExclusiveAccess,  "device is exclusive access"        },
4995        {kIOReturnBadMessageID,     "bad IPC message ID"                },
4996        {kIOReturnUnsupported,      "unsupported function"              },
4997        {kIOReturnVMError,          "virtual memory error"              },
4998        {kIOReturnInternalError,    "internal driver error"             },
4999        {kIOReturnIOError,          "I/O error"                         },
5000        {kIOReturnCannotLock,       "cannot acquire lock"               },
5001        {kIOReturnNotOpen,          "device is not open"                },
5002        {kIOReturnNotReadable,      "device is not readable"            },
5003        {kIOReturnNotWritable,      "device is not writeable"           },
5004        {kIOReturnNotAligned,       "alignment error"                   },
5005        {kIOReturnBadMedia,         "media error"                       },
5006        {kIOReturnStillOpen,        "device is still open"              },
5007        {kIOReturnRLDError,         "rld failure"                       },
5008        {kIOReturnDMAError,         "DMA failure"                       },
5009        {kIOReturnBusy,             "device is busy"                    },
5010        {kIOReturnTimeout,          "I/O timeout"                       },
5011        {kIOReturnOffline,          "device is offline"                 },
5012        {kIOReturnNotReady,         "device is not ready"               },
5013        {kIOReturnNotAttached,      "device/channel is not attached"    },
5014        {kIOReturnNoChannels,       "no DMA channels available"         },
5015        {kIOReturnNoSpace,          "no space for data"                 },
5016        {kIOReturnPortExists,       "device port already exists"        },
5017        {kIOReturnCannotWire,       "cannot wire physical memory"       },
5018        {kIOReturnNoInterrupt,      "no interrupt attached"             },
5019        {kIOReturnNoFrames,         "no DMA frames enqueued"            },
5020        {kIOReturnMessageTooLarge,  "message is too large"              },
5021        {kIOReturnNotPermitted,     "operation is not permitted"        },
5022        {kIOReturnNoPower,          "device is without power"           },
5023        {kIOReturnNoMedia,          "media is not present"              },
5024        {kIOReturnUnformattedMedia, "media is not formatted"            },
5025        {kIOReturnUnsupportedMode,  "unsupported mode"                  },
5026        {kIOReturnUnderrun,         "data underrun"                     },
5027        {kIOReturnOverrun,          "data overrun"                      },
5028        {kIOReturnDeviceError,      "device error"                      },
5029        {kIOReturnNoCompletion,     "no completion routine"             },
5030        {kIOReturnAborted,          "operation was aborted"             },
5031        {kIOReturnNoBandwidth,      "bus bandwidth would be exceeded"   },
5032        {kIOReturnNotResponding,    "device is not responding"          },
5033        {kIOReturnInvalid,          "unanticipated driver error"        },
5034        {0,                         NULL                                }
5035    };
5036
5037    return IOFindNameForValue(rtn, IOReturn_values);
5038}
5039
5040/*
5041 * Convert an IOReturn to an errno.
5042 */
5043int IOService::errnoFromReturn( IOReturn rtn )
5044{
5045    if (unix_err(err_get_code(rtn)) == rtn)
5046        return err_get_code(rtn);
5047
5048    switch(rtn) {
5049        // (obvious match)
5050        case kIOReturnSuccess:
5051            return(0);
5052        case kIOReturnNoMemory:
5053            return(ENOMEM);
5054        case kIOReturnNoDevice:
5055            return(ENXIO);
5056        case kIOReturnVMError:
5057            return(EFAULT);
5058        case kIOReturnNotPermitted:
5059            return(EPERM);
5060        case kIOReturnNotPrivileged:
5061            return(EACCES);
5062        case kIOReturnIOError:
5063            return(EIO);
5064        case kIOReturnNotWritable:
5065            return(EROFS);
5066        case kIOReturnBadArgument:
5067            return(EINVAL);
5068        case kIOReturnUnsupported:
5069            return(ENOTSUP);
5070        case kIOReturnBusy:
5071            return(EBUSY);
5072        case kIOReturnNoPower:
5073            return(EPWROFF);
5074        case kIOReturnDeviceError:
5075            return(EDEVERR);
5076        case kIOReturnTimeout:
5077            return(ETIMEDOUT);
5078        case kIOReturnMessageTooLarge:
5079            return(EMSGSIZE);
5080        case kIOReturnNoSpace:
5081            return(ENOSPC);
5082        case kIOReturnCannotLock:
5083            return(ENOLCK);
5084
5085        // (best match)
5086        case kIOReturnBadMessageID:
5087        case kIOReturnNoCompletion:
5088        case kIOReturnNotAligned:
5089            return(EINVAL);
5090        case kIOReturnNotReady:
5091            return(EBUSY);
5092        case kIOReturnRLDError:
5093            return(EBADMACHO);
5094        case kIOReturnPortExists:
5095        case kIOReturnStillOpen:
5096            return(EEXIST);
5097        case kIOReturnExclusiveAccess:
5098        case kIOReturnLockedRead:
5099        case kIOReturnLockedWrite:
5100        case kIOReturnNotOpen:
5101        case kIOReturnNotReadable:
5102            return(EACCES);
5103        case kIOReturnCannotWire:
5104        case kIOReturnNoResources:
5105            return(ENOMEM);
5106        case kIOReturnAborted:
5107        case kIOReturnOffline:
5108        case kIOReturnNotResponding:
5109            return(EBUSY);
5110        case kIOReturnBadMedia:
5111        case kIOReturnNoMedia:
5112        case kIOReturnNotAttached:
5113        case kIOReturnUnformattedMedia:
5114            return(ENXIO); // (media error)
5115        case kIOReturnDMAError:
5116        case kIOReturnOverrun:
5117        case kIOReturnUnderrun:
5118            return(EIO); // (transfer error)
5119        case kIOReturnNoBandwidth:
5120        case kIOReturnNoChannels:
5121        case kIOReturnNoFrames:
5122        case kIOReturnNoInterrupt:
5123            return(EIO); // (hardware error)
5124        case kIOReturnError:
5125        case kIOReturnInternalError:
5126        case kIOReturnInvalid:
5127            return(EIO); // (generic error)
5128        case kIOReturnIPCError:
5129            return(EIO); // (ipc error)
5130        default:
5131            return(EIO); // (all other errors)
5132    }
5133}
5134
5135IOReturn IOService::message( UInt32 type, IOService * provider,
5136				void * argument )
5137{
5138    /*
5139     * Generic entry point for calls from the provider.  A return value of
5140     * kIOReturnSuccess indicates that the message was received, and where
5141     * applicable, that it was successful.
5142     */
5143
5144    return kIOReturnUnsupported;
5145}
5146
5147/*
5148 * Device memory
5149 */
5150
5151IOItemCount IOService::getDeviceMemoryCount( void )
5152{
5153    OSArray *		array;
5154    IOItemCount		count;
5155
5156    array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
5157    if( array)
5158	count = array->getCount();
5159    else
5160	count = 0;
5161
5162    return( count);
5163}
5164
5165IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index )
5166{
5167    OSArray *		array;
5168    IODeviceMemory *	range;
5169
5170    array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
5171    if( array)
5172	range = (IODeviceMemory *) array->getObject( index );
5173    else
5174	range = 0;
5175
5176    return( range);
5177}
5178
5179IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index,
5180						IOOptionBits options )
5181{
5182    IODeviceMemory *	range;
5183    IOMemoryMap *	map;
5184
5185    range = getDeviceMemoryWithIndex( index );
5186    if( range)
5187	map = range->map( options );
5188    else
5189	map = 0;
5190
5191    return( map );
5192}
5193
5194OSArray * IOService::getDeviceMemory( void )
5195{
5196    return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
5197}
5198
5199
5200void IOService::setDeviceMemory( OSArray * array )
5201{
5202    setProperty( gIODeviceMemoryKey, array);
5203}
5204
5205/*
5206 * For machines where the transfers on an I/O bus can stall because
5207 * the CPU is in an idle mode, These APIs allow a driver to specify
5208 * the maximum bus stall that they can handle.  0 indicates no limit.
5209 */
5210void IOService::
5211setCPUSnoopDelay(UInt32 __unused ns)
5212{
5213#if defined(__i386__) || defined(__x86_64__)
5214    ml_set_maxsnoop(ns);
5215#endif /* defined(__i386__) || defined(__x86_64__) */
5216}
5217
5218UInt32 IOService::
5219getCPUSnoopDelay()
5220{
5221#if defined(__i386__) || defined(__x86_64__)
5222    return ml_get_maxsnoop();
5223#else
5224    return 0;
5225#endif /* defined(__i386__) || defined(__x86_64__) */
5226}
5227
5228#if defined(__i386__) || defined(__x86_64__)
5229static void
5230requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
5231{
5232    static const UInt kNoReplace = -1U;	// Must be an illegal index
5233    UInt replace = kNoReplace;
5234    bool setCpuDelay = false;
5235
5236    IORecursiveLockLock(sCpuDelayLock);
5237
5238    UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5239    CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5240    IOService * holder = NULL;
5241
5242    if (ns) {
5243        const CpuDelayEntry ne = {service, ns, delayType};
5244	holder = service;
5245        // Set maximum delay.
5246        for (UInt i = 0; i < count; i++) {
5247            IOService *thisService = entries[i].fService;
5248            bool sameType = (delayType == entries[i].fDelayType);
5249            if ((service == thisService) && sameType)
5250                replace = i;
5251            else if (!thisService) {
5252                if (kNoReplace == replace)
5253                    replace = i;
5254            }
5255            else if (sameType) {
5256                const UInt32 thisMax = entries[i].fMaxDelay;
5257                if (thisMax < ns)
5258		{
5259                    ns = thisMax;
5260		    holder = thisService;
5261		}
5262            }
5263        }
5264
5265        setCpuDelay = true;
5266        if (kNoReplace == replace)
5267            sCpuDelayData->appendBytes(&ne, sizeof(ne));
5268        else
5269            entries[replace] = ne;
5270    }
5271    else {
5272        ns = -1U;	// Set to max unsigned, i.e. no restriction
5273
5274        for (UInt i = 0; i < count; i++) {
5275            // Clear a maximum delay.
5276            IOService *thisService = entries[i].fService;
5277            if (thisService && (delayType == entries[i].fDelayType)) {
5278                UInt32 thisMax = entries[i].fMaxDelay;
5279                if (service == thisService)
5280                    replace = i;
5281                else if (thisMax < ns) {
5282                    ns = thisMax;
5283		    holder = thisService;
5284		}
5285            }
5286        }
5287
5288        // Check if entry found
5289        if (kNoReplace != replace) {
5290            entries[replace].fService = 0;	// Null the entry
5291            setCpuDelay = true;
5292        }
5293    }
5294
5295    if (setCpuDelay)
5296    {
5297        // Must be safe to call from locked context
5298        if (delayType == kCpuDelayBusStall)
5299        {
5300            ml_set_maxbusdelay(ns);
5301        }
5302        else if (delayType == kCpuDelayInterrupt)
5303        {
5304            ml_set_maxintdelay(ns);
5305        }
5306
5307	OSArray * handlers = sCpuLatencyHandlers[delayType];
5308	IOService * target;
5309	if (handlers) for (unsigned int idx = 0;
5310			    (target = (IOService *) handlers->getObject(idx));
5311			    idx++)
5312	{
5313	    target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
5314					    (void *) (uintptr_t) ns, holder,
5315					    NULL, NULL);
5316	}
5317    }
5318
5319    IORecursiveLockUnlock(sCpuDelayLock);
5320}
5321
5322static IOReturn
5323setLatencyHandler(UInt32 delayType, IOService * target, bool enable)
5324{
5325    IOReturn result = kIOReturnNotFound;
5326    OSArray * array;
5327    unsigned int idx;
5328
5329    IORecursiveLockLock(sCpuDelayLock);
5330
5331    do
5332    {
5333	if (enable && !sCpuLatencyHandlers[delayType])
5334	    sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4);
5335	array = sCpuLatencyHandlers[delayType];
5336	if (!array)
5337	    break;
5338	idx = array->getNextIndexOfObject(target, 0);
5339	if (!enable)
5340	{
5341	    if (-1U != idx)
5342	    {
5343		array->removeObject(idx);
5344		result = kIOReturnSuccess;
5345	    }
5346	}
5347	else
5348	{
5349	    if (-1U != idx) {
5350		result = kIOReturnExclusiveAccess;
5351		break;
5352	    }
5353	    array->setObject(target);
5354
5355	    UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5356	    CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5357	    UInt32 ns = -1U;	// Set to max unsigned, i.e. no restriction
5358	    IOService * holder = NULL;
5359
5360	    for (UInt i = 0; i < count; i++) {
5361		if (entries[i].fService
5362		  && (delayType == entries[i].fDelayType)
5363		  && (entries[i].fMaxDelay < ns)) {
5364		    ns = entries[i].fMaxDelay;
5365		    holder = entries[i].fService;
5366		}
5367	    }
5368	    target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
5369					    (void *) (uintptr_t) ns, holder,
5370					    NULL, NULL);
5371	    result = kIOReturnSuccess;
5372	}
5373    }
5374    while (false);
5375
5376    IORecursiveLockUnlock(sCpuDelayLock);
5377
5378    return (result);
5379}
5380
5381#endif /* defined(__i386__) || defined(__x86_64__) */
5382
5383void IOService::
5384requireMaxBusStall(UInt32 __unused ns)
5385{
5386#if defined(__i386__) || defined(__x86_64__)
5387    requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
5388#endif
5389}
5390
5391void IOService::
5392requireMaxInterruptDelay(uint32_t __unused ns)
5393{
5394#if defined(__i386__) || defined(__x86_64__)
5395    requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
5396#endif
5397}
5398
5399/*
5400 * Device interrupts
5401 */
5402
5403IOReturn IOService::resolveInterrupt(IOService *nub, int source)
5404{
5405  IOInterruptController *interruptController;
5406  OSArray               *array;
5407  OSData                *data;
5408  OSSymbol              *interruptControllerName;
5409  long                  numSources;
5410  IOInterruptSource     *interruptSources;
5411
5412  // Get the parents list from the nub.
5413  array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
5414  if (array == 0) return kIOReturnNoResources;
5415
5416  // Allocate space for the IOInterruptSources if needed... then return early.
5417  if (nub->_interruptSources == 0) {
5418    numSources = array->getCount();
5419    interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource));
5420    if (interruptSources == 0) return kIOReturnNoMemory;
5421
5422    bzero(interruptSources, numSources * sizeof(IOInterruptSource));
5423
5424    nub->_numInterruptSources = numSources;
5425    nub->_interruptSources = interruptSources;
5426    return kIOReturnSuccess;
5427  }
5428
5429  interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source));
5430  if (interruptControllerName == 0) return kIOReturnNoResources;
5431
5432  interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
5433  if (interruptController == 0) return kIOReturnNoResources;
5434
5435  // Get the interrupt numbers from the nub.
5436  array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
5437  if (array == 0) return kIOReturnNoResources;
5438  data = OSDynamicCast(OSData, array->getObject(source));
5439  if (data == 0) return kIOReturnNoResources;
5440
5441  // Set the interruptController and interruptSource in the nub's table.
5442  interruptSources = nub->_interruptSources;
5443  interruptSources[source].interruptController = interruptController;
5444  interruptSources[source].vectorData = data;
5445
5446  return kIOReturnSuccess;
5447}
5448
5449IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
5450{
5451  IOReturn ret;
5452
5453  /* Make sure the _interruptSources are set */
5454  if (_interruptSources == 0) {
5455    ret = resolveInterrupt(this, source);
5456    if (ret != kIOReturnSuccess) return ret;
5457  }
5458
5459  /* Make sure the local source number is valid */
5460  if ((source < 0) || (source >= _numInterruptSources))
5461    return kIOReturnNoInterrupt;
5462
5463  /* Look up the contoller for the local source */
5464  *interruptController = _interruptSources[source].interruptController;
5465
5466  if (*interruptController == NULL) {
5467    if (!resolve) return kIOReturnNoInterrupt;
5468
5469    /* Try to reslove the interrupt */
5470    ret = resolveInterrupt(this, source);
5471    if (ret != kIOReturnSuccess) return ret;
5472
5473    *interruptController = _interruptSources[source].interruptController;
5474  }
5475
5476  return kIOReturnSuccess;
5477}
5478
5479IOReturn IOService::registerInterrupt(int source, OSObject *target,
5480				      IOInterruptAction handler,
5481				      void *refCon)
5482{
5483  IOInterruptController *interruptController;
5484  IOReturn              ret;
5485
5486  ret = lookupInterrupt(source, true, &interruptController);
5487  if (ret != kIOReturnSuccess) return ret;
5488
5489  /* Register the source */
5490  return interruptController->registerInterrupt(this, source, target,
5491						(IOInterruptHandler)handler,
5492						refCon);
5493}
5494
5495IOReturn IOService::unregisterInterrupt(int source)
5496{
5497  IOInterruptController *interruptController;
5498  IOReturn              ret;
5499
5500  ret = lookupInterrupt(source, false, &interruptController);
5501  if (ret != kIOReturnSuccess) return ret;
5502
5503  /* Unregister the source */
5504  return interruptController->unregisterInterrupt(this, source);
5505}
5506
5507IOReturn IOService::getInterruptType(int source, int *interruptType)
5508{
5509  IOInterruptController *interruptController;
5510  IOReturn              ret;
5511
5512  ret = lookupInterrupt(source, true, &interruptController);
5513  if (ret != kIOReturnSuccess) return ret;
5514
5515  /* Return the type */
5516  return interruptController->getInterruptType(this, source, interruptType);
5517}
5518
5519IOReturn IOService::enableInterrupt(int source)
5520{
5521  IOInterruptController *interruptController;
5522  IOReturn              ret;
5523
5524  ret = lookupInterrupt(source, false, &interruptController);
5525  if (ret != kIOReturnSuccess) return ret;
5526
5527  /* Enable the source */
5528  return interruptController->enableInterrupt(this, source);
5529}
5530
5531IOReturn IOService::disableInterrupt(int source)
5532{
5533  IOInterruptController *interruptController;
5534  IOReturn              ret;
5535
5536  ret = lookupInterrupt(source, false, &interruptController);
5537  if (ret != kIOReturnSuccess) return ret;
5538
5539  /* Disable the source */
5540  return interruptController->disableInterrupt(this, source);
5541}
5542
5543IOReturn IOService::causeInterrupt(int source)
5544{
5545  IOInterruptController *interruptController;
5546  IOReturn              ret;
5547
5548  ret = lookupInterrupt(source, false, &interruptController);
5549  if (ret != kIOReturnSuccess) return ret;
5550
5551  /* Cause an interrupt for the source */
5552  return interruptController->causeInterrupt(this, source);
5553}
5554
5555IOReturn IOService::configureReport(IOReportChannelList    *channelList,
5556                                    IOReportConfigureAction action,
5557                                    void                   *result,
5558                                    void                   *destination)
5559{
5560    unsigned cnt;
5561
5562    for (cnt = 0; cnt < channelList->nchannels; cnt++) {
5563        if ( channelList->channels[cnt].channel_id == kPMPowerStatesChID ) {
5564            if (pwrMgt) configurePowerStatesReport(action, result);
5565            else  return kIOReturnUnsupported;
5566        }
5567        else if ( channelList->channels[cnt].channel_id == kPMCurrStateChID ) {
5568            if (pwrMgt) configureSimplePowerReport(action, result);
5569            else  return kIOReturnUnsupported;
5570        }
5571    }
5572
5573    return kIOReturnSuccess;
5574}
5575
5576IOReturn IOService::updateReport(IOReportChannelList      *channelList,
5577                                 IOReportUpdateAction      action,
5578                                 void                     *result,
5579                                 void                     *destination)
5580{
5581    unsigned cnt;
5582
5583    for (cnt = 0; cnt < channelList->nchannels; cnt++) {
5584        if ( channelList->channels[cnt].channel_id == kPMPowerStatesChID ) {
5585            if (pwrMgt) updatePowerStatesReport(action, result, destination);
5586            else return kIOReturnUnsupported;
5587        }
5588        else if ( channelList->channels[cnt].channel_id == kPMCurrStateChID ) {
5589            if (pwrMgt) updateSimplePowerReport(action, result, destination);
5590            else return kIOReturnUnsupported;
5591        }
5592    }
5593
5594    return kIOReturnSuccess;
5595}
5596
5597#if __LP64__
5598OSMetaClassDefineReservedUsed(IOService, 0);
5599OSMetaClassDefineReservedUsed(IOService, 1);
5600OSMetaClassDefineReservedUnused(IOService, 2);
5601OSMetaClassDefineReservedUnused(IOService, 3);
5602OSMetaClassDefineReservedUnused(IOService, 4);
5603OSMetaClassDefineReservedUnused(IOService, 5);
5604OSMetaClassDefineReservedUnused(IOService, 6);
5605OSMetaClassDefineReservedUnused(IOService, 7);
5606#else
5607OSMetaClassDefineReservedUsed(IOService, 0);
5608OSMetaClassDefineReservedUsed(IOService, 1);
5609OSMetaClassDefineReservedUsed(IOService, 2);
5610OSMetaClassDefineReservedUsed(IOService, 3);
5611OSMetaClassDefineReservedUsed(IOService, 4);
5612OSMetaClassDefineReservedUsed(IOService, 5);
5613OSMetaClassDefineReservedUsed(IOService, 6);
5614OSMetaClassDefineReservedUsed(IOService, 7);
5615#endif
5616OSMetaClassDefineReservedUnused(IOService, 8);
5617OSMetaClassDefineReservedUnused(IOService, 9);
5618OSMetaClassDefineReservedUnused(IOService, 10);
5619OSMetaClassDefineReservedUnused(IOService, 11);
5620OSMetaClassDefineReservedUnused(IOService, 12);
5621OSMetaClassDefineReservedUnused(IOService, 13);
5622OSMetaClassDefineReservedUnused(IOService, 14);
5623OSMetaClassDefineReservedUnused(IOService, 15);
5624OSMetaClassDefineReservedUnused(IOService, 16);
5625OSMetaClassDefineReservedUnused(IOService, 17);
5626OSMetaClassDefineReservedUnused(IOService, 18);
5627OSMetaClassDefineReservedUnused(IOService, 19);
5628OSMetaClassDefineReservedUnused(IOService, 20);
5629OSMetaClassDefineReservedUnused(IOService, 21);
5630OSMetaClassDefineReservedUnused(IOService, 22);
5631OSMetaClassDefineReservedUnused(IOService, 23);
5632OSMetaClassDefineReservedUnused(IOService, 24);
5633OSMetaClassDefineReservedUnused(IOService, 25);
5634OSMetaClassDefineReservedUnused(IOService, 26);
5635OSMetaClassDefineReservedUnused(IOService, 27);
5636OSMetaClassDefineReservedUnused(IOService, 28);
5637OSMetaClassDefineReservedUnused(IOService, 29);
5638OSMetaClassDefineReservedUnused(IOService, 30);
5639OSMetaClassDefineReservedUnused(IOService, 31);
5640OSMetaClassDefineReservedUnused(IOService, 32);
5641OSMetaClassDefineReservedUnused(IOService, 33);
5642OSMetaClassDefineReservedUnused(IOService, 34);
5643OSMetaClassDefineReservedUnused(IOService, 35);
5644OSMetaClassDefineReservedUnused(IOService, 36);
5645OSMetaClassDefineReservedUnused(IOService, 37);
5646OSMetaClassDefineReservedUnused(IOService, 38);
5647OSMetaClassDefineReservedUnused(IOService, 39);
5648OSMetaClassDefineReservedUnused(IOService, 40);
5649OSMetaClassDefineReservedUnused(IOService, 41);
5650OSMetaClassDefineReservedUnused(IOService, 42);
5651OSMetaClassDefineReservedUnused(IOService, 43);
5652OSMetaClassDefineReservedUnused(IOService, 44);
5653OSMetaClassDefineReservedUnused(IOService, 45);
5654OSMetaClassDefineReservedUnused(IOService, 46);
5655OSMetaClassDefineReservedUnused(IOService, 47);
5656