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