|
|
1.1 root 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) 1998 Apple Computer, Inc. All rights reserved.
24: *
25: * HISTORY
26: *
27: */
28:
29: #include <IOKit/IOService.h>
30: #include <libkern/c++/OSContainers.h>
31: #include <IOKit/IOCatalogue.h>
32: #include <libkern/c++/OSUnserialize.h>
33: #include <mach/kmod.h>
34:
35: #include <IOKit/IOLib.h>
36:
37: #include <IOKit/assert.h>
38:
39:
40: #define super OSObject
41: #define kModuleKey "Module"
42:
43: OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
44:
45: #define CATALOGTEST 0
46:
47: IOCatalogue * gIOCatalogue;
48: const OSSymbol * gIOClassKey;
49: const OSSymbol * gIOProbeScoreKey;
50:
51: static void UniqueProperties( OSDictionary * dict )
52: {
53: OSString * data;
54:
55: data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
56: if( data) {
57: const OSSymbol *classSymbol = OSSymbol::withString(data);
58:
59: dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
60: classSymbol->release();
61: } else
62: IOLog("Missing or bad \"%s\" key\n",
63: gIOClassKey->getCStringNoCopy());
64:
65: data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
66: if( data) {
67: const OSSymbol *classSymbol = OSSymbol::withString(data);
68:
69: dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
70: classSymbol->release();
71: }
72: }
73:
74: void IOCatalogue::initialize( void )
75: {
76: OSArray * array;
77: OSString * errorString;
78: bool rc;
79:
80: extern const char * gIOKernelConfigTables;
81:
82: array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
83: if (!array && errorString) {
84: IOLog("KernelConfigTables syntax error: %s\n",
85: errorString->getCStringNoCopy());
86: errorString->release();
87: }
88:
89: gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
90: gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
91: assert( array && gIOClassKey && gIOProbeScoreKey);
92:
93: gIOCatalogue = new IOCatalogue;
94: assert(gIOCatalogue);
95: rc = gIOCatalogue->init(array);
96: assert(rc);
97: array->release();
98: }
99:
100: // Initialize the IOCatalog object.
101: bool IOCatalogue::init(OSArray * initArray)
102: {
103: IORegistryEntry * entry;
104: OSDictionary * dict;
105:
106: if ( !super::init() )
107: return false;
108:
109: generation = 1;
110:
111: array = initArray;
112: array->retain();
113: kernelTables = OSCollectionIterator::withCollection( array );
114:
115: lock = IOLockAlloc();
116:
117: kernelTables->reset();
118: while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
119: UniqueProperties(dict);
120: }
121:
122: #if CATALOGTEST
123: AbsoluteTime deadline;
124: clock_interval_to_deadline( 1000, kMillisecondScale );
125: thread_call_func_delayed( ping, this, deadline );
126: #endif
127:
128: entry = IORegistryEntry::getRegistryRoot();
129: if ( entry )
130: entry->setProperty(kIOCatalogueKey, this);
131:
132: return true;
133: }
134:
135: // Release all resources used by IOCatalogue and deallocate.
136: // This will probably never be called.
137: void IOCatalogue::free( void )
138: {
139: if ( array )
140: array->release();
141:
142: if ( kernelTables )
143: kernelTables->release();
144:
145: super::free();
146: }
147:
148: #if CATALOGTEST
149:
150: static int hackLimit;
151:
152: enum { kDriversPerIter = 4 };
153:
154: void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
155: {
156: IOCatalogue * self = (IOCatalogue *) arg;
157: OSOrderedSet * set;
158: OSDictionary * table;
159: int newLimit;
160:
161: set = OSOrderedSet::withCapacity( 1 );
162:
163: IOTakeLock( &self->lock );
164:
165: for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
166: table = (OSDictionary *) self->array->getObject(
167: hackLimit + newLimit );
168: if( table) {
169: set->setLastObject( table );
170:
171: OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey );
172: kprintf("enabling %s\n", sym->getCStringNoCopy());
173:
174: } else {
175: newLimit--;
176: break;
177: }
178: }
179:
180: IOService::catalogNewDrivers( set );
181:
182: hackLimit += newLimit;
183: self->generation++;
184:
185: IOUnlock( &self->lock );
186:
187: if( kDriversPerIter == newLimit) {
188: AbsoluteTime deadline;
189: clock_interval_to_deadline( 500, kMillisecondScale );
190: thread_call_func_delayed( ping, this, deadline );
191: }
192: }
193: #endif
194:
195: OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
196: SInt32 * generationCount )
197: {
198: OSDictionary * nextTable;
199: OSOrderedSet * set;
200: OSString * imports;
201:
202: set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
203: (void *)gIOProbeScoreKey );
204: if( !set )
205: return( 0 );
206:
207: IOTakeLock( lock );
208: kernelTables->reset();
209:
210: #if CATALOGTEST
211: int hackIndex = 0;
212: #endif
213: while( (nextTable = (OSDictionary *) kernelTables->getNextObject())) {
214: #if CATALOGTEST
215: if( hackIndex++ > hackLimit)
216: break;
217: #endif
218: imports = OSDynamicCast( OSString,
219: nextTable->getObject( gIOProviderClassKey ));
220: if( imports && service->metaCast( imports ))
221: set->setObject( nextTable );
222: }
223:
224: *generationCount = getGenerationCount();
225:
226: IOUnlock( lock );
227:
228: return( set );
229: }
230:
231: // Is personality already in the catalog?
232: OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
233: SInt32 * generationCount)
234: {
235: OSDictionary * dict;
236: OSOrderedSet * set;
237:
238: UniqueProperties(matching);
239:
240: set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
241: (void *)gIOProbeScoreKey );
242:
243: IOTakeLock( lock );
244: kernelTables->reset();
245: while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
246: if ( dict->isEqualTo(matching, matching) )
247: set->setObject(dict);
248: }
249: *generationCount = getGenerationCount();
250: IOUnlock( lock );
251:
252: return set;
253: }
254:
255: // Add a new personality to the set if it has a unique IOResourceMatchKey value.
256: // XXX -- svail: This should be optimized.
257: static void AddNewImports( OSOrderedSet * set, OSDictionary * dict )
258: {
259: OSCollectionIterator * iter;
260: OSDictionary * entry;
261: OSString * imports1;
262: OSString * imports2;
263: bool foundMatch;
264:
265: imports1 = (OSString *)OSDynamicCast(OSString,
266: dict->getObject(gIOProviderClassKey));
267: if ( !imports1 )
268: return;
269:
270: foundMatch = false;
271: iter = OSCollectionIterator::withCollection(set);
272: if ( !iter )
273: return;
274:
275: while ( (entry = (OSDictionary *)iter->getNextObject()) ) {
276: imports2 = (OSString *)OSDynamicCast(OSString,
277: entry->getObject(gIOProviderClassKey));
278: if ( !imports2 )
279: continue;
280:
281: if ( imports1->isEqualTo(imports2) ) {
282: foundMatch = true;
283: break;
284: }
285: }
286: iter->release();
287:
288: if ( !foundMatch )
289: set->setObject(dict);
290: }
291:
292: // Add driver config tables to catalog and start matching process.
293: bool IOCatalogue::addDrivers( OSArray * drivers,
294: bool doNubMatching = true )
295: {
296: OSCollectionIterator * iter;
297: OSDictionary * dict;
298: OSOrderedSet * set;
299: OSArray * persons;
300: bool ret;
301:
302: ret = true;
303: persons = OSDynamicCast(OSArray, drivers);
304: if ( !persons )
305: return false;
306:
307: iter = OSCollectionIterator::withCollection( persons );
308: if (!iter )
309: return false;
310:
311: set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
312: (void *)gIOProbeScoreKey );
313: if ( !set ) {
314: iter->release();
315: return false;
316: }
317:
318: IOTakeLock( lock );
319: while ( (dict = (OSDictionary *) iter->getNextObject()) ) {
320: UInt count;
321:
322: UniqueProperties( dict );
323:
324: // Add driver personality to catalogue.
325: count = array->getCount();
326: while ( count-- ) {
327: OSDictionary * driver;
328:
329: // Be sure not to double up on personalities.
330: driver = (OSDictionary *)array->getObject(count);
331: if ( dict->isEqualTo(driver, driver) ) {
332: array->removeObject(count);
333: break;
334: }
335: }
336:
337: ret = array->setObject( dict );
338: if ( !ret )
339: break;
340:
341: AddNewImports( set, dict );
342: }
343: // Start device matching.
344: if ( doNubMatching && (set->getCount() > 0) ) {
345: IOService::catalogNewDrivers( set );
346: generation++;
347: }
348: IOUnlock( lock );
349:
350: set->release();
351: iter->release();
352:
353: return ret;
354: }
355:
356: // Remove drivers from the catalog which match the
357: // properties in the matching dictionary.
358: bool IOCatalogue::removeDrivers( OSDictionary * matching,
359: bool doNubMatching = true)
360: {
361: OSCollectionIterator * tables;
362: OSDictionary * dict;
363: OSOrderedSet * set;
364: OSArray * arrayCopy;
365:
366: if ( !matching )
367: return false;
368:
369: set = OSOrderedSet::withCapacity(10,
370: IOServiceOrdering,
371: (void *)gIOProbeScoreKey);
372: if ( !set )
373: return false;
374:
375: arrayCopy = OSArray::withCapacity(100);
376: if ( !arrayCopy )
377: return false;
378:
379: tables = OSCollectionIterator::withCollection(arrayCopy);
380: arrayCopy->release();
381: if ( !tables )
382: return false;
383:
384: UniqueProperties( matching );
385:
386: IOTakeLock( lock );
387: kernelTables->reset();
388: arrayCopy->merge(array);
389: array->flushCollection();
390: tables->reset();
391: while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
392: if ( dict->isEqualTo(matching, matching) ) {
393: AddNewImports( set, dict );
394: continue;
395: }
396:
397: array->setObject(dict);
398: }
399: // Start device matching.
400: if ( doNubMatching && (set->getCount() > 0) ) {
401: IOService::catalogNewDrivers(set);
402: generation++;
403: }
404: IOUnlock( lock );
405:
406: set->release();
407: tables->release();
408:
409: return true;
410: }
411:
412: // Return the generation count.
413: SInt32 IOCatalogue::getGenerationCount( void ) const
414: {
415: return( generation );
416: }
417:
418: bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
419: {
420: return isModuleLoaded(moduleName->getCStringNoCopy());
421: }
422:
423: bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
424: {
425: kmod_info_t * k_info;
426:
427: if ( !moduleName )
428: return false;
429:
430: // Is the module already loaded?
431: k_info = kmod_lookupbyname((char *)moduleName);
432: if ( !k_info ) {
433: kern_return_t ret;
434:
435: // If the module hasn't been loaded, then load it.
436: ret = kmod_load_extension((char *)moduleName);
437: if ( ret != kIOReturnSuccess ) {
438: IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
439: }
440:
441: return false;
442: }
443:
444: return true;
445: }
446:
447: // Check to see if module has been loaded already.
448: bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
449: {
450: OSString * moduleName;
451:
452: if ( !driver )
453: return false;
454:
455: // If a personality doesn't have a module key, it is assumed to
456: // be an "in-kernel" driver.
457: moduleName = OSDynamicCast(OSString, driver->getObject(kModuleKey));
458: if ( moduleName )
459: return isModuleLoaded(moduleName);
460:
461: return true;
462: }
463:
464: // This function is called after a module has been loaded.
465: void IOCatalogue::moduleHasLoaded( OSString * moduleName )
466: {
467: OSDictionary * dict;
468:
469: dict = OSDictionary::withCapacity(2);
470: dict->setObject(kModuleKey, moduleName);
471: startMatching(dict);
472: dict->release();
473: }
474:
475: void IOCatalogue::moduleHasLoaded( const char * moduleName )
476: {
477: OSString * name;
478:
479: name = OSString::withCString(moduleName);
480: moduleHasLoaded(name);
481: name->release();
482: }
483:
484: IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
485: {
486: kmod_info_t * k_info;
487: kern_return_t ret;
488: const char * name;
489:
490: ret = kIOReturnBadArgument;
491: if ( moduleName ) {
492: name = moduleName->getCStringNoCopy();
493: k_info = kmod_lookupbyname((char *)name);
494: if ( k_info && (k_info->reference_count < 1) ) {
495: if ( k_info->stop &&
496: !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) )
497: return ret;
498:
499: ret = kmod_destroy((host_t) 1, k_info->id);
500: }
501: }
502:
503: return ret;
504: }
505:
506: static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
507: {
508: OSCollectionIterator * tables;
509: OSCollectionIterator * props;
510: OSDictionary * dict;
511: OSIterator * iter;
512: OSArray * arrayCopy;
513: IOService * service;
514: IOReturn ret;
515:
516: if ( !matching )
517: return kIOReturnBadArgument;
518:
519: ret = kIOReturnSuccess;
520: dict = 0;
521: iter = IORegistryIterator::iterateOver(gIOServicePlane,
522: kIORegistryIterateRecursively);
523: if ( !iter )
524: return kIOReturnNoMemory;
525:
526: UniqueProperties( matching );
527:
528: props = OSCollectionIterator::withCollection(matching);
529: if ( !props ) {
530: iter->release();
531: return kIOReturnNoMemory;
532: }
533:
534: // terminate instances.
535: do {
536: iter->reset();
537: while( (service = (IOService *)iter->getNextObject()) ) {
538: dict = service->getPropertyTable();
539: if ( !dict )
540: continue;
541:
542: if ( !dict->isEqualTo(matching, matching) )
543: continue;
544:
545: if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) {
546: ret = kIOReturnUnsupported;
547: break;
548: }
549: }
550: } while( !service && !iter->isValid());
551: iter->release();
552:
553: // remove configs from catalog.
554: if ( ret != kIOReturnSuccess )
555: return ret;
556:
557: arrayCopy = OSArray::withCapacity(100);
558: if ( !arrayCopy )
559: return kIOReturnNoMemory;
560:
561: tables = OSCollectionIterator::withCollection(arrayCopy);
562: arrayCopy->release();
563: if ( !tables )
564: return kIOReturnNoMemory;
565:
566: arrayCopy->merge(array);
567: array->flushCollection();
568: tables->reset();
569: while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
570: if ( dict->isEqualTo(matching, matching) )
571: continue;
572:
573: array->setObject(dict);
574: }
575:
576: tables->release();
577:
578: return ret;
579: }
580:
581: IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
582: {
583: IOReturn ret;
584:
585: ret = kIOReturnSuccess;
586: IOTakeLock( lock );
587: ret = _terminateDrivers(array, matching);
588: kernelTables->reset();
589: IOUnlock( lock );
590:
591: return ret;
592: }
593:
594: IOReturn IOCatalogue::terminateDriversForModule(
595: OSString * moduleName,
596: bool unload )
597: {
598: IOReturn ret;
599: OSDictionary * dict;
600:
601: dict = OSDictionary::withCapacity(1);
602: if ( !dict )
603: return kIOReturnNoMemory;
604:
605: dict->setObject(kModuleKey, moduleName);
606:
607: IOTakeLock( lock );
608:
609: ret = _terminateDrivers(array, dict);
610: kernelTables->reset();
611:
612: // Unload the module itself.
613: if ( unload && ret == kIOReturnSuccess ) {
614: // Do kmod stop first.
615: ret = unloadModule(moduleName);
616: }
617:
618: IOUnlock( lock );
619:
620: dict->release();
621:
622: return ret;
623: }
624:
625: IOReturn IOCatalogue::terminateDriversForModule(
626: const char * moduleName,
627: bool unload )
628: {
629: OSString * name;
630: IOReturn ret;
631:
632: name = OSString::withCString(moduleName);
633: if ( !name )
634: return kIOReturnNoMemory;
635:
636: ret = terminateDriversForModule(name, unload);
637: name->release();
638:
639: return ret;
640: }
641:
642: bool IOCatalogue::startMatching( OSDictionary * matching )
643: {
644: OSDictionary * dict;
645: OSOrderedSet * set;
646:
647: if ( !matching )
648: return false;
649:
650: set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
651: (void *)gIOProbeScoreKey);
652: if ( !set )
653: return false;
654:
655: IOTakeLock( lock );
656: kernelTables->reset();
657:
658: while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
659: if ( dict->isEqualTo(matching, matching) )
660: AddNewImports(set, dict);
661: }
662: // Start device matching.
663: if ( set->getCount() > 0 ) {
664: IOService::catalogNewDrivers(set);
665: generation++;
666: }
667:
668: IOUnlock( lock );
669:
670: set->release();
671:
672: return true;
673: }
674:
675: void IOCatalogue::reset(void)
676: {
677: OSArray * tables;
678: OSDictionary * entry;
679: unsigned int count;
680:
681: IOLog("Resetting IOCatalogue.\n");
682:
683: IOTakeLock( lock );
684: tables = OSArray::withArray(array);
685: array->flushCollection();
686:
687: count = tables->getCount();
688: while ( count-- ) {
689: entry = (OSDictionary *)tables->getObject(count);
690: if ( entry && !entry->getObject(kModuleKey) ) {
691: array->setObject(entry);
692: }
693: }
694:
695: kernelTables->reset();
696: IOUnlock( lock );
697:
698: tables->release();
699: }
700:
701: bool IOCatalogue::serialize(OSSerialize * s) const
702: {
703: bool ret;
704:
705: if ( !s )
706: return false;
707:
708: IOTakeLock( lock );
709: ret = array->serialize(s);
710: IOUnlock( lock );
711:
712: return ret;
713: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.