Home | History | Annotate | Line # | Download | only in ofctl
ofctl.c revision 1.12
      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(&reg_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