1 /* $OpenBSD: fdt.c,v 1.17 2016/07/09 12:31:05 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net> 5 * Copyright (c) 2009 Mark Kettenis <kettenis@sfires.net> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 24 #include <dev/ofw/fdt.h> 25 #include <dev/ofw/openfirm.h> 26 27 /* XXX */ 28 #define OPROMMAXPARAM 32 29 30 unsigned int fdt_check_head(void *); 31 char *fdt_get_str(u_int32_t); 32 void *skip_property(u_int32_t *); 33 void *skip_props(u_int32_t *); 34 void *skip_node_name(u_int32_t *); 35 void *skip_node(void *); 36 void *skip_nops(u_int32_t *); 37 void *fdt_parent_node_recurse(void *, void *); 38 void *fdt_find_phandle_recurse(void *, uint32_t); 39 int fdt_node_property_int(void *, char *, int *); 40 int fdt_node_property_ints(void *, char *, int *, int); 41 int fdt_translate_memory_address(void *, struct fdt_memory *); 42 #ifdef DEBUG 43 void fdt_print_node_recurse(void *, int); 44 #endif 45 46 static int tree_inited = 0; 47 static struct fdt tree; 48 49 unsigned int 50 fdt_check_head(void *fdt) 51 { 52 struct fdt_head *fh; 53 u_int32_t *ptr, *tok; 54 55 fh = fdt; 56 ptr = (u_int32_t *)fdt; 57 58 if (betoh32(fh->fh_magic) != FDT_MAGIC) 59 return 0; 60 61 if (betoh32(fh->fh_version) > FDT_CODE_VERSION) 62 return 0; 63 64 tok = skip_nops(ptr + (betoh32(fh->fh_struct_off) / 4)); 65 if (betoh32(*tok) != FDT_NODE_BEGIN) 66 return 0; 67 68 /* check for end signature on version 17 blob */ 69 if ((betoh32(fh->fh_version) >= 17) && 70 (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) + 71 (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END)) 72 return 0; 73 74 return betoh32(fh->fh_version); 75 } 76 77 /* 78 * Initializes internal structures of module. 79 * Has to be called once, preferably in machdep.c. 80 */ 81 int 82 fdt_init(void *fdt) 83 { 84 int version; 85 86 bzero(&tree, sizeof(struct fdt)); 87 tree_inited = 0; 88 89 if (!fdt) 90 return 0; 91 92 if (!(version = fdt_check_head(fdt))) 93 return 0; 94 95 tree.header = (struct fdt_head *)fdt; 96 tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off); 97 tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off); 98 tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off); 99 tree.version = version; 100 tree.strings_size = betoh32(tree.header->fh_strings_size); 101 tree_inited = 1; 102 103 return version; 104 } 105 106 /* 107 * Return the size of the FDT. 108 */ 109 size_t 110 fdt_get_size(void *fdt) 111 { 112 if (!fdt) 113 return 0; 114 115 if (!fdt_check_head(fdt)) 116 return 0; 117 118 return betoh32(((struct fdt_head *)fdt)->fh_size); 119 } 120 121 /* 122 * Retrieve string pointer from strings table. 123 */ 124 char * 125 fdt_get_str(u_int32_t num) 126 { 127 if (num > tree.strings_size) 128 return NULL; 129 return (tree.strings) ? (tree.strings + num) : NULL; 130 } 131 132 /* 133 * Utility functions for skipping parts of tree. 134 */ 135 136 void * 137 skip_nops(u_int32_t *ptr) 138 { 139 while (betoh32(*ptr) == FDT_NOP) 140 ptr++; 141 142 return ptr; 143 } 144 145 void * 146 skip_property(u_int32_t *ptr) 147 { 148 u_int32_t size; 149 150 size = betoh32(*(ptr + 1)); 151 /* move forward by magic + size + nameid + rounded up property size */ 152 ptr += 3 + roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t); 153 154 return skip_nops(ptr); 155 } 156 157 void * 158 skip_props(u_int32_t *ptr) 159 { 160 while (betoh32(*ptr) == FDT_PROPERTY) { 161 ptr = skip_property(ptr); 162 } 163 return ptr; 164 } 165 166 void * 167 skip_node_name(u_int32_t *ptr) 168 { 169 /* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */ 170 ptr += roundup(strlen((char *)ptr) + 1, 171 sizeof(u_int32_t)) / sizeof(u_int32_t); 172 173 return skip_nops(ptr); 174 } 175 176 /* 177 * Retrieves node property, the returned pointer is inside the fdt tree, 178 * so we should not modify content pointed by it directly. 179 */ 180 int 181 fdt_node_property(void *node, char *name, char **out) 182 { 183 u_int32_t *ptr; 184 u_int32_t nameid; 185 char *tmp; 186 187 if (!tree_inited) 188 return -1; 189 190 ptr = (u_int32_t *)node; 191 192 if (betoh32(*ptr) != FDT_NODE_BEGIN) 193 return -1; 194 195 ptr = skip_node_name(ptr + 1); 196 197 while (betoh32(*ptr) == FDT_PROPERTY) { 198 nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ 199 tmp = fdt_get_str(nameid); 200 if (!strcmp(name, tmp)) { 201 *out = (char *)(ptr + 3); /* beginning of the value */ 202 return betoh32(*(ptr + 1)); /* size of value */ 203 } 204 ptr = skip_property(ptr); 205 } 206 return -1; 207 } 208 209 /* 210 * Retrieves next node, skipping all the children nodes of the pointed node, 211 * returns pointer to next node, no matter if it exists or not. 212 */ 213 void * 214 skip_node(void *node) 215 { 216 u_int32_t *ptr = node; 217 218 ptr++; 219 220 ptr = skip_node_name(ptr); 221 ptr = skip_props(ptr); 222 223 /* skip children */ 224 while (betoh32(*ptr) == FDT_NODE_BEGIN) 225 ptr = skip_node(ptr); 226 227 return skip_nops(ptr + 1); 228 } 229 230 /* 231 * Retrieves next node, skipping all the children nodes of the pointed node, 232 * returns pointer to next node if exists, otherwise returns NULL. 233 * If passed 0 will return first node of the tree (root). 234 */ 235 void * 236 fdt_next_node(void *node) 237 { 238 u_int32_t *ptr; 239 240 if (!tree_inited) 241 return NULL; 242 243 ptr = node; 244 245 if (node == NULL) { 246 ptr = skip_nops(tree.tree); 247 return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL; 248 } 249 250 if (betoh32(*ptr) != FDT_NODE_BEGIN) 251 return NULL; 252 253 ptr++; 254 255 ptr = skip_node_name(ptr); 256 ptr = skip_props(ptr); 257 258 /* skip children */ 259 while (betoh32(*ptr) == FDT_NODE_BEGIN) 260 ptr = skip_node(ptr); 261 262 if (betoh32(*ptr) != FDT_NODE_END) 263 return NULL; 264 265 ptr = skip_nops(ptr + 1); 266 267 if (betoh32(*ptr) != FDT_NODE_BEGIN) 268 return NULL; 269 270 return ptr; 271 } 272 273 int 274 fdt_next_property(void *node, char *name, char **nextname) 275 { 276 u_int32_t *ptr; 277 u_int32_t nameid; 278 279 if (!tree_inited) 280 return 0; 281 282 ptr = (u_int32_t *)node; 283 284 if (betoh32(*ptr) != FDT_NODE_BEGIN) 285 return 0; 286 287 ptr = skip_node_name(ptr + 1); 288 289 while (betoh32(*ptr) == FDT_PROPERTY) { 290 nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ 291 if (strcmp(name, "") == 0) { 292 *nextname = fdt_get_str(nameid); 293 return 1; 294 } 295 if (strcmp(name, fdt_get_str(nameid)) == 0) { 296 ptr = skip_property(ptr); 297 if (betoh32(*ptr) != FDT_PROPERTY) 298 break; 299 nameid = betoh32(*(ptr + 2)); 300 *nextname = fdt_get_str(nameid); 301 return 1; 302 } 303 ptr = skip_property(ptr); 304 } 305 *nextname = ""; 306 return 1; 307 } 308 309 /* 310 * Retrieves node property as integers and puts them in the given 311 * integer array. 312 */ 313 int 314 fdt_node_property_ints(void *node, char *name, int *out, int outlen) 315 { 316 int *data; 317 int i, inlen; 318 319 inlen = fdt_node_property(node, name, (char **)&data) / sizeof(int); 320 if (inlen <= 0) 321 return -1; 322 323 for (i = 0; i < inlen && i < outlen; i++) 324 out[i] = betoh32(data[i]); 325 326 return i; 327 } 328 329 /* 330 * Retrieves node property as an integer. 331 */ 332 int 333 fdt_node_property_int(void *node, char *name, int *out) 334 { 335 return fdt_node_property_ints(node, name, out, 1); 336 } 337 338 /* 339 * Retrieves next node, skipping all the children nodes of the pointed node 340 */ 341 void * 342 fdt_child_node(void *node) 343 { 344 u_int32_t *ptr; 345 346 if (!tree_inited) 347 return NULL; 348 349 ptr = node; 350 351 if (betoh32(*ptr) != FDT_NODE_BEGIN) 352 return NULL; 353 354 ptr++; 355 356 ptr = skip_node_name(ptr); 357 ptr = skip_props(ptr); 358 /* check if there is a child node */ 359 return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL; 360 } 361 362 /* 363 * Retrieves node name. 364 */ 365 char * 366 fdt_node_name(void *node) 367 { 368 u_int32_t *ptr; 369 370 if (!tree_inited) 371 return NULL; 372 373 ptr = node; 374 375 if (betoh32(*ptr) != FDT_NODE_BEGIN) 376 return NULL; 377 378 return (char *)(ptr + 1); 379 } 380 381 void * 382 fdt_find_node(char *name) 383 { 384 void *node = fdt_next_node(0); 385 const char *p = name; 386 387 if (!tree_inited) 388 return NULL; 389 390 if (*p != '/') 391 return NULL; 392 393 while (*p) { 394 void *child; 395 const char *q; 396 397 while (*p == '/') 398 p++; 399 if (*p == 0) 400 return node; 401 q = strchr(p, '/'); 402 if (q == NULL) 403 q = p + strlen(p); 404 405 for (child = fdt_child_node(node); child; 406 child = fdt_next_node(child)) { 407 if (strncmp(p, fdt_node_name(child), q - p) == 0) { 408 node = child; 409 break; 410 } 411 } 412 413 p = q; 414 } 415 416 return node; 417 } 418 419 void * 420 fdt_parent_node_recurse(void *pnode, void *child) 421 { 422 void *node = fdt_child_node(pnode); 423 void *tmp; 424 425 while (node && (node != child)) { 426 if ((tmp = fdt_parent_node_recurse(node, child))) 427 return tmp; 428 node = fdt_next_node(node); 429 } 430 return (node) ? pnode : NULL; 431 } 432 433 void * 434 fdt_parent_node(void *node) 435 { 436 void *pnode = fdt_next_node(0); 437 438 if (!tree_inited) 439 return NULL; 440 441 if (node == pnode) 442 return NULL; 443 444 return fdt_parent_node_recurse(pnode, node); 445 } 446 447 void * 448 fdt_find_phandle_recurse(void *node, uint32_t phandle) 449 { 450 void *child; 451 char *data; 452 void *tmp; 453 int len; 454 455 len = fdt_node_property(node, "phandle", &data); 456 if (len < 0) 457 len = fdt_node_property(node, "linux,phandle", &data); 458 459 if (len == sizeof(uint32_t) && bemtoh32(data) == phandle) 460 return node; 461 462 for (child = fdt_child_node(node); child; child = fdt_next_node(child)) 463 if ((tmp = fdt_find_phandle_recurse(child, phandle))) 464 return tmp; 465 466 return NULL; 467 } 468 469 void * 470 fdt_find_phandle(uint32_t phandle) 471 { 472 return fdt_find_phandle_recurse(fdt_next_node(0), phandle); 473 } 474 475 /* 476 * Translate memory address depending on parent's range. 477 * 478 * Ranges are a way of mapping one address to another. This ranges attribute 479 * is set on a node's parent. This means if a node does not have a parent, 480 * there's nothing to translate. If it does have a parent and the parent does 481 * not have a ranges attribute, there's nothing to translate either. 482 * 483 * If the parent has a ranges attribute and the attribute is not empty, the 484 * node's memory address has to be in one of the given ranges. This range is 485 * then used to translate the memory address. 486 * 487 * If the parent has a ranges attribute, but the attribute is empty, there's 488 * nothing to translate. But it's not a translation barrier. It can be treated 489 * as a simple 1:1 mapping. 490 * 491 * Translation does not end here. We need to check if the parent's parent also 492 * has a ranges attribute and ask the same questions again. 493 */ 494 int 495 fdt_translate_memory_address(void *node, struct fdt_memory *mem) 496 { 497 void *parent; 498 int pac, psc, ac, sc, ret, rlen, rone, *range; 499 uint64_t from, to, size; 500 501 /* No parent, no translation. */ 502 parent = fdt_parent_node(node); 503 if (parent == NULL) 504 return 0; 505 506 /* Extract ranges property from node. */ 507 rlen = fdt_node_property(node, "ranges", (char **)&range) / sizeof(int); 508 509 /* No ranges means translation barrier. Translation stops here. */ 510 if (range == NULL) 511 return 0; 512 513 /* Empty ranges means 1:1 mapping. Continue translation on parent. */ 514 if (rlen <= 0) 515 return fdt_translate_memory_address(parent, mem); 516 517 /* We only support 32-bit (1), and 64-bit (2) wide addresses here. */ 518 ret = fdt_node_property_int(parent, "#address-cells", &pac); 519 if (ret != 1 || pac <= 0 || pac > 2) 520 return EINVAL; 521 522 /* We only support 32-bit (1), and 64-bit (2) wide sizes here. */ 523 ret = fdt_node_property_int(parent, "#size-cells", &psc); 524 if (ret != 1 || psc <= 0 || psc > 2) 525 return EINVAL; 526 527 /* We only support 32-bit (1), and 64-bit (2) wide addresses here. */ 528 ret = fdt_node_property_int(node, "#address-cells", &ac); 529 if (ret <= 0) 530 ac = pac; 531 else if (ret > 1 || ac <= 0 || ac > 2) 532 return EINVAL; 533 534 /* We only support 32-bit (1), and 64-bit (2) wide sizes here. */ 535 ret = fdt_node_property_int(node, "#size-cells", &sc); 536 if (ret <= 0) 537 sc = psc; 538 else if (ret > 1 || sc <= 0 || sc > 2) 539 return EINVAL; 540 541 /* Must have at least one range. */ 542 rone = pac + ac + sc; 543 if (rlen < rone) 544 return ESRCH; 545 546 /* For each range. */ 547 for (; rlen >= rone; rlen -= rone, range += rone) { 548 /* Extract from and size, so we can see if we fit. */ 549 from = betoh32(range[0]); 550 if (ac == 2) 551 from = (from << 32) + betoh32(range[1]); 552 size = betoh32(range[ac + pac]); 553 if (sc == 2) 554 size = (size << 32) + betoh32(range[ac + pac + 1]); 555 556 /* Try next, if we're not in the range. */ 557 if (mem->addr < from || (mem->addr + mem->size) > (from + size)) 558 continue; 559 560 /* All good, extract to address and translate. */ 561 to = betoh32(range[ac]); 562 if (pac == 2) 563 to = (to << 32) + betoh32(range[ac + 1]); 564 565 mem->addr -= from; 566 mem->addr += to; 567 return fdt_translate_memory_address(parent, mem); 568 } 569 570 /* To be successful, we must have returned in the for-loop. */ 571 return ESRCH; 572 } 573 574 /* 575 * Parse the memory address and size of a node. 576 */ 577 int 578 fdt_get_memory_address(void *node, int idx, struct fdt_memory *mem) 579 { 580 void *parent; 581 int ac, sc, off, ret, *in, inlen; 582 583 if (node == NULL || mem == NULL) 584 return EINVAL; 585 586 parent = fdt_parent_node(node); 587 if (parent == NULL) 588 return EINVAL; 589 590 /* We only support 32-bit (1), and 64-bit (2) wide addresses here. */ 591 ret = fdt_node_property_int(parent, "#address-cells", &ac); 592 if (ret != 1 || ac <= 0 || ac > 2) 593 return EINVAL; 594 595 /* We only support 32-bit (1), and 64-bit (2) wide sizes here. */ 596 ret = fdt_node_property_int(parent, "#size-cells", &sc); 597 if (ret != 1 || sc <= 0 || sc > 2) 598 return EINVAL; 599 600 inlen = fdt_node_property(node, "reg", (char **)&in) / sizeof(int); 601 if (inlen < ((idx + 1) * (ac + sc))) 602 return EINVAL; 603 604 off = idx * (ac + sc); 605 606 mem->addr = betoh32(in[off]); 607 if (ac == 2) 608 mem->addr = (mem->addr << 32) + betoh32(in[off + 1]); 609 610 mem->size = betoh32(in[off + ac]); 611 if (sc == 2) 612 mem->size = (mem->size << 32) + betoh32(in[off + ac + 1]); 613 614 return fdt_translate_memory_address(parent, mem); 615 } 616 617 int 618 fdt_is_compatible(void *node, const char *name) 619 { 620 char *data; 621 int len; 622 623 len = fdt_node_property(node, "compatible", &data); 624 while (len > 0) { 625 if (strcmp(data, name) == 0) 626 return 1; 627 len -= strlen(data) + 1; 628 data += strlen(data) + 1; 629 } 630 631 return 0; 632 } 633 634 #ifdef DEBUG 635 /* 636 * Debug methods for printing whole tree, particular odes and properies 637 */ 638 void * 639 fdt_print_property(void *node, int level) 640 { 641 u_int32_t *ptr; 642 char *tmp, *value; 643 int cnt; 644 u_int32_t nameid, size; 645 646 ptr = (u_int32_t *)node; 647 648 if (!tree_inited) 649 return NULL; 650 651 if (betoh32(*ptr) != FDT_PROPERTY) 652 return ptr; /* should never happen */ 653 654 /* extract property name_id and size */ 655 size = betoh32(*++ptr); 656 nameid = betoh32(*++ptr); 657 658 for (cnt = 0; cnt < level; cnt++) 659 printf("\t"); 660 661 tmp = fdt_get_str(nameid); 662 printf("\t%s : ", tmp ? tmp : "NO_NAME"); 663 664 ptr++; 665 value = (char *)ptr; 666 667 if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") || 668 !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") || 669 !strcmp(tmp, "linux,stdout-path")) { 670 printf("%s", value); 671 } else if (!strcmp(tmp, "clock-frequency") || 672 !strcmp(tmp, "timebase-frequency")) { 673 printf("%d", betoh32(*((unsigned int *)value))); 674 } else { 675 for (cnt = 0; cnt < size; cnt++) { 676 if ((cnt % sizeof(u_int32_t)) == 0) 677 printf(" "); 678 printf("%02x", value[cnt]); 679 } 680 } 681 ptr += roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t); 682 printf("\n"); 683 684 return ptr; 685 } 686 687 void 688 fdt_print_node(void *node, int level) 689 { 690 u_int32_t *ptr; 691 int cnt; 692 693 ptr = (u_int32_t *)node; 694 695 if (betoh32(*ptr) != FDT_NODE_BEGIN) 696 return; 697 698 ptr++; 699 700 for (cnt = 0; cnt < level; cnt++) 701 printf("\t"); 702 printf("%s :\n", fdt_node_name(node)); 703 ptr = skip_node_name(ptr); 704 705 while (betoh32(*ptr) == FDT_PROPERTY) 706 ptr = fdt_print_property(ptr, level); 707 } 708 709 void 710 fdt_print_node_recurse(void *node, int level) 711 { 712 void *child; 713 714 fdt_print_node(node, level); 715 for (child = fdt_child_node(node); child; child = fdt_next_node(child)) 716 fdt_print_node_recurse(child, level + 1); 717 } 718 719 void 720 fdt_print_tree(void) 721 { 722 fdt_print_node_recurse(fdt_next_node(0), 0); 723 } 724 #endif 725 726 int 727 OF_peer(int handle) 728 { 729 void *node = (char *)tree.header + handle; 730 731 if (handle == 0) 732 node = fdt_find_node("/"); 733 else 734 node = fdt_next_node(node); 735 return node ? ((char *)node - (char *)tree.header) : 0; 736 } 737 738 int 739 OF_child(int handle) 740 { 741 void *node = (char *)tree.header + handle; 742 743 node = fdt_child_node(node); 744 return node ? ((char *)node - (char *)tree.header) : 0; 745 } 746 747 int 748 OF_parent(int handle) 749 { 750 void *node = (char *)tree.header + handle; 751 752 node = fdt_parent_node(node); 753 return node ? ((char *)node - (char *)tree.header) : 0; 754 } 755 756 int 757 OF_finddevice(char *name) 758 { 759 void *node; 760 761 node = fdt_find_node(name); 762 return node ? ((char *)node - (char *)tree.header) : -1; 763 } 764 765 int 766 OF_getnodebyname(int handle, const char *name) 767 { 768 void *node = (char *)tree.header + handle; 769 770 if (handle == 0) 771 node = fdt_find_node("/"); 772 773 while (node) { 774 if (strcmp(name, fdt_node_name(node)) == 0) 775 break; 776 777 node = fdt_next_node(node); 778 } 779 780 return node ? ((char *)node - (char *)tree.header) : 0; 781 } 782 783 int 784 OF_getnodebyphandle(uint32_t phandle) 785 { 786 void *node; 787 788 node = fdt_find_phandle(phandle); 789 return node ? ((char *)node - (char *)tree.header) : 0; 790 } 791 792 int 793 OF_getproplen(int handle, char *prop) 794 { 795 void *node = (char *)tree.header + handle; 796 char *data, *name; 797 int len; 798 799 len = fdt_node_property(node, prop, &data); 800 801 /* 802 * The "name" property is optional since version 16 of the 803 * flattened device tree specification, so we synthesize one 804 * from the unit name of the node if it is missing. 805 */ 806 if (len < 0 && strcmp(prop, "name") == 0) { 807 name = fdt_node_name(node); 808 data = strchr(name, '@'); 809 if (data) 810 len = data - name; 811 else 812 len = strlen(name); 813 return len + 1; 814 } 815 816 return len; 817 } 818 819 int 820 OF_getprop(int handle, char *prop, void *buf, int buflen) 821 { 822 void *node = (char *)tree.header + handle; 823 char *data; 824 int len; 825 826 len = fdt_node_property(node, prop, &data); 827 828 /* 829 * The "name" property is optional since version 16 of the 830 * flattened device tree specification, so we synthesize one 831 * from the unit name of the node if it is missing. 832 */ 833 if (len < 0 && strcmp(prop, "name") == 0) { 834 data = fdt_node_name(node); 835 if (data) { 836 len = strlcpy(buf, data, buflen); 837 data = strchr(buf, '@'); 838 if (data) { 839 *data = 0; 840 len = data - (char *)buf; 841 } 842 return len + 1; 843 } 844 } 845 846 if (len > 0) 847 memcpy(buf, data, min(len, buflen)); 848 return len; 849 } 850 851 uint32_t 852 OF_getpropint(int handle, char *prop, uint32_t defval) 853 { 854 uint32_t val; 855 int len; 856 857 len = OF_getprop(handle, prop, &val, sizeof(val)); 858 if (len != sizeof(val)) 859 return defval; 860 861 return betoh32(val); 862 } 863 864 int 865 OF_getpropintarray(int handle, char *prop, uint32_t *buf, int buflen) 866 { 867 int len; 868 int i; 869 870 len = OF_getprop(handle, prop, buf, buflen); 871 if (len < 0 || (len % sizeof(uint32_t))) 872 return -1; 873 874 for (i = 0; i < len / sizeof(uint32_t); i++) 875 buf[i] = betoh32(buf[i]); 876 877 return len; 878 } 879 880 int 881 OF_nextprop(int handle, char *prop, void *nextprop) 882 { 883 void *node = (char *)tree.header + handle; 884 char *data; 885 886 if (fdt_node_property(node, "name", &data) == -1) { 887 if (strcmp(prop, "") == 0) 888 return strlcpy(nextprop, "name", OPROMMAXPARAM); 889 if (strcmp(prop, "name") == 0) 890 prop = ""; 891 } 892 893 if (fdt_next_property(node, prop, &data)) 894 return strlcpy(nextprop, data, OPROMMAXPARAM); 895 return -1; 896 } 897 898 int 899 OF_is_compatible(int handle, const char *name) 900 { 901 void *node = (char *)tree.header + handle; 902 return (fdt_is_compatible(node, name)); 903 } 904 905