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