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