1 | /*␊ |
2 | * Copyright (c) 2005 Apple Computer, Inc. All Rights Reserved.␊ |
3 | */␊ |
4 | ␊ |
5 | #include "libsaio.h"␊ |
6 | #include "device_tree.h"␊ |
7 | ␊ |
8 | //#if 1␊ |
9 | /*␊ |
10 | ␊ |
11 | Structures for a Flattened Device Tree ␊ |
12 | */␊ |
13 | ␊ |
14 | #define kPropNameLength 32␊ |
15 | ␊ |
16 | typedef struct DeviceTreeNodeProperty {␊ |
17 | char name[kPropNameLength]; // NUL terminated property name␊ |
18 | unsigned long length; // Length (bytes) of folloing prop value␊ |
19 | // unsigned long value[1]; // Variable length value of property␊ |
20 | // Padded to a multiple of a longword?␊ |
21 | } DeviceTreeNodeProperty;␊ |
22 | ␊ |
23 | typedef struct OpaqueDTEntry {␊ |
24 | unsigned long nProperties; // Number of props[] elements (0 => end)␊ |
25 | unsigned long nChildren; // Number of children[] elements␊ |
26 | // DeviceTreeNodeProperty props[];// array size == nProperties␊ |
27 | // DeviceTreeNode children[]; // array size == nChildren␊ |
28 | } DeviceTreeNode;␊ |
29 | ␊ |
30 | typedef char DTPropertyNameBuf[32];␊ |
31 | /* Entry Name Definitions (Entry Names are C-Strings)*/␊ |
32 | enum {␊ |
33 | kDTMaxEntryNameLength = 31 /* Max length of a C-String Entry Name (terminator not included) */␊ |
34 | };␊ |
35 | ␊ |
36 | /* length of DTEntryNameBuf = kDTMaxEntryNameLength +1*/␊ |
37 | typedef char DTEntryNameBuf[32];␊ |
38 | //#endif␊ |
39 | ␊ |
40 | #if DEBUG␊ |
41 | #define DPRINTF(args...) printf(args)␊ |
42 | void␊ |
43 | DT__PrintTree(Node *node);␊ |
44 | #else␊ |
45 | #define DPRINTF(args...)␊ |
46 | #endif␊ |
47 | ␊ |
48 | ␊ |
49 | #define RoundToLong(x)␉(((x) + 3) & ~3)␊ |
50 | ␊ |
51 | static struct _DTSizeInfo {␊ |
52 | uint32_t numNodes;␊ |
53 | uint32_t numProperties;␊ |
54 | uint32_t totalPropertySize;␊ |
55 | } DTInfo;␊ |
56 | ␊ |
57 | #define kAllocSize 4096␊ |
58 | ␊ |
59 | static Node *rootNode;␊ |
60 | ␊ |
61 | static Node *freeNodes, *allocedNodes;␊ |
62 | static Property *freeProperties, *allocedProperties;␊ |
63 | ␊ |
64 | static void *␊ |
65 | FlattenNodes(Node *node, void *buffer);␊ |
66 | #if DEBUG␊ |
67 | static void␊ |
68 | _PrintTree(Node *node, int level);␊ |
69 | ␊ |
70 | #endif␊ |
71 | ␊ |
72 | Property *␊ |
73 | DT__AddProperty(Node *node, const char *name, uint32_t length, void *value)␊ |
74 | {␊ |
75 | Property *prop;␊ |
76 | ␊ |
77 | DPRINTF("DT__AddProperty([Node '%s'], '%s', %d, %p)\n", DT__GetName(node), name, length, value);␊ |
78 | if (freeProperties == NULL) {␊ |
79 | void *buf = malloc(kAllocSize);␊ |
80 | if (buf == 0) return 0;␊ |
81 | int i; ␊ |
82 | DPRINTF("Allocating more free properties\n");␊ |
83 | bzero(buf, kAllocSize);␊ |
84 | // Use the first property to record the allocated buffer␊ |
85 | // for later freeing.␊ |
86 | prop = (Property *)buf;␊ |
87 | prop->next = allocedProperties;␊ |
88 | allocedProperties = prop;␊ |
89 | prop->value = buf;␊ |
90 | prop++;␊ |
91 | for (i=1; (unsigned)i<(kAllocSize / sizeof(Property)); i++) {␊ |
92 | prop->next = freeProperties;␊ |
93 | freeProperties = prop;␊ |
94 | prop++;␊ |
95 | }␊ |
96 | }␊ |
97 | prop = freeProperties;␊ |
98 | freeProperties = prop->next;␊ |
99 | ␊ |
100 | prop->name = newString(name);␊ |
101 | prop->length = length;␊ |
102 | prop->value = value;␊ |
103 | ␊ |
104 | // Always add to end of list␊ |
105 | if (node->properties == 0) {␊ |
106 | node->properties = prop;␊ |
107 | } else {␊ |
108 | node->last_prop->next = prop;␊ |
109 | }␊ |
110 | node->last_prop = prop;␊ |
111 | prop->next = 0;␊ |
112 | ␊ |
113 | DPRINTF("Done [%p]\n", prop);␊ |
114 | ␊ |
115 | DTInfo.numProperties++;␊ |
116 | DTInfo.totalPropertySize += RoundToLong(length);␊ |
117 | ␊ |
118 | return prop;␊ |
119 | }␊ |
120 | ␊ |
121 | Node *␊ |
122 | DT__AddChild(Node *parent, const char *name)␊ |
123 | {␊ |
124 | Node *node;␊ |
125 | ␊ |
126 | if (freeNodes == NULL) {␊ |
127 | void *buf = malloc(kAllocSize);␊ |
128 | if (buf == 0) return 0;␊ |
129 | int i; ␊ |
130 | DPRINTF("Allocating more free nodes\n");␊ |
131 | bzero(buf, kAllocSize);␊ |
132 | node = (Node *)buf;␊ |
133 | // Use the first node to record the allocated buffer␊ |
134 | // for later freeing.␊ |
135 | node->next = allocedNodes;␊ |
136 | allocedNodes = node;␊ |
137 | node->children = (Node *)buf;␊ |
138 | node++;␊ |
139 | for (i=1; (unsigned)i<(kAllocSize / sizeof(Node)); i++) {␊ |
140 | node->next = freeNodes;␊ |
141 | freeNodes = node;␊ |
142 | node++;␊ |
143 | }␊ |
144 | }␊ |
145 | DPRINTF("DT__AddChild(%p, '%s')\n", parent, name);␊ |
146 | node = freeNodes;␊ |
147 | freeNodes = node->next;␊ |
148 | DPRINTF("Got free node %p\n", node);␊ |
149 | DPRINTF("prop = %p, children = %p, next = %p\n", node->properties, node->children, node->next);␊ |
150 | ␊ |
151 | if (parent == NULL) {␊ |
152 | rootNode = node;␊ |
153 | node->next = 0;␊ |
154 | } else {␊ |
155 | node->next = parent->children;␊ |
156 | parent->children = node;␊ |
157 | }␊ |
158 | DTInfo.numNodes++;␊ |
159 | DT__AddProperty(node, "name", strlen(name) + 1, (void *) name);␊ |
160 | return node;␊ |
161 | }␊ |
162 | ␊ |
163 | void␊ |
164 | DT__FreeProperty(Property *prop)␊ |
165 | {␊ |
166 | prop->next = freeProperties;␊ |
167 | freeProperties = prop;␊ |
168 | }␊ |
169 | void␊ |
170 | DT__FreeNode(Node *node)␊ |
171 | {␊ |
172 | node->next = freeNodes;␊ |
173 | freeNodes = node;␊ |
174 | }␊ |
175 | ␊ |
176 | void␊ |
177 | DT__Initialize(void)␊ |
178 | {␊ |
179 | DPRINTF("DT__Initialize\n");␊ |
180 | ␊ |
181 | freeNodes = 0;␊ |
182 | allocedNodes = 0;␊ |
183 | freeProperties = 0;␊ |
184 | allocedProperties = 0;␊ |
185 | ␊ |
186 | DTInfo.numNodes = 0;␊ |
187 | DTInfo.numProperties = 0;␊ |
188 | DTInfo.totalPropertySize = 0;␊ |
189 | ␊ |
190 | rootNode = DT__AddChild(NULL, "/");␊ |
191 | DPRINTF("DT__Initialize done\n");␊ |
192 | }␊ |
193 | ␊ |
194 | /*␊ |
195 | * Free up memory used by in-memory representation␊ |
196 | * of device tree.␊ |
197 | */␊ |
198 | void␊ |
199 | DT__Finalize(void)␊ |
200 | {␊ |
201 | Node *node;␊ |
202 | Property *prop;␊ |
203 | ␊ |
204 | DPRINTF("DT__Finalize\n");␊ |
205 | for (prop = allocedProperties; prop != NULL; prop = prop->next) {␊ |
206 | if (prop->value) free(prop->value);␊ |
207 | if (prop->name) free(prop->name);␊ |
208 | ␉␉␊ |
209 | }␊ |
210 | allocedProperties = NULL;␊ |
211 | freeProperties = NULL;␊ |
212 | ␊ |
213 | for (node = allocedNodes; node != NULL; node = node->next) {␊ |
214 | if (node->children) free((void *)node->children);␊ |
215 | }␊ |
216 | allocedNodes = NULL;␊ |
217 | freeNodes = NULL;␊ |
218 | rootNode = NULL;␊ |
219 | ␊ |
220 | // XXX leaks any created strings␊ |
221 | ␊ |
222 | DTInfo.numNodes = 0;␊ |
223 | DTInfo.numProperties = 0;␊ |
224 | DTInfo.totalPropertySize = 0;␊ |
225 | }␊ |
226 | ␊ |
227 | static void *␊ |
228 | FlattenNodes(Node *node, void *buffer)␊ |
229 | {␊ |
230 | Property *prop;␊ |
231 | DeviceTreeNode *flatNode;␊ |
232 | DeviceTreeNodeProperty *flatProp;␊ |
233 | int count;␊ |
234 | ␊ |
235 | if (node == 0) return buffer;␊ |
236 | ␊ |
237 | flatNode = (DeviceTreeNode *)buffer;␊ |
238 | buffer += sizeof(DeviceTreeNode);␊ |
239 | ␊ |
240 | for (count = 0, prop = node->properties; prop != 0; count++, prop = prop->next) {␊ |
241 | flatProp = (DeviceTreeNodeProperty *)buffer;␊ |
242 | strlcpy(flatProp->name, prop->name, kPropNameLength);␊ |
243 | flatProp->length = prop->length;␊ |
244 | buffer += sizeof(DeviceTreeNodeProperty);␊ |
245 | bcopy(prop->value, buffer, prop->length);␊ |
246 | buffer += RoundToLong(prop->length);␊ |
247 | }␊ |
248 | flatNode->nProperties = count;␊ |
249 | ␊ |
250 | for (count = 0, node = node->children; node != 0; count++, node = node->next) {␊ |
251 | buffer = FlattenNodes(node, buffer);␊ |
252 | }␊ |
253 | flatNode->nChildren = count;␊ |
254 | ␊ |
255 | return buffer;␊ |
256 | }␊ |
257 | ␊ |
258 | /*␊ |
259 | * Flatten the in-memory representation of the device tree␊ |
260 | * into a binary DT block.␊ |
261 | * To get the buffer size needed, call with result = 0.␊ |
262 | * To have a buffer allocated for you, call with *result = 0.␊ |
263 | * To use your own buffer, call with *result = &buffer.␊ |
264 | */␊ |
265 | ␊ |
266 | void␊ |
267 | DT__FlattenDeviceTree(void **buffer_p, uint32_t *length)␊ |
268 | {␊ |
269 | uint32_t totalSize;␊ |
270 | void *buf;␊ |
271 | ␊ |
272 | DPRINTF("DT__FlattenDeviceTree(%p, %u)\n", buffer_p, *length);␊ |
273 | #if DEBUG␊ |
274 | if (buffer_p) DT__PrintTree(rootNode);␊ |
275 | #endif␊ |
276 | ␊ |
277 | totalSize = DTInfo.numNodes * sizeof(DeviceTreeNode) + ␊ |
278 | DTInfo.numProperties * sizeof(DeviceTreeNodeProperty) +␊ |
279 | DTInfo.totalPropertySize;␊ |
280 | ␊ |
281 | DPRINTF("Total size 0x%x\n", totalSize);␊ |
282 | if (buffer_p != 0) {␊ |
283 | if (totalSize == 0) {␊ |
284 | buf = 0;␊ |
285 | } else {␊ |
286 | if (*buffer_p == 0) {␊ |
287 | buf = malloc(totalSize);␊ |
288 | } else {␊ |
289 | buf = *buffer_p;␊ |
290 | }␊ |
291 | if (!buf) {␊ |
292 | *length = 0;␊ |
293 | return;␊ |
294 | }␊ |
295 | bzero(buf, totalSize);␊ |
296 | ␊ |
297 | FlattenNodes(rootNode, buf);␊ |
298 | }␊ |
299 | *buffer_p = buf;␊ |
300 | }␊ |
301 | if (length)␊ |
302 | *length = totalSize;␊ |
303 | }␊ |
304 | ␊ |
305 | char *␊ |
306 | DT__GetName(Node *node)␊ |
307 | {␊ |
308 | Property *prop;␊ |
309 | ␊ |
310 | //DPRINTF("DT__GetName(0x%x)\n", node);␊ |
311 | //DPRINTF("Node properties = 0x%x\n", node->properties);␊ |
312 | for (prop = node->properties; prop; prop = prop->next) {␊ |
313 | //DPRINTF("Prop '%s'\n", prop->name);␊ |
314 | if (strcmp(prop->name, "name") == 0) {␊ |
315 | return prop->value;␊ |
316 | }␊ |
317 | }␊ |
318 | //DPRINTF("DT__GetName returns 0\n");␊ |
319 | return "(null)";␊ |
320 | }␊ |
321 | ␊ |
322 | Node *␊ |
323 | DT__FindNode(const char *path, bool createIfMissing)␊ |
324 | {␊ |
325 | Node *node, *child = 0;␊ |
326 | DTPropertyNameBuf nameBuf;␊ |
327 | char *bp;␊ |
328 | int i;␊ |
329 | ␊ |
330 | DPRINTF("DT__FindNode('%s', %d)\n", path, createIfMissing);␊ |
331 | ␊ |
332 | // Start at root␊ |
333 | node = rootNode;␊ |
334 | DPRINTF("root = %p\n", rootNode);␊ |
335 | ␊ |
336 | while (node) {␊ |
337 | // Skip leading slash␊ |
338 | while (*path == '/') path++;␊ |
339 | ␊ |
340 | for (i=0, bp = nameBuf; ++i < kDTMaxEntryNameLength && *path && *path != '/'; bp++, path++) *bp = *path;␊ |
341 | *bp = '\0';␊ |
342 | ␊ |
343 | if (nameBuf[0] == '\0') {␊ |
344 | // last path entry␊ |
345 | break;␊ |
346 | }␊ |
347 | DPRINTF("Node '%s'\n", nameBuf);␊ |
348 | ␊ |
349 | for (child = node->children; child != 0; child = child->next) {␊ |
350 | DPRINTF("Child %p\n", child);␊ |
351 | if (strcmp(DT__GetName(child), nameBuf) == 0) {␊ |
352 | break;␊ |
353 | }␊ |
354 | }␊ |
355 | if (child == 0 && createIfMissing) {␊ |
356 | DPRINTF("Creating node\n");␊ |
357 | //char *str = malloc(strlen(nameBuf) + 1);␊ |
358 | // XXX this will leak␊ |
359 | //strcpy(str, nameBuf);␊ |
360 | ␊ |
361 | const char *str = newString(nameBuf);␊ |
362 | if (str) {␊ |
363 | child = DT__AddChild(node, str);␊ |
364 | }␊ |
365 | }␊ |
366 | node = child;␊ |
367 | }␊ |
368 | return node;␊ |
369 | }␊ |
370 | ␊ |
371 | #if DEBUG␊ |
372 | ␊ |
373 | static void␊ |
374 | DT__PrintNode(Node *node, int level)␊ |
375 | {␊ |
376 | char spaces[10], *cp = spaces;␊ |
377 | Property *prop;␊ |
378 | ␊ |
379 | if (level > 9) level = 9;␊ |
380 | while (level--) *cp++ = ' ';␊ |
381 | *cp = '\0';␊ |
382 | ␊ |
383 | printf("%s===Node===\n", spaces);␊ |
384 | for (prop = node->properties; prop; prop = prop->next) {␊ |
385 | char c = *((char *)prop->value);␊ |
386 | if (prop->length < 64 && (␊ |
387 | strcmp(prop->name, "name") == 0 || ␊ |
388 | (c >= '0' && c <= '9') ||␊ |
389 | (c >= 'a' && c <= 'z') ||␊ |
390 | (c >= 'A' && c <= 'Z') || c == '_')) {␊ |
391 | printf("%s Property '%s' [%d] = '%s'\n", spaces, prop->name, prop->length, prop->value);␊ |
392 | } else {␊ |
393 | printf("%s Property '%s' [%d] = (data)\n", spaces, prop->name, prop->length);␊ |
394 | }␊ |
395 | }␊ |
396 | printf("%s==========\n", spaces);␊ |
397 | }␊ |
398 | ␊ |
399 | static void␊ |
400 | _PrintTree(Node *node, int level)␊ |
401 | {␊ |
402 | DT__PrintNode(node, level);␊ |
403 | level++;␊ |
404 | for (node = node->children; node; node = node->next)␊ |
405 | _PrintTree(node, level);␊ |
406 | }␊ |
407 | ␊ |
408 | void␊ |
409 | DT__PrintTree(Node *node)␊ |
410 | {␊ |
411 | if (node == 0) node = rootNode;␊ |
412 | _PrintTree(node, 0);␊ |
413 | }␊ |
414 | ␊ |
415 | #endif␊ |
416 | ␊ |
417 | |