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