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