]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOService.cpp
xnu-2422.110.17.tar.gz
[apple/xnu.git] / iokit / Kernel / IOService.cpp
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
71 OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
72
73 OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
74
75 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
76
77 OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
78
79 OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
80
81 OSDefineMetaClassAndStructors(IOResources, IOService)
82
83 OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
84
85 OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject)
86
87 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
88
89 static IOPlatformExpert * gIOPlatform;
90 static class IOPMrootDomain * gIOPMRootDomain;
91 const IORegistryPlane * gIOServicePlane;
92 const IORegistryPlane * gIOPowerPlane;
93 const OSSymbol * gIODeviceMemoryKey;
94 const OSSymbol * gIOInterruptControllersKey;
95 const OSSymbol * gIOInterruptSpecifiersKey;
96
97 const OSSymbol * gIOResourcesKey;
98 const OSSymbol * gIOResourceMatchKey;
99 const OSSymbol * gIOProviderClassKey;
100 const OSSymbol * gIONameMatchKey;
101 const OSSymbol * gIONameMatchedKey;
102 const OSSymbol * gIOPropertyMatchKey;
103 const OSSymbol * gIOLocationMatchKey;
104 const OSSymbol * gIOParentMatchKey;
105 const OSSymbol * gIOPathMatchKey;
106 const OSSymbol * gIOMatchCategoryKey;
107 const OSSymbol * gIODefaultMatchCategoryKey;
108 const OSSymbol * gIOMatchedServiceCountKey;
109
110 const OSSymbol * gIOMapperIDKey;
111 const OSSymbol * gIOUserClientClassKey;
112 const OSSymbol * gIOKitDebugKey;
113
114 const OSSymbol * gIOCommandPoolSizeKey;
115
116 const OSSymbol * gIOConsoleLockedKey;
117 const OSSymbol * gIOConsoleUsersKey;
118 const OSSymbol * gIOConsoleSessionUIDKey;
119 const OSSymbol * gIOConsoleSessionAuditIDKey;
120 const OSSymbol * gIOConsoleUsersSeedKey;
121 const OSSymbol * gIOConsoleSessionOnConsoleKey;
122 const OSSymbol * gIOConsoleSessionLoginDoneKey;
123 const OSSymbol * gIOConsoleSessionSecureInputPIDKey;
124 const OSSymbol * gIOConsoleSessionScreenLockedTimeKey;
125
126 clock_sec_t gIOConsoleLockTime;
127 static bool gIOConsoleLoggedIn;
128 #if HIBERNATION
129 static uint32_t gIOScreenLockState;
130 #endif
131 static IORegistryEntry * gIOChosenEntry;
132
133 static int gIOResourceGenerationCount;
134
135 const OSSymbol * gIOServiceKey;
136 const OSSymbol * gIOPublishNotification;
137 const OSSymbol * gIOFirstPublishNotification;
138 const OSSymbol * gIOMatchedNotification;
139 const OSSymbol * gIOFirstMatchNotification;
140 const OSSymbol * gIOTerminatedNotification;
141
142 const OSSymbol * gIOGeneralInterest;
143 const OSSymbol * gIOBusyInterest;
144 const OSSymbol * gIOAppPowerStateInterest;
145 const OSSymbol * gIOPriorityPowerStateInterest;
146 const OSSymbol * gIOConsoleSecurityInterest;
147
148 static OSDictionary * gNotifications;
149 static IORecursiveLock * gNotificationLock;
150
151 static IOService * gIOResources;
152 static IOService * gIOServiceRoot;
153
154 static OSOrderedSet * gJobs;
155 static semaphore_port_t gJobsSemaphore;
156 static IOLock * gJobsLock;
157 static int gOutstandingJobs;
158 static int gNumConfigThreads;
159 static int gNumWaitingThreads;
160 static IOLock * gIOServiceBusyLock;
161
162 static thread_t gIOTerminateThread;
163 static UInt32 gIOTerminateWork;
164 static OSArray * gIOTerminatePhase2List;
165 static OSArray * gIOStopList;
166 static OSArray * gIOStopProviderList;
167 static OSArray * gIOFinalizeList;
168
169 static SInt32 gIOConsoleUsersSeed;
170 static OSData * gIOConsoleUsersSeedValue;
171
172 extern const OSSymbol * gIODTPHandleKey;
173
174 const OSSymbol * gIOPlatformSleepActionKey;
175 const OSSymbol * gIOPlatformWakeActionKey;
176 const OSSymbol * gIOPlatformQuiesceActionKey;
177 const OSSymbol * gIOPlatformActiveActionKey;
178
179 const OSSymbol * gIOPlatformFunctionHandlerSet;
180
181 static IOLock * gIOConsoleUsersLock;
182 static 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
220 struct ArbitrationLockQueueElement {
221 queue_chain_t link;
222 IOThread thread;
223 IOService * service;
224 unsigned count;
225 bool required;
226 bool aborted;
227 };
228
229 static queue_head_t gArbitrationLockQueueActive;
230 static queue_head_t gArbitrationLockQueueWaiting;
231 static queue_head_t gArbitrationLockQueueFree;
232 static IOLock * gArbitrationLockQueueLock;
233
234 bool 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)
244 struct CpuDelayEntry
245 {
246 IOService * fService;
247 UInt32 fMaxDelay;
248 UInt32 fDelayType;
249 };
250
251 enum {
252 kCpuDelayBusStall, kCpuDelayInterrupt,
253 kCpuNumDelayTypes
254 };
255
256 static OSData *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry));
257 static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc();
258 static OSArray *sCpuLatencyHandlers[kCpuNumDelayTypes];
259 const OSSymbol *sCPULatencyFunctionName[kCpuNumDelayTypes];
260
261 static void
262 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType);
263 static IOReturn
264 setLatencyHandler(UInt32 delayType, IOService * target, bool enable);
265
266 #endif /* defined(__i386__) || defined(__x86_64__) */
267
268 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
269
270 void 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
399 static 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
421 IOService * IOService::probe( IOService * provider,
422 SInt32 * score )
423 {
424 return( this );
425 }
426
427 bool IOService::start( IOService * provider )
428 {
429 return( true );
430 }
431
432 void IOService::stop( IOService * provider )
433 {
434 }
435
436 void 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 */
449 bool 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
476 IOService * IOService::getServiceRoot( void )
477 {
478 return( gIOServiceRoot );
479 }
480
481 void 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
531 void 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
584 void 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
666 IOReturn 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
745 bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score )
746 {
747 return( matchPropertyTable(table) );
748 }
749
750 bool 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
760 IOReturn IOService::getResources( void )
761 {
762 return( kIOReturnSuccess);
763 }
764
765 /*
766 * Client/provider accessors
767 */
768
769 IOService * 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
792 IOWorkLoop * IOService::getWorkLoop() const
793 {
794 IOService *provider = getProvider();
795
796 if (provider)
797 return provider->getWorkLoop();
798 else
799 return 0;
800 }
801
802 OSIterator * IOService::getProviderIterator( void ) const
803 {
804 return( getParentIterator( gIOServicePlane));
805 }
806
807 IOService * IOService::getClient( void ) const
808 {
809 return( (IOService *) getChildEntry( gIOServicePlane));
810 }
811
812 OSIterator * IOService::getClientIterator( void ) const
813 {
814 return( getChildIterator( gIOServicePlane));
815 }
816
817 OSIterator * _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
841 void _IOOpenServiceIterator::free()
842 {
843 iter->release();
844 if( last)
845 last->unlockForArbitration();
846 OSIterator::free();
847 }
848
849 OSObject * _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
870 bool _IOOpenServiceIterator::isValid()
871 {
872 return( iter->isValid() );
873 }
874
875 void _IOOpenServiceIterator::reset()
876 {
877 if( last) {
878 last->unlockForArbitration();
879 last = 0;
880 }
881 iter->reset();
882 }
883
884 OSIterator * IOService::getOpenProviderIterator( void ) const
885 {
886 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 ));
887 }
888
889 OSIterator * IOService::getOpenClientIterator( void ) const
890 {
891 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this ));
892 }
893
894
895 IOReturn 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
925 IOReturn 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
947 IOPlatformExpert * IOService::getPlatform( void )
948 {
949 return( gIOPlatform);
950 }
951
952 class IOPMrootDomain * IOService::getPMRootDomain( void )
953 {
954 return( gIOPMRootDomain);
955 }
956
957 IOService * IOService::getResourceService( void )
958 {
959 return( gIOResources );
960 }
961
962 void IOService::setPlatform( IOPlatformExpert * platform)
963 {
964 gIOPlatform = platform;
965 gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
966 }
967
968 void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
969 {
970 gIOPMRootDomain = rootDomain;
971 publishResource("IOKit");
972 }
973
974 /*
975 * Stacking change
976 */
977
978 bool 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
1139 restart_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
1263 void 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
1343 void IOService::applyToProviders( IOServiceApplierFunction applier,
1344 void * context )
1345 {
1346 applyToParents( (IORegistryEntryApplierFunction) applier,
1347 context, gIOServicePlane );
1348 }
1349
1350 void 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
1364 IOReturn 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
1413 static void
1414 applyToInterestNotifiers(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
1449 void 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
1458 struct MessageClientsContext {
1459 IOService * service;
1460 UInt32 type;
1461 void * argument;
1462 vm_size_t argSize;
1463 IOReturn ret;
1464 };
1465
1466 static 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
1478 IOReturn 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
1495 IOReturn IOService::acknowledgeNotification( IONotificationRef notification,
1496 IOOptionBits response )
1497 {
1498 return( kIOReturnUnsupported );
1499 }
1500
1501 IONotifier * 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
1557 static 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
1575 void 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
1591 void _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
1613 void _IOServiceInterestNotifier::free()
1614 {
1615 assert( queue_empty( &handlerInvocations ));
1616 OSObject::free();
1617 }
1618
1619 void _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
1638 bool _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
1654 void _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
1674 static 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
1689 bool 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
1706 bool 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
1840 void 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
1858 void 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
1923 void 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
1937 void 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
1964 void 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
1988 bool IOService::willTerminate( IOService * provider, IOOptionBits options )
1989 {
1990 return( true );
1991 }
1992
1993 bool 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
2014 void 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
2045 void 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
2079 void 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
2095 void 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
2117 void 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
2295 bool 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
2335 void IOService::doServiceTerminate( IOOptionBits options )
2336 {
2337 }
2338
2339 // a method in case someone needs to override it
2340 bool 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
2353 bool IOService::terminate( IOOptionBits options )
2354 {
2355 options |= kIOServiceTerminate;
2356
2357 return( terminatePhase1( options ));
2358 }
2359
2360 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2361
2362 /*
2363 * Open & close
2364 */
2365
2366 struct ServiceOpenMessageContext
2367 {
2368 IOService * service;
2369 UInt32 type;
2370 IOService * excludeClient;
2371 IOOptionBits options;
2372 };
2373
2374 static 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
2382 bool 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
2409 void 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
2442 bool 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
2456 bool 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
2477 void IOService::handleClose( IOService * forClient,
2478 IOOptionBits options )
2479 {
2480 if( __owner == forClient)
2481 __owner = 0;
2482 }
2483
2484 bool 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 */
2495 static 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
2514 static 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
2540 SInt32 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
2559 IOService * 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
2583 IOService * IOService::getClientWithCategory( const OSSymbol * category )
2584 {
2585 IOService *
2586 service = copyClientWithCategory(category);
2587 if (service)
2588 service->release();
2589 return (service);
2590 }
2591
2592 bool 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
2631 void 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
2937 bool 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
2980 void 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
2990 void 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
3004 bool 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
3034 bool 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
3066 bool 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
3093 void _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
3116 void _IOConfigThread::free( void )
3117 {
3118 thread_deallocate(current_thread());
3119 OSObject::free();
3120 }
3121
3122 void 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
3206 UInt32 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
3283 void IOService::adjustBusy( SInt32 delta )
3284 {
3285 lockForArbitration();
3286 _adjustBusy( delta );
3287 unlockForArbitration();
3288 }
3289
3290 uint64_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
3310 UInt32 IOService::getBusyState( void )
3311 {
3312 return( __state[1] & kIOServiceBusyStateMask );
3313 }
3314
3315 IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3316 mach_timespec_t * timeout )
3317 {
3318 panic("waitForState");
3319 return (kIOReturnUnsupported);
3320 }
3321
3322 IOReturn 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
3362 IOReturn 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
3373 IOReturn 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
3389 bool 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
3399 void _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
3477 IOReturn 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
3510 void _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
3545 struct 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
3555 bool 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
3597 OSObject * 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
3748 OSIterator * 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
3763 IOService * 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
3778 struct _IOServiceMatchingNotificationHandlerRef
3779 {
3780 IOServiceNotificationHandler handler;
3781 void * ref;
3782 };
3783
3784 static 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
3792 IONotifier * 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
3844 IONotifier * 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__)
3885 IONotifier * 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
3906 IONotifier * 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
3924 IONotifier * 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
3945 IONotifier * 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
3976 bool 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
3994 IOService * 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
4041 IOService * 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
4065 void 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
4112 IOOptionBits IOService::getState( void ) const
4113 {
4114 return( __state[0] );
4115 }
4116
4117 /*
4118 * Helpers to make matching objects for simple cases
4119 */
4120
4121 OSDictionary * 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
4140 OSDictionary * 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
4154 OSDictionary * 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
4165 OSDictionary * 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
4179 OSDictionary * 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
4189 OSDictionary * 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
4204 OSDictionary * 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
4224 OSDictionary * 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
4252 void _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
4274 void _IOServiceNotifier::free()
4275 {
4276 assert( queue_empty( &handlerInvocations ));
4277 OSObject::free();
4278 }
4279
4280 void _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
4302 bool _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
4318 void _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
4332 IOService * 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
4345 bool 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
4373 IOWorkLoop * 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
4383 bool 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
4410 void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
4411 {
4412 IOService::updateConsoleUsers(NULL, 0);
4413 }
4414
4415 void 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
4523 IOReturn 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
4568 bool 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
4584 bool 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
4599 bool 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
4624 OSDictionary * 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
4644 IOService * 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
4656 bool 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
4805 bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
4806 {
4807 return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0));
4808 }
4809
4810 bool 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
4904 IOReturn 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
4964 IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4965 UInt32 type, IOUserClient ** handler )
4966 {
4967 return( kIOReturnUnsupported );
4968 }
4969
4970 IOReturn 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
4981 const 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 */
5043 int 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
5135 IOReturn 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
5151 IOItemCount 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
5165 IODeviceMemory * 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
5179 IOMemoryMap * 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
5194 OSArray * IOService::getDeviceMemory( void )
5195 {
5196 return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
5197 }
5198
5199
5200 void 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 */
5210 void IOService::
5211 setCPUSnoopDelay(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
5218 UInt32 IOService::
5219 getCPUSnoopDelay()
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__)
5229 static void
5230 requireMaxCpuDelay(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
5322 static IOReturn
5323 setLatencyHandler(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
5383 void IOService::
5384 requireMaxBusStall(UInt32 __unused ns)
5385 {
5386 #if defined(__i386__) || defined(__x86_64__)
5387 requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
5388 #endif
5389 }
5390
5391 void IOService::
5392 requireMaxInterruptDelay(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
5403 IOReturn 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
5449 IOReturn 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
5479 IOReturn 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
5495 IOReturn 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
5507 IOReturn 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
5519 IOReturn 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
5531 IOReturn 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
5543 IOReturn 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
5555 IOReturn 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
5576 IOReturn 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__
5598 OSMetaClassDefineReservedUsed(IOService, 0);
5599 OSMetaClassDefineReservedUsed(IOService, 1);
5600 OSMetaClassDefineReservedUnused(IOService, 2);
5601 OSMetaClassDefineReservedUnused(IOService, 3);
5602 OSMetaClassDefineReservedUnused(IOService, 4);
5603 OSMetaClassDefineReservedUnused(IOService, 5);
5604 OSMetaClassDefineReservedUnused(IOService, 6);
5605 OSMetaClassDefineReservedUnused(IOService, 7);
5606 #else
5607 OSMetaClassDefineReservedUsed(IOService, 0);
5608 OSMetaClassDefineReservedUsed(IOService, 1);
5609 OSMetaClassDefineReservedUsed(IOService, 2);
5610 OSMetaClassDefineReservedUsed(IOService, 3);
5611 OSMetaClassDefineReservedUsed(IOService, 4);
5612 OSMetaClassDefineReservedUsed(IOService, 5);
5613 OSMetaClassDefineReservedUsed(IOService, 6);
5614 OSMetaClassDefineReservedUsed(IOService, 7);
5615 #endif
5616 OSMetaClassDefineReservedUnused(IOService, 8);
5617 OSMetaClassDefineReservedUnused(IOService, 9);
5618 OSMetaClassDefineReservedUnused(IOService, 10);
5619 OSMetaClassDefineReservedUnused(IOService, 11);
5620 OSMetaClassDefineReservedUnused(IOService, 12);
5621 OSMetaClassDefineReservedUnused(IOService, 13);
5622 OSMetaClassDefineReservedUnused(IOService, 14);
5623 OSMetaClassDefineReservedUnused(IOService, 15);
5624 OSMetaClassDefineReservedUnused(IOService, 16);
5625 OSMetaClassDefineReservedUnused(IOService, 17);
5626 OSMetaClassDefineReservedUnused(IOService, 18);
5627 OSMetaClassDefineReservedUnused(IOService, 19);
5628 OSMetaClassDefineReservedUnused(IOService, 20);
5629 OSMetaClassDefineReservedUnused(IOService, 21);
5630 OSMetaClassDefineReservedUnused(IOService, 22);
5631 OSMetaClassDefineReservedUnused(IOService, 23);
5632 OSMetaClassDefineReservedUnused(IOService, 24);
5633 OSMetaClassDefineReservedUnused(IOService, 25);
5634 OSMetaClassDefineReservedUnused(IOService, 26);
5635 OSMetaClassDefineReservedUnused(IOService, 27);
5636 OSMetaClassDefineReservedUnused(IOService, 28);
5637 OSMetaClassDefineReservedUnused(IOService, 29);
5638 OSMetaClassDefineReservedUnused(IOService, 30);
5639 OSMetaClassDefineReservedUnused(IOService, 31);
5640 OSMetaClassDefineReservedUnused(IOService, 32);
5641 OSMetaClassDefineReservedUnused(IOService, 33);
5642 OSMetaClassDefineReservedUnused(IOService, 34);
5643 OSMetaClassDefineReservedUnused(IOService, 35);
5644 OSMetaClassDefineReservedUnused(IOService, 36);
5645 OSMetaClassDefineReservedUnused(IOService, 37);
5646 OSMetaClassDefineReservedUnused(IOService, 38);
5647 OSMetaClassDefineReservedUnused(IOService, 39);
5648 OSMetaClassDefineReservedUnused(IOService, 40);
5649 OSMetaClassDefineReservedUnused(IOService, 41);
5650 OSMetaClassDefineReservedUnused(IOService, 42);
5651 OSMetaClassDefineReservedUnused(IOService, 43);
5652 OSMetaClassDefineReservedUnused(IOService, 44);
5653 OSMetaClassDefineReservedUnused(IOService, 45);
5654 OSMetaClassDefineReservedUnused(IOService, 46);
5655 OSMetaClassDefineReservedUnused(IOService, 47);