diff options
Diffstat (limited to 'scripts/dtc/libfdt/fdt_ro.c')
| -rw-r--r-- | scripts/dtc/libfdt/fdt_ro.c | 275 |
1 files changed, 85 insertions, 190 deletions
diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index 02b6d687537..22e692919ff 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c | |||
| @@ -80,14 +80,6 @@ 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 | |||
| 91 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) | 83 | int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) |
| 92 | { | 84 | { |
| 93 | FDT_CHECK_HEADER(fdt); | 85 | FDT_CHECK_HEADER(fdt); |
| @@ -105,30 +97,6 @@ int fdt_num_mem_rsv(const void *fdt) | |||
| 105 | return i; | 97 | return i; |
| 106 | } | 98 | } |
| 107 | 99 | ||
| 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 | |||
| 132 | int fdt_subnode_offset_namelen(const void *fdt, int offset, | 100 | int fdt_subnode_offset_namelen(const void *fdt, int offset, |
| 133 | const char *name, int namelen) | 101 | const char *name, int namelen) |
| 134 | { | 102 | { |
| @@ -136,16 +104,20 @@ int fdt_subnode_offset_namelen(const void *fdt, int offset, | |||
| 136 | 104 | ||
| 137 | FDT_CHECK_HEADER(fdt); | 105 | FDT_CHECK_HEADER(fdt); |
| 138 | 106 | ||
| 139 | for (depth = 0; | 107 | for (depth = 0, offset = fdt_next_node(fdt, offset, &depth); |
| 140 | (offset >= 0) && (depth >= 0); | 108 | (offset >= 0) && (depth > 0); |
| 141 | offset = fdt_next_node(fdt, offset, &depth)) | 109 | offset = fdt_next_node(fdt, offset, &depth)) { |
| 142 | if ((depth == 1) | 110 | if (depth < 0) |
| 143 | && _fdt_nodename_eq(fdt, offset, name, namelen)) | 111 | return -FDT_ERR_NOTFOUND; |
| 112 | else if ((depth == 1) | ||
| 113 | && _fdt_nodename_eq(fdt, offset, name, namelen)) | ||
| 144 | return offset; | 114 | return offset; |
| 115 | } | ||
| 145 | 116 | ||
| 146 | if (depth < 0) | 117 | if (offset < 0) |
| 118 | return offset; /* error */ | ||
| 119 | else | ||
| 147 | return -FDT_ERR_NOTFOUND; | 120 | return -FDT_ERR_NOTFOUND; |
| 148 | return offset; /* error */ | ||
| 149 | } | 121 | } |
| 150 | 122 | ||
| 151 | int fdt_subnode_offset(const void *fdt, int parentoffset, | 123 | int fdt_subnode_offset(const void *fdt, int parentoffset, |
| @@ -162,20 +134,8 @@ int fdt_path_offset(const void *fdt, const char *path) | |||
| 162 | 134 | ||
| 163 | FDT_CHECK_HEADER(fdt); | 135 | FDT_CHECK_HEADER(fdt); |
| 164 | 136 | ||
| 165 | /* see if we have an alias */ | 137 | if (*path != '/') |
| 166 | if (*path != '/') { | 138 | return -FDT_ERR_BADPATH; |
| 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 | } | ||
| 179 | 139 | ||
| 180 | while (*p) { | 140 | while (*p) { |
| 181 | const char *q; | 141 | const char *q; |
| @@ -218,142 +178,93 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) | |||
| 218 | return NULL; | 178 | return NULL; |
| 219 | } | 179 | } |
| 220 | 180 | ||
| 221 | int fdt_first_property_offset(const void *fdt, int nodeoffset) | 181 | const struct fdt_property *fdt_get_property(const void *fdt, |
| 222 | { | 182 | int nodeoffset, |
| 223 | int offset; | 183 | const char *name, int *lenp) |
| 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) | ||
| 242 | { | 184 | { |
| 243 | int err; | 185 | uint32_t tag; |
| 244 | const struct fdt_property *prop; | 186 | const struct fdt_property *prop; |
| 187 | int namestroff; | ||
| 188 | int offset, nextoffset; | ||
| 189 | int err; | ||
| 245 | 190 | ||
| 246 | if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { | 191 | if (((err = fdt_check_header(fdt)) != 0) |
| 247 | if (lenp) | 192 | || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) |
| 248 | *lenp = err; | 193 | goto fail; |
| 249 | return NULL; | ||
| 250 | } | ||
| 251 | |||
| 252 | prop = _fdt_offset_ptr(fdt, offset); | ||
| 253 | 194 | ||
| 254 | if (lenp) | 195 | nextoffset = err; |
| 255 | *lenp = fdt32_to_cpu(prop->len); | 196 | do { |
| 197 | offset = nextoffset; | ||
| 256 | 198 | ||
| 257 | return prop; | 199 | tag = fdt_next_tag(fdt, offset, &nextoffset); |
| 258 | } | 200 | switch (tag) { |
| 201 | case FDT_END: | ||
| 202 | err = -FDT_ERR_TRUNCATED; | ||
| 203 | goto fail; | ||
| 259 | 204 | ||
| 260 | const struct fdt_property *fdt_get_property_namelen(const void *fdt, | 205 | case FDT_BEGIN_NODE: |
| 261 | int offset, | 206 | case FDT_END_NODE: |
| 262 | const char *name, | 207 | case FDT_NOP: |
| 263 | int namelen, int *lenp) | 208 | break; |
| 264 | { | ||
| 265 | for (offset = fdt_first_property_offset(fdt, offset); | ||
| 266 | (offset >= 0); | ||
| 267 | (offset = fdt_next_property_offset(fdt, offset))) { | ||
| 268 | const struct fdt_property *prop; | ||
| 269 | 209 | ||
| 270 | if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { | 210 | case FDT_PROP: |
| 271 | offset = -FDT_ERR_INTERNAL; | 211 | err = -FDT_ERR_BADSTRUCTURE; |
| 212 | prop = fdt_offset_ptr(fdt, offset, sizeof(*prop)); | ||
| 213 | if (! prop) | ||
| 214 | goto fail; | ||
| 215 | namestroff = fdt32_to_cpu(prop->nameoff); | ||
| 216 | if (strcmp(fdt_string(fdt, namestroff), name) == 0) { | ||
| 217 | /* Found it! */ | ||
| 218 | int len = fdt32_to_cpu(prop->len); | ||
| 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 | } | ||
| 272 | break; | 229 | break; |
| 230 | |||
| 231 | default: | ||
| 232 | err = -FDT_ERR_BADSTRUCTURE; | ||
| 233 | goto fail; | ||
| 273 | } | 234 | } |
| 274 | if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), | 235 | } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE)); |
| 275 | name, namelen)) | ||
| 276 | return prop; | ||
| 277 | } | ||
| 278 | 236 | ||
| 237 | err = -FDT_ERR_NOTFOUND; | ||
| 238 | fail: | ||
| 279 | if (lenp) | 239 | if (lenp) |
| 280 | *lenp = offset; | 240 | *lenp = err; |
| 281 | return NULL; | 241 | return NULL; |
| 282 | } | 242 | } |
| 283 | 243 | ||
| 284 | const struct fdt_property *fdt_get_property(const void *fdt, | 244 | const void *fdt_getprop(const void *fdt, int nodeoffset, |
| 285 | int nodeoffset, | 245 | const char *name, int *lenp) |
| 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) | ||
| 294 | { | 246 | { |
| 295 | const struct fdt_property *prop; | 247 | const struct fdt_property *prop; |
| 296 | 248 | ||
| 297 | prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); | 249 | prop = fdt_get_property(fdt, nodeoffset, name, lenp); |
| 298 | if (! prop) | 250 | if (! prop) |
| 299 | return NULL; | 251 | return NULL; |
| 300 | 252 | ||
| 301 | return prop->data; | 253 | return prop->data; |
| 302 | } | 254 | } |
| 303 | 255 | ||
| 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 | |||
| 323 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) | 256 | uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) |
| 324 | { | 257 | { |
| 325 | const uint32_t *php; | 258 | const uint32_t *php; |
| 326 | int len; | 259 | int len; |
| 327 | 260 | ||
| 328 | /* FIXME: This is a bit sub-optimal, since we potentially scan | 261 | php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); |
| 329 | * over all the properties twice. */ | 262 | if (!php || (len != sizeof(*php))) |
| 330 | php = fdt_getprop(fdt, nodeoffset, "phandle", &len); | 263 | return 0; |
| 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 | } | ||
| 336 | 264 | ||
| 337 | return fdt32_to_cpu(*php); | 265 | return fdt32_to_cpu(*php); |
| 338 | } | 266 | } |
| 339 | 267 | ||
| 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 | |||
| 357 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | 268 | int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) |
| 358 | { | 269 | { |
| 359 | int pdepth = 0, p = 0; | 270 | int pdepth = 0, p = 0; |
| @@ -368,6 +279,9 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | |||
| 368 | for (offset = 0, depth = 0; | 279 | for (offset = 0, depth = 0; |
| 369 | (offset >= 0) && (offset <= nodeoffset); | 280 | (offset >= 0) && (offset <= nodeoffset); |
| 370 | offset = fdt_next_node(fdt, offset, &depth)) { | 281 | offset = fdt_next_node(fdt, offset, &depth)) { |
| 282 | if (pdepth < depth) | ||
| 283 | continue; /* overflowed buffer */ | ||
| 284 | |||
| 371 | while (pdepth > depth) { | 285 | while (pdepth > depth) { |
| 372 | do { | 286 | do { |
| 373 | p--; | 287 | p--; |
| @@ -375,16 +289,14 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | |||
| 375 | pdepth--; | 289 | pdepth--; |
| 376 | } | 290 | } |
| 377 | 291 | ||
| 378 | if (pdepth >= depth) { | 292 | name = fdt_get_name(fdt, offset, &namelen); |
| 379 | name = fdt_get_name(fdt, offset, &namelen); | 293 | if (!name) |
| 380 | if (!name) | 294 | return namelen; |
| 381 | return namelen; | 295 | if ((p + namelen + 1) <= buflen) { |
| 382 | if ((p + namelen + 1) <= buflen) { | 296 | memcpy(buf + p, name, namelen); |
| 383 | memcpy(buf + p, name, namelen); | 297 | p += namelen; |
| 384 | p += namelen; | 298 | buf[p++] = '/'; |
| 385 | buf[p++] = '/'; | 299 | pdepth++; |
| 386 | pdepth++; | ||
| 387 | } | ||
| 388 | } | 300 | } |
| 389 | 301 | ||
| 390 | if (offset == nodeoffset) { | 302 | if (offset == nodeoffset) { |
| @@ -394,7 +306,7 @@ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) | |||
| 394 | if (p > 1) /* special case so that root path is "/", not "" */ | 306 | if (p > 1) /* special case so that root path is "/", not "" */ |
| 395 | p--; | 307 | p--; |
| 396 | buf[p] = '\0'; | 308 | buf[p] = '\0'; |
| 397 | return 0; | 309 | return p; |
| 398 | } | 310 | } |
| 399 | } | 311 | } |
| 400 | 312 | ||
| @@ -492,31 +404,14 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, | |||
| 492 | 404 | ||
| 493 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) | 405 | int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) |
| 494 | { | 406 | { |
| 495 | int offset; | ||
| 496 | |||
| 497 | if ((phandle == 0) || (phandle == -1)) | 407 | if ((phandle == 0) || (phandle == -1)) |
| 498 | return -FDT_ERR_BADPHANDLE; | 408 | return -FDT_ERR_BADPHANDLE; |
| 499 | 409 | phandle = cpu_to_fdt32(phandle); | |
| 500 | FDT_CHECK_HEADER(fdt); | 410 | return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle", |
| 501 | 411 | &phandle, sizeof(phandle)); | |
| 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() */ | ||
| 516 | } | 412 | } |
| 517 | 413 | ||
| 518 | static int _fdt_stringlist_contains(const char *strlist, int listlen, | 414 | static int _stringlist_contains(const char *strlist, int listlen, const char *str) |
| 519 | const char *str) | ||
| 520 | { | 415 | { |
| 521 | int len = strlen(str); | 416 | int len = strlen(str); |
| 522 | const char *p; | 417 | const char *p; |
| @@ -542,7 +437,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset, | |||
| 542 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); | 437 | prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); |
| 543 | if (!prop) | 438 | if (!prop) |
| 544 | return len; | 439 | return len; |
| 545 | if (_fdt_stringlist_contains(prop, len, compatible)) | 440 | if (_stringlist_contains(prop, len, compatible)) |
| 546 | return 0; | 441 | return 0; |
| 547 | else | 442 | else |
| 548 | return 1; | 443 | return 1; |
