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