]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IODeviceTreeSupport.cpp
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IODeviceTreeSupport.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <IOKit/IODeviceTreeSupport.h>
30 #include <libkern/c++/OSContainers.h>
31 #include <libkern/c++/OSSharedPtr.h>
32 #include <IOKit/IODeviceMemory.h>
33 #include <IOKit/IOService.h>
34 #include <IOKit/IOCatalogue.h>
35
36 #include <IOKit/IOLib.h>
37 #include <IOKit/IOKitKeys.h>
38
39 #include <pexpert/device_tree.h>
40
41 #if __arm64__
42 typedef UInt64 dtptr_t;
43 #else
44 typedef UInt32 dtptr_t;
45 #endif
46
47 #include <machine/machine_routines.h>
48
49 extern "C" {
50 int IODTGetLoaderInfo( const char *key, void **infoAddr, int *infosize );
51 void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize );
52 int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize );
53 }
54
55 #include <IOKit/assert.h>
56
57 #define IODTSUPPORTDEBUG 0
58
59 const IORegistryPlane * gIODTPlane;
60
61 static OSArray * gIODTPHandles;
62 static OSArray * gIODTPHandleMap;
63 static OSData * gIODTResolvers;
64
65 const OSSymbol * gIODTNameKey;
66 const OSSymbol * gIODTUnitKey;
67 const OSSymbol * gIODTCompatibleKey;
68 const OSSymbol * gIODTTypeKey;
69 const OSSymbol * gIODTModelKey;
70 const OSSymbol * gIODTBridgeModelKey;
71 const OSSymbol * gIODTTargetTypeKey;
72
73 const OSSymbol * gIODTSizeCellKey;
74 const OSSymbol * gIODTAddressCellKey;
75 const OSSymbol * gIODTRangeKey;
76
77 const OSSymbol * gIODTPersistKey;
78
79 const OSSymbol * gIODTDefaultInterruptController;
80 const OSSymbol * gIODTAAPLInterruptsKey;
81 const OSSymbol * gIODTPHandleKey;
82 const OSSymbol * gIODTInterruptCellKey;
83 const OSSymbol * gIODTInterruptParentKey;
84 const OSSymbol * gIODTNWInterruptMappingKey;
85
86 OSDictionary * gIODTSharedInterrupts;
87
88 static IOLock * gIODTResolversLock;
89
90 static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy );
91 static void AddPHandle( IORegistryEntry * regEntry );
92 static void FreePhysicalMemory( vm_offset_t * range );
93 static bool IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts );
94
95 // FIXME: Implementation of this function is hidden from the static analyzer.
96 // The analyzer doesn't know that the registry holds retains, and gets confused
97 // about releases after calls to 'attachToParent'.
98 // Feel free to remove the #ifndef and address the warning!
99 #ifndef __clang_analyzer__
100 IORegistryEntry *
101 IODeviceTreeAlloc( void * dtTop )
102 {
103 IORegistryEntry * parent;
104 IORegistryEntry * child;
105 IORegistryIterator * regIter;
106 OpaqueDTEntryIterator iter;
107 DTEntry dtChild;
108 DTEntry mapEntry;
109 OSArray * stack;
110 OSData * prop;
111 OSDictionary * allInts;
112 vm_offset_t * dtMap;
113 unsigned int propSize;
114 bool intMap;
115 bool foundDTNode;
116 bool freeDT;
117
118 gIODTPlane = IORegistryEntry::makePlane( kIODeviceTreePlane );
119
120 gIODTNameKey = OSSymbol::withCStringNoCopy( "name" );
121 gIODTUnitKey = OSSymbol::withCStringNoCopy( "AAPL,unit-string" );
122 gIODTCompatibleKey = OSSymbol::withCStringNoCopy( "compatible" );
123 gIODTTypeKey = OSSymbol::withCStringNoCopy( "device_type" );
124 gIODTModelKey = OSSymbol::withCStringNoCopy( "model" );
125 gIODTBridgeModelKey = OSSymbol::withCStringNoCopy( "bridge-model" );
126 gIODTTargetTypeKey = OSSymbol::withCStringNoCopy( "target-type" );
127 gIODTSizeCellKey = OSSymbol::withCStringNoCopy( "#size-cells" );
128 gIODTAddressCellKey = OSSymbol::withCStringNoCopy( "#address-cells" );
129 gIODTRangeKey = OSSymbol::withCStringNoCopy( "ranges" );
130 gIODTPersistKey = OSSymbol::withCStringNoCopy( "IODTPersist" );
131
132 assert( gIODTPlane && gIODTCompatibleKey
133 && gIODTTypeKey && gIODTModelKey
134 && gIODTSizeCellKey && gIODTAddressCellKey && gIODTRangeKey
135 && gIODTPersistKey );
136
137 gIODTDefaultInterruptController
138 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
139 gIODTNWInterruptMappingKey
140 = OSSymbol::withCStringNoCopy("IONWInterrupts");
141
142 gIODTAAPLInterruptsKey
143 = OSSymbol::withCStringNoCopy("AAPL,interrupts");
144 gIODTPHandleKey
145 = OSSymbol::withCStringNoCopy("AAPL,phandle");
146
147 gIODTInterruptParentKey
148 = OSSymbol::withCStringNoCopy("interrupt-parent");
149
150 gIODTPHandles = OSArray::withCapacity( 1 );
151 gIODTPHandleMap = OSArray::withCapacity( 1 );
152 gIODTResolvers = OSData::withCapacity(16);
153
154 gIODTResolversLock = IOLockAlloc();
155
156 gIODTInterruptCellKey
157 = OSSymbol::withCStringNoCopy("#interrupt-cells");
158
159 assert( gIODTDefaultInterruptController && gIODTNWInterruptMappingKey
160 && gIODTAAPLInterruptsKey
161 && gIODTPHandleKey && gIODTInterruptParentKey
162 && gIODTPHandles && gIODTPHandleMap && gIODTResolvers && gIODTResolversLock
163 && gIODTInterruptCellKey
164 );
165
166 foundDTNode = (kSuccess == SecureDTLookupEntry( NULL, "/chosen/memory-map", &mapEntry ))
167 && (kSuccess == SecureDTGetProperty( mapEntry,
168 "DeviceTree", (void const **) &dtMap, &propSize ))
169 && ((2 * sizeof(uint32_t)) == propSize);
170
171 freeDT = foundDTNode && !SecureDTIsLockedDown();
172
173 parent = MakeReferenceTable((DTEntry)dtTop, freeDT );
174
175 stack = OSArray::withObjects((const OSObject **) &parent, 1, 10 );
176 SecureDTInitEntryIterator((DTEntry)dtTop, &iter );
177
178 do {
179 parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1);
180 //parent->release();
181 stack->removeObject( stack->getCount() - 1);
182
183 while (kSuccess == SecureDTIterateEntries( &iter, &dtChild)) {
184 child = MakeReferenceTable( dtChild, freeDT );
185 child->attachToParent( parent, gIODTPlane);
186
187 AddPHandle( child );
188
189 if (kSuccess == SecureDTEnterEntry( &iter, dtChild)) {
190 stack->setObject( parent);
191 parent = child;
192 }
193 // only registry holds retain
194 child->release();
195 }
196 } while (stack->getCount()
197 && (kSuccess == SecureDTExitEntry( &iter, &dtChild)));
198
199 stack->release();
200 assert(kSuccess != SecureDTExitEntry(&iter, &dtChild));
201
202 // parent is now root of the created tree
203
204 // make root name first compatible entry (purely cosmetic)
205 if ((prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) {
206 parent->setName( parent->getName(), gIODTPlane );
207 parent->setName((const char *) prop->getBytesNoCopy());
208 }
209
210 // attach tree to meta root
211 parent->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane);
212 parent->release();
213
214 if (freeDT) {
215 // free original device tree
216 SecureDTInit(NULL, 0);
217 IODTFreeLoaderInfo( "DeviceTree",
218 (void *)dtMap[0], (int) round_page(dtMap[1]));
219 }
220
221 // adjust tree
222
223 gIODTSharedInterrupts = OSDictionary::withCapacity(4);
224 allInts = OSDictionary::withCapacity(4);
225 intMap = false;
226 regIter = IORegistryIterator::iterateOver( gIODTPlane,
227 kIORegistryIterateRecursively );
228 assert( regIter && allInts && gIODTSharedInterrupts );
229 if (regIter && allInts && gIODTSharedInterrupts) {
230 while ((child = regIter->getNextObject())) {
231 IODTMapInterruptsSharing( child, allInts );
232 if (!intMap && child->getProperty( gIODTInterruptParentKey)) {
233 intMap = true;
234 }
235 if (!strcmp("sep", child->getName())
236 || !strcmp("aop", child->getName())
237 || !strcmp("disp0", child->getName())) {
238 uint32_t aotFlags = 1;
239 child->setProperty("aot-power", &aotFlags, sizeof(aotFlags));
240 }
241 }
242 regIter->release();
243 }
244
245 #if IODTSUPPORTDEBUG
246 parent->setProperty("allInts", allInts);
247 parent->setProperty("sharedInts", gIODTSharedInterrupts);
248
249 regIter = IORegistryIterator::iterateOver( gIODTPlane,
250 kIORegistryIterateRecursively );
251 if (regIter) {
252 while ((child = regIter->getNextObject())) {
253 OSArray *
254 array = OSDynamicCast(OSArray, child->getProperty( gIOInterruptSpecifiersKey ));
255 for (UInt32 i = 0; array && (i < array->getCount()); i++) {
256 IOOptionBits options;
257 IOReturn ret = IODTGetInterruptOptions( child, i, &options );
258 if ((ret != kIOReturnSuccess) || options) {
259 IOLog("%s[%ld] %ld (%x)\n", child->getName(), i, options, ret);
260 }
261 }
262 }
263 regIter->release();
264 }
265 #endif
266
267 allInts->release();
268
269 if (intMap) {
270 // set a key in the root to indicate we found NW interrupt mapping
271 parent->setProperty( gIODTNWInterruptMappingKey,
272 (OSObject *) gIODTNWInterruptMappingKey );
273 }
274
275 return parent;
276 }
277 #endif
278
279 int
280 IODTGetLoaderInfo( const char *key, void **infoAddr, int *infoSize )
281 {
282 IORegistryEntry *chosen;
283 OSData *propObj;
284 dtptr_t *propPtr;
285 unsigned int propSize;
286 int ret = -1;
287
288 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
289 if (chosen == NULL) {
290 return -1;
291 }
292
293 propObj = OSDynamicCast( OSData, chosen->getProperty(key));
294 if (propObj == NULL) {
295 goto cleanup;
296 }
297
298 propSize = propObj->getLength();
299 if (propSize != (2 * sizeof(dtptr_t))) {
300 goto cleanup;
301 }
302
303 propPtr = (dtptr_t *)propObj->getBytesNoCopy();
304 if (propPtr == NULL) {
305 goto cleanup;
306 }
307
308 *infoAddr = (void *)(uintptr_t) (propPtr[0]);
309 *infoSize = (int) (propPtr[1]);
310
311 ret = 0;
312
313 cleanup:
314 chosen->release();
315
316 return ret;
317 }
318
319 void
320 IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize )
321 {
322 vm_offset_t range[2];
323 IORegistryEntry *chosen;
324
325 range[0] = (vm_offset_t)infoAddr;
326 range[1] = (vm_offset_t)infoSize;
327 FreePhysicalMemory( range );
328
329 if (key != NULL) {
330 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane );
331 if (chosen != NULL) {
332 chosen->removeProperty(key);
333 chosen->release();
334 }
335 }
336 }
337
338 int
339 IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize )
340 {
341 IORegistryEntry *defaults;
342 OSData *defaultObj;
343 unsigned int defaultSize;
344
345 defaults = IORegistryEntry::fromPath( "/defaults", gIODTPlane );
346 if (defaults == NULL) {
347 return -1;
348 }
349
350 defaultObj = OSDynamicCast( OSData, defaults->getProperty(key));
351 if (defaultObj == NULL) {
352 return -1;
353 }
354
355 defaultSize = defaultObj->getLength();
356 if (defaultSize > infoSize) {
357 return -1;
358 }
359
360 memcpy( infoAddr, defaultObj->getBytesNoCopy(), defaultSize );
361
362 return 0;
363 }
364
365 static void
366 FreePhysicalMemory( vm_offset_t * range )
367 {
368 vm_offset_t virt;
369
370 virt = ml_static_ptovirt( range[0] );
371 if (virt) {
372 ml_static_mfree( virt, range[1] );
373 }
374 }
375
376 static IORegistryEntry *
377 MakeReferenceTable( DTEntry dtEntry, bool copy )
378 {
379 IORegistryEntry *regEntry;
380 OSDictionary *propTable;
381 const OSSymbol *nameKey;
382 OSData *data;
383 const OSSymbol *sym;
384 OpaqueDTPropertyIterator dtIter;
385 void const *prop;
386 unsigned int propSize;
387 char const *name;
388 char location[32];
389 bool noLocation = true;
390 bool kernelOnly;
391
392 regEntry = new IOService;
393
394 if (regEntry && (false == regEntry->init())) {
395 regEntry->release();
396 regEntry = NULL;
397 }
398
399 if (regEntry &&
400 (kSuccess == SecureDTInitPropertyIterator( dtEntry, &dtIter))) {
401 kernelOnly = (kSuccess == SecureDTGetProperty(dtEntry, "kernel-only", &prop, &propSize));
402 propTable = regEntry->getPropertyTable();
403
404 while (kSuccess == SecureDTIterateProperties( &dtIter, &name)) {
405 if (kSuccess != SecureDTGetProperty( dtEntry, name, &prop, &propSize )) {
406 continue;
407 }
408
409 if (copy) {
410 nameKey = OSSymbol::withCString(name);
411 data = OSData::withBytes(prop, propSize);
412 } else {
413 nameKey = OSSymbol::withCStringNoCopy(name);
414 /* There is no OSDataConst or other way to indicate
415 * that the OSData is actually immutable. But CTRR
416 * will catch any write attempts. */
417 data = OSData::withBytesNoCopy((void**)(uintptr_t)prop, propSize);
418 }
419 assert( nameKey && data );
420
421 if (kernelOnly) {
422 data->setSerializable(false);
423 }
424
425 propTable->setObject( nameKey, data);
426 data->release();
427 nameKey->release();
428
429 if (nameKey == gIODTNameKey) {
430 if (copy) {
431 sym = OSSymbol::withCString((const char *) prop);
432 } else {
433 sym = OSSymbol::withCStringNoCopy((const char *) prop);
434 }
435 regEntry->setName( sym );
436 sym->release();
437 } else if (nameKey == gIODTUnitKey) {
438 // all OF strings are null terminated... except this one
439 if (propSize >= (int) sizeof(location)) {
440 propSize = sizeof(location) - 1;
441 }
442 strncpy( location, (const char *) prop, propSize );
443 location[propSize] = 0;
444 regEntry->setLocation( location );
445 propTable->removeObject( gIODTUnitKey );
446 noLocation = false;
447 } else if (noLocation && (!strncmp(name, "reg", sizeof("reg")))) {
448 // default location - override later
449 snprintf(location, sizeof(location), "%X", *((uint32_t *) prop));
450 regEntry->setLocation( location );
451 }
452 }
453 }
454
455 return regEntry;
456 }
457
458 static void
459 AddPHandle( IORegistryEntry * regEntry )
460 {
461 OSData * data;
462
463 if (regEntry->getProperty( gIODTInterruptCellKey)
464 && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) {
465 // a possible interrupt-parent
466 gIODTPHandles->setObject( data );
467 gIODTPHandleMap->setObject( regEntry );
468 }
469 }
470
471 static IORegistryEntry *
472 FindPHandle( UInt32 phandle )
473 {
474 OSData *data;
475 IORegistryEntry *regEntry = NULL;
476 int i;
477
478 for (i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++) {
479 if (phandle == *((UInt32 *)data->getBytesNoCopy())) {
480 regEntry = (IORegistryEntry *)
481 gIODTPHandleMap->getObject( i );
482 break;
483 }
484 }
485
486 return regEntry;
487 }
488
489 static bool
490 GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name,
491 UInt32 * value )
492 {
493 OSObject * obj;
494 OSData * data;
495 bool result;
496
497 if (!(obj = regEntry->copyProperty(name))) {
498 return false;
499 }
500
501 result = ((data = OSDynamicCast(OSData, obj)) && (sizeof(UInt32) == data->getLength()));
502 if (result) {
503 *value = *((UInt32 *) data->getBytesNoCopy());
504 }
505
506 obj->release();
507 return result;
508 }
509
510 static IORegistryEntry *
511 IODTFindInterruptParent( IORegistryEntry * regEntry, IOItemCount index )
512 {
513 IORegistryEntry * parent;
514 UInt32 phandle;
515 OSData * data;
516 unsigned int len;
517
518 if ((data = OSDynamicCast( OSData, regEntry->getProperty( gIODTInterruptParentKey )))
519 && (sizeof(UInt32) <= (len = data->getLength()))) {
520 if (((index + 1) * sizeof(UInt32)) > len) {
521 index = 0;
522 }
523 phandle = ((UInt32 *) data->getBytesNoCopy())[index];
524 parent = FindPHandle( phandle );
525 } else if (NULL == regEntry->getProperty( "interrupt-controller")) {
526 parent = regEntry->getParentEntry( gIODTPlane);
527 } else {
528 parent = NULL;
529 }
530
531 return parent;
532 }
533
534 const OSSymbol *
535 IODTInterruptControllerName( IORegistryEntry * regEntry )
536 {
537 const OSSymbol *sym;
538 UInt32 phandle;
539 bool ok;
540 char buf[48];
541
542 ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle);
543 assert( ok );
544
545 if (ok) {
546 snprintf(buf, sizeof(buf), "IOInterruptController%08X", (uint32_t)phandle);
547 sym = OSSymbol::withCString( buf );
548 } else {
549 sym = NULL;
550 }
551
552 return sym;
553 }
554
555 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; }
556
557 static void
558 IODTGetICellCounts( IORegistryEntry * regEntry,
559 UInt32 * iCellCount, UInt32 * aCellCount)
560 {
561 if (!GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount)) {
562 unexpected( *iCellCount = 1 );
563 }
564 if (!GetUInt32( regEntry, gIODTAddressCellKey, aCellCount)) {
565 *aCellCount = 0;
566 }
567 }
568
569 static UInt32
570 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, UInt32 index,
571 LIBKERN_RETURNS_RETAINED OSData ** spec,
572 LIBKERN_RETURNS_RETAINED const OSSymbol ** controller )
573 {
574 IORegistryEntry *parent = NULL;
575 OSData *data;
576 UInt32 *addrCmp;
577 UInt32 *maskCmp;
578 UInt32 *map;
579 UInt32 *endMap;
580 UInt32 acells, icells, pacells, picells, cell;
581 UInt32 i, original_icells;
582 bool cmp, ok = false;
583
584 parent = IODTFindInterruptParent( regEntry, index );
585 IODTGetICellCounts( parent, &icells, &acells );
586 addrCmp = NULL;
587 if (acells) {
588 data = OSDynamicCast( OSData, regEntry->getProperty( "reg" ));
589 if (data && (data->getLength() >= (acells * sizeof(UInt32)))) {
590 addrCmp = (UInt32 *) data->getBytesNoCopy();
591 }
592 }
593 original_icells = icells;
594 regEntry = parent;
595
596 do {
597 #if IODTSUPPORTDEBUG
598 kprintf("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName());
599 kprintf("acells - icells: ");
600 for (i = 0; i < acells; i++) {
601 kprintf("0x%08X ", addrCmp[i]);
602 }
603 kprintf("- ");
604 for (i = 0; i < icells; i++) {
605 kprintf("0x%08X ", intSpec[i]);
606 }
607 kprintf("\n");
608 #endif
609
610 if (parent && (data = OSDynamicCast( OSData,
611 regEntry->getProperty( "interrupt-controller")))) {
612 // found a controller - don't want to follow cascaded controllers
613 parent = NULL;
614 *spec = OSData::withBytesNoCopy((void *) intSpec,
615 icells * sizeof(UInt32));
616 *controller = IODTInterruptControllerName( regEntry );
617 ok = (*spec && *controller);
618 } else if (parent && (data = OSDynamicCast( OSData,
619 regEntry->getProperty( "interrupt-map")))) {
620 // interrupt-map
621 map = (UInt32 *) data->getBytesNoCopy();
622 endMap = map + (data->getLength() / sizeof(UInt32));
623 data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" ));
624 if (data && (data->getLength() >= ((acells + icells) * sizeof(UInt32)))) {
625 maskCmp = (UInt32 *) data->getBytesNoCopy();
626 } else {
627 maskCmp = NULL;
628 }
629
630 #if IODTSUPPORTDEBUG
631 if (maskCmp) {
632 kprintf(" maskCmp: ");
633 for (i = 0; i < acells + icells; i++) {
634 if (i == acells) {
635 kprintf("- ");
636 }
637 kprintf("0x%08X ", maskCmp[i]);
638 }
639 kprintf("\n");
640 kprintf(" masked: ");
641 for (i = 0; i < acells + icells; i++) {
642 if (i == acells) {
643 kprintf("- ");
644 }
645 kprintf("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i - acells]) & maskCmp[i]);
646 }
647 kprintf("\n");
648 } else {
649 kprintf("no maskCmp\n");
650 }
651 #endif
652 do {
653 #if IODTSUPPORTDEBUG
654 kprintf(" map: ");
655 for (i = 0; i < acells + icells; i++) {
656 if (i == acells) {
657 kprintf("- ");
658 }
659 kprintf("0x%08X ", map[i]);
660 }
661 kprintf("\n");
662 #endif
663 for (i = 0, cmp = true; cmp && (i < (acells + icells)); i++) {
664 cell = (i < acells) ? addrCmp[i] : intSpec[i - acells];
665 if (maskCmp) {
666 cell &= maskCmp[i];
667 }
668 cmp = (cell == map[i]);
669 }
670
671 map += acells + icells;
672 if (NULL == (parent = FindPHandle( *(map++)))) {
673 unexpected(break);
674 }
675
676 IODTGetICellCounts( parent, &picells, &pacells );
677 if (cmp) {
678 addrCmp = map;
679 intSpec = map + pacells;
680 regEntry = parent;
681 } else {
682 map += pacells + picells;
683 }
684 } while (!cmp && (map < endMap));
685 if (!cmp) {
686 parent = NULL;
687 }
688 }
689
690 if (parent) {
691 IODTGetICellCounts( parent, &icells, &acells );
692 regEntry = parent;
693 }
694 } while (parent);
695
696 return ok ? original_icells : 0;
697 }
698
699 IOReturn
700 IODTGetInterruptOptions( IORegistryEntry * regEntry, int source, IOOptionBits * options )
701 {
702 OSArray * controllers;
703 OSArray * specifiers;
704 OSArray * shared;
705 OSObject * spec;
706 OSObject * oneSpec;
707
708 *options = 0;
709
710 controllers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptControllersKey));
711 specifiers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptSpecifiersKey));
712
713 if (!controllers || !specifiers) {
714 return kIOReturnNoInterrupt;
715 }
716
717 shared = (OSArray *) gIODTSharedInterrupts->getObject(
718 (const OSSymbol *) controllers->getObject(source));
719 if (!shared) {
720 return kIOReturnSuccess;
721 }
722
723 spec = specifiers->getObject(source);
724 if (!spec) {
725 return kIOReturnNoInterrupt;
726 }
727
728 for (unsigned int i = 0;
729 (oneSpec = shared->getObject(i))
730 && (!oneSpec->isEqualTo(spec));
731 i++) {
732 }
733
734 if (oneSpec) {
735 *options = kIODTInterruptShared;
736 }
737
738 return kIOReturnSuccess;
739 }
740
741 static bool
742 IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts )
743 {
744 IORegistryEntry * parent;
745 OSData * local;
746 OSData * local2;
747 UInt32 * localBits;
748 UInt32 * localEnd;
749 IOItemCount index;
750 OSData * map;
751 OSObject * oneMap;
752 OSArray * mapped;
753 OSArray * controllerInts;
754 const OSSymbol * controller = NULL;
755 OSArray * controllers;
756 UInt32 skip = 1;
757 bool ok, nw;
758
759 nw = (NULL == (local = OSDynamicCast( OSData,
760 regEntry->getProperty( gIODTAAPLInterruptsKey))));
761 if (nw && (NULL == (local = OSDynamicCast( OSData,
762 regEntry->getProperty( "interrupts"))))) {
763 return true; // nothing to see here
764 }
765 if (nw && (parent = regEntry->getParentEntry( gIODTPlane))) {
766 // check for bridges on old world
767 if ((local2 = OSDynamicCast( OSData,
768 parent->getProperty( gIODTAAPLInterruptsKey)))) {
769 local = local2;
770 nw = false;
771 }
772 }
773
774 localBits = (UInt32 *) local->getBytesNoCopy();
775 localEnd = localBits + (local->getLength() / sizeof(UInt32));
776 index = 0;
777 mapped = OSArray::withCapacity( 1 );
778 controllers = OSArray::withCapacity( 1 );
779
780 ok = (mapped && controllers);
781
782 if (ok) {
783 do {
784 if (nw) {
785 skip = IODTMapOneInterrupt( regEntry, localBits, index, &map, &controller );
786 if (0 == skip) {
787 IOLog("%s: error mapping interrupt[%d]\n",
788 regEntry->getName(), mapped->getCount());
789 break;
790 }
791 } else {
792 map = OSData::withData( local, mapped->getCount() * sizeof(UInt32),
793 sizeof(UInt32));
794 controller = gIODTDefaultInterruptController;
795 controller->retain();
796 }
797
798 index++;
799 localBits += skip;
800 mapped->setObject( map );
801 controllers->setObject( controller );
802
803 if (allInts) {
804 controllerInts = (OSArray *) allInts->getObject( controller );
805 if (controllerInts) {
806 for (unsigned int i = 0; (oneMap = controllerInts->getObject(i)); i++) {
807 if (map->isEqualTo(oneMap)) {
808 controllerInts = (OSArray *) gIODTSharedInterrupts->getObject( controller );
809 if (controllerInts) {
810 controllerInts->setObject(map);
811 } else {
812 controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 4 );
813 if (controllerInts) {
814 gIODTSharedInterrupts->setObject( controller, controllerInts );
815 controllerInts->release();
816 }
817 }
818 break;
819 }
820 }
821 if (!oneMap) {
822 controllerInts->setObject(map);
823 }
824 } else {
825 controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 16 );
826 if (controllerInts) {
827 allInts->setObject( controller, controllerInts );
828 controllerInts->release();
829 }
830 }
831 }
832
833 map->release();
834 controller->release();
835 } while (localBits < localEnd);
836 }
837
838 ok &= (localBits == localEnd);
839
840 if (ok) {
841 // store results
842 ok = regEntry->setProperty( gIOInterruptControllersKey, controllers);
843 ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped);
844 }
845
846 if (controllers) {
847 controllers->release();
848 }
849 if (mapped) {
850 mapped->release();
851 }
852
853 return ok;
854 }
855
856 bool
857 IODTMapInterrupts( IORegistryEntry * regEntry )
858 {
859 return IODTMapInterruptsSharing( regEntry, NULL );
860 }
861
862 /*
863 */
864
865 static bool
866 CompareKey( OSString * key,
867 const IORegistryEntry * table, const OSSymbol * propName,
868 LIBKERN_RETURNS_RETAINED OSString ** matchingName )
869 {
870 OSObject *prop;
871 OSData *data;
872 OSString *string;
873 const char *ckey;
874 UInt32 keyLen;
875 UInt32 nlen;
876 const char *names;
877 const char *lastName;
878 bool wild;
879 bool matched;
880 const char *result = NULL;
881
882 if (NULL == (prop = table->copyProperty( propName ))) {
883 return 0;
884 }
885
886 if ((data = OSDynamicCast( OSData, prop ))) {
887 names = (const char *) data->getBytesNoCopy();
888 lastName = names + data->getLength();
889 } else if ((string = OSDynamicCast( OSString, prop ))) {
890 names = string->getCStringNoCopy();
891 lastName = names + string->getLength() + 1;
892 } else {
893 names = NULL;
894 }
895
896 if (names) {
897 ckey = key->getCStringNoCopy();
898 keyLen = key->getLength();
899 wild = ('*' == key->getChar( keyLen - 1 ));
900
901 do {
902 // for each name in the property
903 nlen = (unsigned int) strnlen(names, lastName - names);
904 if (wild) {
905 matched = ((nlen >= (keyLen - 1)) && (0 == strncmp(ckey, names, keyLen - 1)));
906 } else {
907 matched = (keyLen == nlen) && (0 == strncmp(ckey, names, keyLen));
908 }
909
910 if (matched) {
911 result = names;
912 }
913
914 names = names + nlen + 1;
915 } while ((names < lastName) && (false == matched));
916 }
917
918 if (result && matchingName) {
919 *matchingName = OSString::withCString( result );
920 }
921
922 if (prop) {
923 prop->release();
924 }
925
926 return result != NULL;
927 }
928
929
930 bool
931 IODTCompareNubName( const IORegistryEntry * regEntry,
932 OSString * name, OSString ** matchingName )
933 {
934 bool matched;
935
936 matched = CompareKey( name, regEntry, gIODTNameKey, matchingName)
937 || CompareKey( name, regEntry, gIODTCompatibleKey, matchingName)
938 || CompareKey( name, regEntry, gIODTTypeKey, matchingName)
939 || CompareKey( name, regEntry, gIODTModelKey, matchingName);
940
941 return matched;
942 }
943
944 bool
945 IODTCompareNubName( const IORegistryEntry * regEntry,
946 OSString * name, OSSharedPtr<OSString>& matchingName )
947 {
948 OSString* matchingNameRaw = NULL;
949 bool result = IODTCompareNubName(regEntry, name, &matchingNameRaw);
950 matchingName.reset(matchingNameRaw, OSNoRetain);
951 return result;
952 }
953
954 bool
955 IODTMatchNubWithKeys( IORegistryEntry * regEntry,
956 const char * keys )
957 {
958 OSObject *obj;
959 bool result = false;
960
961 obj = OSUnserialize( keys, NULL );
962
963 if (obj) {
964 result = regEntry->compareNames( obj );
965 obj->release();
966 }
967 #if DEBUG
968 else {
969 IOLog("Couldn't unserialize %s\n", keys );
970 }
971 #endif
972
973 return result;
974 }
975
976 OSCollectionIterator *
977 IODTFindMatchingEntries( IORegistryEntry * from,
978 IOOptionBits options, const char * keys )
979 {
980 OSSet *result = NULL;
981 IORegistryEntry *next;
982 IORegistryIterator *iter;
983 OSCollectionIterator *cIter;
984 bool cmp;
985 bool minus = options & kIODTExclusive;
986
987
988 iter = IORegistryIterator::iterateOver( from, gIODTPlane,
989 (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 );
990 if (iter) {
991 do {
992 if (result) {
993 result->release();
994 }
995 result = OSSet::withCapacity( 3 );
996 if (!result) {
997 break;
998 }
999
1000 iter->reset();
1001 while ((next = iter->getNextObject())) {
1002 // Look for existence of a debug property to skip
1003 if (next->getProperty("AAPL,ignore")) {
1004 continue;
1005 }
1006
1007 if (keys) {
1008 cmp = IODTMatchNubWithKeys( next, keys );
1009 if ((minus && (false == cmp))
1010 || ((false == minus) && (false != cmp))) {
1011 result->setObject( next);
1012 }
1013 } else {
1014 result->setObject( next);
1015 }
1016 }
1017 } while (!iter->isValid());
1018
1019 iter->release();
1020 }
1021
1022 cIter = OSCollectionIterator::withCollection( result);
1023 if (result) {
1024 result->release();
1025 }
1026
1027 return cIter;
1028 }
1029
1030
1031 struct IODTPersistent {
1032 IODTCompareAddressCellFunc compareFunc;
1033 };
1034
1035 void
1036 IODTSetResolving( IORegistryEntry * regEntry,
1037 IODTCompareAddressCellFunc compareFunc,
1038 IODTNVLocationFunc locationFunc __unused )
1039 {
1040 IODTPersistent persist;
1041 IODTPersistent * entry;
1042 OSNumber * num;
1043 unsigned int index, count;
1044
1045 IOLockLock(gIODTResolversLock);
1046
1047 count = (gIODTResolvers->getLength() / sizeof(IODTPersistent));
1048 entry = (typeof(entry))gIODTResolvers->getBytesNoCopy();
1049 for (index = 0; index < count; index++) {
1050 if (compareFunc == entry->compareFunc) {
1051 break;
1052 }
1053 entry++;
1054 }
1055 if (index == count) {
1056 persist.compareFunc = compareFunc;
1057 if (!gIODTResolvers->appendBytes(&persist, sizeof(IODTPersistent))) {
1058 panic("IODTSetResolving");
1059 }
1060 }
1061
1062 IOLockUnlock(gIODTResolversLock);
1063
1064 num = OSNumber::withNumber(index, 32);
1065 regEntry->setProperty(gIODTPersistKey, num);
1066 OSSafeReleaseNULL(num);
1067
1068 return;
1069 }
1070
1071 #if defined(__arm64__)
1072 static SInt64
1073 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
1074 {
1075 SInt64 diff = 0;
1076
1077 if (cellCount == 2) {
1078 diff = IOPhysical32(left[1], left[0]) - IOPhysical32(right[1], right[0]);
1079 } else if (cellCount == 1) {
1080 diff = (left[0] - right[0]);
1081 } else {
1082 panic("DefaultCompare only knows how to handle 1 or 2 cells.");
1083 }
1084
1085 return diff;
1086 }
1087 #elif defined(__arm__) || defined(__i386__) || defined(__x86_64__)
1088 static SInt32
1089 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
1090 {
1091 cellCount--;
1092 return left[cellCount] - right[cellCount];
1093 }
1094 #else
1095 #error Unknown architecture.
1096 #endif
1097
1098 static void
1099 AddLengthToCells( UInt32 numCells, UInt32 *cells, UInt64 offset)
1100 {
1101 if (numCells == 1) {
1102 cells[0] += (UInt32)offset;
1103 } else {
1104 #if defined(__arm64__) || defined(__arm__)
1105 UInt64 sum = cells[numCells - 2] + offset;
1106 cells[numCells - 2] = (UInt32)sum;
1107 if (sum > UINT32_MAX) {
1108 cells[numCells - 1] += (UInt32)(sum >> 32);
1109 }
1110 #else
1111 UInt64 sum = cells[numCells - 1] + offset;
1112 cells[numCells - 1] = (UInt32)sum;
1113 if (sum > UINT32_MAX) {
1114 cells[numCells - 2] += (UInt32)(sum >> 32);
1115 }
1116 #endif
1117 }
1118 }
1119
1120 static IOPhysicalAddress
1121 CellsValue( UInt32 numCells, UInt32 *cells)
1122 {
1123 if (numCells == 1) {
1124 return IOPhysical32( 0, cells[0] );
1125 } else {
1126 #if defined(__arm64__) || defined(arm)
1127 return IOPhysical32( cells[numCells - 1], cells[numCells - 2] );
1128 #else
1129 return IOPhysical32( cells[numCells - 2], cells[numCells - 1] );
1130 #endif
1131 }
1132 }
1133
1134 void
1135 IODTGetCellCounts( IORegistryEntry * regEntry,
1136 UInt32 * sizeCount, UInt32 * addressCount)
1137 {
1138 if (!GetUInt32( regEntry, gIODTSizeCellKey, sizeCount)) {
1139 *sizeCount = 1;
1140 }
1141 if (!GetUInt32( regEntry, gIODTAddressCellKey, addressCount)) {
1142 *addressCount = 2;
1143 }
1144 return;
1145 }
1146
1147 // Given addr & len cells from our child, find it in our ranges property, then
1148 // look in our parent to resolve the base of the range for us.
1149
1150 // Range[]: child-addr our-addr child-len
1151 // #cells: child ours child
1152
1153 bool
1154 IODTResolveAddressCell( IORegistryEntry * startEntry,
1155 UInt32 cellsIn[],
1156 IOPhysicalAddress * phys, IOPhysicalLength * lenOut )
1157 {
1158 IORegistryEntry * parent;
1159 IORegistryEntry * regEntry;
1160 OSData * prop;
1161 OSNumber * num;
1162 unsigned int index, count;
1163 // cells in addresses at regEntry
1164 UInt32 sizeCells, addressCells;
1165 // cells in addresses below regEntry
1166 UInt32 childSizeCells, childAddressCells;
1167 UInt32 childCells;
1168 UInt32 cell[8], propLen;
1169 UInt64 offset = 0;
1170 UInt32 endCell[8];
1171 UInt32 *range;
1172 UInt32 *lookRange;
1173 UInt32 *startRange;
1174 UInt32 *endRanges;
1175 bool ok = true;
1176 SInt64 diff, diff2, endDiff;
1177 UInt64 len, rangeLen;
1178
1179 IODTPersistent *persist;
1180 IODTCompareAddressCellFunc compare;
1181
1182 regEntry = startEntry;
1183 IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells );
1184 childCells = childAddressCells + childSizeCells;
1185
1186 if (childCells > sizeof(cell) / sizeof(cell[0])) {
1187 panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells, (uint32_t)childSizeCells);
1188 }
1189
1190 bcopy( cellsIn, cell, sizeof(UInt32) * childCells );
1191 *lenOut = CellsValue( childSizeCells, cellsIn + childAddressCells );
1192
1193 do{
1194 prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey ));
1195 if (NULL == prop) {
1196 /* end of the road */
1197 *phys = CellsValue( childAddressCells, cell );
1198 *phys += offset;
1199 if (regEntry != startEntry) {
1200 regEntry->release();
1201 }
1202 break;
1203 }
1204
1205 parent = regEntry->copyParentEntry( gIODTPlane );
1206 IODTGetCellCounts( parent, &sizeCells, &addressCells );
1207
1208 if ((propLen = prop->getLength())) {
1209 // search
1210 startRange = (UInt32 *) prop->getBytesNoCopy();
1211 range = startRange;
1212 endRanges = range + (propLen / sizeof(UInt32));
1213
1214 compare = NULL;
1215 num = OSDynamicCast(OSNumber, regEntry->getProperty(gIODTPersistKey));
1216 if (num) {
1217 IOLockLock(gIODTResolversLock);
1218 index = num->unsigned32BitValue();
1219 count = gIODTResolvers->getLength() / sizeof(IODTPersistent);
1220 if (index < count) {
1221 persist = ((IODTPersistent *) gIODTResolvers->getBytesNoCopy()) + index;
1222 compare = persist->compareFunc;
1223 }
1224 IOLockUnlock(gIODTResolversLock);
1225 }
1226
1227 if (!compare && (addressCells == childAddressCells)) {
1228 compare = DefaultCompare;
1229 }
1230 if (!compare) {
1231 panic("There is no mixed comparison function yet...");
1232 }
1233
1234 for (ok = false;
1235 range < endRanges;
1236 range += (childCells + addressCells)) {
1237 // is cell start within range?
1238 diff = (*compare)( childAddressCells, cell, range );
1239
1240 if (childAddressCells > sizeof(endCell) / sizeof(endCell[0])) {
1241 panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells);
1242 }
1243
1244 bcopy(range, endCell, childAddressCells * sizeof(UInt32));
1245
1246 rangeLen = CellsValue(childSizeCells, range + childAddressCells + addressCells);
1247 AddLengthToCells(childAddressCells, endCell, rangeLen);
1248
1249 diff2 = (*compare)( childAddressCells, cell, endCell );
1250
1251 // if start of cell < start of range, or end of range >= start of cell, skip
1252 if ((diff < 0) || (diff2 >= 0)) {
1253 continue;
1254 }
1255
1256 len = CellsValue(childSizeCells, cell + childAddressCells);
1257 ok = (0 == len);
1258
1259 if (!ok) {
1260 // search for cell end
1261 bcopy(cell, endCell, childAddressCells * sizeof(UInt32));
1262
1263 AddLengthToCells(childAddressCells, endCell, len - 1);
1264
1265 for (lookRange = startRange;
1266 lookRange < endRanges;
1267 lookRange += (childCells + addressCells)) {
1268 // make sure end of cell >= range start
1269 endDiff = (*compare)( childAddressCells, endCell, lookRange );
1270 if (endDiff < 0) {
1271 continue;
1272 }
1273
1274 UInt64 rangeStart = CellsValue(addressCells, range + childAddressCells);
1275 UInt64 lookRangeStart = CellsValue(addressCells, lookRange + childAddressCells);
1276 if ((endDiff - len + 1 + lookRangeStart) == (diff + rangeStart)) {
1277 ok = true;
1278 break;
1279 }
1280 }
1281 if (!ok) {
1282 continue;
1283 }
1284 }
1285 offset += diff;
1286 break;
1287 }
1288
1289 if (addressCells + sizeCells > sizeof(cell) / sizeof(cell[0])) {
1290 panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells, (uint32_t)sizeCells);
1291 }
1292
1293 // Get the physical start of the range from our parent
1294 bcopy( range + childAddressCells, cell, sizeof(UInt32) * addressCells );
1295 bzero( cell + addressCells, sizeof(UInt32) * sizeCells );
1296 } /* else zero length range => pass thru to parent */
1297
1298 if (regEntry != startEntry) {
1299 regEntry->release();
1300 }
1301 regEntry = parent;
1302 childSizeCells = sizeCells;
1303 childAddressCells = addressCells;
1304 childCells = childAddressCells + childSizeCells;
1305 }while (ok && regEntry);
1306
1307 return ok;
1308 }
1309
1310
1311 OSArray *
1312 IODTResolveAddressing( IORegistryEntry * regEntry,
1313 const char * addressPropertyName,
1314 IODeviceMemory * parent )
1315 {
1316 IORegistryEntry *parentEntry;
1317 OSData *addressProperty;
1318 UInt32 sizeCells, addressCells, cells;
1319 int i, num;
1320 UInt32 *reg;
1321 IOPhysicalAddress phys;
1322 IOPhysicalLength len;
1323 OSArray *array;
1324 IODeviceMemory *range;
1325
1326 array = NULL;
1327 do{
1328 parentEntry = regEntry->copyParentEntry( gIODTPlane );
1329 addressProperty = (OSData *) regEntry->getProperty( addressPropertyName );
1330 if ((NULL == addressProperty) || (NULL == parentEntry)) {
1331 break;
1332 }
1333
1334 IODTGetCellCounts( parentEntry, &sizeCells, &addressCells );
1335 if (0 == sizeCells) {
1336 break;
1337 }
1338
1339 cells = sizeCells + addressCells;
1340 reg = (UInt32 *) addressProperty->getBytesNoCopy();
1341 num = addressProperty->getLength() / (4 * cells);
1342
1343 array = OSArray::withCapacity( 1 );
1344 if (NULL == array) {
1345 break;
1346 }
1347
1348 for (i = 0; i < num; i++) {
1349 if (IODTResolveAddressCell( parentEntry, reg, &phys, &len )) {
1350 range = NULL;
1351 if (parent) {
1352 range = IODeviceMemory::withSubRange( parent,
1353 phys - parent->getPhysicalSegment(0, NULL, kIOMemoryMapperNone), len );
1354 }
1355 if (NULL == range) {
1356 range = IODeviceMemory::withRange( phys, len );
1357 }
1358 if (range) {
1359 array->setObject( range );
1360 }
1361 }
1362 reg += cells;
1363 }
1364
1365 regEntry->setProperty( gIODeviceMemoryKey, array);
1366 array->release(); /* ??? */
1367 }while (false);
1368
1369 OSSafeReleaseNULL(parentEntry);
1370
1371 return array;
1372 }
1373
1374 OSData *
1375 IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber )
1376 {
1377 IORegistryEntry *parent;
1378 OSData *data;
1379 OSData *ret = NULL;
1380 UInt32 *bits;
1381 UInt32 i;
1382 UInt32 nlen;
1383 char *names;
1384 char *lastName;
1385 UInt32 mask;
1386
1387 data = (OSData *) regEntry->getProperty("AAPL,slot-name");
1388 if (data) {
1389 return data;
1390 }
1391
1392 do{
1393 parent = regEntry->copyParentEntry( gIODTPlane );
1394 if (!parent) {
1395 break;
1396 }
1397
1398 data = OSDynamicCast( OSData, parent->getProperty("slot-names"));
1399 if (!data) {
1400 break;
1401 }
1402 if (data->getLength() <= 4) {
1403 break;
1404 }
1405
1406 bits = (UInt32 *) data->getBytesNoCopy();
1407 mask = *bits;
1408 if ((0 == (mask & (1 << deviceNumber)))) {
1409 break;
1410 }
1411
1412 names = (char *)(bits + 1);
1413 lastName = names + (data->getLength() - 4);
1414
1415 for (i = 0; (i <= deviceNumber) && (names < lastName); i++) {
1416 if (mask & (1 << i)) {
1417 nlen = 1 + ((unsigned int) strnlen(names, lastName - names));
1418 if (i == deviceNumber) {
1419 data = OSData::withBytesNoCopy(names, nlen);
1420 if (data) {
1421 regEntry->setProperty("AAPL,slot-name", data);
1422 ret = data;
1423 data->release();
1424 }
1425 } else {
1426 names += nlen;
1427 }
1428 }
1429 }
1430 }while (false);
1431
1432 OSSafeReleaseNULL(parent);
1433
1434 return ret;
1435 }
1436
1437 extern "C" IOReturn
1438 IONDRVLibrariesInitialize( IOService * provider )
1439 {
1440 return kIOReturnUnsupported;
1441 }