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