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