1 | /*␊ |
2 | * Copyright (c) 2005 Apple Computer, Inc. All Rights Reserved.␊ |
3 | */␊ |
4 | ␊ |
5 | #if 1 //Azi: clean ??␊ |
6 | /*␊ |
7 | ␊ |
8 | Structures for a Flattened Device Tree ␊ |
9 | */␊ |
10 | ␊ |
11 | #define kPropNameLength 32␊ |
12 | ␊ |
13 | typedef struct DeviceTreeNodeProperty {␊ |
14 | char name[kPropNameLength]; // NUL terminated property name␊ |
15 | unsigned long length; // Length (bytes) of folloing prop value␊ |
16 | // unsigned long value[1]; // Variable length value of property␊ |
17 | // Padded to a multiple of a longword?␊ |
18 | } DeviceTreeNodeProperty;␊ |
19 | ␊ |
20 | typedef struct OpaqueDTEntry {␊ |
21 | unsigned long nProperties; // Number of props[] elements (0 => end)␊ |
22 | unsigned long nChildren; // Number of children[] elements␊ |
23 | // DeviceTreeNodeProperty props[];// array size == nProperties␊ |
24 | // DeviceTreeNode children[]; // array size == nChildren␊ |
25 | } DeviceTreeNode;␊ |
26 | ␊ |
27 | typedef char DTPropertyNameBuf[32];␊ |
28 | /* Entry Name Definitions (Entry Names are C-Strings)*/␊ |
29 | enum {␊ |
30 | kDTMaxEntryNameLength = 31 /* Max length of a C-String Entry Name (terminator not included) */␊ |
31 | };␊ |
32 | ␊ |
33 | /* length of DTEntryNameBuf = kDTMaxEntryNameLength +1*/␊ |
34 | typedef char DTEntryNameBuf[32];␊ |
35 | #endif␊ |
36 | ␊ |
37 | //Azi: check location.␊ |
38 | //#include "libsaio.h"␊ |
39 | #include "libsa.h"␊ |
40 | #include "device_tree.h"␊ |
41 | ␊ |
42 | //#define DEBUG 1␊ |
43 | #if DEBUG␊ |
44 | #include "saio_internal.h" //Azi: remember - see zalloc.c␊ |
45 | #define DPRINTF(args...) printf(args)␊ |
46 | void␊ |
47 | DT__PrintTree(Node *node);␊ |
48 | #else␊ |
49 | #define DPRINTF(args...)␊ |
50 | #endif␊ |
51 | ␊ |
52 | ␊ |
53 | #define RoundToLong(x)␉(((x) + 3) & ~3)␊ |
54 | ␊ |
55 | static struct _DTSizeInfo {␊ |
56 | uint32_t numNodes;␊ |
57 | uint32_t numProperties;␊ |
58 | uint32_t totalPropertySize;␊ |
59 | } DTInfo;␊ |
60 | ␊ |
61 | #define kAllocSize 4096␊ |
62 | ␊ |
63 | static Node *rootNode;␊ |
64 | ␊ |
65 | static Node *freeNodes, *allocedNodes;␊ |
66 | static Property *freeProperties, *allocedProperties;␊ |
67 | ␊ |
68 | Property *␊ |
69 | DT__AddProperty(Node *node, const char *name, uint32_t length, void *value)␊ |
70 | {␊ |
71 | Property *prop;␊ |
72 | ␊ |
73 | DPRINTF("DT__AddProperty([Node '%s'], '%s', %d, 0x%x)\n", DT__GetName(node), name, length, value);␊ |
74 | if (freeProperties == NULL) {␊ |
75 | void *buf = malloc(kAllocSize);␊ |
76 | int i;␊ |
77 | ␊ |
78 | DPRINTF("Allocating more free properties\n");␊ |
79 | if (buf == 0) return 0;␊ |
80 | bzero(buf, kAllocSize);␊ |
81 | // Use the first property to record the allocated buffer␊ |
82 | // for later freeing.␊ |
83 | prop = (Property *)buf;␊ |
84 | prop->next = allocedProperties;␊ |
85 | allocedProperties = prop;␊ |
86 | prop->value = buf;␊ |
87 | prop++;␊ |
88 | for (i=1; i<(kAllocSize / sizeof(Property)); i++) {␊ |
89 | prop->next = freeProperties;␊ |
90 | freeProperties = prop;␊ |
91 | prop++;␊ |
92 | }␊ |
93 | }␊ |
94 | prop = freeProperties;␊ |
95 | freeProperties = prop->next;␊ |
96 | ␊ |
97 | prop->name = name;␊ |
98 | prop->length = length;␊ |
99 | prop->value = value;␊ |
100 | ␊ |
101 | // Always add to end of list␊ |
102 | if (node->properties == 0) {␊ |
103 | node->properties = prop;␊ |
104 | } else {␊ |
105 | node->last_prop->next = prop;␊ |
106 | }␊ |
107 | node->last_prop = prop;␊ |
108 | prop->next = 0;␊ |
109 | ␊ |
110 | DPRINTF("Done [0x%x]\n", prop);␊ |
111 | ␊ |
112 | DTInfo.numProperties++;␊ |
113 | DTInfo.totalPropertySize += RoundToLong(length);␊ |
114 | ␊ |
115 | return prop;␊ |
116 | }␊ |
117 | ␊ |
118 | Node *␊ |
119 | DT__AddChild(Node *parent, const char *name)␊ |
120 | {␊ |
121 | Node *node;␊ |
122 | ␊ |
123 | if (freeNodes == NULL) {␊ |
124 | void *buf = malloc(kAllocSize);␊ |
125 | int i;␊ |
126 | ␊ |
127 | DPRINTF("Allocating more free nodes\n");␊ |
128 | if (buf == 0) return 0;␊ |
129 | bzero(buf, kAllocSize);␊ |
130 | node = (Node *)buf;␊ |
131 | // Use the first node to record the allocated buffer␊ |
132 | // for later freeing.␊ |
133 | node->next = allocedNodes;␊ |
134 | allocedNodes = node;␊ |
135 | node->children = (Node *)buf;␊ |
136 | node++;␊ |
137 | for (i=1; i<(kAllocSize / sizeof(Node)); i++) {␊ |
138 | node->next = freeNodes;␊ |
139 | freeNodes = node;␊ |
140 | node++;␊ |
141 | }␊ |
142 | }␊ |
143 | DPRINTF("DT__AddChild(0x%x, '%s')\n", parent, name);␊ |
144 | node = freeNodes;␊ |
145 | freeNodes = node->next;␊ |
146 | DPRINTF("Got free node 0x%x\n", node);␊ |
147 | DPRINTF("prop = 0x%x, children = 0x%x, next = 0x%x\n", node->properties, node->children, node->next);␊ |
148 | ␊ |
149 | if (parent == NULL) {␊ |
150 | rootNode = node;␊ |
151 | node->next = 0;␊ |
152 | } else {␊ |
153 | node->next = parent->children;␊ |
154 | parent->children = node;␊ |
155 | }␊ |
156 | DTInfo.numNodes++;␊ |
157 | DT__AddProperty(node, "name", strlen(name) + 1, (void *) name);␊ |
158 | return node;␊ |
159 | }␊ |
160 | ␊ |
161 | void␊ |
162 | DT__FreeProperty(Property *prop)␊ |
163 | {␊ |
164 | prop->next = freeProperties;␊ |
165 | freeProperties = prop;␊ |
166 | }␊ |
167 | void␊ |
168 | DT__FreeNode(Node *node)␊ |
169 | {␊ |
170 | node->next = freeNodes;␊ |
171 | freeNodes = node;␊ |
172 | }␊ |
173 | ␊ |
174 | void␊ |
175 | DT__Initialize(void)␊ |
176 | {␊ |
177 | DPRINTF("DT__Initialize\n");␊ |
178 | ␊ |
179 | freeNodes = 0;␊ |
180 | allocedNodes = 0;␊ |
181 | freeProperties = 0;␊ |
182 | allocedProperties = 0;␊ |
183 | ␊ |
184 | DTInfo.numNodes = 0;␊ |
185 | DTInfo.numProperties = 0;␊ |
186 | DTInfo.totalPropertySize = 0;␊ |
187 | ␊ |
188 | rootNode = DT__AddChild(NULL, "/");␊ |
189 | DPRINTF("DT__Initialize done\n");␊ |
190 | }␊ |
191 | ␊ |
192 | /*␊ |
193 | * Free up memory used by in-memory representation␊ |
194 | * of device tree.␊ |
195 | */␊ |
196 | void␊ |
197 | DT__Finalize(void)␊ |
198 | {␊ |
199 | Node *node;␊ |
200 | Property *prop;␊ |
201 | ␊ |
202 | DPRINTF("DT__Finalize\n");␊ |
203 | for (prop = allocedProperties; prop != NULL; prop = prop->next) {␊ |
204 | free(prop->value);␊ |
205 | }␊ |
206 | allocedProperties = NULL;␊ |
207 | freeProperties = NULL;␊ |
208 | ␊ |
209 | for (node = allocedNodes; node != NULL; node = node->next) {␊ |
210 | free((void *)node->children);␊ |
211 | }␊ |
212 | allocedNodes = NULL;␊ |
213 | freeNodes = NULL;␊ |
214 | rootNode = NULL;␊ |
215 | ␊ |
216 | // XXX leaks any created strings␊ |
217 | ␊ |
218 | DTInfo.numNodes = 0;␊ |
219 | DTInfo.numProperties = 0;␊ |
220 | DTInfo.totalPropertySize = 0;␊ |
221 | }␊ |
222 | ␊ |
223 | static void *␊ |
224 | FlattenNodes(Node *node, void *buffer)␊ |
225 | {␊ |
226 | Property *prop;␊ |
227 | DeviceTreeNode *flatNode;␊ |
228 | DeviceTreeNodeProperty *flatProp;␊ |
229 | int count;␊ |
230 | ␊ |
231 | if (node == 0) return buffer;␊ |
232 | ␊ |
233 | flatNode = (DeviceTreeNode *)buffer;␊ |
234 | buffer += sizeof(DeviceTreeNode);␊ |
235 | ␊ |
236 | for (count = 0, prop = node->properties; prop != 0; count++, prop = prop->next) {␊ |
237 | flatProp = (DeviceTreeNodeProperty *)buffer;␊ |
238 | strcpy(flatProp->name, prop->name);␊ |
239 | flatProp->length = prop->length;␊ |
240 | buffer += sizeof(DeviceTreeNodeProperty);␊ |
241 | bcopy(prop->value, buffer, prop->length);␊ |
242 | buffer += RoundToLong(prop->length);␊ |
243 | }␊ |
244 | flatNode->nProperties = count;␊ |
245 | ␊ |
246 | for (count = 0, node = node->children; node != 0; count++, node = node->next) {␊ |
247 | buffer = FlattenNodes(node, buffer);␊ |
248 | }␊ |
249 | flatNode->nChildren = count;␊ |
250 | ␊ |
251 | return buffer;␊ |
252 | }␊ |
253 | ␊ |
254 | /*␊ |
255 | * Flatten the in-memory representation of the device tree␊ |
256 | * into a binary DT block.␊ |
257 | * To get the buffer size needed, call with result = 0.␊ |
258 | * To have a buffer allocated for you, call with *result = 0.␊ |
259 | * To use your own buffer, call with *result = &buffer.␊ |
260 | */␊ |
261 | ␊ |
262 | void␊ |
263 | DT__FlattenDeviceTree(void **buffer_p, uint32_t *length)␊ |
264 | {␊ |
265 | uint32_t totalSize;␊ |
266 | void *buf;␊ |
267 | ␊ |
268 | DPRINTF("DT__FlattenDeviceTree(0x%x, 0x%x)\n", buffer_p, length);␊ |
269 | #if DEBUG␊ |
270 | if (buffer_p) DT__PrintTree(rootNode);␊ |
271 | #endif␊ |
272 | ␊ |
273 | totalSize = DTInfo.numNodes * sizeof(DeviceTreeNode) + ␊ |
274 | DTInfo.numProperties * sizeof(DeviceTreeNodeProperty) +␊ |
275 | DTInfo.totalPropertySize;␊ |
276 | ␊ |
277 | DPRINTF("Total size 0x%x\n", totalSize);␊ |
278 | if (buffer_p != 0) {␊ |
279 | if (totalSize == 0) {␊ |
280 | buf = 0;␊ |
281 | } else {␊ |
282 | if (*buffer_p == 0) {␊ |
283 | buf = malloc(totalSize);␊ |
284 | } else {␊ |
285 | buf = *buffer_p;␊ |
286 | }␊ |
287 | bzero(buf, totalSize);␊ |
288 | ␊ |
289 | FlattenNodes(rootNode, buf);␊ |
290 | }␊ |
291 | *buffer_p = buf;␊ |
292 | }␊ |
293 | if (length)␊ |
294 | *length = totalSize;␊ |
295 | }␊ |
296 | ␊ |
297 | char *␊ |
298 | DT__GetName(Node *node)␊ |
299 | {␊ |
300 | Property *prop;␊ |
301 | ␊ |
302 | //DPRINTF("DT__GetName(0x%x)\n", node);␊ |
303 | //DPRINTF("Node properties = 0x%x\n", node->properties);␊ |
304 | for (prop = node->properties; prop; prop = prop->next) {␊ |
305 | //DPRINTF("Prop '%s'\n", prop->name);␊ |
306 | if (strcmp(prop->name, "name") == 0) {␊ |
307 | return prop->value;␊ |
308 | }␊ |
309 | }␊ |
310 | //DPRINTF("DT__GetName returns 0\n");␊ |
311 | return "(null)";␊ |
312 | }␊ |
313 | ␊ |
314 | Node *␊ |
315 | DT__FindNode(const char *path, bool createIfMissing)␊ |
316 | {␊ |
317 | Node *node, *child;␊ |
318 | DTPropertyNameBuf nameBuf;␊ |
319 | char *bp;␊ |
320 | int i;␊ |
321 | ␊ |
322 | DPRINTF("DT__FindNode('%s', %d)\n", path, createIfMissing);␊ |
323 | ␊ |
324 | // Start at root␊ |
325 | node = rootNode;␊ |
326 | DPRINTF("root = 0x%x\n", rootNode);␊ |
327 | ␊ |
328 | while (node) {␊ |
329 | // Skip leading slash␊ |
330 | while (*path == '/') path++;␊ |
331 | ␊ |
332 | for (i=0, bp = nameBuf; ++i < kDTMaxEntryNameLength && *path && *path != '/'; bp++, path++) *bp = *path;␊ |
333 | *bp = '\0';␊ |
334 | ␊ |
335 | if (nameBuf[0] == '\0') {␊ |
336 | // last path entry␊ |
337 | break;␊ |
338 | }␊ |
339 | DPRINTF("Node '%s'\n", nameBuf);␊ |
340 | ␊ |
341 | for (child = node->children; child != 0; child = child->next) {␊ |
342 | DPRINTF("Child 0x%x\n", child);␊ |
343 | if (strcmp(DT__GetName(child), nameBuf) == 0) {␊ |
344 | break;␊ |
345 | }␊ |
346 | }␊ |
347 | if (child == 0 && createIfMissing) {␊ |
348 | DPRINTF("Creating node\n");␊ |
349 | char *str = malloc(strlen(nameBuf) + 1);␊ |
350 | // XXX this will leak␊ |
351 | strcpy(str, nameBuf);␊ |
352 | ␊ |
353 | child = DT__AddChild(node, str);␊ |
354 | }␊ |
355 | node = child;␊ |
356 | }␊ |
357 | return node;␊ |
358 | }␊ |
359 | ␊ |
360 | #if DEBUG␊ |
361 | ␊ |
362 | void␊ |
363 | DT__PrintNode(Node *node, int level)␊ |
364 | {␊ |
365 | char spaces[10], *cp = spaces;␊ |
366 | Property *prop;␊ |
367 | ␊ |
368 | if (level > 9) level = 9;␊ |
369 | while (level--) *cp++ = ' ';␊ |
370 | *cp = '\0';␊ |
371 | ␊ |
372 | printf("%s===Node===\n", spaces);␊ |
373 | for (prop = node->properties; prop; prop = prop->next) {␊ |
374 | char c = *((char *)prop->value);␊ |
375 | if (prop->length < 64 && (␊ |
376 | strcmp(prop->name, "name") == 0 || ␊ |
377 | (c >= '0' && c <= '9') ||␊ |
378 | (c >= 'a' && c <= 'z') ||␊ |
379 | (c >= 'A' && c <= 'Z') || c == '_')) {␊ |
380 | printf("%s Property '%s' [%d] = '%s'\n", spaces, prop->name, prop->length, prop->value);␊ |
381 | } else {␊ |
382 | printf("%s Property '%s' [%d] = (data)\n", spaces, prop->name, prop->length);␊ |
383 | }␊ |
384 | }␊ |
385 | printf("%s==========\n", spaces);␊ |
386 | }␊ |
387 | ␊ |
388 | static void␊ |
389 | _PrintTree(Node *node, int level)␊ |
390 | {␊ |
391 | DT__PrintNode(node, level);␊ |
392 | level++;␊ |
393 | for (node = node->children; node; node = node->next)␊ |
394 | _PrintTree(node, level);␊ |
395 | }␊ |
396 | ␊ |
397 | void␊ |
398 | DT__PrintTree(Node *node)␊ |
399 | {␊ |
400 | if (node == 0) node = rootNode;␊ |
401 | _PrintTree(node, 0);␊ |
402 | }␊ |
403 | ␊ |
404 | //Azi: from autoresolution - check this stuff␊ |
405 | #if 0␊ |
406 | void␊ |
407 | DT__PrintFlattenedNode(DTEntry entry, int level)␊ |
408 | {␊ |
409 | char spaces[10], *cp = spaces;␊ |
410 | DTPropertyIterator␉ propIter;␊ |
411 | char *name;␊ |
412 | void *prop;␊ |
413 | int propSize;␊ |
414 | ␊ |
415 | if (level > 9) level = 9;␊ |
416 | while (level--) *cp++ = ' ';␊ |
417 | *cp = '\0';␊ |
418 | ␊ |
419 | printf("%s===Entry %p===\n", spaces, entry);␊ |
420 | if (kSuccess != DTCreatePropertyIterator(entry, &propIter)) {␊ |
421 | printf("Couldn't create property iterator\n");␊ |
422 | return;␊ |
423 | }␊ |
424 | while( kSuccess == DTIterateProperties( propIter, &name)) {␊ |
425 | if( kSuccess != DTGetProperty( entry, name, &prop, &propSize ))␊ |
426 | continue;␊ |
427 | printf("%s Property %s = %s\n", spaces, name, prop);␊ |
428 | }␊ |
429 | DTDisposePropertyIterator(propIter);␊ |
430 | ␊ |
431 | printf("%s==========\n", spaces);␊ |
432 | }␊ |
433 | ␊ |
434 | static void␊ |
435 | _PrintFlattenedTree(DTEntry entry, int level)␊ |
436 | {␊ |
437 | DTEntryIterator entryIter;␊ |
438 | ␊ |
439 | PrintFlattenedNode(entry, level);␊ |
440 | ␊ |
441 | if (kSuccess != DTCreateEntryIterator(entry, &entryIter)) {␊ |
442 | printf("Couldn't create entry iterator\n");␊ |
443 | return;␊ |
444 | }␊ |
445 | level++;␊ |
446 | while (kSuccess == DTIterateEntries( entryIter, &entry )) {␊ |
447 | _PrintFlattenedTree(entry, level);␊ |
448 | }␊ |
449 | DTDisposeEntryIterator(entryIter);␊ |
450 | }␊ |
451 | ␊ |
452 | void␊ |
453 | DT__PrintFlattenedTree(DTEntry entry)␊ |
454 | {␊ |
455 | _PrintFlattenedTree(entry, 0);␊ |
456 | }␊ |
457 | ␊ |
458 | ␊ |
459 | int␊ |
460 | main(int argc, char **argv)␊ |
461 | {␊ |
462 | DTEntry dtEntry;␊ |
463 | DTPropertyIterator␉ propIter;␊ |
464 | DTEntryIterator entryIter;␊ |
465 | void␉␉␉␉*prop;␊ |
466 | int␉␉␉␉␉propSize;␊ |
467 | char␉␉␉␉*name;␊ |
468 | void *flatTree;␊ |
469 | uint32_t flatSize;␊ |
470 | ␊ |
471 | Node *node;␊ |
472 | ␊ |
473 | node = AddChild(NULL, "device-tree");␊ |
474 | AddProperty(node, "potato", 4, "foo");␊ |
475 | AddProperty(node, "chemistry", 4, "bar");␊ |
476 | AddProperty(node, "physics", 4, "baz");␊ |
477 | ␊ |
478 | node = AddChild(node, "dev");␊ |
479 | AddProperty(node, "one", 4, "one");␊ |
480 | AddProperty(node, "two", 4, "two");␊ |
481 | AddProperty(node, "three", 6, "three");␊ |
482 | ␊ |
483 | node = AddChild(rootNode, "foo");␊ |
484 | AddProperty(node, "aaa", 4, "aab");␊ |
485 | AddProperty(node, "bbb", 4, "bbc");␊ |
486 | AddProperty(node, "cccc", 6, "ccccd");␊ |
487 | ␊ |
488 | node = FindNode("/this/is/a/test", 1);␊ |
489 | AddProperty(node, "dddd", 12, "abcdefghijk");␊ |
490 | ␊ |
491 | printf("In-memory tree:\n\n");␊ |
492 | ␊ |
493 | PrintTree(rootNode);␊ |
494 | ␊ |
495 | FlattenDeviceTree(&flatTree, &flatSize);␊ |
496 | ␊ |
497 | printf("Flat tree = %p, size %d\n", flatTree, flatSize);␊ |
498 | ␊ |
499 | dtEntry = (DTEntry)flatTree;␊ |
500 | ␊ |
501 | printf("\n\nPrinting flat tree\n\n");␊ |
502 | ␊ |
503 | DTInit(dtEntry);␊ |
504 | ␊ |
505 | PrintFlattenedTree((DTEntry)flatTree);␊ |
506 | #if 0␊ |
507 | printf("=== Entry %p ===\n", dtEntry);␊ |
508 | if (kSuccess != DTCreatePropertyIterator(dtEntry, &propIter)) {␊ |
509 | printf("Couldn't create property iterator\n");␊ |
510 | return 1;␊ |
511 | }␊ |
512 | while( kSuccess == DTIterateProperties( propIter, &name)) {␊ |
513 | if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize ))␊ |
514 | continue;␊ |
515 | printf(" Property %s = %s\n", name, prop);␊ |
516 | }␊ |
517 | DTDisposePropertyIterator(propIter);␊ |
518 | printf("========\n");␊ |
519 | ␊ |
520 | if (kSuccess != DTCreateEntryIterator(dtEntry, &entryIter)) {␊ |
521 | printf("Couldn't create entry iterator\n");␊ |
522 | return 1;␊ |
523 | }␊ |
524 | while (kSuccess == DTIterateEntries( entryIter, &dtEntry )) {␊ |
525 | printf("=== Entry %p ===\n", dtEntry);␊ |
526 | ␊ |
527 | if (kSuccess != DTCreatePropertyIterator(dtEntry, &propIter)) {␊ |
528 | printf("Couldn't create property iterator\n");␊ |
529 | return 1;␊ |
530 | }␊ |
531 | while( kSuccess == DTIterateProperties( propIter, &name)) {␊ |
532 | if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize ))␊ |
533 | continue;␊ |
534 | printf(" Property %s = %s\n", name, prop);␊ |
535 | }␊ |
536 | DTDisposePropertyIterator(propIter);␊ |
537 | printf("========\n");␊ |
538 | }␊ |
539 | DTDisposeEntryIterator(entryIter);␊ |
540 | #endif␊ |
541 | ␊ |
542 | return 0;␊ |
543 | }␊ |
544 | #endif␊ |
545 | #endif␊ |
546 | |