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