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