diff options
author | Stephen Warren <swarren@nvidia.com> | 2012-09-28 17:25:59 -0400 |
---|---|---|
committer | Rob Herring <rob.herring@calxeda.com> | 2012-10-01 12:11:35 -0400 |
commit | cd296721a9645f9f28800a072490fa15458d1fb7 (patch) | |
tree | 492b9a268a48af07844fbbd39519f95676ee73fe /scripts/dtc/libfdt/fdt_ro.c | |
parent | acc2097934b5403b97f95763fe99fc115b818061 (diff) |
dtc: import latest upstream dtc
This updates scripts/dtc to commit 317a5d9 "dtc: zero out new label
objects" from git://git.jdl.com/software/dtc.git.
This adds features such as:
* /bits/ syntax for cell data.
* Math expressions within cell data.
* The ability to delete properties or nodes.
* Support for #line directives in the input file, which allows the use of
cpp on *.dts.
* -i command-line option (/include/ path)
* -W/-E command-line options for error/warning control.
* Removal of spew to STDOUT containing the filename being compiled.
* Many additions to the libfdt API.
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Jon Loeliger <jdl@jdl.com>
Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Diffstat (limited to 'scripts/dtc/libfdt/fdt_ro.c')
-rw-r--r-- | scripts/dtc/libfdt/fdt_ro.c | 275 |
1 files changed, 190 insertions, 85 deletions
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 22e692919ff9..02b6d687537f 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c | |||
@@ -80,6 +80,14 @@ const char *fdt_string(const void *fdt, int stroffset) | |||
80 | return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; | 80 | return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; |
81 | } | 81 | } |
82 | 82 | ||
83 | static int _fdt_string_eq(const void *fdt, int stroffset, | ||
84 | const char *s, int len) | ||
85 | { | ||
86 | const char *p = fdt_string(fdt, stroffset); | ||
87 | |||
88 | return (strlen(p) == len) && (memcmp(p, s, len) == 0); | ||
89 | } | ||
90 | |||
83 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | 91 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) |
84 | { | 92 | { |
85 | FDT_CHECK_HEADER(fdt); | 93 | FDT_CHECK_HEADER(fdt); |
@@ -97,6 +105,30 @@ int fdt_num_mem_rsv(const void *fdt) | |||
97 | return i; | 105 | return i; |
98 | } | 106 | } |
99 | 107 | ||
108 | static int _nextprop(const void *fdt, int offset) | ||
109 | { | ||
110 | uint32_t tag; | ||
111 | int nextoffset; | ||
112 | |||
113 | do { | ||
114 | tag = fdt_next_tag(fdt, offset, &nextoffset); | ||
115 | |||
116 | switch (tag) { | ||
117 | case FDT_END: | ||
118 | if (nextoffset >= 0) | ||
119 | return -FDT_ERR_BADSTRUCTURE; | ||
120 | else | ||
121 | return nextoffset; | ||
122 | |||
123 | case FDT_PROP: | ||
124 | return offset; | ||
125 | } | ||
126 | offset = nextoffset; | ||
127 | } while (tag == FDT_NOP); | ||
128 | |||
129 | return -FDT_ERR_NOTFOUND; | ||
130 | } | ||
131 | |||
100 | int fdt_subnode_offset_namelen(const void *fdt, int offset, | 132 | int fdt_subnode_offset_namelen(const void *fdt, int offset, |
101 | const char *name, int namelen) | 133 | const char *name, int namelen) |
102 | { | 134 | { |
@@ -104,20 +136,16 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, | |||
104 | 136 | ||
105 | FDT_CHECK_HEADER(fdt); | 137 | FDT_CHECK_HEADER(fdt); |
106 | 138 | ||
107 | for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); | 139 | for (depth = 0; |
108 | (offset >= 0) && (depth > 0); | 140 | (offset >= 0) && (depth >= 0); |
109 | offset = fdt_next_node(fdt, offset, &depth)) { | 141 | offset = fdt_next_node(fdt, offset, &depth)) |
110 | if (depth < 0) | 142 | if ((depth == 1) |
111 | return -FDT_ERR_NOTFOUND; | 143 | && _fdt_nodename_eq(fdt, offset, name, namelen)) |
112 | else if ((depth == 1) | ||
113 | && _fdt_nodename_eq(fdt, offset, name, namelen)) | ||
114 | return offset; | 144 | return offset; |
115 | } | ||
116 | 145 | ||
117 | if (offset < 0) | 146 | if (depth < 0) |
118 | return offset; /* error */ | ||
119 | else | ||
120 | return -FDT_ERR_NOTFOUND; | 147 | return -FDT_ERR_NOTFOUND; |
148 | return offset; /* error */ | ||
121 | } | 149 | } |
122 | 150 | ||
123 | int fdt_subnode_offset(const void *fdt, int parentoffset, | 151 | int fdt_subnode_offset(const void *fdt, int parentoffset, |
@@ -134,8 +162,20 @@ int fdt_path_offset(const void *fdt, const char *path) | |||
134 | 162 | ||
135 | FDT_CHECK_HEADER(fdt); | 163 | FDT_CHECK_HEADER(fdt); |
136 | 164 | ||
137 | if (*path != '/') | 165 | /* see if we have an alias */ |
138 | return -FDT_ERR_BADPATH; | 166 | if (*path != '/') { |
167 | const char *q = strchr(path, '/'); | ||
168 | |||
169 | if (!q) | ||
170 | q = end; | ||
171 | |||
172 | p = fdt_get_alias_namelen(fdt, p, q - p); | ||
173 | if (!p) | ||
174 | return -FDT_ERR_BADPATH; | ||
175 | offset = fdt_path_offset(fdt, p); | ||
176 | |||
177 | p = q; | ||
178 | } | ||
139 | 179 | ||
140 | while (*p) { | 180 | while (*p) { |
141 | const char *q; | 181 | const char *q; |
@@ -178,93 +218,142 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) | |||
178 | return NULL; | 218 | return NULL; |
179 | } | 219 | } |
180 | 220 | ||
181 | const struct fdt_property *fdt_get_property(const void *fdt, | 221 | int fdt_first_property_offset(const void *fdt, int nodeoffset) |
182 | int nodeoffset, | 222 | { |
183 | const char *name, int *lenp) | 223 | int offset; |
224 | |||
225 | if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) | ||
226 | return offset; | ||
227 | |||
228 | return _nextprop(fdt, offset); | ||
229 | } | ||
230 | |||
231 | int fdt_next_property_offset(const void *fdt, int offset) | ||
232 | { | ||
233 | if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) | ||
234 | return offset; | ||
235 | |||
236 | return _nextprop(fdt, offset); | ||
237 | } | ||
238 | |||
239 | const struct fdt_property *fdt_get_property_by_offset(const void *fdt, | ||
240 | int offset, | ||
241 | int *lenp) | ||
184 | { | 242 | { |
185 | uint32_t tag; | ||
186 | const struct fdt_property *prop; | ||
187 | int namestroff; | ||
188 | int offset, nextoffset; | ||
189 | int err; | 243 | int err; |
244 | const struct fdt_property *prop; | ||
190 | 245 | ||
191 | if (((err = fdt_check_header(fdt)) != 0) | 246 | if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { |
192 | || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) | 247 | if (lenp) |
193 | goto fail; | 248 | *lenp = err; |
249 | return NULL; | ||
250 | } | ||
194 | 251 | ||
195 | nextoffset = err; | 252 | prop = _fdt_offset_ptr(fdt, offset); |
196 | do { | ||
197 | offset = nextoffset; | ||
198 | 253 | ||
199 | tag = fdt_next_tag(fdt, offset, &nextoffset); | 254 | if (lenp) |
200 | switch (tag) { | 255 | *lenp = fdt32_to_cpu(prop->len); |
201 | case FDT_END: | ||
202 | err = -FDT_ERR_TRUNCATED; | ||
203 | goto fail; | ||
204 | 256 | ||
205 | case FDT_BEGIN_NODE: | 257 | return prop; |
206 | case FDT_END_NODE: | 258 | } |
207 | case FDT_NOP: | ||
208 | break; | ||
209 | 259 | ||
210 | case FDT_PROP: | 260 | const struct fdt_property *fdt_get_property_namelen(const void *fdt, |
211 | err = -FDT_ERR_BADSTRUCTURE; | 261 | int offset, |
212 | prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); | 262 | const char *name, |
213 | if (! prop) | 263 | int namelen, int *lenp) |
214 | goto fail; | 264 | { |
215 | namestroff = fdt32_to_cpu(prop->nameoff); | 265 | for (offset = fdt_first_property_offset(fdt, offset); |
216 | if (strcmp(fdt_string(fdt, namestroff), name) == 0) { | 266 | (offset >= 0); |
217 | /* Found it! */ | 267 | (offset = fdt_next_property_offset(fdt, offset))) { |
218 | int len = fdt32_to_cpu(prop->len); | 268 | const struct fdt_property *prop; |
219 | prop = fdt_offset_ptr(fdt, offset, | ||
220 | sizeof(*prop)+len); | ||
221 | if (! prop) | ||
222 | goto fail; | ||
223 | |||
224 | if (lenp) | ||
225 | *lenp = len; | ||
226 | |||
227 | return prop; | ||
228 | } | ||
229 | break; | ||
230 | 269 | ||
231 | default: | 270 | if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { |
232 | err = -FDT_ERR_BADSTRUCTURE; | 271 | offset = -FDT_ERR_INTERNAL; |
233 | goto fail; | 272 | break; |
234 | } | 273 | } |
235 | } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); | 274 | if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), |
275 | name, namelen)) | ||
276 | return prop; | ||
277 | } | ||
236 | 278 | ||
237 | err = -FDT_ERR_NOTFOUND; | ||
238 | fail: | ||
239 | if (lenp) | 279 | if (lenp) |
240 | *lenp = err; | 280 | *lenp = offset; |
241 | return NULL; | 281 | return NULL; |
242 | } | 282 | } |
243 | 283 | ||
244 | const void *fdt_getprop(const void *fdt, int nodeoffset, | 284 | const struct fdt_property *fdt_get_property(const void *fdt, |
245 | const char *name, int *lenp) | 285 | int nodeoffset, |
286 | const char *name, int *lenp) | ||
287 | { | ||
288 | return fdt_get_property_namelen(fdt, nodeoffset, name, | ||
289 | strlen(name), lenp); | ||
290 | } | ||
291 | |||
292 | const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, | ||
293 | const char *name, int namelen, int *lenp) | ||
246 | { | 294 | { |
247 | const struct fdt_property *prop; | 295 | const struct fdt_property *prop; |
248 | 296 | ||
249 | prop = fdt_get_property(fdt, nodeoffset, name, lenp); | 297 | prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); |
250 | if (! prop) | 298 | if (! prop) |
251 | return NULL; | 299 | return NULL; |
252 | 300 | ||
253 | return prop->data; | 301 | return prop->data; |
254 | } | 302 | } |
255 | 303 | ||
304 | const void *fdt_getprop_by_offset(const void *fdt, int offset, | ||
305 | const char **namep, int *lenp) | ||
306 | { | ||
307 | const struct fdt_property *prop; | ||
308 | |||
309 | prop = fdt_get_property_by_offset(fdt, offset, lenp); | ||
310 | if (!prop) | ||
311 | return NULL; | ||
312 | if (namep) | ||
313 | *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); | ||
314 | return prop->data; | ||
315 | } | ||
316 | |||
317 | const void *fdt_getprop(const void *fdt, int nodeoffset, | ||
318 | const char *name, int *lenp) | ||
319 | { | ||
320 | return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); | ||
321 | } | ||
322 | |||
256 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) | 323 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) |
257 | { | 324 | { |
258 | const uint32_t *php; | 325 | const uint32_t *php; |
259 | int len; | 326 | int len; |
260 | 327 | ||
261 | php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); | 328 | /* FIXME: This is a bit sub-optimal, since we potentially scan |
262 | if (!php || (len != sizeof(*php))) | 329 | * over all the properties twice. */ |
263 | return 0; | 330 | php = fdt_getprop(fdt, nodeoffset, "phandle", &len); |
331 | if (!php || (len != sizeof(*php))) { | ||
332 | php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); | ||
333 | if (!php || (len != sizeof(*php))) | ||
334 | return 0; | ||
335 | } | ||
264 | 336 | ||
265 | return fdt32_to_cpu(*php); | 337 | return fdt32_to_cpu(*php); |
266 | } | 338 | } |
267 | 339 | ||
340 | const char *fdt_get_alias_namelen(const void *fdt, | ||
341 | const char *name, int namelen) | ||
342 | { | ||
343 | int aliasoffset; | ||
344 | |||
345 | aliasoffset = fdt_path_offset(fdt, "/aliases"); | ||
346 | if (aliasoffset < 0) | ||
347 | return NULL; | ||
348 | |||
349 | return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); | ||
350 | } | ||
351 | |||
352 | const char *fdt_get_alias(const void *fdt, const char *name) | ||
353 | { | ||
354 | return fdt_get_alias_namelen(fdt, name, strlen(name)); | ||
355 | } | ||
356 | |||
268 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | 357 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) |
269 | { | 358 | { |
270 | int pdepth = 0, p = 0; | 359 | int pdepth = 0, p = 0; |
@@ -279,9 +368,6 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | |||
279 | for (offset = 0, depth = 0; | 368 | for (offset = 0, depth = 0; |
280 | (offset >= 0) && (offset <= nodeoffset); | 369 | (offset >= 0) && (offset <= nodeoffset); |
281 | offset = fdt_next_node(fdt, offset, &depth)) { | 370 | offset = fdt_next_node(fdt, offset, &depth)) { |
282 | if (pdepth < depth) | ||
283 | continue; /* overflowed buffer */ | ||
284 | |||
285 | while (pdepth > depth) { | 371 | while (pdepth > depth) { |
286 | do { | 372 | do { |
287 | p--; | 373 | p--; |
@@ -289,14 +375,16 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | |||
289 | pdepth--; | 375 | pdepth--; |
290 | } | 376 | } |
291 | 377 | ||
292 | name = fdt_get_name(fdt, offset, &namelen); | 378 | if (pdepth >= depth) { |
293 | if (!name) | 379 | name = fdt_get_name(fdt, offset, &namelen); |
294 | return namelen; | 380 | if (!name) |
295 | if ((p + namelen + 1) <= buflen) { | 381 | return namelen; |
296 | memcpy(buf + p, name, namelen); | 382 | if ((p + namelen + 1) <= buflen) { |
297 | p += namelen; | 383 | memcpy(buf + p, name, namelen); |
298 | buf[p++] = '/'; | 384 | p += namelen; |
299 | pdepth++; | 385 | buf[p++] = '/'; |
386 | pdepth++; | ||
387 | } | ||
300 | } | 388 | } |
301 | 389 | ||
302 | if (offset == nodeoffset) { | 390 | if (offset == nodeoffset) { |
@@ -306,7 +394,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | |||
306 | if (p > 1) /* special case so that root path is "/", not "" */ | 394 | if (p > 1) /* special case so that root path is "/", not "" */ |
307 | p--; | 395 | p--; |
308 | buf[p] = '\0'; | 396 | buf[p] = '\0'; |
309 | return p; | 397 | return 0; |
310 | } | 398 | } |
311 | } | 399 | } |
312 | 400 | ||
@@ -404,14 +492,31 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | |||
404 | 492 | ||
405 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | 493 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) |
406 | { | 494 | { |
495 | int offset; | ||
496 | |||
407 | if ((phandle == 0) || (phandle == -1)) | 497 | if ((phandle == 0) || (phandle == -1)) |
408 | return -FDT_ERR_BADPHANDLE; | 498 | return -FDT_ERR_BADPHANDLE; |
409 | phandle = cpu_to_fdt32(phandle); | 499 | |
410 | return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", | 500 | FDT_CHECK_HEADER(fdt); |
411 | &phandle, sizeof(phandle)); | 501 | |
502 | /* FIXME: The algorithm here is pretty horrible: we | ||
503 | * potentially scan each property of a node in | ||
504 | * fdt_get_phandle(), then if that didn't find what | ||
505 | * we want, we scan over them again making our way to the next | ||
506 | * node. Still it's the easiest to implement approach; | ||
507 | * performance can come later. */ | ||
508 | for (offset = fdt_next_node(fdt, -1, NULL); | ||
509 | offset >= 0; | ||
510 | offset = fdt_next_node(fdt, offset, NULL)) { | ||
511 | if (fdt_get_phandle(fdt, offset) == phandle) | ||
512 | return offset; | ||
513 | } | ||
514 | |||
515 | return offset; /* error from fdt_next_node() */ | ||
412 | } | 516 | } |
413 | 517 | ||
414 | static int _stringlist_contains(const char *strlist, int listlen, const char *str) | 518 | static int _fdt_stringlist_contains(const char *strlist, int listlen, |
519 | const char *str) | ||
415 | { | 520 | { |
416 | int len = strlen(str); | 521 | int len = strlen(str); |
417 | const char *p; | 522 | const char *p; |
@@ -437,7 +542,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, | |||
437 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); | 542 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); |
438 | if (!prop) | 543 | if (!prop) |
439 | return len; | 544 | return len; |
440 | if (_stringlist_contains(prop, len, compatible)) | 545 | if (_fdt_stringlist_contains(prop, len, compatible)) |
441 | return 0; | 546 | return 0; |
442 | else | 547 | else |
443 | return 1; | 548 | return 1; |