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