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