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