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