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