1 /* $NetBSD: ofw_subr.c,v 1.27 2015/12/16 19:33:39 jmcneill Exp $ */ 2 3 /* 4 * Copyright 1998 5 * Digital Equipment Corporation. All rights reserved. 6 * 7 * This software is furnished under license and may be used and 8 * copied only in accordance with the following terms and conditions. 9 * Subject to these conditions, you may download, copy, install, 10 * use, modify and distribute this software in source and/or binary 11 * form. No title or ownership is transferred hereby. 12 * 13 * 1) Any source code used, modified or distributed must reproduce 14 * and retain this copyright notice and list of conditions as 15 * they appear in the source file. 16 * 17 * 2) No right is granted to use any trade name, trademark, or logo of 18 * Digital Equipment Corporation. Neither the "Digital Equipment 19 * Corporation" name nor any trademark or logo of Digital Equipment 20 * Corporation may be used to endorse or promote products derived 21 * from this software without the prior written permission of 22 * Digital Equipment Corporation. 23 * 24 * 3) This software is provided "AS-IS" and any express or implied 25 * warranties, including but not limited to, any implied warranties 26 * of merchantability, fitness for a particular purpose, or 27 * non-infringement are disclaimed. In no event shall DIGITAL be 28 * liable for any damages whatsoever, and in particular, DIGITAL 29 * shall not be liable for special, indirect, consequential, or 30 * incidental damages or damages for lost profits, loss of 31 * revenue or loss of use, whether such damages arise in contract, 32 * negligence, tort, under statute, in equity, at law or otherwise, 33 * even if advised of the possibility of such damage. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: ofw_subr.c,v 1.27 2015/12/16 19:33:39 jmcneill Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/malloc.h> 42 #include <dev/ofw/openfirm.h> 43 44 #define OFW_MAX_STACK_BUF_SIZE 256 45 #define OFW_PATH_BUF_SIZE 512 46 47 /* 48 * int of_decode_int(p) 49 * 50 * This routine converts OFW encoded-int datums 51 * into the integer format of the host machine. 52 * 53 * It is primarily used to convert integer properties 54 * returned by the OF_getprop routine. 55 * 56 * Arguments: 57 * p pointer to unsigned char array which is an 58 * OFW-encoded integer. 59 * 60 * Return Value: 61 * Decoded integer value of argument p. 62 * 63 * Side Effects: 64 * None. 65 */ 66 int 67 of_decode_int(const unsigned char *p) 68 { 69 unsigned int i = *p++ << 8; 70 i = (i + *p++) << 8; 71 i = (i + *p++) << 8; 72 return (i + *p); 73 } 74 75 /* 76 * int of_compatible(phandle, strings) 77 * 78 * This routine checks an OFW node's "compatible" entry to see if 79 * it matches any of the provided strings. 80 * 81 * It should be used when determining whether a driver can drive 82 * a particular device. 83 * 84 * Arguments: 85 * phandle OFW phandle of device to be checked for 86 * compatibility. 87 * strings Array of containing expected "compatibility" 88 * property values, presence of any of which 89 * indicates compatibility. 90 * 91 * Return Value: 92 * -1 if none of the strings are found in phandle's "compatibility" 93 * property, or the reverse index of the matching string in the 94 * phandle's "compatibility" property. 95 * 96 * Side Effects: 97 * None. 98 */ 99 int 100 of_compatible(int phandle, const char * const *strings) 101 { 102 103 int len, olen, allocated, nstr, cstr, rv; 104 char *buf; 105 const char *sp, *nsp; 106 107 len = OF_getproplen(phandle, "compatible"); 108 if (len <= 0) 109 return (-1); 110 111 if (len > OFW_MAX_STACK_BUF_SIZE) { 112 buf = malloc(len, M_TEMP, M_WAITOK); 113 allocated = 1; 114 } else { 115 buf = alloca(len); 116 allocated = 0; 117 } 118 119 /* 'compatible' size should not change. */ 120 if (OF_getprop(phandle, "compatible", buf, len) != len) { 121 rv = -1; 122 goto out; 123 } 124 125 /* count 'compatible' strings */ 126 sp = buf; 127 nstr = 0; 128 olen = len; 129 while (len && (nsp = memchr(sp, 0, len)) != NULL) { 130 nsp++; /* skip over NUL char */ 131 len -= (nsp - sp); 132 sp = nsp; 133 nstr++; 134 } 135 len = olen; 136 137 sp = buf; 138 rv = nstr; 139 while (len && (nsp = memchr(sp, 0, len)) != NULL) { 140 rv--; 141 /* look for a match among the strings provided */ 142 for (cstr = 0; strings[cstr] != NULL; cstr++) 143 if (strcmp(sp, strings[cstr]) == 0) 144 goto out; 145 146 nsp++; /* skip over NUL char */ 147 len -= (nsp - sp); 148 sp = nsp; 149 } 150 rv = -1; 151 152 out: 153 if (allocated) 154 free(buf, M_TEMP); 155 return (rv); 156 } 157 158 /* 159 * int of_match_compatible(phandle, strings) 160 * 161 * This routine checks an OFW node's "compatible" entry to see if 162 * it matches any of the provided strings. 163 * 164 * It should be used when determining whether a driver can drive 165 * a particular device. 166 * 167 * Arguments: 168 * phandle OFW phandle of device to be checked for 169 * compatibility. 170 * strings Array of containing expected "compatibility" 171 * property values, presence of any of which 172 * indicates compatibility. 173 * 174 * Return Value: 175 * 0 if none of the strings are found in phandle's "compatibility" 176 * property, or a positive number based on the reverse index of the 177 * matching string in the phandle's "compatibility" property, plus 1. 178 * 179 * Side Effects: 180 * None. 181 */ 182 int 183 of_match_compatible(int phandle, const char * const *strings) 184 { 185 return of_compatible(phandle, strings) + 1; 186 } 187 188 /* 189 * int of_packagename(phandle, buf, bufsize) 190 * 191 * This routine places the last component of an OFW node's name 192 * into a user-provided buffer. 193 * 194 * It can be used during autoconfiguration to make printing of 195 * device names more informative. 196 * 197 * Arguments: 198 * phandle OFW phandle of device whose name name is 199 * desired. 200 * buf Buffer to contain device name, provided by 201 * caller. (For now, must be at least 4 202 * bytes long.) 203 * bufsize Length of buffer referenced by 'buf', in 204 * bytes. 205 * 206 * Return Value: 207 * -1 if the device path name could not be obtained or would 208 * not fit in the allocated temporary buffer, or zero otherwise 209 * (meaning that the leaf node name was successfully extracted). 210 * 211 * Side Effects: 212 * If the leaf node name was successfully extracted, 'buf' is 213 * filled in with at most 'bufsize' bytes of the leaf node 214 * name. If the leaf node was not successfully extracted, a 215 * somewhat meaningful string is placed in the buffer. In 216 * either case, the contents of 'buf' will be NUL-terminated. 217 */ 218 int 219 of_packagename(int phandle, char *buf, int bufsize) 220 { 221 char *pbuf; 222 const char *lastslash; 223 int l, rv; 224 225 pbuf = malloc(OFW_PATH_BUF_SIZE, M_TEMP, M_WAITOK); 226 l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE); 227 228 /* check that we could get the name, and that it's not too long. */ 229 if (l < 0 || 230 (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) { 231 if (bufsize >= 25) 232 snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle); 233 else if (bufsize >= 4) 234 strlcpy(buf, "???", bufsize); 235 else 236 panic("of_packagename: bufsize = %d is silly", 237 bufsize); 238 rv = -1; 239 } else { 240 pbuf[l] = '\0'; 241 lastslash = strrchr(pbuf, '/'); 242 strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1), 243 bufsize); 244 rv = 0; 245 } 246 247 free(pbuf, M_TEMP); 248 return (rv); 249 } 250 251 /* 252 * Find the first child of a given node that matches name. Does not recurse. 253 */ 254 int 255 of_find_firstchild_byname(int node, const char *name) 256 { 257 char namex[32]; 258 int nn; 259 260 for (nn = OF_child(node); nn; nn = OF_peer(nn)) { 261 memset(namex, 0, sizeof(namex)); 262 if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1) 263 continue; 264 if (strcmp(name, namex) == 0) 265 return nn; 266 } 267 return -1; 268 } 269 270 /* 271 * Find a give node by name. Recurses, and seems to walk upwards too. 272 */ 273 274 int 275 of_getnode_byname(int start, const char *target) 276 { 277 int node, next; 278 char name[64]; 279 280 if (start == 0) 281 start = OF_peer(0); 282 283 for (node = start; node; node = next) { 284 memset(name, 0, sizeof name); 285 OF_getprop(node, "name", name, sizeof name - 1); 286 if (strcmp(name, target) == 0) 287 break; 288 289 if ((next = OF_child(node)) != 0) 290 continue; 291 292 while (node) { 293 if ((next = OF_peer(node)) != 0) 294 break; 295 node = OF_parent(node); 296 } 297 } 298 299 /* XXX is this correct? */ 300 return node; 301 } 302 303 /* 304 * Create a uint32_t integer property from an OFW node property. 305 */ 306 307 boolean_t 308 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname, 309 const char *propname) 310 { 311 uint32_t prop; 312 313 if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop)) 314 return FALSE; 315 316 return(prop_dictionary_set_uint32(dict, propname, prop)); 317 } 318 319 /* 320 * Create a data property from an OFW node property. Max size of 256bytes. 321 */ 322 323 boolean_t 324 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname, 325 const char *propname) 326 { 327 prop_data_t data; 328 int len; 329 uint8_t prop[256]; 330 boolean_t res; 331 332 len = OF_getprop(node, ofname, prop, 256); 333 if (len < 1) 334 return FALSE; 335 336 data = prop_data_create_data(prop, len); 337 res = prop_dictionary_set(dict, propname, data); 338 prop_object_release(data); 339 return res; 340 } 341 342 /* 343 * look at output-device, see if there's a Sun-typical video mode specifier as 344 * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise 345 * return NULL 346 */ 347 348 char * 349 of_get_mode_string(char *buffer, int len) 350 { 351 int options; 352 char *pos, output_device[256]; 353 354 /* 355 * finally, let's see if there's a video mode specified in 356 * output-device and pass it on so there's at least some way 357 * to program video modes 358 */ 359 options = OF_finddevice("/options"); 360 if ((options == 0) || (options == -1)) 361 return NULL; 362 if (OF_getprop(options, "output-device", output_device, 256) == 0) 363 return NULL; 364 365 /* find the mode string if there is one */ 366 pos = strstr(output_device, ":r"); 367 if (pos == NULL) 368 return NULL; 369 strncpy(buffer, pos + 2, len); 370 return buffer; 371 } 372 373 /* 374 * Iterate over the subtree of a i2c controller node. 375 * Add all sub-devices into an array as part of the controller's 376 * device properties. 377 * This is used by the i2c bus attach code to do direct configuration. 378 */ 379 void 380 of_enter_i2c_devs(prop_dictionary_t props, int ofnode, size_t cell_size, 381 int addr_shift) 382 { 383 int node, len; 384 char name[32], compatible[32]; 385 uint64_t reg64; 386 uint32_t reg32; 387 uint64_t addr; 388 prop_array_t array = NULL; 389 prop_dictionary_t dev; 390 391 for (node = OF_child(ofnode); node; node = OF_peer(node)) { 392 if (OF_getprop(node, "name", name, sizeof(name)) <= 0) 393 continue; 394 len = OF_getproplen(node, "reg"); 395 addr = 0; 396 if (cell_size == 8 && len >= sizeof(reg64)) { 397 if (OF_getprop(node, "reg", ®64, sizeof(reg64)) 398 < sizeof(reg64)) 399 continue; 400 addr = be64toh(reg64); 401 /* 402 * The i2c bus number (0 or 1) is encoded in bit 33 403 * of the register, but we encode it in bit 8 of 404 * i2c_addr_t. 405 */ 406 if (addr & 0x100000000) 407 addr = (addr & 0xff) | 0x100; 408 } else if (cell_size == 4 && len >= sizeof(reg32)) { 409 if (OF_getprop(node, "reg", ®32, sizeof(reg32)) 410 < sizeof(reg32)) 411 continue; 412 addr = be32toh(reg32); 413 } else { 414 continue; 415 } 416 addr >>= addr_shift; 417 if (addr == 0) continue; 418 419 if (array == NULL) 420 array = prop_array_create(); 421 422 dev = prop_dictionary_create(); 423 prop_dictionary_set_cstring(dev, "name", name); 424 prop_dictionary_set_uint32(dev, "addr", addr); 425 prop_dictionary_set_uint64(dev, "cookie", node); 426 of_to_dataprop(dev, node, "compatible", "compatible"); 427 if (OF_getprop(node, "compatible", compatible, 428 sizeof(compatible)) > 0) { 429 /* Set size for EEPROM's that we know about */ 430 if (strcmp(compatible, "i2c-at24c64") == 0) 431 prop_dictionary_set_uint32(dev, "size", 8192); 432 if (strcmp(compatible, "i2c-at34c02") == 0) 433 prop_dictionary_set_uint32(dev, "size", 256); 434 } 435 prop_array_add(array, dev); 436 prop_object_release(dev); 437 } 438 439 if (array != NULL) { 440 prop_dictionary_set(props, "i2c-child-devices", array); 441 prop_object_release(array); 442 } 443 444 prop_dictionary_set_bool(props, "i2c-indirect-config", false); 445 } 446 447 /* 448 * Get the value of a boolean property. If the property is present, 449 * return true. Otherwise, return false. 450 */ 451 bool 452 of_getprop_bool(int node, const char *prop) 453 { 454 return OF_getproplen(node, prop) >= 0; 455 } 456 457 /* 458 * Get the value of a uint32 property, compensating for host byte order. 459 * Returns 0 on success, non-zero on failure. 460 */ 461 int 462 of_getprop_uint32(int node, const char *prop, uint32_t *val) 463 { 464 uint32_t v; 465 int len; 466 467 len = OF_getprop(node, prop, &v, sizeof(v)); 468 if (len != sizeof(v)) 469 return -1; 470 471 *val = be32toh(v); 472 return 0; 473 } 474