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