1 /* $NetBSD: ofw_subr.c,v 1.58 2021/04/24 23:36:57 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright 1998 31 * Digital Equipment Corporation. All rights reserved. 32 * 33 * This software is furnished under license and may be used and 34 * copied only in accordance with the following terms and conditions. 35 * Subject to these conditions, you may download, copy, install, 36 * use, modify and distribute this software in source and/or binary 37 * form. No title or ownership is transferred hereby. 38 * 39 * 1) Any source code used, modified or distributed must reproduce 40 * and retain this copyright notice and list of conditions as 41 * they appear in the source file. 42 * 43 * 2) No right is granted to use any trade name, trademark, or logo of 44 * Digital Equipment Corporation. Neither the "Digital Equipment 45 * Corporation" name nor any trademark or logo of Digital Equipment 46 * Corporation may be used to endorse or promote products derived 47 * from this software without the prior written permission of 48 * Digital Equipment Corporation. 49 * 50 * 3) This software is provided "AS-IS" and any express or implied 51 * warranties, including but not limited to, any implied warranties 52 * of merchantability, fitness for a particular purpose, or 53 * non-infringement are disclaimed. In no event shall DIGITAL be 54 * liable for any damages whatsoever, and in particular, DIGITAL 55 * shall not be liable for special, indirect, consequential, or 56 * incidental damages or damages for lost profits, loss of 57 * revenue or loss of use, whether such damages arise in contract, 58 * negligence, tort, under statute, in equity, at law or otherwise, 59 * even if advised of the possibility of such damage. 60 */ 61 62 #include <sys/cdefs.h> 63 __KERNEL_RCSID(0, "$NetBSD: ofw_subr.c,v 1.58 2021/04/24 23:36:57 thorpej Exp $"); 64 65 #include <sys/param.h> 66 #include <sys/device.h> 67 #include <sys/kmem.h> 68 #include <sys/systm.h> 69 #include <dev/ofw/openfirm.h> 70 71 #define OFW_MAX_STACK_BUF_SIZE 256 72 #define OFW_PATH_BUF_SIZE 512 73 74 /* 75 * OpenFirmware device handle support. 76 */ 77 78 static device_call_t 79 of_devhandle_lookup_device_call(devhandle_t handle, const char *name, 80 devhandle_t *call_handlep) 81 { 82 __link_set_decl(of_device_calls, struct device_call_descriptor); 83 struct device_call_descriptor * const *desc; 84 85 __link_set_foreach(desc, of_device_calls) { 86 if (strcmp((*desc)->name, name) == 0) { 87 return (*desc)->call; 88 } 89 } 90 return NULL; 91 } 92 93 static const struct devhandle_impl of_devhandle_impl = { 94 .type = DEVHANDLE_TYPE_OF, 95 .lookup_device_call = of_devhandle_lookup_device_call, 96 }; 97 98 devhandle_t 99 devhandle_from_of(int phandle) 100 { 101 devhandle_t handle = { 102 .impl = &of_devhandle_impl, 103 .integer = phandle, 104 }; 105 106 return handle; 107 } 108 109 int 110 devhandle_to_of(devhandle_t const handle) 111 { 112 KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_OF); 113 114 return handle.integer; 115 } 116 117 static int 118 of_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v) 119 { 120 struct device_enumerate_children_args *args = v; 121 int phandle = devhandle_to_of(call_handle); 122 int child; 123 124 for (child = OF_child(phandle); child != 0; child = OF_peer(child)) { 125 if (!args->callback(dev, devhandle_from_of(child), 126 args->callback_arg)) { 127 break; 128 } 129 } 130 131 return 0; 132 } 133 OF_DEVICE_CALL_REGISTER("device-enumerate-children", 134 of_device_enumerate_children) 135 136 /* 137 * int of_decode_int(p) 138 * 139 * This routine converts OFW encoded-int datums 140 * into the integer format of the host machine. 141 * 142 * It is primarily used to convert integer properties 143 * returned by the OF_getprop routine. 144 * 145 * Arguments: 146 * p pointer to unsigned char array which is an 147 * OFW-encoded integer. 148 * 149 * Return Value: 150 * Decoded integer value of argument p. 151 * 152 * Side Effects: 153 * None. 154 */ 155 int 156 of_decode_int(const unsigned char *p) 157 { 158 unsigned int i = *p++ << 8; 159 i = (i + *p++) << 8; 160 i = (i + *p++) << 8; 161 return (i + *p); 162 } 163 164 /* 165 * int of_compatible(phandle, strings) 166 * 167 * This routine checks an OFW node's "compatible" entry to see if 168 * it matches any of the provided strings. 169 * 170 * of_compatible_match() is the preferred way to perform driver 171 * compatibility match. However, this routine that deals with 172 * only strings is useful in some situations and is provided for 173 * convenience. 174 * 175 * Arguments: 176 * phandle OFW phandle of device to be checked for 177 * compatibility. 178 * strings Array of containing expected "compatibility" 179 * property values, presence of any of which 180 * indicates compatibility. 181 * 182 * Return Value: 183 * 0 if none of the strings are found in phandle's "compatibility" 184 * property, or the reverse index of the matching string in the 185 * phandle's "compatibility" property plus 1. 186 * 187 * Side Effects: 188 * None. 189 */ 190 int 191 of_compatible(int phandle, const char * const *strings) 192 { 193 char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE]; 194 const char *cp; 195 int proplen, match = 0; 196 197 proplen = OF_getproplen(phandle, "compatible"); 198 if (proplen <= 0) { 199 return 0; 200 } 201 202 prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP); 203 204 if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) { 205 goto out; 206 } 207 208 for (; (cp = *strings) != NULL; strings++) { 209 if ((match = strlist_match(prop, proplen, cp)) != 0) { 210 break; 211 } 212 } 213 214 out: 215 kmem_tmpbuf_free(prop, proplen, propbuf); 216 return match; 217 } 218 219 /* 220 * int of_compatible_match(phandle, compat_data) 221 * 222 * This routine searches an array of device_compatible_entry structures 223 * for a matching "compatible" entry matching the supplied OFW node, 224 * and returns a weighted match value corresponding to which string 225 * from the "compatible" property was matched, which more weight given 226 * to the first string than the last. 227 * 228 * It should be used when determining whether a driver can drive 229 * a particular device. 230 * 231 * Arguments: 232 * phandle OFW phandle of device to be checked for 233 * compatibility. 234 * compat_data Array of possible compat entry strings and 235 * associated metadata. The last entry in the 236 * list should have a "compat" of NULL to terminate 237 * the list. 238 * 239 * Return Value: 240 * 0 if none of the strings are found in phandle's "compatibility" 241 * property, or a positive number based on the reverse index of the 242 * matching string in the phandle's "compatibility" property, plus 1. 243 * 244 * Side Effects: 245 * None. 246 */ 247 int 248 of_compatible_match(int phandle, 249 const struct device_compatible_entry *compat_data) 250 { 251 char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE]; 252 int proplen, match = 0; 253 254 proplen = OF_getproplen(phandle, "compatible"); 255 if (proplen <= 0) { 256 return 0; 257 } 258 259 prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP); 260 261 if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) { 262 goto out; 263 } 264 265 match = device_compatible_match_strlist(prop, proplen, compat_data); 266 267 out: 268 kmem_tmpbuf_free(prop, proplen, propbuf); 269 return match; 270 } 271 272 /* 273 * const struct device_compatible_entry *of_compatible_lookup(phandle, 274 * compat_data) 275 * 276 * This routine searches an array of device_compatible_entry structures 277 * for a "compatible" entry matching the supplied OFW node. 278 * 279 * Arguments: 280 * phandle OFW phandle of device to be checked for 281 * compatibility. 282 * compat_data Array of possible compat entry strings and 283 * associated metadata. The last entry in the 284 * list should have a "compat" of NULL to terminate 285 * the list. 286 * 287 * Return Value: 288 * The first matching compat_data entry in the array. If no matches 289 * are found, NULL is returned. 290 * 291 * Side Effects: 292 * None. 293 */ 294 const struct device_compatible_entry * 295 of_compatible_lookup(int phandle, 296 const struct device_compatible_entry *compat_data) 297 { 298 char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE]; 299 const struct device_compatible_entry *match = NULL; 300 int proplen; 301 302 proplen = OF_getproplen(phandle, "compatible"); 303 if (proplen <= 0) { 304 return 0; 305 } 306 307 prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP); 308 309 if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) { 310 goto out; 311 } 312 313 match = device_compatible_lookup_strlist(prop, proplen, compat_data); 314 315 out: 316 kmem_tmpbuf_free(prop, proplen, propbuf); 317 return match; 318 } 319 320 /* 321 * int of_packagename(phandle, buf, bufsize) 322 * 323 * This routine places the last component of an OFW node's name 324 * into a user-provided buffer. 325 * 326 * It can be used during autoconfiguration to make printing of 327 * device names more informative. 328 * 329 * Arguments: 330 * phandle OFW phandle of device whose name name is 331 * desired. 332 * buf Buffer to contain device name, provided by 333 * caller. (For now, must be at least 4 334 * bytes long.) 335 * bufsize Length of buffer referenced by 'buf', in 336 * bytes. 337 * 338 * Return Value: 339 * -1 if the device path name could not be obtained or would 340 * not fit in the allocated temporary buffer, or zero otherwise 341 * (meaning that the leaf node name was successfully extracted). 342 * 343 * Side Effects: 344 * If the leaf node name was successfully extracted, 'buf' is 345 * filled in with at most 'bufsize' bytes of the leaf node 346 * name. If the leaf node was not successfully extracted, a 347 * somewhat meaningful string is placed in the buffer. In 348 * either case, the contents of 'buf' will be NUL-terminated. 349 */ 350 int 351 of_packagename(int phandle, char *buf, int bufsize) 352 { 353 char *pbuf; 354 const char *lastslash; 355 int l, rv; 356 357 pbuf = kmem_alloc(OFW_PATH_BUF_SIZE, KM_SLEEP); 358 l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE); 359 360 /* check that we could get the name, and that it's not too long. */ 361 if (l < 0 || 362 (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) { 363 if (bufsize >= 25) 364 snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle); 365 else if (bufsize >= 4) 366 strlcpy(buf, "???", bufsize); 367 else 368 panic("of_packagename: bufsize = %d is silly", 369 bufsize); 370 rv = -1; 371 } else { 372 pbuf[l] = '\0'; 373 lastslash = strrchr(pbuf, '/'); 374 strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1), 375 bufsize); 376 rv = 0; 377 } 378 379 kmem_free(pbuf, OFW_PATH_BUF_SIZE); 380 return (rv); 381 } 382 383 /* 384 * Find the first child of a given node that matches name. Does not recurse. 385 */ 386 int 387 of_find_firstchild_byname(int node, const char *name) 388 { 389 char namex[32]; 390 int nn; 391 392 for (nn = OF_child(node); nn; nn = OF_peer(nn)) { 393 memset(namex, 0, sizeof(namex)); 394 if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1) 395 continue; 396 if (strcmp(name, namex) == 0) 397 return nn; 398 } 399 return -1; 400 } 401 402 /* 403 * Find a child node that is compatible with str. Recurses, starting at node. 404 */ 405 int 406 of_find_bycompat(int node, const char *str) 407 { 408 const char * compatible[] = { str, NULL }; 409 int child, ret; 410 411 for (child = OF_child(node); child; child = OF_peer(child)) { 412 if (of_compatible(child, compatible)) 413 return child; 414 ret = of_find_bycompat(child, str); 415 if (ret != -1) 416 return ret; 417 } 418 419 return -1; 420 } 421 422 /* 423 * Find a give node by name. Recurses, and seems to walk upwards too. 424 */ 425 426 int 427 of_getnode_byname(int start, const char *target) 428 { 429 int node, next; 430 char name[64]; 431 432 if (start == 0) 433 start = OF_peer(0); 434 435 for (node = start; node; node = next) { 436 memset(name, 0, sizeof name); 437 OF_getprop(node, "name", name, sizeof name - 1); 438 if (strcmp(name, target) == 0) 439 break; 440 441 if ((next = OF_child(node)) != 0) 442 continue; 443 444 while (node) { 445 if ((next = OF_peer(node)) != 0) 446 break; 447 node = OF_parent(node); 448 } 449 } 450 451 /* XXX is this correct? */ 452 return node; 453 } 454 455 /* 456 * Create a uint32_t integer property from an OFW node property. 457 */ 458 459 bool 460 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname, 461 const char *propname) 462 { 463 uint32_t prop; 464 465 if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop)) 466 return FALSE; 467 468 return(prop_dictionary_set_uint32(dict, propname, prop)); 469 } 470 471 /* 472 * Create a data property from an OFW node property. Max size of 256bytes. 473 */ 474 475 bool 476 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname, 477 const char *propname) 478 { 479 int len; 480 uint8_t prop[256]; 481 482 len = OF_getprop(node, ofname, prop, 256); 483 if (len < 1) 484 return FALSE; 485 486 return prop_dictionary_set_data(dict, propname, prop, len); 487 } 488 489 /* 490 * look at output-device, see if there's a Sun-typical video mode specifier as 491 * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise 492 * return NULL 493 */ 494 495 char * 496 of_get_mode_string(char *buffer, int len) 497 { 498 int options; 499 char *pos, output_device[256]; 500 501 /* 502 * finally, let's see if there's a video mode specified in 503 * output-device and pass it on so there's at least some way 504 * to program video modes 505 */ 506 options = OF_finddevice("/options"); 507 if ((options == 0) || (options == -1)) 508 return NULL; 509 if (OF_getprop(options, "output-device", output_device, 256) == 0) 510 return NULL; 511 512 /* find the mode string if there is one */ 513 pos = strstr(output_device, ":r"); 514 if (pos == NULL) 515 return NULL; 516 strncpy(buffer, pos + 2, len); 517 return buffer; 518 } 519 520 /* 521 * of_device_from_phandle -- 522 * 523 * Return a device_t associated with the specified phandle. 524 * 525 * This is expected to be used rarely, so we don't care if 526 * it's fast. Also, it can only find devices that have 527 * gone through of_device_register() (obviously). 528 */ 529 device_t 530 of_device_from_phandle(int phandle) 531 { 532 devhandle_t devhandle; 533 deviter_t di; 534 device_t dev; 535 536 for (dev = deviter_first(&di, DEVITER_F_ROOT_FIRST); 537 dev != NULL; 538 dev = deviter_next(&di)) { 539 devhandle = device_handle(dev); 540 if (devhandle_type(devhandle) == DEVHANDLE_TYPE_OF) { 541 if (devhandle_to_of(devhandle) == phandle) { 542 /* Found it! */ 543 break; 544 } 545 } 546 } 547 deviter_release(&di); 548 return dev; 549 } 550 551 /* 552 * Returns true if the specified property is present. 553 */ 554 bool 555 of_hasprop(int node, const char *prop) 556 { 557 return OF_getproplen(node, prop) >= 0; 558 } 559 560 /* 561 * Get the value of a uint32 property, compensating for host byte order. 562 * Returns 0 on success, non-zero on failure. 563 */ 564 int 565 of_getprop_uint32(int node, const char *prop, uint32_t *val) 566 { 567 uint32_t v; 568 int len; 569 570 len = OF_getprop(node, prop, &v, sizeof(v)); 571 if (len != sizeof(v)) 572 return -1; 573 574 *val = be32toh(v); 575 return 0; 576 } 577 578 int 579 of_getprop_uint32_array(int node, const char *prop, uint32_t *array, int n) 580 { 581 uint32_t *v = array; 582 int len; 583 584 len = OF_getprop(node, prop, array, n * sizeof(*v)); 585 if (len < (int)(n * sizeof(*v))) 586 return -1; 587 588 for (; n > 0; n--) { 589 BE32TOH(*v); 590 v++; 591 } 592 593 return 0; 594 } 595 /* 596 * Get the value of a uint64 property, compensating for host byte order. 597 * Returns 0 on success, non-zero on failure. 598 */ 599 int 600 of_getprop_uint64(int node, const char *prop, uint64_t *val) 601 { 602 uint64_t v; 603 int len; 604 605 len = OF_getprop(node, prop, &v, sizeof(v)); 606 if (len != sizeof(v)) 607 return -1; 608 609 *val = be64toh(v); 610 return 0; 611 } 612