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