]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOService.cpp
0eabf83f9d70ebd488ce9ff04b5d4ebd2964723c
[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 deliverNotification( gIOFirstPublishNotification,
3113 kIOServiceFirstPublishState, 0xffffffff );
3114 LOCKREADNOTIFY();
3115 __state[1] &= ~kIOServiceNeedConfigState;
3116 __state[1] |= kIOServiceConfigState;
3117 didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
3118 __state[0] |= kIOServiceRegisteredState;
3119
3120 keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
3121 if (reRegistered && keepGuessing) {
3122 iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
3123 gNotifications->getObject( gIOPublishNotification ) );
3124 if( iter) {
3125 while((notify = (_IOServiceNotifier *)
3126 iter->getNextObject())) {
3127
3128 if( matchPassive(notify->matching, 0)
3129 && (kIOServiceNotifyEnable & notify->state))
3130 matches->setObject( notify );
3131 }
3132 iter->release();
3133 }
3134 }
3135
3136 UNLOCKNOTIFY();
3137 if (didRegister) {
3138 getMetaClass()->addInstance(this);
3139 }
3140 unlockForArbitration();
3141
3142 if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources()))
3143 probeCandidates( matches );
3144 else
3145 matches->release();
3146 }
3147
3148 lockForArbitration();
3149 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
3150 keepGuessing =
3151 (reRegistered || (catalogGeneration !=
3152 gIOCatalogue->getGenerationCount()))
3153 && (0 == (__state[0] & kIOServiceInactiveState));
3154
3155 if( keepGuessing)
3156 unlockForArbitration();
3157 }
3158
3159 if( (0 == (__state[0] & kIOServiceInactiveState))
3160 && (0 == (__state[1] & kIOServiceModuleStallState)) ) {
3161 deliverNotification( gIOMatchedNotification,
3162 kIOServiceMatchedState, 0xffffffff );
3163 if( 0 == (__state[0] & kIOServiceFirstMatchState))
3164 deliverNotification( gIOFirstMatchNotification,
3165 kIOServiceFirstMatchState, 0xffffffff );
3166 }
3167
3168 __state[1] &= ~kIOServiceConfigState;
3169 if( __state[0] & kIOServiceInactiveState)
3170 scheduleTerminatePhase2();
3171
3172 _adjustBusy( -1 );
3173 unlockForArbitration();
3174 }
3175
3176 UInt32 IOService::_adjustBusy( SInt32 delta )
3177 {
3178 IOService * next;
3179 UInt32 count;
3180 UInt32 result;
3181 bool wasQuiet, nowQuiet, needWake;
3182
3183 next = this;
3184 result = __state[1] & kIOServiceBusyStateMask;
3185
3186 if( delta) do {
3187 if( next != this)
3188 next->lockForArbitration();
3189 count = next->__state[1] & kIOServiceBusyStateMask;
3190 wasQuiet = (0 == count);
3191 if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count)))
3192 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), count, delta);
3193 else
3194 count += delta;
3195 next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count;
3196 nowQuiet = (0 == count);
3197 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
3198
3199 if( needWake) {
3200 next->__state[1] &= ~kIOServiceBusyWaiterState;
3201 IOLockLock( gIOServiceBusyLock );
3202 thread_wakeup( (event_t) next);
3203 IOLockUnlock( gIOServiceBusyLock );
3204 }
3205 if( next != this)
3206 next->unlockForArbitration();
3207
3208 if( (wasQuiet || nowQuiet) ) {
3209 uint64_t regID = next->getRegistryEntryID();
3210
3211 IOServiceTrace(
3212 ((wasQuiet/*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY),
3213 (uintptr_t) regID,
3214 (uintptr_t) (regID >> 32),
3215 (uintptr_t) next,
3216 0);
3217
3218 if (wasQuiet)
3219 {
3220 next->__timeBusy = mach_absolute_time();
3221 }
3222 else
3223 {
3224 next->__accumBusy += mach_absolute_time() - next->__timeBusy;
3225 next->__timeBusy = 0;
3226 }
3227
3228 MessageClientsContext context;
3229
3230 context.service = next;
3231 context.type = kIOMessageServiceBusyStateChange;
3232 context.argument = (void *) wasQuiet; /*nowBusy*/
3233 context.argSize = 0;
3234
3235 applyToInterestNotifiers( next, gIOBusyInterest,
3236 &messageClientsApplier, &context );
3237
3238 #if !NO_KEXTD
3239 if( nowQuiet && (next == gIOServiceRoot)) {
3240 OSKext::considerUnloads();
3241 IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
3242 }
3243 #endif
3244 }
3245
3246 delta = nowQuiet ? -1 : +1;
3247
3248 } while( (wasQuiet || nowQuiet) && (next = next->getProvider()));
3249
3250 return( result );
3251 }
3252
3253 void IOService::adjustBusy( SInt32 delta )
3254 {
3255 lockForArbitration();
3256 _adjustBusy( delta );
3257 unlockForArbitration();
3258 }
3259
3260 uint64_t IOService::getAccumulatedBusyTime( void )
3261 {
3262 uint64_t accumBusy = __accumBusy;
3263 uint64_t timeBusy = __timeBusy;
3264 uint64_t nano;
3265
3266 do
3267 {
3268 accumBusy = __accumBusy;
3269 timeBusy = __timeBusy;
3270 if (timeBusy)
3271 accumBusy += mach_absolute_time() - timeBusy;
3272 }
3273 while (timeBusy != __timeBusy);
3274
3275 absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano);
3276
3277 return (nano);
3278 }
3279
3280 UInt32 IOService::getBusyState( void )
3281 {
3282 return( __state[1] & kIOServiceBusyStateMask );
3283 }
3284
3285 IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3286 mach_timespec_t * timeout )
3287 {
3288 panic("waitForState");
3289 return (kIOReturnUnsupported);
3290 }
3291
3292 IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
3293 uint64_t timeout )
3294 {
3295 bool wait;
3296 int waitResult = THREAD_AWAKENED;
3297 bool computeDeadline = true;
3298 AbsoluteTime abstime;
3299
3300 do {
3301 lockForArbitration();
3302 IOLockLock( gIOServiceBusyLock );
3303 wait = (value != (__state[1] & mask));
3304 if( wait) {
3305 __state[1] |= kIOServiceBusyWaiterState;
3306 unlockForArbitration();
3307 if( timeout != UINT64_MAX ) {
3308 if( computeDeadline ) {
3309 AbsoluteTime nsinterval;
3310 nanoseconds_to_absolutetime(timeout, &nsinterval );
3311 clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
3312 computeDeadline = false;
3313 }
3314 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
3315 }
3316 else
3317 assert_wait((event_t)this, THREAD_UNINT );
3318 } else
3319 unlockForArbitration();
3320 IOLockUnlock( gIOServiceBusyLock );
3321 if( wait)
3322 waitResult = thread_block(THREAD_CONTINUE_NULL);
3323
3324 } while( wait && (waitResult != THREAD_TIMED_OUT));
3325
3326 if( waitResult == THREAD_TIMED_OUT)
3327 return( kIOReturnTimeout );
3328 else
3329 return( kIOReturnSuccess );
3330 }
3331
3332 IOReturn IOService::waitQuiet( uint64_t timeout )
3333 {
3334 return( waitForState( kIOServiceBusyStateMask, 0, timeout ));
3335 }
3336
3337 IOReturn IOService::waitQuiet( mach_timespec_t * timeout )
3338 {
3339 uint64_t timeoutNS;
3340
3341 if (timeout)
3342 {
3343 timeoutNS = timeout->tv_sec;
3344 timeoutNS *= kSecondScale;
3345 timeoutNS += timeout->tv_nsec;
3346 }
3347 else
3348 timeoutNS = UINT64_MAX;
3349
3350 return( waitForState( kIOServiceBusyStateMask, 0, timeoutNS ));
3351 }
3352
3353 bool IOService::serializeProperties( OSSerialize * s ) const
3354 {
3355 #if 0
3356 ((IOService *)this)->setProperty( ((IOService *)this)->__state,
3357 sizeof( __state), "__state");
3358 #endif
3359 return( super::serializeProperties(s) );
3360 }
3361
3362
3363 void _IOConfigThread::main(void * arg, wait_result_t result)
3364 {
3365 _IOConfigThread * self = (_IOConfigThread *) arg;
3366 _IOServiceJob * job;
3367 IOService * nub;
3368 bool alive = true;
3369 kern_return_t kr;
3370 thread_precedence_policy_data_t precedence = { -1 };
3371
3372 kr = thread_policy_set(current_thread(),
3373 THREAD_PRECEDENCE_POLICY,
3374 (thread_policy_t) &precedence,
3375 THREAD_PRECEDENCE_POLICY_COUNT);
3376 if (KERN_SUCCESS != kr)
3377 IOLog("thread_policy_set(%d)\n", kr);
3378
3379 do {
3380
3381 // randomDelay();
3382
3383 semaphore_wait( gJobsSemaphore );
3384
3385 IOTakeLock( gJobsLock );
3386 job = (_IOServiceJob *) gJobs->getFirstObject();
3387 job->retain();
3388 gJobs->removeObject(job);
3389 if( job) {
3390 gOutstandingJobs--;
3391 // gNumConfigThreads--; // we're out of service
3392 gNumWaitingThreads--; // we're out of service
3393 }
3394 IOUnlock( gJobsLock );
3395
3396 if( job) {
3397
3398 nub = job->nub;
3399
3400 if( gIOKitDebug & kIOLogConfig)
3401 LOG("config(%p): starting on %s, %d\n",
3402 IOThreadSelf(), job->nub->getName(), job->type);
3403
3404 switch( job->type) {
3405
3406 case kMatchNubJob:
3407 nub->doServiceMatch( job->options );
3408 break;
3409
3410 default:
3411 LOG("config(%p): strange type (%d)\n",
3412 IOThreadSelf(), job->type );
3413 break;
3414 }
3415
3416 nub->release();
3417 job->release();
3418
3419 IOTakeLock( gJobsLock );
3420 alive = (gOutstandingJobs > gNumWaitingThreads);
3421 if( alive)
3422 gNumWaitingThreads++; // back in service
3423 // gNumConfigThreads++;
3424 else {
3425 if( 0 == --gNumConfigThreads) {
3426 // IOLog("MATCH IDLE\n");
3427 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
3428 }
3429 }
3430 IOUnlock( gJobsLock );
3431 }
3432
3433 } while( alive );
3434
3435 if( gIOKitDebug & kIOLogConfig)
3436 LOG("config(%p): terminating\n", IOThreadSelf() );
3437
3438 self->release();
3439 }
3440
3441 IOReturn IOService::waitMatchIdle( UInt32 msToWait )
3442 {
3443 bool wait;
3444 int waitResult = THREAD_AWAKENED;
3445 bool computeDeadline = true;
3446 AbsoluteTime deadline;
3447
3448 IOLockLock( gJobsLock );
3449 do {
3450 wait = (0 != gNumConfigThreads);
3451 if( wait) {
3452 if( msToWait) {
3453 if( computeDeadline ) {
3454 clock_interval_to_deadline(
3455 msToWait, kMillisecondScale, &deadline );
3456 computeDeadline = false;
3457 }
3458 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
3459 deadline, THREAD_UNINT );
3460 } else {
3461 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
3462 THREAD_UNINT );
3463 }
3464 }
3465 } while( wait && (waitResult != THREAD_TIMED_OUT));
3466 IOLockUnlock( gJobsLock );
3467
3468 if( waitResult == THREAD_TIMED_OUT)
3469 return( kIOReturnTimeout );
3470 else
3471 return( kIOReturnSuccess );
3472 }
3473
3474 void _IOServiceJob::pingConfig( _IOServiceJob * job )
3475 {
3476 int count;
3477 bool create;
3478
3479 assert( job );
3480
3481 IOTakeLock( gJobsLock );
3482
3483 gOutstandingJobs++;
3484 gJobs->setLastObject( job );
3485
3486 count = gNumWaitingThreads;
3487 // if( gNumConfigThreads) count++;// assume we're called from a config thread
3488
3489 create = ( (gOutstandingJobs > count)
3490 && (gNumConfigThreads < kMaxConfigThreads) );
3491 if( create) {
3492 gNumConfigThreads++;
3493 gNumWaitingThreads++;
3494 }
3495
3496 IOUnlock( gJobsLock );
3497
3498 job->release();
3499
3500 if( create) {
3501 if( gIOKitDebug & kIOLogConfig)
3502 LOG("config(%d): creating\n", gNumConfigThreads - 1);
3503 _IOConfigThread::configThread();
3504 }
3505
3506 semaphore_signal( gJobsSemaphore );
3507 }
3508
3509 struct IOServiceMatchContext
3510 {
3511 OSDictionary * table;
3512 OSObject * result;
3513 uint32_t options;
3514 uint32_t state;
3515 uint32_t count;
3516 uint32_t done;
3517 };
3518
3519 bool IOService::instanceMatch(const OSObject * entry, void * context)
3520 {
3521 IOServiceMatchContext * ctx = (typeof(ctx)) context;
3522 IOService * service = (typeof(service)) entry;
3523 OSDictionary * table = ctx->table;
3524 uint32_t options = ctx->options;
3525 uint32_t state = ctx->state;
3526 uint32_t done;
3527 bool match;
3528
3529 done = 0;
3530 do
3531 {
3532 match = ((state == (state & service->__state[0]))
3533 && (0 == (service->__state[0] & kIOServiceInactiveState)));
3534 if (!match) break;
3535 ctx->count += table->getCount();
3536 match = service->matchInternal(table, options, &done);
3537 ctx->done += done;
3538 }
3539 while (false);
3540 if (!match)
3541 return (false);
3542
3543 if ((kIONotifyOnce & options) && (ctx->done == ctx->count))
3544 {
3545 service->retain();
3546 ctx->result = service;
3547 return (true);
3548 }
3549 else if (!ctx->result)
3550 {
3551 ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1);
3552 }
3553 else
3554 {
3555 ((OSSet *)ctx->result)->setObject(service);
3556 }
3557 return (false);
3558 }
3559
3560 // internal - call with gNotificationLock
3561 OSObject * IOService::copyExistingServices( OSDictionary * matching,
3562 IOOptionBits inState, IOOptionBits options )
3563 {
3564 OSObject * current = 0;
3565 OSIterator * iter;
3566 IOService * service;
3567 OSObject * obj;
3568 OSString * str;
3569
3570 if( !matching)
3571 return( 0 );
3572
3573 #if MATCH_DEBUG
3574 OSSerialize * s = OSSerialize::withCapacity(128);
3575 matching->serialize(s);
3576 #endif
3577
3578 if((obj = matching->getObject(gIOProviderClassKey))
3579 && gIOResourcesKey
3580 && gIOResourcesKey->isEqualTo(obj)
3581 && (service = gIOResources))
3582 {
3583 if( (inState == (service->__state[0] & inState))
3584 && (0 == (service->__state[0] & kIOServiceInactiveState))
3585 && service->matchPassive(matching, options))
3586 {
3587 if( options & kIONotifyOnce)
3588 {
3589 service->retain();
3590 current = service;
3591 }
3592 else
3593 current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
3594 }
3595 }
3596 else
3597 {
3598 IOServiceMatchContext ctx;
3599 ctx.table = matching;
3600 ctx.state = inState;
3601 ctx.count = 0;
3602 ctx.done = 0;
3603 ctx.options = options;
3604 ctx.result = 0;
3605
3606 if ((str = OSDynamicCast(OSString, obj)))
3607 {
3608 const OSSymbol * sym = OSSymbol::withString(str);
3609 OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx);
3610 sym->release();
3611 }
3612 else
3613 {
3614 IOService::gMetaClass.applyToInstances(instanceMatch, &ctx);
3615 }
3616
3617
3618 current = ctx.result;
3619
3620 options |= kIOServiceInternalDone | kIOServiceClassDone;
3621 if (current && (ctx.done != ctx.count))
3622 {
3623 OSSet *
3624 source = OSDynamicCast(OSSet, current);
3625 current = 0;
3626 while ((service = (IOService *) source->getAnyObject()))
3627 {
3628 if (service->matchPassive(matching, options))
3629 {
3630 if( options & kIONotifyOnce)
3631 {
3632 service->retain();
3633 current = service;
3634 break;
3635 }
3636 if( current)
3637 {
3638 ((OSSet *)current)->setObject( service );
3639 }
3640 else
3641 {
3642 current = OSSet::withObjects(
3643 (const OSObject **) &service, 1, 1 );
3644 }
3645 }
3646 source->removeObject(service);
3647 }
3648 source->release();
3649 }
3650 }
3651
3652 #if MATCH_DEBUG
3653 {
3654 OSObject * _current = 0;
3655
3656 iter = IORegistryIterator::iterateOver( gIOServicePlane,
3657 kIORegistryIterateRecursively );
3658 if( iter) {
3659 do {
3660 iter->reset();
3661 while( (service = (IOService *) iter->getNextObject())) {
3662 if( (inState == (service->__state[0] & inState))
3663 && (0 == (service->__state[0] & kIOServiceInactiveState))
3664 && service->matchPassive(matching, 0)) {
3665
3666 if( options & kIONotifyOnce) {
3667 service->retain();
3668 _current = service;
3669 break;
3670 }
3671 if( _current)
3672 ((OSSet *)_current)->setObject( service );
3673 else
3674 _current = OSSet::withObjects(
3675 (const OSObject **) &service, 1, 1 );
3676 }
3677 }
3678 } while( !service && !iter->isValid());
3679 iter->release();
3680 }
3681
3682
3683 if ( ((current != 0) != (_current != 0))
3684 || (current && _current && !current->isEqualTo(_current)))
3685 {
3686 OSSerialize * s1 = OSSerialize::withCapacity(128);
3687 OSSerialize * s2 = OSSerialize::withCapacity(128);
3688 current->serialize(s1);
3689 _current->serialize(s2);
3690 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", current, _current, s->text(), s1->text(), s2->text());
3691 s1->release();
3692 s2->release();
3693 }
3694
3695 if (_current) _current->release();
3696 }
3697
3698 s->release();
3699 #endif
3700
3701 if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
3702 iter = OSCollectionIterator::withCollection( (OSSet *)current );
3703 current->release();
3704 current = iter;
3705 }
3706
3707 return( current );
3708 }
3709
3710 // public version
3711 OSIterator * IOService::getMatchingServices( OSDictionary * matching )
3712 {
3713 OSIterator * iter;
3714
3715 // is a lock even needed?
3716 LOCKWRITENOTIFY();
3717
3718 iter = (OSIterator *) copyExistingServices( matching,
3719 kIOServiceMatchedState );
3720
3721 UNLOCKNOTIFY();
3722
3723 return( iter );
3724 }
3725
3726 IOService * IOService::copyMatchingService( OSDictionary * matching )
3727 {
3728 IOService * service;
3729
3730 // is a lock even needed?
3731 LOCKWRITENOTIFY();
3732
3733 service = (IOService *) copyExistingServices( matching,
3734 kIOServiceMatchedState, kIONotifyOnce );
3735
3736 UNLOCKNOTIFY();
3737
3738 return( service );
3739 }
3740
3741 struct _IOServiceMatchingNotificationHandlerRef
3742 {
3743 IOServiceNotificationHandler handler;
3744 void * ref;
3745 };
3746
3747 static bool _IOServiceMatchingNotificationHandler( void * target, void * refCon,
3748 IOService * newService,
3749 IONotifier * notifier )
3750 {
3751 return ((*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService));
3752 }
3753
3754 // internal - call with gNotificationLock
3755 IONotifier * IOService::setNotification(
3756 const OSSymbol * type, OSDictionary * matching,
3757 IOServiceMatchingNotificationHandler handler, void * target, void * ref,
3758 SInt32 priority )
3759 {
3760 _IOServiceNotifier * notify = 0;
3761 OSOrderedSet * set;
3762
3763 if( !matching)
3764 return( 0 );
3765
3766 notify = new _IOServiceNotifier;
3767 if( notify && !notify->init()) {
3768 notify->release();
3769 notify = 0;
3770 }
3771
3772 if( notify) {
3773 notify->handler = handler;
3774 notify->target = target;
3775 notify->matching = matching;
3776 matching->retain();
3777 if (handler == &_IOServiceMatchingNotificationHandler)
3778 {
3779 notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler;
3780 notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref;
3781 }
3782 else
3783 notify->ref = ref;
3784 notify->priority = priority;
3785 notify->state = kIOServiceNotifyEnable;
3786 queue_init( &notify->handlerInvocations );
3787
3788 ////// queue
3789
3790 if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
3791 set = OSOrderedSet::withCapacity( 1,
3792 IONotifyOrdering, 0 );
3793 if( set) {
3794 gNotifications->setObject( type, set );
3795 set->release();
3796 }
3797 }
3798 notify->whence = set;
3799 if( set)
3800 set->setObject( notify );
3801 }
3802
3803 return( notify );
3804 }
3805
3806 // internal - call with gNotificationLock
3807 IONotifier * IOService::doInstallNotification(
3808 const OSSymbol * type, OSDictionary * matching,
3809 IOServiceMatchingNotificationHandler handler,
3810 void * target, void * ref,
3811 SInt32 priority, OSIterator ** existing )
3812 {
3813 OSIterator * exist;
3814 IONotifier * notify;
3815 IOOptionBits inState;
3816
3817 if( !matching)
3818 return( 0 );
3819
3820 if( type == gIOPublishNotification)
3821 inState = kIOServiceRegisteredState;
3822
3823 else if( type == gIOFirstPublishNotification)
3824 inState = kIOServiceFirstPublishState;
3825
3826 else if( (type == gIOMatchedNotification)
3827 || (type == gIOFirstMatchNotification))
3828 inState = kIOServiceMatchedState;
3829 else if( type == gIOTerminatedNotification)
3830 inState = 0;
3831 else
3832 return( 0 );
3833
3834 notify = setNotification( type, matching, handler, target, ref, priority );
3835
3836 if( inState)
3837 // get the current set
3838 exist = (OSIterator *) copyExistingServices( matching, inState );
3839 else
3840 exist = 0;
3841
3842 *existing = exist;
3843
3844 return( notify );
3845 }
3846
3847 #if !defined(__LP64__)
3848 IONotifier * IOService::installNotification(const OSSymbol * type, OSDictionary * matching,
3849 IOServiceNotificationHandler handler,
3850 void * target, void * refCon,
3851 SInt32 priority, OSIterator ** existing )
3852 {
3853 IONotifier * result;
3854 _IOServiceMatchingNotificationHandlerRef ref;
3855 ref.handler = handler;
3856 ref.ref = refCon;
3857
3858 result = (_IOServiceNotifier *) installNotification( type, matching,
3859 &_IOServiceMatchingNotificationHandler,
3860 target, &ref, priority, existing );
3861 if (result)
3862 matching->release();
3863
3864 return (result);
3865 }
3866 #endif /* !defined(__LP64__) */
3867
3868
3869 IONotifier * IOService::installNotification(
3870 const OSSymbol * type, OSDictionary * matching,
3871 IOServiceMatchingNotificationHandler handler,
3872 void * target, void * ref,
3873 SInt32 priority, OSIterator ** existing )
3874 {
3875 IONotifier * notify;
3876
3877 LOCKWRITENOTIFY();
3878
3879 notify = doInstallNotification( type, matching, handler, target, ref,
3880 priority, existing );
3881
3882 UNLOCKNOTIFY();
3883
3884 return( notify );
3885 }
3886
3887 IONotifier * IOService::addNotification(
3888 const OSSymbol * type, OSDictionary * matching,
3889 IOServiceNotificationHandler handler,
3890 void * target, void * refCon,
3891 SInt32 priority )
3892 {
3893 IONotifier * result;
3894 _IOServiceMatchingNotificationHandlerRef ref;
3895
3896 ref.handler = handler;
3897 ref.ref = refCon;
3898
3899 result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler,
3900 target, &ref, priority);
3901
3902 if (result)
3903 matching->release();
3904
3905 return (result);
3906 }
3907
3908 IONotifier * IOService::addMatchingNotification(
3909 const OSSymbol * type, OSDictionary * matching,
3910 IOServiceMatchingNotificationHandler handler,
3911 void * target, void * ref,
3912 SInt32 priority )
3913 {
3914 OSIterator * existing = NULL;
3915 _IOServiceNotifier * notify;
3916 IOService * next;
3917
3918 notify = (_IOServiceNotifier *) installNotification( type, matching,
3919 handler, target, ref, priority, &existing );
3920
3921 // send notifications for existing set
3922 if( existing) {
3923
3924 notify->retain(); // in case handler remove()s
3925 while( (next = (IOService *) existing->getNextObject())) {
3926
3927 next->lockForArbitration();
3928 if( 0 == (next->__state[0] & kIOServiceInactiveState))
3929 next->invokeNotifer( notify );
3930 next->unlockForArbitration();
3931 }
3932 notify->release();
3933 existing->release();
3934 }
3935
3936 return( notify );
3937 }
3938
3939 bool IOService::syncNotificationHandler(
3940 void * /* target */, void * ref,
3941 IOService * newService,
3942 IONotifier * notifier )
3943 {
3944
3945 LOCKWRITENOTIFY();
3946 if (!*((IOService **) ref))
3947 {
3948 newService->retain();
3949 (*(IOService **) ref) = newService;
3950 WAKEUPNOTIFY(ref);
3951 }
3952 UNLOCKNOTIFY();
3953
3954 return( false );
3955 }
3956
3957 IOService * IOService::waitForMatchingService( OSDictionary * matching,
3958 uint64_t timeout)
3959 {
3960 IONotifier * notify = 0;
3961 // priority doesn't help us much since we need a thread wakeup
3962 SInt32 priority = 0;
3963 IOService * result;
3964
3965 if (!matching)
3966 return( 0 );
3967
3968 result = NULL;
3969
3970 LOCKWRITENOTIFY();
3971 do
3972 {
3973 result = (IOService *) copyExistingServices( matching,
3974 kIOServiceMatchedState, kIONotifyOnce );
3975 if (result)
3976 break;
3977 notify = IOService::setNotification( gIOMatchedNotification, matching,
3978 &IOService::syncNotificationHandler, (void *) 0,
3979 &result, priority );
3980 if (!notify)
3981 break;
3982 if (UINT64_MAX != timeout)
3983 {
3984 AbsoluteTime deadline;
3985 nanoseconds_to_absolutetime(timeout, &deadline);
3986 clock_absolutetime_interval_to_deadline(deadline, &deadline);
3987 SLEEPNOTIFYTO(&result, deadline);
3988 }
3989 else
3990 {
3991 SLEEPNOTIFY(&result);
3992 }
3993 }
3994 while( false );
3995
3996 UNLOCKNOTIFY();
3997
3998 if (notify)
3999 notify->remove(); // dequeues
4000
4001 return( result );
4002 }
4003
4004 IOService * IOService::waitForService( OSDictionary * matching,
4005 mach_timespec_t * timeout )
4006 {
4007 IOService * result;
4008 uint64_t timeoutNS;
4009
4010 if (timeout)
4011 {
4012 timeoutNS = timeout->tv_sec;
4013 timeoutNS *= kSecondScale;
4014 timeoutNS += timeout->tv_nsec;
4015 }
4016 else
4017 timeoutNS = UINT64_MAX;
4018
4019 result = waitForMatchingService(matching, timeoutNS);
4020
4021 matching->release();
4022 if (result)
4023 result->release();
4024
4025 return (result);
4026 }
4027
4028 void IOService::deliverNotification( const OSSymbol * type,
4029 IOOptionBits orNewState, IOOptionBits andNewState )
4030 {
4031 _IOServiceNotifier * notify;
4032 OSIterator * iter;
4033 OSArray * willSend = 0;
4034
4035 lockForArbitration();
4036
4037 if( (0 == (__state[0] & kIOServiceInactiveState))
4038 || (type == gIOTerminatedNotification)) {
4039
4040 LOCKREADNOTIFY();
4041
4042 iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
4043 gNotifications->getObject( type ) );
4044
4045 if( iter) {
4046 while( (notify = (_IOServiceNotifier *) iter->getNextObject())) {
4047
4048 if( matchPassive(notify->matching, 0)
4049 && (kIOServiceNotifyEnable & notify->state)) {
4050 if( 0 == willSend)
4051 willSend = OSArray::withCapacity(8);
4052 if( willSend)
4053 willSend->setObject( notify );
4054 }
4055 }
4056 iter->release();
4057 }
4058
4059 __state[0] = (__state[0] | orNewState) & andNewState;
4060
4061 UNLOCKNOTIFY();
4062 }
4063
4064 if( willSend) {
4065 for( unsigned int idx = 0;
4066 (notify = (_IOServiceNotifier *) willSend->getObject(idx));
4067 idx++) {
4068 invokeNotifer( notify );
4069 }
4070 willSend->release();
4071 }
4072 unlockForArbitration();
4073 }
4074
4075 IOOptionBits IOService::getState( void ) const
4076 {
4077 return( __state[0] );
4078 }
4079
4080 /*
4081 * Helpers to make matching objects for simple cases
4082 */
4083
4084 OSDictionary * IOService::serviceMatching( const OSString * name,
4085 OSDictionary * table )
4086 {
4087
4088 const OSString * str;
4089
4090 str = OSSymbol::withString(name);
4091 if( !str)
4092 return( 0 );
4093
4094 if( !table)
4095 table = OSDictionary::withCapacity( 2 );
4096 if( table)
4097 table->setObject(gIOProviderClassKey, (OSObject *)str );
4098 str->release();
4099
4100 return( table );
4101 }
4102
4103 OSDictionary * IOService::serviceMatching( const char * name,
4104 OSDictionary * table )
4105 {
4106 const OSString * str;
4107
4108 str = OSSymbol::withCString( name );
4109 if( !str)
4110 return( 0 );
4111
4112 table = serviceMatching( str, table );
4113 str->release();
4114 return( table );
4115 }
4116
4117 OSDictionary * IOService::nameMatching( const OSString * name,
4118 OSDictionary * table )
4119 {
4120 if( !table)
4121 table = OSDictionary::withCapacity( 2 );
4122 if( table)
4123 table->setObject( gIONameMatchKey, (OSObject *)name );
4124
4125 return( table );
4126 }
4127
4128 OSDictionary * IOService::nameMatching( const char * name,
4129 OSDictionary * table )
4130 {
4131 const OSString * str;
4132
4133 str = OSSymbol::withCString( name );
4134 if( !str)
4135 return( 0 );
4136
4137 table = nameMatching( str, table );
4138 str->release();
4139 return( table );
4140 }
4141
4142 OSDictionary * IOService::resourceMatching( const OSString * str,
4143 OSDictionary * table )
4144 {
4145 table = serviceMatching( gIOResourcesKey, table );
4146 if( table)
4147 table->setObject( gIOResourceMatchKey, (OSObject *) str );
4148
4149 return( table );
4150 }
4151
4152 OSDictionary * IOService::resourceMatching( const char * name,
4153 OSDictionary * table )
4154 {
4155 const OSSymbol * str;
4156
4157 str = OSSymbol::withCString( name );
4158 if( !str)
4159 return( 0 );
4160
4161 table = resourceMatching( str, table );
4162 str->release();
4163
4164 return( table );
4165 }
4166
4167 OSDictionary * IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
4168 OSDictionary * table )
4169 {
4170 OSDictionary * properties;
4171
4172 properties = OSDictionary::withCapacity( 2 );
4173 if( !properties)
4174 return( 0 );
4175 properties->setObject( key, value );
4176
4177 if( !table)
4178 table = OSDictionary::withCapacity( 2 );
4179 if( table)
4180 table->setObject( gIOPropertyMatchKey, properties );
4181
4182 properties->release();
4183
4184 return( table );
4185 }
4186
4187 OSDictionary * IOService::registryEntryIDMatching( uint64_t entryID,
4188 OSDictionary * table )
4189 {
4190 OSNumber * num;
4191
4192 num = OSNumber::withNumber( entryID, 64 );
4193 if( !num)
4194 return( 0 );
4195
4196 if( !table)
4197 table = OSDictionary::withCapacity( 2 );
4198 if( table)
4199 table->setObject( gIORegistryEntryIDKey, num );
4200
4201 if (num)
4202 num->release();
4203
4204 return( table );
4205 }
4206
4207
4208 /*
4209 * _IOServiceNotifier
4210 */
4211
4212 // wait for all threads, other than the current one,
4213 // to exit the handler
4214
4215 void _IOServiceNotifier::wait()
4216 {
4217 _IOServiceNotifierInvocation * next;
4218 bool doWait;
4219
4220 do {
4221 doWait = false;
4222 queue_iterate( &handlerInvocations, next,
4223 _IOServiceNotifierInvocation *, link) {
4224 if( next->thread != current_thread() ) {
4225 doWait = true;
4226 break;
4227 }
4228 }
4229 if( doWait) {
4230 state |= kIOServiceNotifyWaiter;
4231 SLEEPNOTIFY(this);
4232 }
4233
4234 } while( doWait );
4235 }
4236
4237 void _IOServiceNotifier::free()
4238 {
4239 assert( queue_empty( &handlerInvocations ));
4240 OSObject::free();
4241 }
4242
4243 void _IOServiceNotifier::remove()
4244 {
4245 LOCKWRITENOTIFY();
4246
4247 if( whence) {
4248 whence->removeObject( (OSObject *) this );
4249 whence = 0;
4250 }
4251 if( matching) {
4252 matching->release();
4253 matching = 0;
4254 }
4255
4256 state &= ~kIOServiceNotifyEnable;
4257
4258 wait();
4259
4260 UNLOCKNOTIFY();
4261
4262 release();
4263 }
4264
4265 bool _IOServiceNotifier::disable()
4266 {
4267 bool ret;
4268
4269 LOCKWRITENOTIFY();
4270
4271 ret = (0 != (kIOServiceNotifyEnable & state));
4272 state &= ~kIOServiceNotifyEnable;
4273 if( ret)
4274 wait();
4275
4276 UNLOCKNOTIFY();
4277
4278 return( ret );
4279 }
4280
4281 void _IOServiceNotifier::enable( bool was )
4282 {
4283 LOCKWRITENOTIFY();
4284 if( was)
4285 state |= kIOServiceNotifyEnable;
4286 else
4287 state &= ~kIOServiceNotifyEnable;
4288 UNLOCKNOTIFY();
4289 }
4290
4291 /*
4292 * IOResources
4293 */
4294
4295 IOService * IOResources::resources( void )
4296 {
4297 IOResources * inst;
4298
4299 inst = new IOResources;
4300 if( inst && !inst->init()) {
4301 inst->release();
4302 inst = 0;
4303 }
4304
4305 return( inst );
4306 }
4307
4308 bool IOResources::init( OSDictionary * dictionary )
4309 {
4310 // Do super init first
4311 if ( !super::init() )
4312 return false;
4313
4314 // Allow PAL layer to publish a value
4315 const char *property_name;
4316 int property_value;
4317
4318 pal_get_resource_property( &property_name, &property_value );
4319
4320 if( property_name ) {
4321 OSNumber *num;
4322 const OSSymbol * sym;
4323
4324 if( (num = OSNumber::withNumber(property_value, 32)) != 0 ) {
4325 if( (sym = OSSymbol::withCString( property_name)) != 0 ) {
4326 this->setProperty( sym, num );
4327 sym->release();
4328 }
4329 num->release();
4330 }
4331 }
4332
4333 return true;
4334 }
4335
4336 IOWorkLoop * IOResources::getWorkLoop() const
4337 {
4338 // If we are the resource root
4339 // then use the platform's workloop
4340 if (this == (IOResources *) gIOResources)
4341 return getPlatform()->getWorkLoop();
4342 else
4343 return IOService::getWorkLoop();
4344 }
4345
4346 bool IOResources::matchPropertyTable( OSDictionary * table )
4347 {
4348 OSObject * prop;
4349 OSString * str;
4350 OSSet * set;
4351 OSIterator * iter;
4352 bool ok = false;
4353
4354 prop = table->getObject( gIOResourceMatchKey );
4355 str = OSDynamicCast( OSString, prop );
4356 if( str)
4357 ok = (0 != getProperty( str ));
4358
4359 else if( (set = OSDynamicCast( OSSet, prop))) {
4360
4361 iter = OSCollectionIterator::withCollection( set );
4362 ok = (iter != 0);
4363 while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) ))
4364 ok = (0 != getProperty( str ));
4365
4366 if( iter)
4367 iter->release();
4368 }
4369
4370 return( ok );
4371 }
4372
4373 void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
4374 {
4375 IOService::updateConsoleUsers(NULL, 0);
4376 }
4377
4378 void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage)
4379 {
4380 IORegistryEntry * regEntry;
4381 OSObject * locked = kOSBooleanFalse;
4382 uint32_t idx;
4383 bool publish;
4384 OSDictionary * user;
4385 static IOMessage sSystemPower;
4386
4387 regEntry = IORegistryEntry::getRegistryRoot();
4388
4389 if (!gIOChosenEntry)
4390 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
4391
4392 IOLockLock(gIOConsoleUsersLock);
4393
4394 if (systemMessage)
4395 {
4396 sSystemPower = systemMessage;
4397 #if HIBERNATION
4398 if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked())
4399 {
4400 locked = kOSBooleanTrue;
4401 }
4402 #endif /* HIBERNATION */
4403 }
4404
4405 if (consoleUsers)
4406 {
4407 OSNumber * num = 0;
4408 gIOConsoleLoggedIn = false;
4409 for (idx = 0;
4410 (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
4411 idx++)
4412 {
4413 gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
4414 && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
4415 if (!num)
4416 {
4417 num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
4418 }
4419 }
4420 gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
4421 }
4422
4423 if (!gIOConsoleLoggedIn
4424 || (kIOMessageSystemWillSleep == sSystemPower)
4425 || (kIOMessageSystemPagingOff == sSystemPower))
4426 {
4427 locked = kOSBooleanTrue;
4428 }
4429 else if (gIOConsoleLockTime)
4430 {
4431 clock_sec_t now;
4432 clock_usec_t microsecs;
4433
4434 clock_get_calendar_microtime(&now, &microsecs);
4435 if (gIOConsoleLockTime > now)
4436 {
4437 AbsoluteTime deadline;
4438 clock_interval_to_deadline(gIOConsoleLockTime - now, kSecondScale, &deadline);
4439 thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
4440 }
4441 else
4442 {
4443 locked = kOSBooleanTrue;
4444 }
4445 }
4446
4447 publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
4448 if (publish)
4449 {
4450 regEntry->setProperty(gIOConsoleLockedKey, locked);
4451 if (consoleUsers)
4452 {
4453 regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
4454 }
4455 OSIncrementAtomic( &gIOConsoleUsersSeed );
4456 }
4457
4458 #if HIBERNATION
4459 if (gIOChosenEntry)
4460 {
4461 uint32_t screenLockState;
4462
4463 if (locked == kOSBooleanTrue) screenLockState = kIOScreenLockLocked;
4464 else if (gIOConsoleLockTime) screenLockState = kIOScreenLockUnlocked;
4465 else screenLockState = kIOScreenLockNoLock;
4466
4467 if (screenLockState != gIOScreenLockState) gIOChosenEntry->setProperty(kIOScreenLockStateKey, &screenLockState, sizeof(screenLockState));
4468 gIOScreenLockState = screenLockState;
4469 }
4470 #endif /* HIBERNATION */
4471
4472 IOLockUnlock(gIOConsoleUsersLock);
4473
4474 if (publish)
4475 {
4476 publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
4477
4478 MessageClientsContext context;
4479
4480 context.service = getServiceRoot();
4481 context.type = kIOMessageConsoleSecurityChange;
4482 context.argument = (void *) regEntry;
4483 context.argSize = 0;
4484
4485 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
4486 &messageClientsApplier, &context );
4487 }
4488 }
4489
4490 IOReturn IOResources::setProperties( OSObject * properties )
4491 {
4492 IOReturn err;
4493 const OSSymbol * key;
4494 OSDictionary * dict;
4495 OSCollectionIterator * iter;
4496
4497 err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
4498 if ( kIOReturnSuccess != err)
4499 return( err );
4500
4501 dict = OSDynamicCast(OSDictionary, properties);
4502 if( 0 == dict)
4503 return( kIOReturnBadArgument);
4504
4505 iter = OSCollectionIterator::withCollection( dict);
4506 if( 0 == iter)
4507 return( kIOReturnBadArgument);
4508
4509 while( (key = OSDynamicCast(OSSymbol, iter->getNextObject())))
4510 {
4511 if (gIOConsoleUsersKey == key) do
4512 {
4513 OSArray * consoleUsers;
4514 consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
4515 if (!consoleUsers)
4516 continue;
4517 IOService::updateConsoleUsers(consoleUsers, 0);
4518 }
4519 while (false);
4520
4521 publishResource( key, dict->getObject(key) );
4522 }
4523
4524 iter->release();
4525
4526 return( kIOReturnSuccess );
4527 }
4528
4529 /*
4530 * Helpers for matching dictionaries.
4531 * Keys existing in matching are checked in properties.
4532 * Keys may be a string or OSCollection of IOStrings
4533 */
4534
4535 bool IOService::compareProperty( OSDictionary * matching,
4536 const char * key )
4537 {
4538 OSObject * value;
4539 bool ok;
4540
4541 value = matching->getObject( key );
4542 if( value)
4543 ok = value->isEqualTo( getProperty( key ));
4544 else
4545 ok = true;
4546
4547 return( ok );
4548 }
4549
4550
4551 bool IOService::compareProperty( OSDictionary * matching,
4552 const OSString * key )
4553 {
4554 OSObject * value;
4555 bool ok;
4556
4557 value = matching->getObject( key );
4558 if( value)
4559 ok = value->isEqualTo( getProperty( key ));
4560 else
4561 ok = true;
4562
4563 return( ok );
4564 }
4565
4566 bool IOService::compareProperties( OSDictionary * matching,
4567 OSCollection * keys )
4568 {
4569 OSCollectionIterator * iter;
4570 const OSString * key;
4571 bool ok = true;
4572
4573 if( !matching || !keys)
4574 return( false );
4575
4576 iter = OSCollectionIterator::withCollection( keys );
4577
4578 if( iter) {
4579 while( ok && (key = OSDynamicCast( OSString, iter->getNextObject())))
4580 ok = compareProperty( matching, key );
4581
4582 iter->release();
4583 }
4584 keys->release(); // !! consume a ref !!
4585
4586 return( ok );
4587 }
4588
4589 /* Helper to add a location matching dict to the table */
4590
4591 OSDictionary * IOService::addLocation( OSDictionary * table )
4592 {
4593 OSDictionary * dict;
4594
4595 if( !table)
4596 return( 0 );
4597
4598 dict = OSDictionary::withCapacity( 1 );
4599 if( dict) {
4600 table->setObject( gIOLocationMatchKey, dict );
4601 dict->release();
4602 }
4603
4604 return( dict );
4605 }
4606
4607 /*
4608 * Go looking for a provider to match a location dict.
4609 */
4610
4611 IOService * IOService::matchLocation( IOService * /* client */ )
4612 {
4613 IOService * parent;
4614
4615 parent = getProvider();
4616
4617 if( parent)
4618 parent = parent->matchLocation( this );
4619
4620 return( parent );
4621 }
4622
4623 bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
4624 {
4625 OSString * matched;
4626 OSObject * obj;
4627 OSString * str;
4628 IORegistryEntry * entry;
4629 OSNumber * num;
4630 bool match = true;
4631 bool changesOK = (0 != (kIOServiceChangesOK & options));
4632 uint32_t count;
4633 uint32_t done;
4634
4635 do
4636 {
4637 count = table->getCount();
4638 done = 0;
4639 str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
4640 if (str) {
4641 done++;
4642 match = ((kIOServiceClassDone & options) || (0 != metaCast(str)));
4643 #if MATCH_DEBUG
4644 match = (0 != metaCast( str ));
4645 if ((kIOServiceClassDone & options) && !match) panic("classDone");
4646 #endif
4647 if ((!match) || (done == count)) break;
4648 }
4649
4650 obj = table->getObject( gIONameMatchKey );
4651 if( obj) {
4652 done++;
4653 match = compareNames( obj, changesOK ? &matched : 0 );
4654 if (!match) break;
4655 if( changesOK && matched) {
4656 // leave a hint as to which name matched
4657 table->setObject( gIONameMatchedKey, matched );
4658 matched->release();
4659 }
4660 if (done == count) break;
4661 }
4662
4663 str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
4664 if (str)
4665 {
4666 const OSSymbol * sym;
4667 done++;
4668 match = false;
4669 sym = copyLocation();
4670 if (sym) {
4671 match = sym->isEqualTo( str );
4672 sym->release();
4673 }
4674 if ((!match) || (done == count)) break;
4675 }
4676
4677 obj = table->getObject( gIOPropertyMatchKey );
4678 if( obj)
4679 {
4680 OSDictionary * dict;
4681 OSDictionary * nextDict;
4682 OSIterator * iter;
4683 done++;
4684 match = false;
4685 dict = dictionaryWithProperties();
4686 if( dict) {
4687 nextDict = OSDynamicCast( OSDictionary, obj);
4688 if( nextDict)
4689 iter = 0;
4690 else
4691 iter = OSCollectionIterator::withCollection(
4692 OSDynamicCast(OSCollection, obj));
4693
4694 while( nextDict
4695 || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary,
4696 iter->getNextObject()))))) {
4697 match = dict->isEqualTo( nextDict, nextDict);
4698 if( match)
4699 break;
4700 nextDict = 0;
4701 }
4702 dict->release();
4703 if( iter)
4704 iter->release();
4705 }
4706 if ((!match) || (done == count)) break;
4707 }
4708
4709 str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
4710 if( str) {
4711 done++;
4712 entry = IORegistryEntry::fromPath( str->getCStringNoCopy() );
4713 match = (this == entry);
4714 if( entry)
4715 entry->release();
4716 if ((!match) || (done == count)) break;
4717 }
4718
4719 num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
4720 if (num) {
4721 done++;
4722 match = (getRegistryEntryID() == num->unsigned64BitValue());
4723 if ((!match) || (done == count)) break;
4724 }
4725
4726 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
4727 if( num)
4728 {
4729 OSIterator * iter;
4730 IOService * service = 0;
4731 UInt32 serviceCount = 0;
4732
4733 done++;
4734 iter = getClientIterator();
4735 if( iter) {
4736 while( (service = (IOService *) iter->getNextObject())) {
4737 if( kIOServiceInactiveState & service->__state[0])
4738 continue;
4739 if( 0 == service->getProperty( gIOMatchCategoryKey ))
4740 continue;
4741 ++serviceCount;
4742 }
4743 iter->release();
4744 }
4745 match = (serviceCount == num->unsigned32BitValue());
4746 if ((!match) || (done == count)) break;
4747 }
4748
4749 #define propMatch(key) \
4750 obj = table->getObject(key); \
4751 if (obj) \
4752 { \
4753 OSObject * prop; \
4754 done++; \
4755 prop = copyProperty(key); \
4756 match = obj->isEqualTo(prop); \
4757 if (prop) prop->release(); \
4758 if ((!match) || (done == count)) break; \
4759 }
4760 propMatch(kIOBSDNameKey)
4761 propMatch(kIOBSDMajorKey)
4762 propMatch(kIOBSDMinorKey)
4763 propMatch(kIOBSDUnitKey)
4764 #undef propMatch
4765 }
4766 while (false);
4767
4768 if (did) *did = done;
4769 return (match);
4770 }
4771
4772 bool IOService::passiveMatch( OSDictionary * table, bool changesOK )
4773 {
4774 return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0));
4775 }
4776
4777 bool IOService::matchPassive(OSDictionary * table, uint32_t options)
4778 {
4779 IOService * where;
4780 OSDictionary * nextTable;
4781 SInt32 score;
4782 OSNumber * newPri;
4783 bool match = true;
4784 bool matchParent = false;
4785 uint32_t count;
4786 uint32_t done;
4787
4788 assert( table );
4789
4790 #if MATCH_DEBUG
4791 OSDictionary * root = table;
4792 #endif
4793
4794 where = this;
4795 do
4796 {
4797 do
4798 {
4799 count = table->getCount();
4800 if (!(kIOServiceInternalDone & options))
4801 {
4802 match = where->matchInternal(table, options, &done);
4803 // don't call family if we've done all the entries in the table
4804 if ((!match) || (done == count)) break;
4805 }
4806
4807 // pass in score from property table
4808 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
4809
4810 // do family specific matching
4811 match = where->matchPropertyTable( table, &score );
4812
4813 if( !match) {
4814 #if IOMATCHDEBUG
4815 if( kIOLogMatch & getDebugFlags( table ))
4816 LOG("%s: family specific matching fails\n", where->getName());
4817 #endif
4818 break;
4819 }
4820
4821 if (kIOServiceChangesOK & options) {
4822 // save the score
4823 newPri = OSNumber::withNumber( score, 32 );
4824 if( newPri) {
4825 table->setObject( gIOProbeScoreKey, newPri );
4826 newPri->release();
4827 }
4828 }
4829
4830 options = 0;
4831 matchParent = false;
4832
4833 nextTable = OSDynamicCast(OSDictionary,
4834 table->getObject( gIOParentMatchKey ));
4835 if( nextTable) {
4836 // look for a matching entry anywhere up to root
4837 match = false;
4838 matchParent = true;
4839 table = nextTable;
4840 break;
4841 }
4842
4843 table = OSDynamicCast(OSDictionary,
4844 table->getObject( gIOLocationMatchKey ));
4845 if (table) {
4846 // look for a matching entry at matchLocation()
4847 match = false;
4848 where = where->getProvider();
4849 if (where && (where = where->matchLocation(where))) continue;
4850 }
4851 break;
4852 }
4853 while (true);
4854 }
4855 while( matchParent && (!match) && (where = where->getProvider()) );
4856
4857 #if MATCH_DEBUG
4858 if (where != this)
4859 {
4860 OSSerialize * s = OSSerialize::withCapacity(128);
4861 root->serialize(s);
4862 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text());
4863 s->release();
4864 }
4865 #endif
4866
4867 return( match );
4868 }
4869
4870
4871 IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4872 UInt32 type, OSDictionary * properties,
4873 IOUserClient ** handler )
4874 {
4875 const OSSymbol *userClientClass = 0;
4876 IOUserClient *client;
4877 OSObject *temp;
4878
4879 if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler ))
4880 return kIOReturnSuccess;
4881
4882 // First try my own properties for a user client class name
4883 temp = getProperty(gIOUserClientClassKey);
4884 if (temp) {
4885 if (OSDynamicCast(OSSymbol, temp))
4886 userClientClass = (const OSSymbol *) temp;
4887 else if (OSDynamicCast(OSString, temp)) {
4888 userClientClass = OSSymbol::withString((OSString *) temp);
4889 if (userClientClass)
4890 setProperty(kIOUserClientClassKey,
4891 (OSObject *) userClientClass);
4892 }
4893 }
4894
4895 // Didn't find one so lets just bomb out now without further ado.
4896 if (!userClientClass)
4897 return kIOReturnUnsupported;
4898
4899 // This reference is consumed by the IOServiceOpen call
4900 temp = OSMetaClass::allocClassWithName(userClientClass);
4901 if (!temp)
4902 return kIOReturnNoMemory;
4903
4904 if (OSDynamicCast(IOUserClient, temp))
4905 client = (IOUserClient *) temp;
4906 else {
4907 temp->release();
4908 return kIOReturnUnsupported;
4909 }
4910
4911 if ( !client->initWithTask(owningTask, securityID, type, properties) ) {
4912 client->release();
4913 return kIOReturnBadArgument;
4914 }
4915
4916 if ( !client->attach(this) ) {
4917 client->release();
4918 return kIOReturnUnsupported;
4919 }
4920
4921 if ( !client->start(this) ) {
4922 client->detach(this);
4923 client->release();
4924 return kIOReturnUnsupported;
4925 }
4926
4927 *handler = client;
4928 return kIOReturnSuccess;
4929 }
4930
4931 IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
4932 UInt32 type, IOUserClient ** handler )
4933 {
4934 return( kIOReturnUnsupported );
4935 }
4936
4937 IOReturn IOService::requestProbe( IOOptionBits options )
4938 {
4939 return( kIOReturnUnsupported);
4940 }
4941
4942 /*
4943 * Convert an IOReturn to text. Subclasses which add additional
4944 * IOReturn's should override this method and call
4945 * super::stringFromReturn if the desired value is not found.
4946 */
4947
4948 const char * IOService::stringFromReturn( IOReturn rtn )
4949 {
4950 static const IONamedValue IOReturn_values[] = {
4951 {kIOReturnSuccess, "success" },
4952 {kIOReturnError, "general error" },
4953 {kIOReturnNoMemory, "memory allocation error" },
4954 {kIOReturnNoResources, "resource shortage" },
4955 {kIOReturnIPCError, "Mach IPC failure" },
4956 {kIOReturnNoDevice, "no such device" },
4957 {kIOReturnNotPrivileged, "privilege violation" },
4958 {kIOReturnBadArgument, "invalid argument" },
4959 {kIOReturnLockedRead, "device is read locked" },
4960 {kIOReturnLockedWrite, "device is write locked" },
4961 {kIOReturnExclusiveAccess, "device is exclusive access" },
4962 {kIOReturnBadMessageID, "bad IPC message ID" },
4963 {kIOReturnUnsupported, "unsupported function" },
4964 {kIOReturnVMError, "virtual memory error" },
4965 {kIOReturnInternalError, "internal driver error" },
4966 {kIOReturnIOError, "I/O error" },
4967 {kIOReturnCannotLock, "cannot acquire lock" },
4968 {kIOReturnNotOpen, "device is not open" },
4969 {kIOReturnNotReadable, "device is not readable" },
4970 {kIOReturnNotWritable, "device is not writeable" },
4971 {kIOReturnNotAligned, "alignment error" },
4972 {kIOReturnBadMedia, "media error" },
4973 {kIOReturnStillOpen, "device is still open" },
4974 {kIOReturnRLDError, "rld failure" },
4975 {kIOReturnDMAError, "DMA failure" },
4976 {kIOReturnBusy, "device is busy" },
4977 {kIOReturnTimeout, "I/O timeout" },
4978 {kIOReturnOffline, "device is offline" },
4979 {kIOReturnNotReady, "device is not ready" },
4980 {kIOReturnNotAttached, "device/channel is not attached" },
4981 {kIOReturnNoChannels, "no DMA channels available" },
4982 {kIOReturnNoSpace, "no space for data" },
4983 {kIOReturnPortExists, "device port already exists" },
4984 {kIOReturnCannotWire, "cannot wire physical memory" },
4985 {kIOReturnNoInterrupt, "no interrupt attached" },
4986 {kIOReturnNoFrames, "no DMA frames enqueued" },
4987 {kIOReturnMessageTooLarge, "message is too large" },
4988 {kIOReturnNotPermitted, "operation is not permitted" },
4989 {kIOReturnNoPower, "device is without power" },
4990 {kIOReturnNoMedia, "media is not present" },
4991 {kIOReturnUnformattedMedia, "media is not formatted" },
4992 {kIOReturnUnsupportedMode, "unsupported mode" },
4993 {kIOReturnUnderrun, "data underrun" },
4994 {kIOReturnOverrun, "data overrun" },
4995 {kIOReturnDeviceError, "device error" },
4996 {kIOReturnNoCompletion, "no completion routine" },
4997 {kIOReturnAborted, "operation was aborted" },
4998 {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" },
4999 {kIOReturnNotResponding, "device is not responding" },
5000 {kIOReturnInvalid, "unanticipated driver error" },
5001 {0, NULL }
5002 };
5003
5004 return IOFindNameForValue(rtn, IOReturn_values);
5005 }
5006
5007 /*
5008 * Convert an IOReturn to an errno.
5009 */
5010 int IOService::errnoFromReturn( IOReturn rtn )
5011 {
5012 switch(rtn) {
5013 // (obvious match)
5014 case kIOReturnSuccess:
5015 return(0);
5016 case kIOReturnNoMemory:
5017 return(ENOMEM);
5018 case kIOReturnNoDevice:
5019 return(ENXIO);
5020 case kIOReturnVMError:
5021 return(EFAULT);
5022 case kIOReturnNotPermitted:
5023 return(EPERM);
5024 case kIOReturnNotPrivileged:
5025 return(EACCES);
5026 case kIOReturnIOError:
5027 return(EIO);
5028 case kIOReturnNotWritable:
5029 return(EROFS);
5030 case kIOReturnBadArgument:
5031 return(EINVAL);
5032 case kIOReturnUnsupported:
5033 return(ENOTSUP);
5034 case kIOReturnBusy:
5035 return(EBUSY);
5036 case kIOReturnNoPower:
5037 return(EPWROFF);
5038 case kIOReturnDeviceError:
5039 return(EDEVERR);
5040 case kIOReturnTimeout:
5041 return(ETIMEDOUT);
5042 case kIOReturnMessageTooLarge:
5043 return(EMSGSIZE);
5044 case kIOReturnNoSpace:
5045 return(ENOSPC);
5046 case kIOReturnCannotLock:
5047 return(ENOLCK);
5048
5049 // (best match)
5050 case kIOReturnBadMessageID:
5051 case kIOReturnNoCompletion:
5052 case kIOReturnNotAligned:
5053 return(EINVAL);
5054 case kIOReturnNotReady:
5055 return(EBUSY);
5056 case kIOReturnRLDError:
5057 return(EBADMACHO);
5058 case kIOReturnPortExists:
5059 case kIOReturnStillOpen:
5060 return(EEXIST);
5061 case kIOReturnExclusiveAccess:
5062 case kIOReturnLockedRead:
5063 case kIOReturnLockedWrite:
5064 case kIOReturnNotOpen:
5065 case kIOReturnNotReadable:
5066 return(EACCES);
5067 case kIOReturnCannotWire:
5068 case kIOReturnNoResources:
5069 return(ENOMEM);
5070 case kIOReturnAborted:
5071 case kIOReturnOffline:
5072 case kIOReturnNotResponding:
5073 return(EBUSY);
5074 case kIOReturnBadMedia:
5075 case kIOReturnNoMedia:
5076 case kIOReturnNotAttached:
5077 case kIOReturnUnformattedMedia:
5078 return(ENXIO); // (media error)
5079 case kIOReturnDMAError:
5080 case kIOReturnOverrun:
5081 case kIOReturnUnderrun:
5082 return(EIO); // (transfer error)
5083 case kIOReturnNoBandwidth:
5084 case kIOReturnNoChannels:
5085 case kIOReturnNoFrames:
5086 case kIOReturnNoInterrupt:
5087 return(EIO); // (hardware error)
5088 case kIOReturnError:
5089 case kIOReturnInternalError:
5090 case kIOReturnInvalid:
5091 return(EIO); // (generic error)
5092 case kIOReturnIPCError:
5093 return(EIO); // (ipc error)
5094 default:
5095 return(EIO); // (all other errors)
5096 }
5097 }
5098
5099 IOReturn IOService::message( UInt32 type, IOService * provider,
5100 void * argument )
5101 {
5102 /*
5103 * Generic entry point for calls from the provider. A return value of
5104 * kIOReturnSuccess indicates that the message was received, and where
5105 * applicable, that it was successful.
5106 */
5107
5108 return kIOReturnUnsupported;
5109 }
5110
5111 /*
5112 * Device memory
5113 */
5114
5115 IOItemCount IOService::getDeviceMemoryCount( void )
5116 {
5117 OSArray * array;
5118 IOItemCount count;
5119
5120 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
5121 if( array)
5122 count = array->getCount();
5123 else
5124 count = 0;
5125
5126 return( count);
5127 }
5128
5129 IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index )
5130 {
5131 OSArray * array;
5132 IODeviceMemory * range;
5133
5134 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
5135 if( array)
5136 range = (IODeviceMemory *) array->getObject( index );
5137 else
5138 range = 0;
5139
5140 return( range);
5141 }
5142
5143 IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index,
5144 IOOptionBits options )
5145 {
5146 IODeviceMemory * range;
5147 IOMemoryMap * map;
5148
5149 range = getDeviceMemoryWithIndex( index );
5150 if( range)
5151 map = range->map( options );
5152 else
5153 map = 0;
5154
5155 return( map );
5156 }
5157
5158 OSArray * IOService::getDeviceMemory( void )
5159 {
5160 return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)));
5161 }
5162
5163
5164 void IOService::setDeviceMemory( OSArray * array )
5165 {
5166 setProperty( gIODeviceMemoryKey, array);
5167 }
5168
5169 /*
5170 * For machines where the transfers on an I/O bus can stall because
5171 * the CPU is in an idle mode, These APIs allow a driver to specify
5172 * the maximum bus stall that they can handle. 0 indicates no limit.
5173 */
5174 void IOService::
5175 setCPUSnoopDelay(UInt32 __unused ns)
5176 {
5177 #if defined(__i386__) || defined(__x86_64__)
5178 ml_set_maxsnoop(ns);
5179 #endif /* defined(__i386__) || defined(__x86_64__) */
5180 }
5181
5182 UInt32 IOService::
5183 getCPUSnoopDelay()
5184 {
5185 #if defined(__i386__) || defined(__x86_64__)
5186 return ml_get_maxsnoop();
5187 #else
5188 return 0;
5189 #endif /* defined(__i386__) || defined(__x86_64__) */
5190 }
5191
5192 #if defined(__i386__) || defined(__x86_64__)
5193 static void
5194 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
5195 {
5196 static const UInt kNoReplace = -1U; // Must be an illegal index
5197 UInt replace = kNoReplace;
5198 bool setCpuDelay = false;
5199
5200 IORecursiveLockLock(sCpuDelayLock);
5201
5202 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5203 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5204 IOService * holder = NULL;
5205
5206 if (ns) {
5207 const CpuDelayEntry ne = {service, ns, delayType};
5208 holder = service;
5209 // Set maximum delay.
5210 for (UInt i = 0; i < count; i++) {
5211 IOService *thisService = entries[i].fService;
5212 bool sameType = (delayType == entries[i].fDelayType);
5213 if ((service == thisService) && sameType)
5214 replace = i;
5215 else if (!thisService) {
5216 if (kNoReplace == replace)
5217 replace = i;
5218 }
5219 else if (sameType) {
5220 const UInt32 thisMax = entries[i].fMaxDelay;
5221 if (thisMax < ns)
5222 {
5223 ns = thisMax;
5224 holder = thisService;
5225 }
5226 }
5227 }
5228
5229 setCpuDelay = true;
5230 if (kNoReplace == replace)
5231 sCpuDelayData->appendBytes(&ne, sizeof(ne));
5232 else
5233 entries[replace] = ne;
5234 }
5235 else {
5236 ns = -1U; // Set to max unsigned, i.e. no restriction
5237
5238 for (UInt i = 0; i < count; i++) {
5239 // Clear a maximum delay.
5240 IOService *thisService = entries[i].fService;
5241 if (thisService && (delayType == entries[i].fDelayType)) {
5242 UInt32 thisMax = entries[i].fMaxDelay;
5243 if (service == thisService)
5244 replace = i;
5245 else if (thisMax < ns) {
5246 ns = thisMax;
5247 holder = thisService;
5248 }
5249 }
5250 }
5251
5252 // Check if entry found
5253 if (kNoReplace != replace) {
5254 entries[replace].fService = 0; // Null the entry
5255 setCpuDelay = true;
5256 }
5257 }
5258
5259 if (setCpuDelay)
5260 {
5261 // Must be safe to call from locked context
5262 if (delayType == kCpuDelayBusStall)
5263 {
5264 ml_set_maxbusdelay(ns);
5265 }
5266 else if (delayType == kCpuDelayInterrupt)
5267 {
5268 ml_set_maxintdelay(ns);
5269 }
5270
5271 OSArray * handlers = sCpuLatencyHandlers[delayType];
5272 IOService * target;
5273 if (handlers) for (unsigned int idx = 0;
5274 (target = (IOService *) handlers->getObject(idx));
5275 idx++)
5276 {
5277 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
5278 (void *) (uintptr_t) ns, holder,
5279 NULL, NULL);
5280 }
5281 }
5282
5283 IORecursiveLockUnlock(sCpuDelayLock);
5284 }
5285
5286 static IOReturn
5287 setLatencyHandler(UInt32 delayType, IOService * target, bool enable)
5288 {
5289 IOReturn result = kIOReturnNotFound;
5290 OSArray * array;
5291 unsigned int idx;
5292
5293 IORecursiveLockLock(sCpuDelayLock);
5294
5295 do
5296 {
5297 if (enable && !sCpuLatencyHandlers[delayType])
5298 sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4);
5299 array = sCpuLatencyHandlers[delayType];
5300 if (!array)
5301 break;
5302 idx = array->getNextIndexOfObject(target, 0);
5303 if (!enable)
5304 {
5305 if (-1U != idx)
5306 {
5307 array->removeObject(idx);
5308 result = kIOReturnSuccess;
5309 }
5310 }
5311 else
5312 {
5313 if (-1U != idx) {
5314 result = kIOReturnExclusiveAccess;
5315 break;
5316 }
5317 array->setObject(target);
5318
5319 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
5320 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
5321 UInt32 ns = -1U; // Set to max unsigned, i.e. no restriction
5322 IOService * holder = NULL;
5323
5324 for (UInt i = 0; i < count; i++) {
5325 if (entries[i].fService
5326 && (delayType == entries[i].fDelayType)
5327 && (entries[i].fMaxDelay < ns)) {
5328 ns = entries[i].fMaxDelay;
5329 holder = entries[i].fService;
5330 }
5331 }
5332 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
5333 (void *) (uintptr_t) ns, holder,
5334 NULL, NULL);
5335 result = kIOReturnSuccess;
5336 }
5337 }
5338 while (false);
5339
5340 IORecursiveLockUnlock(sCpuDelayLock);
5341
5342 return (result);
5343 }
5344
5345 #endif /* defined(__i386__) || defined(__x86_64__) */
5346
5347 void IOService::
5348 requireMaxBusStall(UInt32 __unused ns)
5349 {
5350 #if defined(__i386__) || defined(__x86_64__)
5351 requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
5352 #endif
5353 }
5354
5355 void IOService::
5356 requireMaxInterruptDelay(uint32_t __unused ns)
5357 {
5358 #if defined(__i386__) || defined(__x86_64__)
5359 requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
5360 #endif
5361 }
5362
5363 /*
5364 * Device interrupts
5365 */
5366
5367 IOReturn IOService::resolveInterrupt(IOService *nub, int source)
5368 {
5369 IOInterruptController *interruptController;
5370 OSArray *array;
5371 OSData *data;
5372 OSSymbol *interruptControllerName;
5373 long numSources;
5374 IOInterruptSource *interruptSources;
5375
5376 // Get the parents list from the nub.
5377 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
5378 if (array == 0) return kIOReturnNoResources;
5379
5380 // Allocate space for the IOInterruptSources if needed... then return early.
5381 if (nub->_interruptSources == 0) {
5382 numSources = array->getCount();
5383 interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource));
5384 if (interruptSources == 0) return kIOReturnNoMemory;
5385
5386 bzero(interruptSources, numSources * sizeof(IOInterruptSource));
5387
5388 nub->_numInterruptSources = numSources;
5389 nub->_interruptSources = interruptSources;
5390 return kIOReturnSuccess;
5391 }
5392
5393 interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source));
5394 if (interruptControllerName == 0) return kIOReturnNoResources;
5395
5396 interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
5397 if (interruptController == 0) return kIOReturnNoResources;
5398
5399 // Get the interrupt numbers from the nub.
5400 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
5401 if (array == 0) return kIOReturnNoResources;
5402 data = OSDynamicCast(OSData, array->getObject(source));
5403 if (data == 0) return kIOReturnNoResources;
5404
5405 // Set the interruptController and interruptSource in the nub's table.
5406 interruptSources = nub->_interruptSources;
5407 interruptSources[source].interruptController = interruptController;
5408 interruptSources[source].vectorData = data;
5409
5410 return kIOReturnSuccess;
5411 }
5412
5413 IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
5414 {
5415 IOReturn ret;
5416
5417 /* Make sure the _interruptSources are set */
5418 if (_interruptSources == 0) {
5419 ret = resolveInterrupt(this, source);
5420 if (ret != kIOReturnSuccess) return ret;
5421 }
5422
5423 /* Make sure the local source number is valid */
5424 if ((source < 0) || (source >= _numInterruptSources))
5425 return kIOReturnNoInterrupt;
5426
5427 /* Look up the contoller for the local source */
5428 *interruptController = _interruptSources[source].interruptController;
5429
5430 if (*interruptController == NULL) {
5431 if (!resolve) return kIOReturnNoInterrupt;
5432
5433 /* Try to reslove the interrupt */
5434 ret = resolveInterrupt(this, source);
5435 if (ret != kIOReturnSuccess) return ret;
5436
5437 *interruptController = _interruptSources[source].interruptController;
5438 }
5439
5440 return kIOReturnSuccess;
5441 }
5442
5443 IOReturn IOService::registerInterrupt(int source, OSObject *target,
5444 IOInterruptAction handler,
5445 void *refCon)
5446 {
5447 IOInterruptController *interruptController;
5448 IOReturn ret;
5449
5450 ret = lookupInterrupt(source, true, &interruptController);
5451 if (ret != kIOReturnSuccess) return ret;
5452
5453 /* Register the source */
5454 return interruptController->registerInterrupt(this, source, target,
5455 (IOInterruptHandler)handler,
5456 refCon);
5457 }
5458
5459 IOReturn IOService::unregisterInterrupt(int source)
5460 {
5461 IOInterruptController *interruptController;
5462 IOReturn ret;
5463
5464 ret = lookupInterrupt(source, false, &interruptController);
5465 if (ret != kIOReturnSuccess) return ret;
5466
5467 /* Unregister the source */
5468 return interruptController->unregisterInterrupt(this, source);
5469 }
5470
5471 IOReturn IOService::getInterruptType(int source, int *interruptType)
5472 {
5473 IOInterruptController *interruptController;
5474 IOReturn ret;
5475
5476 ret = lookupInterrupt(source, true, &interruptController);
5477 if (ret != kIOReturnSuccess) return ret;
5478
5479 /* Return the type */
5480 return interruptController->getInterruptType(this, source, interruptType);
5481 }
5482
5483 IOReturn IOService::enableInterrupt(int source)
5484 {
5485 IOInterruptController *interruptController;
5486 IOReturn ret;
5487
5488 ret = lookupInterrupt(source, false, &interruptController);
5489 if (ret != kIOReturnSuccess) return ret;
5490
5491 /* Enable the source */
5492 return interruptController->enableInterrupt(this, source);
5493 }
5494
5495 IOReturn IOService::disableInterrupt(int source)
5496 {
5497 IOInterruptController *interruptController;
5498 IOReturn ret;
5499
5500 ret = lookupInterrupt(source, false, &interruptController);
5501 if (ret != kIOReturnSuccess) return ret;
5502
5503 /* Disable the source */
5504 return interruptController->disableInterrupt(this, source);
5505 }
5506
5507 IOReturn IOService::causeInterrupt(int source)
5508 {
5509 IOInterruptController *interruptController;
5510 IOReturn ret;
5511
5512 ret = lookupInterrupt(source, false, &interruptController);
5513 if (ret != kIOReturnSuccess) return ret;
5514
5515 /* Cause an interrupt for the source */
5516 return interruptController->causeInterrupt(this, source);
5517 }
5518
5519 #if __LP64__
5520 OSMetaClassDefineReservedUnused(IOService, 0);
5521 OSMetaClassDefineReservedUnused(IOService, 1);
5522 OSMetaClassDefineReservedUnused(IOService, 2);
5523 OSMetaClassDefineReservedUnused(IOService, 3);
5524 OSMetaClassDefineReservedUnused(IOService, 4);
5525 OSMetaClassDefineReservedUnused(IOService, 5);
5526 #else
5527 OSMetaClassDefineReservedUsed(IOService, 0);
5528 OSMetaClassDefineReservedUsed(IOService, 1);
5529 OSMetaClassDefineReservedUsed(IOService, 2);
5530 OSMetaClassDefineReservedUsed(IOService, 3);
5531 OSMetaClassDefineReservedUsed(IOService, 4);
5532 OSMetaClassDefineReservedUsed(IOService, 5);
5533 #endif
5534 OSMetaClassDefineReservedUnused(IOService, 6);
5535 OSMetaClassDefineReservedUnused(IOService, 7);
5536 OSMetaClassDefineReservedUnused(IOService, 8);
5537 OSMetaClassDefineReservedUnused(IOService, 9);
5538 OSMetaClassDefineReservedUnused(IOService, 10);
5539 OSMetaClassDefineReservedUnused(IOService, 11);
5540 OSMetaClassDefineReservedUnused(IOService, 12);
5541 OSMetaClassDefineReservedUnused(IOService, 13);
5542 OSMetaClassDefineReservedUnused(IOService, 14);
5543 OSMetaClassDefineReservedUnused(IOService, 15);
5544 OSMetaClassDefineReservedUnused(IOService, 16);
5545 OSMetaClassDefineReservedUnused(IOService, 17);
5546 OSMetaClassDefineReservedUnused(IOService, 18);
5547 OSMetaClassDefineReservedUnused(IOService, 19);
5548 OSMetaClassDefineReservedUnused(IOService, 20);
5549 OSMetaClassDefineReservedUnused(IOService, 21);
5550 OSMetaClassDefineReservedUnused(IOService, 22);
5551 OSMetaClassDefineReservedUnused(IOService, 23);
5552 OSMetaClassDefineReservedUnused(IOService, 24);
5553 OSMetaClassDefineReservedUnused(IOService, 25);
5554 OSMetaClassDefineReservedUnused(IOService, 26);
5555 OSMetaClassDefineReservedUnused(IOService, 27);
5556 OSMetaClassDefineReservedUnused(IOService, 28);
5557 OSMetaClassDefineReservedUnused(IOService, 29);
5558 OSMetaClassDefineReservedUnused(IOService, 30);
5559 OSMetaClassDefineReservedUnused(IOService, 31);
5560 OSMetaClassDefineReservedUnused(IOService, 32);
5561 OSMetaClassDefineReservedUnused(IOService, 33);
5562 OSMetaClassDefineReservedUnused(IOService, 34);
5563 OSMetaClassDefineReservedUnused(IOService, 35);
5564 OSMetaClassDefineReservedUnused(IOService, 36);
5565 OSMetaClassDefineReservedUnused(IOService, 37);
5566 OSMetaClassDefineReservedUnused(IOService, 38);
5567 OSMetaClassDefineReservedUnused(IOService, 39);
5568 OSMetaClassDefineReservedUnused(IOService, 40);
5569 OSMetaClassDefineReservedUnused(IOService, 41);
5570 OSMetaClassDefineReservedUnused(IOService, 42);
5571 OSMetaClassDefineReservedUnused(IOService, 43);
5572 OSMetaClassDefineReservedUnused(IOService, 44);
5573 OSMetaClassDefineReservedUnused(IOService, 45);
5574 OSMetaClassDefineReservedUnused(IOService, 46);
5575 OSMetaClassDefineReservedUnused(IOService, 47);