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