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