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