]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IODeviceTreeSupport.cpp
xnu-517.3.15.tar.gz
[apple/xnu.git] / iokit / Kernel / IODeviceTreeSupport.cpp
1 /*
2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
27 *
28 * HISTORY
29 * 23 Nov 98 sdouglas, created from IODeviceTreeBus.m, & MacOS exp mgr.
30 * 05 Apr 99 sdouglas, add interrupt mapping.
31 *
32 */
33
34 #include <IOKit/IODeviceTreeSupport.h>
35 #include <libkern/c++/OSContainers.h>
36 #include <IOKit/IODeviceMemory.h>
37 #include <IOKit/IOService.h>
38 #include <IOKit/IOCatalogue.h>
39
40 #include <IOKit/IOLib.h>
41 #include <IOKit/IOKitKeys.h>
42
43 #include <pexpert/device_tree.h>
44
45 extern "C" {
46 #include <machine/machine_routines.h>
47 void DTInit( void * data );
48
49 int IODTGetLoaderInfo( char *key, void **infoAddr, int *infosize );
50 void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
51 }
52
53 #include <IOKit/assert.h>
54
55 #define IODTSUPPORTDEBUG 0
56
57 const IORegistryPlane * gIODTPlane;
58
59 static OSArray * gIODTPHandles;
60 static OSArray * gIODTPHandleMap;
61
62 const OSSymbol * gIODTNameKey;
63 const OSSymbol * gIODTUnitKey;
64 const OSSymbol * gIODTCompatibleKey;
65 const OSSymbol * gIODTTypeKey;
66 const OSSymbol * gIODTModelKey;
67
68 const OSSymbol * gIODTSizeCellKey;
69 const OSSymbol * gIODTAddressCellKey;
70 const OSSymbol * gIODTRangeKey;
71
72 const OSSymbol * gIODTPersistKey;
73
74 const OSSymbol * gIODTDefaultInterruptController;
75 const OSSymbol * gIODTAAPLInterruptsKey;
76 const OSSymbol * gIODTPHandleKey;
77 const OSSymbol * gIODTInterruptCellKey;
78 const OSSymbol * gIODTInterruptParentKey;
79 const OSSymbol * gIODTNWInterruptMappingKey;
80
81
82 static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy );
83 static void AddPHandle( IORegistryEntry * regEntry );
84 static void FreePhysicalMemory( vm_offset_t * range );
85
86 IORegistryEntry *
87 IODeviceTreeAlloc( void * dtTop )
88 {
89 IORegistryEntry *parent;
90 IORegistryEntry *child;
91 IORegistryIterator *regIter;
92 DTEntryIterator iter;
93 DTEntry dtChild;
94 DTEntry mapEntry;
95 OSArray *stack;
96 OSData *prop;
97 OSObject *obj;
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 intMap = false;
203 regIter = IORegistryIterator::iterateOver( gIODTPlane,
204 kIORegistryIterateRecursively );
205 assert( regIter );
206 if( regIter) {
207 while( (child = regIter->getNextObject())) {
208 IODTMapInterrupts( child );
209 if( !intMap && child->getProperty( gIODTInterruptParentKey))
210 intMap = true;
211
212 // Look for a "driver,AAPL,MacOSX,PowerPC" property.
213 if( (obj = child->getProperty( "driver,AAPL,MacOSX,PowerPC"))) {
214 gIOCatalogue->addExtensionsFromArchive((OSData *)obj);
215 child->removeProperty( "driver,AAPL,MacOSX,PowerPC");
216 }
217
218 // some gross pruning
219 child->removeProperty( "lanLib,AAPL,MacOS,PowerPC");
220
221 if( (obj = child->getProperty( "driver,AAPL,MacOS,PowerPC"))) {
222
223 if( (0 == (prop = (OSData *)child->getProperty( gIODTTypeKey )))
224 || (strcmp( "display", (char *) prop->getBytesNoCopy())) ) {
225 child->removeProperty( "driver,AAPL,MacOS,PowerPC");
226 }
227 }
228 }
229 regIter->release();
230 }
231
232 if( intMap)
233 // set a key in the root to indicate we found NW interrupt mapping
234 parent->setProperty( gIODTNWInterruptMappingKey,
235 (OSObject *) gIODTNWInterruptMappingKey );
236
237 return( parent);
238 }
239
240 int 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
265 void 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
282 static 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
292 static IORegistryEntry *
293 MakeReferenceTable( 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
367 static 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
379 static 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
396 static 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
409 IORegistryEntry * 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
425 const 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
446 static 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
455 UInt32 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
571 bool 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
649 static const char *
650 CompareKey( 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
699 bool 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
716 bool 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
735 OSCollectionIterator * 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
785 struct IODTPersistent {
786 IODTCompareAddressCellFunc compareFunc;
787 IODTNVLocationFunc locationFunc;
788 };
789
790 void 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
808 static SInt32 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] )
809 {
810 cellCount--;
811 return( left[ cellCount ] - right[ cellCount ] );
812 }
813
814
815 void 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
831 bool 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
920 OSArray * 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
971 static 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
1004 IOReturn 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
1037 OSData * 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 }