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