1 /* $OpenBSD: fdt.c,v 1.19 2016/08/23 18:12:09 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_reg(void *, struct fdt_reg *); 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 if (child == NULL) 414 return NULL; /* No match found. */ 415 416 p = q; 417 } 418 419 return node; 420 } 421 422 void * 423 fdt_parent_node_recurse(void *pnode, void *child) 424 { 425 void *node = fdt_child_node(pnode); 426 void *tmp; 427 428 while (node && (node != child)) { 429 if ((tmp = fdt_parent_node_recurse(node, child))) 430 return tmp; 431 node = fdt_next_node(node); 432 } 433 return (node) ? pnode : NULL; 434 } 435 436 void * 437 fdt_parent_node(void *node) 438 { 439 void *pnode = fdt_next_node(0); 440 441 if (!tree_inited) 442 return NULL; 443 444 if (node == pnode) 445 return NULL; 446 447 return fdt_parent_node_recurse(pnode, node); 448 } 449 450 void * 451 fdt_find_phandle_recurse(void *node, uint32_t phandle) 452 { 453 void *child; 454 char *data; 455 void *tmp; 456 int len; 457 458 len = fdt_node_property(node, "phandle", &data); 459 if (len < 0) 460 len = fdt_node_property(node, "linux,phandle", &data); 461 462 if (len == sizeof(uint32_t) && bemtoh32(data) == phandle) 463 return node; 464 465 for (child = fdt_child_node(node); child; child = fdt_next_node(child)) 466 if ((tmp = fdt_find_phandle_recurse(child, phandle))) 467 return tmp; 468 469 return NULL; 470 } 471 472 void * 473 fdt_find_phandle(uint32_t phandle) 474 { 475 return fdt_find_phandle_recurse(fdt_next_node(0), phandle); 476 } 477 478 /* 479 * Translate memory address depending on parent's range. 480 * 481 * Ranges are a way of mapping one address to another. This ranges attribute 482 * is set on a node's parent. This means if a node does not have a parent, 483 * there's nothing to translate. If it does have a parent and the parent does 484 * not have a ranges attribute, there's nothing to translate either. 485 * 486 * If the parent has a ranges attribute and the attribute is not empty, the 487 * node's memory address has to be in one of the given ranges. This range is 488 * then used to translate the memory address. 489 * 490 * If the parent has a ranges attribute, but the attribute is empty, there's 491 * nothing to translate. But it's not a translation barrier. It can be treated 492 * as a simple 1:1 mapping. 493 * 494 * Translation does not end here. We need to check if the parent's parent also 495 * has a ranges attribute and ask the same questions again. 496 */ 497 int 498 fdt_translate_reg(void *node, struct fdt_reg *reg) 499 { 500 void *parent; 501 int pac, psc, ac, sc, ret, rlen, rone, *range; 502 uint64_t from, to, size; 503 504 /* No parent, no translation. */ 505 parent = fdt_parent_node(node); 506 if (parent == NULL) 507 return 0; 508 509 /* Extract ranges property from node. */ 510 rlen = fdt_node_property(node, "ranges", (char **)&range) / sizeof(int); 511 512 /* No ranges means translation barrier. Translation stops here. */ 513 if (range == NULL) 514 return 0; 515 516 /* Empty ranges means 1:1 mapping. Continue translation on parent. */ 517 if (rlen <= 0) 518 return fdt_translate_reg(parent, reg); 519 520 /* We only support 32-bit (1), and 64-bit (2) wide addresses here. */ 521 ret = fdt_node_property_int(parent, "#address-cells", &pac); 522 if (ret != 1 || pac <= 0 || pac > 2) 523 return EINVAL; 524 525 /* We only support 32-bit (1), and 64-bit (2) wide sizes here. */ 526 ret = fdt_node_property_int(parent, "#size-cells", &psc); 527 if (ret != 1 || psc <= 0 || psc > 2) 528 return EINVAL; 529 530 /* We only support 32-bit (1), and 64-bit (2) wide addresses here. */ 531 ret = fdt_node_property_int(node, "#address-cells", &ac); 532 if (ret <= 0) 533 ac = pac; 534 else if (ret > 1 || ac <= 0 || ac > 2) 535 return EINVAL; 536 537 /* We only support 32-bit (1), and 64-bit (2) wide sizes here. */ 538 ret = fdt_node_property_int(node, "#size-cells", &sc); 539 if (ret <= 0) 540 sc = psc; 541 else if (ret > 1 || sc <= 0 || sc > 2) 542 return EINVAL; 543 544 /* Must have at least one range. */ 545 rone = pac + ac + sc; 546 if (rlen < rone) 547 return ESRCH; 548 549 /* For each range. */ 550 for (; rlen >= rone; rlen -= rone, range += rone) { 551 /* Extract from and size, so we can see if we fit. */ 552 from = betoh32(range[0]); 553 if (ac == 2) 554 from = (from << 32) + betoh32(range[1]); 555 size = betoh32(range[ac + pac]); 556 if (sc == 2) 557 size = (size << 32) + betoh32(range[ac + pac + 1]); 558 559 /* Try next, if we're not in the range. */ 560 if (reg->addr < from || (reg->addr + reg->size) > (from + size)) 561 continue; 562 563 /* All good, extract to address and translate. */ 564 to = betoh32(range[ac]); 565 if (pac == 2) 566 to = (to << 32) + betoh32(range[ac + 1]); 567 568 reg->addr -= from; 569 reg->addr += to; 570 return fdt_translate_reg(parent, reg); 571 } 572 573 /* To be successful, we must have returned in the for-loop. */ 574 return ESRCH; 575 } 576 577 /* 578 * Parse the memory address and size of a node. 579 */ 580 int 581 fdt_get_reg(void *node, int idx, struct fdt_reg *reg) 582 { 583 void *parent; 584 int ac, sc, off, ret, *in, inlen; 585 586 if (node == NULL || reg == NULL) 587 return EINVAL; 588 589 parent = fdt_parent_node(node); 590 if (parent == NULL) 591 return EINVAL; 592 593 /* We only support 32-bit (1), and 64-bit (2) wide addresses here. */ 594 ret = fdt_node_property_int(parent, "#address-cells", &ac); 595 if (ret != 1 || ac <= 0 || ac > 2) 596 return EINVAL; 597 598 /* We only support 32-bit (1), and 64-bit (2) wide sizes here. */ 599 ret = fdt_node_property_int(parent, "#size-cells", &sc); 600 if (ret != 1 || sc <= 0 || sc > 2) 601 return EINVAL; 602 603 inlen = fdt_node_property(node, "reg", (char **)&in) / sizeof(int); 604 if (inlen < ((idx + 1) * (ac + sc))) 605 return EINVAL; 606 607 off = idx * (ac + sc); 608 609 reg->addr = betoh32(in[off]); 610 if (ac == 2) 611 reg->addr = (reg->addr << 32) + betoh32(in[off + 1]); 612 613 reg->size = betoh32(in[off + ac]); 614 if (sc == 2) 615 reg->size = (reg->size << 32) + betoh32(in[off + ac + 1]); 616 617 return fdt_translate_reg(parent, reg); 618 } 619 620 int 621 fdt_is_compatible(void *node, const char *name) 622 { 623 char *data; 624 int len; 625 626 len = fdt_node_property(node, "compatible", &data); 627 while (len > 0) { 628 if (strcmp(data, name) == 0) 629 return 1; 630 len -= strlen(data) + 1; 631 data += strlen(data) + 1; 632 } 633 634 return 0; 635 } 636 637 #ifdef DEBUG 638 /* 639 * Debug methods for printing whole tree, particular odes and properies 640 */ 641 void * 642 fdt_print_property(void *node, int level) 643 { 644 u_int32_t *ptr; 645 char *tmp, *value; 646 int cnt; 647 u_int32_t nameid, size; 648 649 ptr = (u_int32_t *)node; 650 651 if (!tree_inited) 652 return NULL; 653 654 if (betoh32(*ptr) != FDT_PROPERTY) 655 return ptr; /* should never happen */ 656 657 /* extract property name_id and size */ 658 size = betoh32(*++ptr); 659 nameid = betoh32(*++ptr); 660 661 for (cnt = 0; cnt < level; cnt++) 662 printf("\t"); 663 664 tmp = fdt_get_str(nameid); 665 printf("\t%s : ", tmp ? tmp : "NO_NAME"); 666 667 ptr++; 668 value = (char *)ptr; 669 670 if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") || 671 !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") || 672 !strcmp(tmp, "linux,stdout-path")) { 673 printf("%s", value); 674 } else if (!strcmp(tmp, "clock-frequency") || 675 !strcmp(tmp, "timebase-frequency")) { 676 printf("%d", betoh32(*((unsigned int *)value))); 677 } else { 678 for (cnt = 0; cnt < size; cnt++) { 679 if ((cnt % sizeof(u_int32_t)) == 0) 680 printf(" "); 681 printf("%02x", value[cnt]); 682 } 683 } 684 ptr += roundup(size, sizeof(u_int32_t)) / sizeof(u_int32_t); 685 printf("\n"); 686 687 return ptr; 688 } 689 690 void 691 fdt_print_node(void *node, int level) 692 { 693 u_int32_t *ptr; 694 int cnt; 695 696 ptr = (u_int32_t *)node; 697 698 if (betoh32(*ptr) != FDT_NODE_BEGIN) 699 return; 700 701 ptr++; 702 703 for (cnt = 0; cnt < level; cnt++) 704 printf("\t"); 705 printf("%s :\n", fdt_node_name(node)); 706 ptr = skip_node_name(ptr); 707 708 while (betoh32(*ptr) == FDT_PROPERTY) 709 ptr = fdt_print_property(ptr, level); 710 } 711 712 void 713 fdt_print_node_recurse(void *node, int level) 714 { 715 void *child; 716 717 fdt_print_node(node, level); 718 for (child = fdt_child_node(node); child; child = fdt_next_node(child)) 719 fdt_print_node_recurse(child, level + 1); 720 } 721 722 void 723 fdt_print_tree(void) 724 { 725 fdt_print_node_recurse(fdt_next_node(0), 0); 726 } 727 #endif 728 729 int 730 OF_peer(int handle) 731 { 732 void *node = (char *)tree.header + handle; 733 734 if (handle == 0) 735 node = fdt_find_node("/"); 736 else 737 node = fdt_next_node(node); 738 return node ? ((char *)node - (char *)tree.header) : 0; 739 } 740 741 int 742 OF_child(int handle) 743 { 744 void *node = (char *)tree.header + handle; 745 746 node = fdt_child_node(node); 747 return node ? ((char *)node - (char *)tree.header) : 0; 748 } 749 750 int 751 OF_parent(int handle) 752 { 753 void *node = (char *)tree.header + handle; 754 755 node = fdt_parent_node(node); 756 return node ? ((char *)node - (char *)tree.header) : 0; 757 } 758 759 int 760 OF_finddevice(char *name) 761 { 762 void *node; 763 764 node = fdt_find_node(name); 765 return node ? ((char *)node - (char *)tree.header) : -1; 766 } 767 768 int 769 OF_getnodebyname(int handle, const char *name) 770 { 771 void *node = (char *)tree.header + handle; 772 773 if (handle == 0) 774 node = fdt_find_node("/"); 775 776 while (node) { 777 if (strcmp(name, fdt_node_name(node)) == 0) 778 break; 779 780 node = fdt_next_node(node); 781 } 782 783 return node ? ((char *)node - (char *)tree.header) : 0; 784 } 785 786 int 787 OF_getnodebyphandle(uint32_t phandle) 788 { 789 void *node; 790 791 node = fdt_find_phandle(phandle); 792 return node ? ((char *)node - (char *)tree.header) : 0; 793 } 794 795 int 796 OF_getproplen(int handle, char *prop) 797 { 798 void *node = (char *)tree.header + handle; 799 char *data, *name; 800 int len; 801 802 len = fdt_node_property(node, prop, &data); 803 804 /* 805 * The "name" property is optional since version 16 of the 806 * flattened device tree specification, so we synthesize one 807 * from the unit name of the node if it is missing. 808 */ 809 if (len < 0 && strcmp(prop, "name") == 0) { 810 name = fdt_node_name(node); 811 data = strchr(name, '@'); 812 if (data) 813 len = data - name; 814 else 815 len = strlen(name); 816 return len + 1; 817 } 818 819 return len; 820 } 821 822 int 823 OF_getprop(int handle, char *prop, void *buf, int buflen) 824 { 825 void *node = (char *)tree.header + handle; 826 char *data; 827 int len; 828 829 len = fdt_node_property(node, prop, &data); 830 831 /* 832 * The "name" property is optional since version 16 of the 833 * flattened device tree specification, so we synthesize one 834 * from the unit name of the node if it is missing. 835 */ 836 if (len < 0 && strcmp(prop, "name") == 0) { 837 data = fdt_node_name(node); 838 if (data) { 839 len = strlcpy(buf, data, buflen); 840 data = strchr(buf, '@'); 841 if (data) { 842 *data = 0; 843 len = data - (char *)buf; 844 } 845 return len + 1; 846 } 847 } 848 849 if (len > 0) 850 memcpy(buf, data, min(len, buflen)); 851 return len; 852 } 853 854 uint32_t 855 OF_getpropint(int handle, char *prop, uint32_t defval) 856 { 857 uint32_t val; 858 int len; 859 860 len = OF_getprop(handle, prop, &val, sizeof(val)); 861 if (len != sizeof(val)) 862 return defval; 863 864 return betoh32(val); 865 } 866 867 int 868 OF_getpropintarray(int handle, char *prop, uint32_t *buf, int buflen) 869 { 870 int len; 871 int i; 872 873 len = OF_getprop(handle, prop, buf, buflen); 874 if (len < 0 || (len % sizeof(uint32_t))) 875 return -1; 876 877 for (i = 0; i < len / sizeof(uint32_t); i++) 878 buf[i] = betoh32(buf[i]); 879 880 return len; 881 } 882 883 int 884 OF_nextprop(int handle, char *prop, void *nextprop) 885 { 886 void *node = (char *)tree.header + handle; 887 char *data; 888 889 if (fdt_node_property(node, "name", &data) == -1) { 890 if (strcmp(prop, "") == 0) 891 return strlcpy(nextprop, "name", OPROMMAXPARAM); 892 if (strcmp(prop, "name") == 0) 893 prop = ""; 894 } 895 896 if (fdt_next_property(node, prop, &data)) 897 return strlcpy(nextprop, data, OPROMMAXPARAM); 898 return -1; 899 } 900 901 int 902 OF_is_compatible(int handle, const char *name) 903 { 904 void *node = (char *)tree.header + handle; 905 return (fdt_is_compatible(node, name)); 906 } 907 908