1 /* $NetBSD: ofw_subr.c,v 1.18 2010/02/28 13:59:05 martin 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.18 2010/02/28 13:59:05 martin 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 partcular 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 index of the string in "strings" of the first 94 * string found in phandle's "compatibility" property. 95 * 96 * Side Effects: 97 * None. 98 */ 99 int 100 of_compatible(int phandle, const char * const *strings) 101 { 102 int len, allocated, rv; 103 char *buf; 104 const char *sp, *nsp; 105 106 len = OF_getproplen(phandle, "compatible"); 107 if (len <= 0) 108 return (-1); 109 110 if (len > OFW_MAX_STACK_BUF_SIZE) { 111 buf = malloc(len, M_TEMP, M_WAITOK); 112 allocated = 1; 113 } else { 114 buf = alloca(len); 115 allocated = 0; 116 } 117 118 /* 'compatible' size should not change. */ 119 if (OF_getprop(phandle, "compatible", buf, len) != len) { 120 rv = -1; 121 goto out; 122 } 123 124 sp = buf; 125 while (len && (nsp = memchr(sp, 0, len)) != NULL) { 126 /* look for a match among the strings provided */ 127 for (rv = 0; strings[rv] != NULL; rv++) 128 if (strcmp(sp, strings[rv]) == 0) 129 goto out; 130 131 nsp++; /* skip over NUL char */ 132 len -= (nsp - sp); 133 sp = nsp; 134 } 135 rv = -1; 136 137 out: 138 if (allocated) 139 free(buf, M_TEMP); 140 return (rv); 141 142 } 143 144 /* 145 * int of_packagename(phandle, buf, bufsize) 146 * 147 * This routine places the last component of an OFW node's name 148 * into a user-provided buffer. 149 * 150 * It can be used during autoconfiguration to make printing of 151 * device names more informative. 152 * 153 * Arguments: 154 * phandle OFW phandle of device whose name name is 155 * desired. 156 * buf Buffer to contain device name, provided by 157 * caller. (For now, must be at least 4 158 * bytes long.) 159 * bufsize Length of buffer referenced by 'buf', in 160 * bytes. 161 * 162 * Return Value: 163 * -1 if the device path name could not be obtained or would 164 * not fit in the allocated temporary buffer, or zero otherwise 165 * (meaning that the leaf node name was successfully extracted). 166 * 167 * Side Effects: 168 * If the leaf node name was successfully extracted, 'buf' is 169 * filled in with at most 'bufsize' bytes of the leaf node 170 * name. If the leaf node was not successfully extracted, a 171 * somewhat meaningful string is placed in the buffer. In 172 * either case, the contents of 'buf' will be NUL-terminated. 173 */ 174 int 175 of_packagename(int phandle, char *buf, int bufsize) 176 { 177 char *pbuf; 178 const char *lastslash; 179 int l, rv; 180 181 pbuf = malloc(OFW_PATH_BUF_SIZE, M_TEMP, M_WAITOK); 182 l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE); 183 184 /* check that we could get the name, and that it's not too long. */ 185 if (l < 0 || 186 (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) { 187 if (bufsize >= 25) 188 snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle); 189 else if (bufsize >= 4) 190 strlcpy(buf, "???", bufsize); 191 else 192 panic("of_packagename: bufsize = %d is silly", 193 bufsize); 194 rv = -1; 195 } else { 196 pbuf[l] = '\0'; 197 lastslash = strrchr(pbuf, '/'); 198 strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1), 199 bufsize); 200 rv = 0; 201 } 202 203 free(pbuf, M_TEMP); 204 return (rv); 205 } 206 207 /* 208 * Find the first child of a given node that matches name. Does not recurse. 209 */ 210 int 211 of_find_firstchild_byname(int node, const char *name) 212 { 213 char namex[32]; 214 int nn; 215 216 for (nn = OF_child(node); nn; nn = OF_peer(nn)) { 217 memset(namex, 0, sizeof(namex)); 218 if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1) 219 continue; 220 if (strcmp(name, namex) == 0) 221 return nn; 222 } 223 return -1; 224 } 225 226 /* 227 * Find a give node by name. Recurses, and seems to walk upwards too. 228 */ 229 230 int 231 of_getnode_byname(int start, const char *target) 232 { 233 int node, next; 234 char name[64]; 235 236 if (start == 0) 237 start = OF_peer(0); 238 239 for (node = start; node; node = next) { 240 memset(name, 0, sizeof name); 241 OF_getprop(node, "name", name, sizeof name - 1); 242 if (strcmp(name, target) == 0) 243 break; 244 245 if ((next = OF_child(node)) != 0) 246 continue; 247 248 while (node) { 249 if ((next = OF_peer(node)) != 0) 250 break; 251 node = OF_parent(node); 252 } 253 } 254 255 /* XXX is this correct? */ 256 return node; 257 } 258 259 /* 260 * Create a uint32_t integer property from an OFW node property. 261 */ 262 263 boolean_t 264 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname, 265 const char *propname) 266 { 267 uint32_t prop; 268 269 if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop)) 270 return FALSE; 271 272 return(prop_dictionary_set_uint32(dict, propname, prop)); 273 } 274 275 /* 276 * Create a data property from an OFW node property. Max size of 256bytes. 277 */ 278 279 boolean_t 280 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname, 281 const char *propname) 282 { 283 prop_data_t data; 284 int len; 285 uint8_t prop[256]; 286 boolean_t res; 287 288 len = OF_getprop(node, ofname, prop, 256); 289 if (len < 1) 290 return FALSE; 291 292 data = prop_data_create_data(prop, len); 293 res = prop_dictionary_set(dict, propname, data); 294 prop_object_release(data); 295 return res; 296 } 297 298 /* 299 * look at output-device, see if there's a Sun-typical video mode specifier as 300 * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise 301 * return NULL 302 */ 303 304 char * 305 of_get_mode_string(char *buffer, int len) 306 { 307 int options; 308 char *pos, output_device[256]; 309 310 /* 311 * finally, let's see if there's a video mode specified in 312 * output-device and pass it on so there's at least some way 313 * to program video modes 314 */ 315 options = OF_finddevice("/options"); 316 if ((options == 0) || (options == -1)) 317 return NULL; 318 if (OF_getprop(options, "output-device", output_device, 256) == 0) 319 return NULL; 320 321 /* find the mode string if there is one */ 322 pos = strstr(output_device, ":r"); 323 if (pos == NULL) 324 return NULL; 325 strncpy(buffer, pos + 2, len); 326 return buffer; 327 } 328 329 /* 330 * Iterate over the subtree of a i2c controller node. 331 * Add all sub-devices into an array as part of the controller's 332 * device properties. 333 * This is used by the i2c bus attach code to do direct configuration. 334 */ 335 void 336 of_enter_i2c_devs(prop_dictionary_t props, int ofnode, size_t cell_size) 337 { 338 int node, len; 339 char name[32]; 340 uint64_t reg64; 341 uint32_t reg32; 342 uint64_t addr; 343 prop_array_t array; 344 prop_dictionary_t dev; 345 346 array = prop_array_create(); 347 348 for (node = OF_child(ofnode); node; node = OF_peer(node)) { 349 if (OF_getprop(node, "name", name, sizeof(name)) <= 0) 350 continue; 351 len = OF_getproplen(node, "reg"); 352 addr = 0; 353 if (cell_size == 8 && len >= sizeof(reg64)) { 354 if (OF_getprop(node, "reg", ®64, sizeof(reg64)) 355 < sizeof(reg64)) 356 continue; 357 addr = reg64; 358 } else if (cell_size == 4 && len >= sizeof(reg32)) { 359 if (OF_getprop(node, "reg", ®32, sizeof(reg32)) 360 < sizeof(reg32)) 361 continue; 362 addr = reg32; 363 } else { 364 continue; 365 } 366 addr >>= 1; 367 if (addr == 0) continue; 368 369 dev = prop_dictionary_create(); 370 prop_dictionary_set_cstring(dev, "name", name); 371 prop_dictionary_set_uint32(dev, "addr", addr); 372 prop_dictionary_set_uint64(dev, "cookie", node); 373 of_to_dataprop(dev, node, "compatible", "compatible"); 374 prop_array_add(array, dev); 375 prop_object_release(dev); 376 } 377 378 prop_dictionary_set(props, "i2c-child-devices", array); 379 prop_object_release(array); 380 } 381