Home | History | Annotate | Line # | Download | only in ofw
ofw_subr.c revision 1.56
      1 /*	$NetBSD: ofw_subr.c,v 1.56 2021/02/04 20:19:09 thorpej 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.56 2021/02/04 20:19:09 thorpej Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/device.h>
     41 #include <sys/kmem.h>
     42 #include <sys/systm.h>
     43 #include <dev/ofw/openfirm.h>
     44 
     45 #define	OFW_MAX_STACK_BUF_SIZE	256
     46 #define	OFW_PATH_BUF_SIZE	512
     47 
     48 /*
     49  * int of_decode_int(p)
     50  *
     51  * This routine converts OFW encoded-int datums
     52  * into the integer format of the host machine.
     53  *
     54  * It is primarily used to convert integer properties
     55  * returned by the OF_getprop routine.
     56  *
     57  * Arguments:
     58  *	p		pointer to unsigned char array which is an
     59  *			OFW-encoded integer.
     60  *
     61  * Return Value:
     62  *	Decoded integer value of argument p.
     63  *
     64  * Side Effects:
     65  *	None.
     66  */
     67 int
     68 of_decode_int(const unsigned char *p)
     69 {
     70 	unsigned int i = *p++ << 8;
     71 	i = (i + *p++) << 8;
     72 	i = (i + *p++) << 8;
     73 	return (i + *p);
     74 }
     75 
     76 /*
     77  * int of_compatible(phandle, strings)
     78  *
     79  * This routine checks an OFW node's "compatible" entry to see if
     80  * it matches any of the provided strings.
     81  *
     82  * of_compatible_match() is the preferred way to perform driver
     83  * compatibility match.  However, this routine that deals with
     84  * only strings is useful in some situations and is provided for
     85  * convenience.
     86  *
     87  * Arguments:
     88  *	phandle		OFW phandle of device to be checked for
     89  *			compatibility.
     90  *	strings		Array of containing expected "compatibility"
     91  *			property values, presence of any of which
     92  *			indicates compatibility.
     93  *
     94  * Return Value:
     95  *	0 if none of the strings are found in phandle's "compatibility"
     96  *	property, or the reverse index of the matching string in the
     97  *	phandle's "compatibility" property plus 1.
     98  *
     99  * Side Effects:
    100  *	None.
    101  */
    102 int
    103 of_compatible(int phandle, const char * const *strings)
    104 {
    105 	char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
    106 	const char *cp;
    107 	int proplen, match = 0;
    108 
    109 	proplen = OF_getproplen(phandle, "compatible");
    110 	if (proplen <= 0) {
    111 		return 0;
    112 	}
    113 
    114 	prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
    115 
    116 	if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
    117 		goto out;
    118 	}
    119 
    120 	for (; (cp = *strings) != NULL; strings++) {
    121 		if ((match = strlist_match(prop, proplen, cp)) != 0) {
    122 			break;
    123 		}
    124 	}
    125 
    126  out:
    127 	kmem_tmpbuf_free(prop, proplen, propbuf);
    128 	return match;
    129 }
    130 
    131 /*
    132  * int of_compatible_match(phandle, compat_data)
    133  *
    134  * This routine searches an array of device_compatible_entry structures
    135  * for a matching "compatible" entry matching the supplied OFW node,
    136  * and returns a weighted match value corresponding to which string
    137  * from the "compatible" property was matched, which more weight given
    138  * to the first string than the last.
    139  *
    140  * It should be used when determining whether a driver can drive
    141  * a particular device.
    142  *
    143  * Arguments:
    144  *	phandle		OFW phandle of device to be checked for
    145  *			compatibility.
    146  *	compat_data	Array of possible compat entry strings and
    147  *			associated metadata. The last entry in the
    148  *			list should have a "compat" of NULL to terminate
    149  *			the list.
    150  *
    151  * Return Value:
    152  *	0 if none of the strings are found in phandle's "compatibility"
    153  *	property, or a positive number based on the reverse index of the
    154  *	matching string in the phandle's "compatibility" property, plus 1.
    155  *
    156  * Side Effects:
    157  *	None.
    158  */
    159 int
    160 of_compatible_match(int phandle,
    161     const struct device_compatible_entry *compat_data)
    162 {
    163 	char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
    164 	int proplen, match = 0;
    165 
    166 	proplen = OF_getproplen(phandle, "compatible");
    167 	if (proplen <= 0) {
    168 		return 0;
    169 	}
    170 
    171 	prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
    172 
    173 	if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
    174 		goto out;
    175 	}
    176 
    177 	match = device_compatible_match_strlist(prop, proplen, compat_data);
    178 
    179  out:
    180 	kmem_tmpbuf_free(prop, proplen, propbuf);
    181 	return match;
    182 }
    183 
    184 /*
    185  * const struct device_compatible_entry *of_compatible_lookup(phandle,
    186  *							      compat_data)
    187  *
    188  * This routine searches an array of device_compatible_entry structures
    189  * for a "compatible" entry matching the supplied OFW node.
    190  *
    191  * Arguments:
    192  *	phandle		OFW phandle of device to be checked for
    193  *			compatibility.
    194  *	compat_data	Array of possible compat entry strings and
    195  *			associated metadata. The last entry in the
    196  *			list should have a "compat" of NULL to terminate
    197  *			the list.
    198  *
    199  * Return Value:
    200  *	The first matching compat_data entry in the array. If no matches
    201  *	are found, NULL is returned.
    202  *
    203  * Side Effects:
    204  *	None.
    205  */
    206 const struct device_compatible_entry *
    207 of_compatible_lookup(int phandle,
    208     const struct device_compatible_entry *compat_data)
    209 {
    210 	char *prop, propbuf[OFW_MAX_STACK_BUF_SIZE];
    211 	const struct device_compatible_entry *match = NULL;
    212 	int proplen;
    213 
    214 	proplen = OF_getproplen(phandle, "compatible");
    215 	if (proplen <= 0) {
    216 		return 0;
    217 	}
    218 
    219 	prop = kmem_tmpbuf_alloc(proplen, propbuf, sizeof(propbuf), KM_SLEEP);
    220 
    221 	if (OF_getprop(phandle, "compatible", prop, proplen) != proplen) {
    222 		goto out;
    223 	}
    224 
    225 	match = device_compatible_lookup_strlist(prop, proplen, compat_data);
    226 
    227  out:
    228 	kmem_tmpbuf_free(prop, proplen, propbuf);
    229 	return match;
    230 }
    231 
    232 /*
    233  * int of_packagename(phandle, buf, bufsize)
    234  *
    235  * This routine places the last component of an OFW node's name
    236  * into a user-provided buffer.
    237  *
    238  * It can be used during autoconfiguration to make printing of
    239  * device names more informative.
    240  *
    241  * Arguments:
    242  *	phandle		OFW phandle of device whose name name is
    243  *			desired.
    244  *	buf		Buffer to contain device name, provided by
    245  *			caller.  (For now, must be at least 4
    246  *			bytes long.)
    247  *	bufsize		Length of buffer referenced by 'buf', in
    248  *			bytes.
    249  *
    250  * Return Value:
    251  *	-1 if the device path name could not be obtained or would
    252  *	not fit in the allocated temporary buffer, or zero otherwise
    253  *	(meaning that the leaf node name was successfully extracted).
    254  *
    255  * Side Effects:
    256  *	If the leaf node name was successfully extracted, 'buf' is
    257  *	filled in with at most 'bufsize' bytes of the leaf node
    258  *	name.  If the leaf node was not successfully extracted, a
    259  *	somewhat meaningful string is placed in the buffer.  In
    260  *	either case, the contents of 'buf' will be NUL-terminated.
    261  */
    262 int
    263 of_packagename(int phandle, char *buf, int bufsize)
    264 {
    265 	char *pbuf;
    266 	const char *lastslash;
    267 	int l, rv;
    268 
    269 	pbuf = kmem_alloc(OFW_PATH_BUF_SIZE, KM_SLEEP);
    270 	l = OF_package_to_path(phandle, pbuf, OFW_PATH_BUF_SIZE);
    271 
    272 	/* check that we could get the name, and that it's not too long. */
    273 	if (l < 0 ||
    274 	    (l == OFW_PATH_BUF_SIZE && pbuf[OFW_PATH_BUF_SIZE - 1] != '\0')) {
    275 		if (bufsize >= 25)
    276 			snprintf(buf, bufsize, "??? (phandle 0x%x)", phandle);
    277 		else if (bufsize >= 4)
    278 			strlcpy(buf, "???", bufsize);
    279 		else
    280 			panic("of_packagename: bufsize = %d is silly",
    281 			    bufsize);
    282 		rv = -1;
    283 	} else {
    284 		pbuf[l] = '\0';
    285 		lastslash = strrchr(pbuf, '/');
    286 		strlcpy(buf, (lastslash == NULL) ? pbuf : (lastslash + 1),
    287 		    bufsize);
    288 		rv = 0;
    289 	}
    290 
    291 	kmem_free(pbuf, OFW_PATH_BUF_SIZE);
    292 	return (rv);
    293 }
    294 
    295 /*
    296  * Find the first child of a given node that matches name. Does not recurse.
    297  */
    298 int
    299 of_find_firstchild_byname(int node, const char *name)
    300 {
    301 	char namex[32];
    302 	int nn;
    303 
    304 	for (nn = OF_child(node); nn; nn = OF_peer(nn)) {
    305 		memset(namex, 0, sizeof(namex));
    306 		if (OF_getprop(nn, "name", namex, sizeof(namex)) == -1)
    307 			continue;
    308 		if (strcmp(name, namex) == 0)
    309 			return nn;
    310 	}
    311 	return -1;
    312 }
    313 
    314 /*
    315  * Find a child node that is compatible with str. Recurses, starting at node.
    316  */
    317 int
    318 of_find_bycompat(int node, const char *str)
    319 {
    320 	const char * compatible[] = { str, NULL };
    321 	int child, ret;
    322 
    323 	for (child = OF_child(node); child; child = OF_peer(child)) {
    324 		if (of_compatible(child, compatible))
    325 			return child;
    326 		ret = of_find_bycompat(child, str);
    327 		if (ret != -1)
    328 			return ret;
    329 	}
    330 
    331 	return -1;
    332 }
    333 
    334 /*
    335  * Find a give node by name.  Recurses, and seems to walk upwards too.
    336  */
    337 
    338 int
    339 of_getnode_byname(int start, const char *target)
    340 {
    341 	int node, next;
    342 	char name[64];
    343 
    344 	if (start == 0)
    345 		start = OF_peer(0);
    346 
    347 	for (node = start; node; node = next) {
    348 		memset(name, 0, sizeof name);
    349 		OF_getprop(node, "name", name, sizeof name - 1);
    350 		if (strcmp(name, target) == 0)
    351 			break;
    352 
    353 		if ((next = OF_child(node)) != 0)
    354 			continue;
    355 
    356 		while (node) {
    357 			if ((next = OF_peer(node)) != 0)
    358 				break;
    359 			node = OF_parent(node);
    360 		}
    361 	}
    362 
    363 	/* XXX is this correct? */
    364 	return node;
    365 }
    366 
    367 /*
    368  * Create a uint32_t integer property from an OFW node property.
    369  */
    370 
    371 bool
    372 of_to_uint32_prop(prop_dictionary_t dict, int node, const char *ofname,
    373     const char *propname)
    374 {
    375 	uint32_t prop;
    376 
    377 	if (OF_getprop(node, ofname, &prop, sizeof(prop)) != sizeof(prop))
    378 		return FALSE;
    379 
    380 	return(prop_dictionary_set_uint32(dict, propname, prop));
    381 }
    382 
    383 /*
    384  * Create a data property from an OFW node property.  Max size of 256bytes.
    385  */
    386 
    387 bool
    388 of_to_dataprop(prop_dictionary_t dict, int node, const char *ofname,
    389     const char *propname)
    390 {
    391 	int len;
    392 	uint8_t prop[256];
    393 
    394 	len = OF_getprop(node, ofname, prop, 256);
    395 	if (len < 1)
    396 		return FALSE;
    397 
    398 	return prop_dictionary_set_data(dict, propname, prop, len);
    399 }
    400 
    401 /*
    402  * look at output-device, see if there's a Sun-typical video mode specifier as
    403  * in screen:r1024x768x60 attached. If found copy it into *buffer, otherwise
    404  * return NULL
    405  */
    406 
    407 char *
    408 of_get_mode_string(char *buffer, int len)
    409 {
    410 	int options;
    411 	char *pos, output_device[256];
    412 
    413 	/*
    414 	 * finally, let's see if there's a video mode specified in
    415 	 * output-device and pass it on so there's at least some way
    416 	 * to program video modes
    417 	 */
    418 	options = OF_finddevice("/options");
    419 	if ((options == 0) || (options == -1))
    420 		return NULL;
    421 	if (OF_getprop(options, "output-device", output_device, 256) == 0)
    422 		return NULL;
    423 
    424 	/* find the mode string if there is one */
    425 	pos = strstr(output_device, ":r");
    426 	if (pos == NULL)
    427 		return NULL;
    428 	strncpy(buffer, pos + 2, len);
    429 	return buffer;
    430 }
    431 
    432 /*
    433  * Returns true if the specified property is present.
    434  */
    435 bool
    436 of_hasprop(int node, const char *prop)
    437 {
    438 	return OF_getproplen(node, prop) >= 0;
    439 }
    440 
    441 /*
    442  * Get the value of a uint32 property, compensating for host byte order.
    443  * Returns 0 on success, non-zero on failure.
    444  */
    445 int
    446 of_getprop_uint32(int node, const char *prop, uint32_t *val)
    447 {
    448 	uint32_t v;
    449 	int len;
    450 
    451 	len = OF_getprop(node, prop, &v, sizeof(v));
    452 	if (len != sizeof(v))
    453 		return -1;
    454 
    455 	*val = be32toh(v);
    456 	return 0;
    457 }
    458 
    459 int
    460 of_getprop_uint32_array(int node, const char *prop, uint32_t *array, int n)
    461 {
    462 	uint32_t *v = array;
    463 	int len;
    464 
    465 	len = OF_getprop(node, prop, array, n * sizeof(*v));
    466 	if (len < (int)(n * sizeof(*v)))
    467 		return -1;
    468 
    469 	for (; n > 0; n--) {
    470 		BE32TOH(*v);
    471 		v++;
    472 	}
    473 
    474 	return 0;
    475 }
    476 /*
    477  * Get the value of a uint64 property, compensating for host byte order.
    478  * Returns 0 on success, non-zero on failure.
    479  */
    480 int
    481 of_getprop_uint64(int node, const char *prop, uint64_t *val)
    482 {
    483 	uint64_t v;
    484 	int len;
    485 
    486 	len = OF_getprop(node, prop, &v, sizeof(v));
    487 	if (len != sizeof(v))
    488 		return -1;
    489 
    490 	*val = be64toh(v);
    491 	return 0;
    492 }
    493