1 /* $NetBSD: ofctl.c,v 1.15 2020/06/06 22:33:23 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 34 #ifndef lint 35 __COPYRIGHT("@(#) Copyright (c) 2006, 2007\ 36 The NetBSD Foundation, Inc. All rights reserved."); 37 __RCSID("$NetBSD: ofctl.c,v 1.15 2020/06/06 22:33:23 thorpej Exp $"); 38 #endif /* not lint */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 #include <errno.h> 44 #include <ctype.h> 45 #include <string.h> 46 #include <assert.h> 47 #include <err.h> 48 #include <sys/types.h> 49 #include <sys/ioctl.h> 50 #include <sys/file.h> 51 #include <sys/queue.h> 52 #include <dev/ofw/openfirmio.h> 53 54 #include <prop/proplib.h> 55 56 static void oflist(int, const char *, int, void *, size_t); 57 static void ofprop(int); 58 static void ofgetprop(int, const char *); 59 #if 0 60 static int isstrprint(const char *, size_t, int); 61 #endif 62 63 static int lflag; 64 static int pflag; 65 static int vflag; 66 67 struct of_node { 68 TAILQ_ENTRY(of_node) of_sibling; 69 TAILQ_HEAD(,of_node) of_children; 70 TAILQ_HEAD(,of_prop) of_properties; 71 struct of_node *of_parent; 72 struct of_prop *of_name; 73 struct of_prop *of_device_type; 74 struct of_prop *of_reg; 75 int of_nodeid; 76 }; 77 78 struct of_prop { 79 TAILQ_ENTRY(of_prop) prop_sibling; 80 char *prop_name; 81 u_int8_t *prop_data; 82 size_t prop_length; 83 size_t prop_namelen; 84 }; 85 86 struct of_node of_root; 87 unsigned long of_node_count; 88 unsigned long of_prop_count; 89 prop_dictionary_t of_proplib; 90 91 int OF_parent(int); 92 int OF_child(int); 93 int OF_peer(int); 94 int OF_finddevice(const char *); 95 int OF_getproplen(int, const char *); 96 int OF_getprop(int, const char *, void *, size_t); 97 int OF_nextprop(int, const char *, void *); 98 99 struct of_prop *of_tree_getprop(int, const char *); 100 101 static int of_fd = -1; 102 103 static void 104 of_tree_mkprop(struct of_node *node, prop_dictionary_t propdict, 105 prop_dictionary_keysym_t key) 106 { 107 struct of_prop *prop; 108 prop_data_t obj; 109 const char *name; 110 111 name = prop_dictionary_keysym_value(key); 112 obj = prop_dictionary_get_keysym(propdict, key); 113 114 prop = malloc(sizeof(*prop) + strlen(name) + 1); 115 if (prop == NULL) 116 err(1, "malloc(%zu)", sizeof(*prop) + strlen(name) + 1); 117 118 memset(prop, 0, sizeof(*prop)); 119 prop->prop_name = (char *) (prop + 1); 120 prop->prop_namelen = strlen(name); 121 memcpy(prop->prop_name, name, prop->prop_namelen+1); 122 TAILQ_INSERT_TAIL(&node->of_properties, prop, prop_sibling); 123 124 if (!strcmp(name, "name")) 125 node->of_name = prop; 126 else if (!strcmp(name, "device_type")) 127 node->of_device_type = prop; 128 else if (!strcmp(name, "reg")) 129 node->of_reg = prop; 130 131 of_prop_count++; 132 133 prop->prop_length = prop_data_size(obj); 134 if (prop->prop_length) { 135 prop->prop_data = malloc(prop->prop_length); 136 prop_data_copy_value(obj, prop->prop_data, prop->prop_length); 137 } 138 } 139 140 static struct of_node * 141 of_tree_mknode(struct of_node *parent) 142 { 143 struct of_node *newnode; 144 newnode = malloc(sizeof(*newnode)); 145 if (newnode == NULL) 146 err(1, "malloc(%zu)", sizeof(*newnode)); 147 148 of_node_count++; 149 150 memset(newnode, 0, sizeof(*newnode)); 151 TAILQ_INIT(&newnode->of_children); 152 TAILQ_INIT(&newnode->of_properties); 153 newnode->of_parent = parent; 154 155 TAILQ_INSERT_TAIL(&parent->of_children, newnode, of_sibling); 156 157 return newnode; 158 } 159 160 static void 161 of_tree_fill(prop_dictionary_t dict, struct of_node *node) 162 { 163 prop_dictionary_t propdict; 164 prop_array_t propkeys; 165 prop_array_t children; 166 unsigned int i, count; 167 168 node->of_nodeid = prop_number_unsigned_value( 169 prop_dictionary_get(dict, "node")); 170 171 propdict = prop_dictionary_get(dict, "properties"); 172 propkeys = prop_dictionary_all_keys(propdict); 173 count = prop_array_count(propkeys); 174 175 for (i = 0; i < count; i++) 176 of_tree_mkprop(node, propdict, prop_array_get(propkeys, i)); 177 178 children = prop_dictionary_get(dict, "children"); 179 if (children) { 180 count = prop_array_count(children); 181 182 for (i = 0; i < count; i++) { 183 of_tree_fill( 184 prop_array_get(children, i), 185 of_tree_mknode(node)); 186 } 187 } 188 } 189 190 static void 191 of_tree_init(prop_dictionary_t dict) 192 { 193 /* 194 * Initialize the root node of the OFW tree. 195 */ 196 TAILQ_INIT(&of_root.of_children); 197 TAILQ_INIT(&of_root.of_properties); 198 199 of_tree_fill(dict, &of_root); 200 } 201 202 static prop_object_t 203 of_proplib_mkprop(int fd, int nodeid, char *name) 204 { 205 struct ofiocdesc ofio; 206 prop_object_t obj; 207 208 ofio.of_nodeid = nodeid; 209 ofio.of_name = name; 210 ofio.of_namelen = strlen(name); 211 ofio.of_buf = NULL; 212 ofio.of_buflen = 32; 213 214 again: 215 if (ofio.of_buf != NULL) 216 free(ofio.of_buf); 217 ofio.of_buf = malloc(ofio.of_buflen); 218 if (ofio.of_buf == NULL) 219 err(1, "malloc(%d)", ofio.of_buflen); 220 if (ioctl(fd, OFIOCGET, &ofio) < 0) { 221 if (errno == ENOMEM) { 222 ofio.of_buflen *= 2; 223 goto again; 224 } 225 warn("OFIOCGET(%d, \"%s\")", fd, name); 226 free(ofio.of_buf); 227 return NULL; 228 } 229 obj = prop_data_create_copy(ofio.of_buf, ofio.of_buflen); 230 free(ofio.of_buf); 231 return obj; 232 } 233 234 static prop_dictionary_t 235 of_proplib_tree_fill(int fd, int nodeid) 236 { 237 int childid = nodeid; 238 struct ofiocdesc ofio; 239 char namebuf[33]; 240 char newnamebuf[33]; 241 prop_array_t children; 242 prop_dictionary_t dict, propdict; 243 prop_object_t obj; 244 245 ofio.of_nodeid = nodeid; 246 ofio.of_name = namebuf; 247 ofio.of_namelen = 1; 248 ofio.of_buf = newnamebuf; 249 250 namebuf[0] = '\0'; 251 252 dict = prop_dictionary_create(); 253 prop_dictionary_set(dict, "node", 254 prop_number_create_unsigned(nodeid)); 255 256 propdict = prop_dictionary_create(); 257 for (;;) { 258 ofio.of_buflen = sizeof(newnamebuf); 259 260 if (ioctl(fd, OFIOCNEXTPROP, &ofio) < 0) { 261 if (errno == ENOENT) 262 break; 263 err(1, "OFIOCNEXTPROP(%d, %#x, \"%s\")", fd, 264 ofio.of_nodeid, ofio.of_name); 265 } 266 267 ofio.of_namelen = ofio.of_buflen; 268 if (ofio.of_namelen == 0) 269 break; 270 newnamebuf[ofio.of_buflen] = '\0'; 271 strcpy(namebuf, newnamebuf); 272 obj = of_proplib_mkprop(fd, nodeid, namebuf); 273 if (obj) 274 prop_dictionary_set(propdict, namebuf, obj); 275 } 276 prop_dictionary_set(dict, "properties", propdict); 277 278 if (ioctl(fd, OFIOCGETCHILD, &childid) < 0) 279 err(1, "OFIOCGETCHILD(%d, %#x)", fd, childid); 280 281 children = NULL; 282 while (childid != 0) { 283 if (children == NULL) 284 children = prop_array_create(); 285 prop_array_add(children, of_proplib_tree_fill(fd, childid)); 286 if (ioctl(fd, OFIOCGETNEXT, &childid) < 0) 287 err(1, "OFIOCGETNEXT(%d, %#x)", fd, childid); 288 } 289 if (children != NULL) { 290 prop_array_make_immutable(children); 291 prop_dictionary_set(dict, "children", children); 292 } 293 294 return dict; 295 } 296 297 static prop_dictionary_t 298 of_proplib_init(const char *file) 299 { 300 prop_dictionary_t dict; 301 int rootid = 0; 302 int fd; 303 304 fd = open(file, O_RDONLY); 305 if (fd < 0) 306 err(1, "%s", file); 307 308 if (ioctl(fd, OFIOCGETNEXT, &rootid) < 0) 309 err(1, "OFIOCGETNEXT(%d, %#x)", fd, rootid); 310 311 dict = of_proplib_tree_fill(fd, rootid); 312 313 /* keep the device open for the benefit of OF_finddevice */ 314 of_fd = fd; 315 316 return dict; 317 } 318 319 static struct of_node * 320 of_tree_walk(struct of_node *node, 321 struct of_node *(*fn)(struct of_node *, const void *), 322 const void *ctx) 323 { 324 struct of_node *child, *match; 325 326 if ((match = (*fn)(node, ctx)) != NULL) 327 return match; 328 329 TAILQ_FOREACH(child, &node->of_children, of_sibling) { 330 if ((match = of_tree_walk(child, fn, ctx)) != NULL) 331 return match; 332 } 333 return NULL; 334 } 335 336 static struct of_node * 337 of_match_by_nodeid(struct of_node *node, const void *ctx) 338 { 339 return (node->of_nodeid == *(const int *) ctx) ? node : NULL; 340 } 341 342 static struct of_node * 343 of_match_by_parentid(struct of_node *node, const void *ctx) 344 { 345 if (node->of_parent == NULL) 346 return NULL; 347 return (node->of_parent->of_nodeid == *(const int *) ctx) ? node : NULL; 348 } 349 350 int 351 OF_parent(int childid) 352 { 353 struct of_node *child; 354 355 if (childid == 0) 356 return 0; 357 358 child = of_tree_walk(&of_root, of_match_by_nodeid, &childid); 359 if (child == NULL || child->of_parent == NULL) 360 return 0; 361 return child->of_parent->of_nodeid; 362 } 363 364 int 365 OF_child(int parentid) 366 { 367 struct of_node *child; 368 369 child = of_tree_walk(&of_root, of_match_by_parentid, &parentid); 370 if (child == NULL) 371 return 0; 372 return child->of_nodeid; 373 } 374 375 int 376 OF_peer(int peerid) 377 { 378 struct of_node *node, *match; 379 380 if (peerid == 0) 381 return of_root.of_nodeid; 382 383 node = of_tree_walk(&of_root, of_match_by_nodeid, &peerid); 384 if (node == NULL || node->of_parent == NULL) 385 return 0; 386 387 /* 388 * The peer should be our next sibling (if one exists). 389 */ 390 match = TAILQ_NEXT(node, of_sibling); 391 return (match != NULL) ? match->of_nodeid : 0; 392 } 393 394 int 395 OF_finddevice(const char *name) 396 { 397 struct ofiocdesc ofio; 398 399 ofio.of_nodeid = 0; 400 ofio.of_name = __UNCONST(name); 401 ofio.of_namelen = strlen(name); 402 ofio.of_buf = NULL; 403 ofio.of_buflen = 0; 404 if (ioctl(of_fd, OFIOCFINDDEVICE, &ofio) < 0) { 405 if (errno == ENOENT) { 406 err(1, "OF node '%s' not found", name); 407 } else { 408 err(1, "OFIOCFINDDEVICE(%d, \"%s\")", of_fd, name); 409 } 410 } 411 412 return ofio.of_nodeid; 413 } 414 415 struct of_prop * 416 of_tree_getprop(int nodeid, const char *name) 417 { 418 struct of_node *node; 419 struct of_prop *prop; 420 421 if (nodeid == 0) 422 return 0; 423 424 node = of_tree_walk(&of_root, of_match_by_nodeid, &nodeid); 425 if (node == NULL) 426 return NULL; 427 428 if (name[0] == '\0') 429 return TAILQ_FIRST(&node->of_properties); 430 431 if (!strcmp(name, "name")) 432 return node->of_name; 433 if (!strcmp(name, "device_type")) 434 return node->of_device_type; 435 if (!strcmp(name, "reg")) 436 return node->of_reg; 437 438 TAILQ_FOREACH(prop, &node->of_properties, prop_sibling) { 439 if (!strcmp(name, prop->prop_name)) 440 break; 441 } 442 return prop; 443 } 444 445 int 446 OF_getproplen(int nodeid, const char *name) 447 { 448 struct of_prop *prop = of_tree_getprop(nodeid, name); 449 return (prop != NULL) ? (int)prop->prop_length : -1; 450 } 451 452 int 453 OF_getprop(int nodeid, const char *name, void *buf, size_t len) 454 { 455 struct of_prop *prop = of_tree_getprop(nodeid, name); 456 if (prop == NULL) 457 return -1; 458 if (len > prop->prop_length) 459 len = prop->prop_length; 460 memcpy(buf, prop->prop_data, len); 461 return len; 462 } 463 464 int 465 OF_nextprop(int nodeid, const char *name, void *nextname) 466 { 467 struct of_prop *prop = of_tree_getprop(nodeid, name); 468 if (prop == NULL) 469 return -1; 470 if (name[0] != '\0') { 471 prop = TAILQ_NEXT(prop, prop_sibling); 472 if (prop == NULL) 473 return -1; 474 } 475 strcpy(nextname, prop->prop_name); 476 return strlen(prop->prop_name); 477 } 478 479 static u_int32_t 480 of_decode_int(const u_int8_t *p) 481 { 482 return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; 483 } 484 485 /* 486 * Now we start the real program 487 */ 488 489 int 490 main(int argc, char **argv) 491 { 492 u_long of_buf[256]; 493 char device_type[33]; 494 int phandle; 495 int errflag = 0; 496 int c; 497 int len; 498 #if defined(__sparc__) || defined(__sparc64__) 499 const char *file = "/dev/openprom"; 500 #else 501 const char *file = "/dev/openfirm"; 502 #endif 503 const char *propfilein = NULL; 504 const char *propfileout = NULL; 505 506 while ((c = getopt(argc, argv, "f:lpr:vw:")) != EOF) { 507 switch (c) { 508 case 'l': lflag++; break; 509 case 'p': pflag++; break; 510 case 'v': vflag++; break; 511 case 'f': file = optarg; break; 512 case 'r': propfilein = optarg; break; 513 case 'w': propfileout = optarg; break; 514 default: errflag++; break; 515 } 516 } 517 if (errflag) 518 errx(1, "usage: ofctl [-lpv] [-f file] [-r propfile] [-w propfile] [node...]"); 519 520 if (propfilein != NULL) { 521 of_proplib = prop_dictionary_internalize_from_file(propfilein); 522 } else { 523 of_proplib = of_proplib_init(file); 524 } 525 526 if (propfileout) 527 prop_dictionary_externalize_to_file(of_proplib, propfileout); 528 529 of_tree_init(of_proplib); 530 printf("[Caching %lu nodes and %lu properties]\n", 531 of_node_count, of_prop_count); 532 533 if (argc == optind) { 534 phandle = OF_peer(0); 535 device_type[0] = '\0'; 536 len = OF_getprop(phandle, "device_type", device_type, 537 sizeof(device_type)); 538 if (len <= 0) 539 len = OF_getprop(phandle, "name", device_type, 540 sizeof(device_type)); 541 if (len >= 0) 542 device_type[len] = '\0'; 543 oflist(phandle, device_type, 0, of_buf, sizeof(of_buf)); 544 } else { 545 phandle = OF_finddevice(argv[optind++]); 546 device_type[0] = '\0'; 547 len = OF_getprop(phandle, "device_type", device_type, 548 sizeof(device_type)); 549 if (len <= 0) 550 len = OF_getprop(phandle, "name", device_type, 551 sizeof(device_type)); 552 if (len >= 0) 553 device_type[len] = '\0'; 554 555 if (argc == optind) { 556 if (lflag) 557 oflist(phandle, device_type, 0, of_buf, sizeof(of_buf)); 558 else 559 ofprop(phandle); 560 } else { 561 for (; optind < argc; optind++) { 562 ofgetprop(phandle, argv[optind]); 563 } 564 } 565 } 566 exit(0); 567 } 568 569 static size_t 570 ofname(int node, char *buf, size_t buflen) 571 { 572 u_int8_t address_cells_buf[4]; 573 u_int8_t reg_buf[4096]; 574 char name[33]; 575 char device_type[33]; 576 size_t off = 0; 577 int parent = OF_parent(node); 578 int reglen; 579 int reg[sizeof(reg_buf)/sizeof(int)]; 580 int address_cells; 581 int len; 582 583 len = OF_getprop(node, "name", name, sizeof(name)); 584 if (len <= 0) 585 name[0] = '\0'; 586 off += snprintf(buf + off, buflen - off, "/%s", name); 587 588 reglen = OF_getprop(node, "reg", reg_buf, sizeof(reg_buf)); 589 if (reglen <= 0) 590 return off; 591 592 len = OF_getprop(parent, "device_type", 593 device_type, sizeof(device_type)); 594 if (len <= 0) 595 len = OF_getprop(parent, "name", 596 device_type, sizeof(device_type)); 597 device_type[len] = '\0'; 598 599 for (;;) { 600 len = OF_getprop(parent, "#address-cells", 601 address_cells_buf, sizeof(address_cells_buf)); 602 if (len >= 0) { 603 assert(len == 4); 604 break; 605 } 606 parent = OF_parent(parent); 607 if (parent == 0) 608 break; 609 } 610 611 if (parent == 0) { 612 613 parent = OF_parent(node); 614 615 for (;;) { 616 len = OF_getprop(parent, "#size-cells", 617 address_cells_buf, sizeof(address_cells_buf)); 618 if (len >= 0) { 619 assert(len == 4); 620 break; 621 } 622 parent = OF_parent(parent); 623 if (parent == 0) 624 break; 625 } 626 /* no #size-cells */ 627 len = 0; 628 } 629 630 if (len == 0) { 631 /* looks like we're on an OBP2 system */ 632 if (reglen > 12) 633 return off; 634 off += snprintf(buf + off, buflen - off, "@"); 635 memcpy(reg, reg_buf, 8); 636 off += snprintf(buf + off, buflen - off, "%x,%x", reg[0], 637 reg[1]); 638 return off; 639 } 640 641 off += snprintf(buf + off, buflen - off, "@"); 642 address_cells = of_decode_int(address_cells_buf); 643 for (len = 0; len < address_cells; len ++) 644 reg[len] = of_decode_int(®_buf[len * 4]); 645 646 if (!strcmp(device_type,"pci")) { 647 off += snprintf(buf + off, buflen - off, 648 "%x", (reg[0] >> 11) & 31); 649 if (reg[0] & 0x700) 650 off += snprintf(buf + off, buflen - off, 651 ",%x", (reg[0] >> 8) & 7); 652 } else if (!strcmp(device_type,"upa")) { 653 off += snprintf(buf + off, buflen - off, 654 "%x", (reg[0] >> 4) & 63); 655 for (len = 1; len < address_cells; len++) 656 off += snprintf(buf + off, buflen - off, 657 ",%x", reg[len]); 658 #if !defined(__sparc__) && !defined(__sparc64__) 659 } else if (!strcmp(device_type,"isa")) { 660 #endif 661 } else { 662 off += snprintf(buf + off, buflen - off, "%x", reg[0]); 663 for (len = 1; len < address_cells; len++) 664 off += snprintf(buf + off, buflen - off, 665 ",%x", reg[len]); 666 } 667 return off; 668 } 669 670 static size_t 671 offullname2(int node, char *buf, size_t len) 672 { 673 size_t off; 674 int parent = OF_parent(node); 675 if (parent == 0) 676 return 0; 677 678 off = offullname2(parent, buf, len); 679 off += ofname(node, buf + off, len - off); 680 return off; 681 } 682 683 static size_t 684 offullname(int node, char *buf, size_t len) 685 { 686 if (node == OF_peer(0)) { 687 size_t off = snprintf(buf, len, "/"); 688 off += OF_getprop(node, "name", buf + off, len - off); 689 return off; 690 } 691 return offullname2(node, buf, len); 692 } 693 694 static void 695 oflist(int node, const char *parent_device_type, int depth, 696 void *of_buf, size_t of_buflen) 697 { 698 int len; 699 while (node != 0) { 700 int child; 701 if (pflag == 0 && vflag == 0) { 702 len = ofname(node, of_buf, of_buflen-1); 703 printf("%08x: %*s%s", node, depth * 2, "", 704 (char *) of_buf); 705 } else { 706 len = offullname(node, of_buf, of_buflen-1); 707 printf("%08x: %s", node, (char *) of_buf); 708 } 709 putchar('\n'); 710 if (pflag) { 711 putchar('\n'); 712 ofprop(node); 713 puts("\n----------------------------------------" 714 "----------------------------------------\n\n"); 715 } 716 child = OF_child(node); 717 if (child != -1 && child != 0) { 718 char device_type[33]; 719 len = OF_getprop(node, "device_type", 720 device_type, sizeof(device_type)); 721 if (len <= 0) 722 len = OF_getprop(node, "name", 723 device_type, sizeof(device_type)); 724 if (len >= 0) 725 device_type[len] = '\0'; 726 depth++; 727 oflist(child, device_type, depth, of_buf, of_buflen); 728 depth--; 729 } 730 if (depth == 0) 731 break; 732 node = OF_peer(node); 733 } 734 } 735 736 static void 737 print_line(const u_int8_t *buf, size_t off, size_t len) 738 { 739 if (len - off > 16) 740 len = off + 16; 741 742 for (; off < ((len + 15) & ~15); off++) { 743 if (off > 0) { 744 if ((off & 15) == 0) 745 printf("%12s%04lx:%7s", "", 746 (unsigned long int) off, ""); 747 else if ((off & 3) == 0) 748 putchar(' '); 749 } 750 if (off < len) 751 printf("%02x", buf[off]); 752 #if 0 753 else if (off >= ((len + 3) & ~3)) 754 printf(" "); 755 #endif 756 else 757 printf(".."); 758 } 759 } 760 761 static void 762 default_format(int node, const u_int8_t *buf, size_t len) 763 { 764 size_t off = 0; 765 while (off < len) { 766 size_t end; 767 print_line(buf, off, len); 768 printf(" "); /* 24 + 32 + 3 = 59, so +3 makes 62 */ 769 end = len; 770 if (end > off + 16) 771 end = off + 16; 772 for (; off < end; off++) { 773 char ch = buf[off]; 774 if (isascii(ch) && 775 (isalnum((int)ch) || ispunct((int)ch) || ch == ' ')) 776 putchar(ch); 777 else 778 putchar('.'); 779 } 780 putchar('\n'); 781 } 782 } 783 784 static void 785 reg_format(int node, const u_int8_t *buf, size_t len) 786 { 787 /* parent = OF_parent(node); */ 788 default_format(node, buf, len); 789 } 790 791 static void 792 frequency_format(int node, const u_int8_t *buf, size_t len) 793 { 794 if (len == 4) { 795 u_int32_t freq = of_decode_int(buf); 796 u_int32_t divisor, whole, frac; 797 const char *units = ""; 798 print_line(buf, 0, len); 799 for (divisor = 1000000000; divisor > 1; divisor /= 1000) { 800 if (freq >= divisor) 801 break; 802 } 803 whole = freq / divisor; 804 if (divisor == 1) 805 frac = 0; 806 else 807 frac = (freq / (divisor / 1000)) % 1000; 808 809 switch (divisor) { 810 case 1000000000: units = "GHz"; break; 811 case 1000000: units = "MHz"; break; 812 case 1000: units = "KHz"; break; 813 case 1: units = "Hz"; break; 814 } 815 if (frac > 0) 816 printf(" %u.%03u%s\n", whole, frac, units); 817 else 818 printf(" %u%s\n", whole, units); 819 } else 820 default_format(node, buf, len); 821 } 822 823 static void 824 size_format(int node, const u_int8_t *buf, size_t len) 825 { 826 if (len == 4) { 827 u_int32_t freq = of_decode_int(buf); 828 u_int32_t divisor, whole, frac; 829 const char *units = ""; 830 print_line(buf, 0, len); 831 for (divisor = 0x40000000; divisor > 1; divisor >>= 10) { 832 if (freq >= divisor) 833 break; 834 } 835 whole = freq / divisor; 836 if (divisor == 1) 837 frac = 0; 838 else 839 frac = (freq / (divisor >> 10)) & 1023; 840 841 switch (divisor) { 842 case 0x40000000: units = "G"; break; 843 case 0x100000: units = "M"; break; 844 case 0x400: units = "K"; break; 845 case 1: units = ""; break; 846 } 847 if (frac > 0) 848 printf(" %3u.%03u%s\n", whole, frac, units); 849 else 850 printf(" %3u%s\n", whole, units); 851 } else 852 default_format(node, buf, len); 853 } 854 855 static void 856 string_format(int node, const u_int8_t *buf, size_t len) 857 { 858 size_t off = 0; 859 int first_line = 1; 860 while (off < len) { 861 size_t string_len = 0; 862 int leading = 1; 863 for (; off + string_len < len; string_len++) { 864 if (buf[off+string_len] == '\0') { 865 string_len++; 866 break; 867 } 868 } 869 while (string_len > 0) { 870 size_t line_len = string_len; 871 if (line_len > 16) 872 line_len = 16; 873 if (!first_line) 874 printf("%12s%04lx:%7s", "", 875 (unsigned long int) off, ""); 876 print_line(buf + off, 0, line_len); 877 printf(" "); 878 if (leading) 879 putchar('"'); 880 first_line = 0; 881 leading = 0; 882 string_len -= line_len; 883 for (; line_len > 0; line_len--, off++) { 884 if (buf[off] != '\0') 885 putchar(buf[off]); 886 } 887 if (string_len == 0) 888 putchar('"'); 889 putchar('\n'); 890 } 891 } 892 } 893 894 static const struct { 895 const char *prop_name; 896 void (*prop_format)(int, const u_int8_t *, size_t); 897 } formatters[] = { 898 { "reg", reg_format }, 899 #if 0 900 { "assigned-addresses", assigned_addresses_format }, 901 { "ranges", ranges_format }, 902 { "interrupt-map", interrup_map_format }, 903 { "interrupt", interrupt_format }, 904 #endif 905 { "model", string_format }, 906 { "name", string_format }, 907 { "device_type", string_format }, 908 { "compatible", string_format }, 909 { "*frequency", frequency_format }, 910 { "*-size", size_format }, 911 { "*-cells", size_format }, 912 { "*-entries", size_format }, 913 { "*-associativity", size_format }, 914 { NULL, default_format } 915 }; 916 917 static void 918 ofgetprop(int node, const char *name) 919 { 920 u_int8_t of_buf[4097]; 921 int len; 922 int i; 923 924 len = OF_getprop(node, name, of_buf, sizeof(of_buf) - 1); 925 if (len < 0) 926 return; 927 of_buf[len] = '\0'; 928 printf("%-24s", name); 929 if (len == 0) { 930 putchar('\n'); 931 return; 932 } 933 if (strlen(name) >= 24) 934 printf("\n%24s", ""); 935 936 for (i = 0; formatters[i].prop_name != NULL; i++) { 937 if (formatters[i].prop_name[0] == '*') { 938 if (strstr(name, &formatters[i].prop_name[1]) != NULL) { 939 (*formatters[i].prop_format)(node, of_buf, len); 940 return; 941 } 942 continue; 943 } 944 if (strcmp(name, formatters[i].prop_name) == 0) { 945 (*formatters[i].prop_format)(node, of_buf, len); 946 return; 947 } 948 } 949 (*formatters[i].prop_format)(node, of_buf, len); 950 } 951 952 static void 953 ofprop(int node) 954 { 955 char namebuf[33]; 956 char newnamebuf[33]; 957 int len; 958 959 namebuf[0] = '\0'; 960 961 for (;;) { 962 len = OF_nextprop(node, namebuf, newnamebuf); 963 if (len <= 0) 964 break; 965 966 newnamebuf[len] = '\0'; 967 strcpy(namebuf, newnamebuf); 968 ofgetprop(node, newnamebuf); 969 } 970 } 971 #if 0 972 static int 973 isstrprint(const char *str, size_t len, int ignorenulls) 974 { 975 if (*str == '\0') 976 return 0; 977 for (; len-- > 0; str++) { 978 if (*str == '\0' && len > 0 && str[1] == '\0') 979 return 0; 980 if (len == 0 && *str == '\0') 981 return 1; 982 if (ignorenulls) { 983 if (*str == '\0') 984 continue; 985 if (isalnum(*str) || ispunct(*str) || *str == ' ') 986 continue; 987 return 0; 988 } 989 if (!isprint(*str)) 990 return 0; 991 } 992 return 1; 993 } 994 #endif 995