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