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(®_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