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