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