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