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