xref: /linux/arch/sparc/prom/tree_64.c (revision 594ce0b8a998aa4d05827cd7c0d0dcec9a1e3ae2)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
25de18cdeSSam Ravnborg /*
35de18cdeSSam Ravnborg  * tree.c: Basic device tree traversal/scanning for the Linux
45de18cdeSSam Ravnborg  *         prom library.
55de18cdeSSam Ravnborg  *
65de18cdeSSam Ravnborg  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
75de18cdeSSam Ravnborg  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
85de18cdeSSam Ravnborg  */
95de18cdeSSam Ravnborg 
105de18cdeSSam Ravnborg #include <linux/string.h>
115de18cdeSSam Ravnborg #include <linux/types.h>
125de18cdeSSam Ravnborg #include <linux/kernel.h>
135de18cdeSSam Ravnborg #include <linux/sched.h>
14917c3660SSam Ravnborg #include <linux/module.h>
155de18cdeSSam Ravnborg 
165de18cdeSSam Ravnborg #include <asm/openprom.h>
175de18cdeSSam Ravnborg #include <asm/oplib.h>
185de18cdeSSam Ravnborg #include <asm/ldc.h>
195de18cdeSSam Ravnborg 
208d125562SAndres Salomon static phandle prom_node_to_node(const char *type, phandle node)
2125edd694SDavid S. Miller {
2225edd694SDavid S. Miller 	unsigned long args[5];
2325edd694SDavid S. Miller 
2425edd694SDavid S. Miller 	args[0] = (unsigned long) type;
2525edd694SDavid S. Miller 	args[1] = 1;
2625edd694SDavid S. Miller 	args[2] = 1;
2725edd694SDavid S. Miller 	args[3] = (unsigned int) node;
2825edd694SDavid S. Miller 	args[4] = (unsigned long) -1;
2925edd694SDavid S. Miller 
3025edd694SDavid S. Miller 	p1275_cmd_direct(args);
3125edd694SDavid S. Miller 
328d125562SAndres Salomon 	return (phandle) args[4];
3325edd694SDavid S. Miller }
3425edd694SDavid S. Miller 
355de18cdeSSam Ravnborg /* Return the child of node 'node' or zero if no this node has no
365de18cdeSSam Ravnborg  * direct descendent.
375de18cdeSSam Ravnborg  */
388d125562SAndres Salomon inline phandle __prom_getchild(phandle node)
395de18cdeSSam Ravnborg {
4025edd694SDavid S. Miller 	return prom_node_to_node("child", node);
415de18cdeSSam Ravnborg }
425de18cdeSSam Ravnborg 
43dbebe0daSDenis Efremov phandle prom_getchild(phandle node)
445de18cdeSSam Ravnborg {
458d125562SAndres Salomon 	phandle cnode;
465de18cdeSSam Ravnborg 
474a3a2552SAndres Salomon 	if ((s32)node == -1)
4825edd694SDavid S. Miller 		return 0;
495de18cdeSSam Ravnborg 	cnode = __prom_getchild(node);
504a3a2552SAndres Salomon 	if ((s32)cnode == -1)
5125edd694SDavid S. Miller 		return 0;
5225edd694SDavid S. Miller 	return cnode;
535de18cdeSSam Ravnborg }
54917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getchild);
555de18cdeSSam Ravnborg 
568d125562SAndres Salomon inline phandle prom_getparent(phandle node)
575de18cdeSSam Ravnborg {
588d125562SAndres Salomon 	phandle cnode;
595de18cdeSSam Ravnborg 
604a3a2552SAndres Salomon 	if ((s32)node == -1)
6125edd694SDavid S. Miller 		return 0;
6225edd694SDavid S. Miller 	cnode = prom_node_to_node("parent", node);
634a3a2552SAndres Salomon 	if ((s32)cnode == -1)
6425edd694SDavid S. Miller 		return 0;
6525edd694SDavid S. Miller 	return cnode;
665de18cdeSSam Ravnborg }
675de18cdeSSam Ravnborg 
685de18cdeSSam Ravnborg /* Return the next sibling of node 'node' or zero if no more siblings
695de18cdeSSam Ravnborg  * at this level of depth in the tree.
705de18cdeSSam Ravnborg  */
718d125562SAndres Salomon inline phandle __prom_getsibling(phandle node)
725de18cdeSSam Ravnborg {
7325edd694SDavid S. Miller 	return prom_node_to_node(prom_peer_name, node);
745de18cdeSSam Ravnborg }
755de18cdeSSam Ravnborg 
76dbebe0daSDenis Efremov phandle prom_getsibling(phandle node)
775de18cdeSSam Ravnborg {
788d125562SAndres Salomon 	phandle sibnode;
795de18cdeSSam Ravnborg 
804a3a2552SAndres Salomon 	if ((s32)node == -1)
815de18cdeSSam Ravnborg 		return 0;
825de18cdeSSam Ravnborg 	sibnode = __prom_getsibling(node);
834a3a2552SAndres Salomon 	if ((s32)sibnode == -1)
845de18cdeSSam Ravnborg 		return 0;
855de18cdeSSam Ravnborg 
865de18cdeSSam Ravnborg 	return sibnode;
875de18cdeSSam Ravnborg }
88917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getsibling);
895de18cdeSSam Ravnborg 
905de18cdeSSam Ravnborg /* Return the length in bytes of property 'prop' at node 'node'.
915de18cdeSSam Ravnborg  * Return -1 on error.
925de18cdeSSam Ravnborg  */
93dbebe0daSDenis Efremov int prom_getproplen(phandle node, const char *prop)
945de18cdeSSam Ravnborg {
9525edd694SDavid S. Miller 	unsigned long args[6];
9625edd694SDavid S. Miller 
9725edd694SDavid S. Miller 	if (!node || !prop)
9825edd694SDavid S. Miller 		return -1;
9925edd694SDavid S. Miller 
10025edd694SDavid S. Miller 	args[0] = (unsigned long) "getproplen";
10125edd694SDavid S. Miller 	args[1] = 2;
10225edd694SDavid S. Miller 	args[2] = 1;
10325edd694SDavid S. Miller 	args[3] = (unsigned int) node;
10425edd694SDavid S. Miller 	args[4] = (unsigned long) prop;
10525edd694SDavid S. Miller 	args[5] = (unsigned long) -1;
10625edd694SDavid S. Miller 
10725edd694SDavid S. Miller 	p1275_cmd_direct(args);
10825edd694SDavid S. Miller 
10925edd694SDavid S. Miller 	return (int) args[5];
1105de18cdeSSam Ravnborg }
111917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproplen);
1125de18cdeSSam Ravnborg 
1135de18cdeSSam Ravnborg /* Acquire a property 'prop' at node 'node' and place it in
1145de18cdeSSam Ravnborg  * 'buffer' which has a size of 'bufsize'.  If the acquisition
1155de18cdeSSam Ravnborg  * was successful the length will be returned, else -1 is returned.
1165de18cdeSSam Ravnborg  */
117dbebe0daSDenis Efremov int prom_getproperty(phandle node, const char *prop,
1185de18cdeSSam Ravnborg 		     char *buffer, int bufsize)
1195de18cdeSSam Ravnborg {
12025edd694SDavid S. Miller 	unsigned long args[8];
1215de18cdeSSam Ravnborg 	int plen;
1225de18cdeSSam Ravnborg 
1235de18cdeSSam Ravnborg 	plen = prom_getproplen(node, prop);
12425edd694SDavid S. Miller 	if ((plen > bufsize) || (plen == 0) || (plen == -1))
1255de18cdeSSam Ravnborg 		return -1;
12625edd694SDavid S. Miller 
12725edd694SDavid S. Miller 	args[0] = (unsigned long) prom_getprop_name;
12825edd694SDavid S. Miller 	args[1] = 4;
12925edd694SDavid S. Miller 	args[2] = 1;
13025edd694SDavid S. Miller 	args[3] = (unsigned int) node;
13125edd694SDavid S. Miller 	args[4] = (unsigned long) prop;
13225edd694SDavid S. Miller 	args[5] = (unsigned long) buffer;
13325edd694SDavid S. Miller 	args[6] = bufsize;
13425edd694SDavid S. Miller 	args[7] = (unsigned long) -1;
13525edd694SDavid S. Miller 
13625edd694SDavid S. Miller 	p1275_cmd_direct(args);
13725edd694SDavid S. Miller 
13825edd694SDavid S. Miller 	return (int) args[7];
1395de18cdeSSam Ravnborg }
140917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproperty);
1415de18cdeSSam Ravnborg 
1425de18cdeSSam Ravnborg /* Acquire an integer property and return its value.  Returns -1
1435de18cdeSSam Ravnborg  * on failure.
1445de18cdeSSam Ravnborg  */
145dbebe0daSDenis Efremov int prom_getint(phandle node, const char *prop)
1465de18cdeSSam Ravnborg {
1475de18cdeSSam Ravnborg 	int intprop;
1485de18cdeSSam Ravnborg 
1495de18cdeSSam Ravnborg 	if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
1505de18cdeSSam Ravnborg 		return intprop;
1515de18cdeSSam Ravnborg 
1525de18cdeSSam Ravnborg 	return -1;
1535de18cdeSSam Ravnborg }
154917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getint);
1555de18cdeSSam Ravnborg 
1565de18cdeSSam Ravnborg /* Acquire an integer property, upon error return the passed default
1575de18cdeSSam Ravnborg  * integer.
1585de18cdeSSam Ravnborg  */
1595de18cdeSSam Ravnborg 
1608d125562SAndres Salomon int prom_getintdefault(phandle node, const char *property, int deflt)
1615de18cdeSSam Ravnborg {
1625de18cdeSSam Ravnborg 	int retval;
1635de18cdeSSam Ravnborg 
1645de18cdeSSam Ravnborg 	retval = prom_getint(node, property);
16525edd694SDavid S. Miller 	if (retval == -1)
16625edd694SDavid S. Miller 		return deflt;
1675de18cdeSSam Ravnborg 
1685de18cdeSSam Ravnborg 	return retval;
1695de18cdeSSam Ravnborg }
170917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getintdefault);
1715de18cdeSSam Ravnborg 
1725de18cdeSSam Ravnborg /* Acquire a boolean property, 1=TRUE 0=FALSE. */
1738d125562SAndres Salomon int prom_getbool(phandle node, const char *prop)
1745de18cdeSSam Ravnborg {
1755de18cdeSSam Ravnborg 	int retval;
1765de18cdeSSam Ravnborg 
1775de18cdeSSam Ravnborg 	retval = prom_getproplen(node, prop);
17825edd694SDavid S. Miller 	if (retval == -1)
17925edd694SDavid S. Miller 		return 0;
1805de18cdeSSam Ravnborg 	return 1;
1815de18cdeSSam Ravnborg }
182917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getbool);
1835de18cdeSSam Ravnborg 
1845de18cdeSSam Ravnborg /* Acquire a property whose value is a string, returns a null
1855de18cdeSSam Ravnborg  * string on error.  The char pointer is the user supplied string
1865de18cdeSSam Ravnborg  * buffer.
1875de18cdeSSam Ravnborg  */
1888d125562SAndres Salomon void prom_getstring(phandle node, const char *prop, char *user_buf,
1898d125562SAndres Salomon 		int ubuf_size)
1905de18cdeSSam Ravnborg {
1915de18cdeSSam Ravnborg 	int len;
1925de18cdeSSam Ravnborg 
1935de18cdeSSam Ravnborg 	len = prom_getproperty(node, prop, user_buf, ubuf_size);
19425edd694SDavid S. Miller 	if (len != -1)
19525edd694SDavid S. Miller 		return;
1965de18cdeSSam Ravnborg 	user_buf[0] = 0;
1975de18cdeSSam Ravnborg }
198917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getstring);
1995de18cdeSSam Ravnborg 
2005de18cdeSSam Ravnborg /* Does the device at node 'node' have name 'name'?
2015de18cdeSSam Ravnborg  * YES = 1   NO = 0
2025de18cdeSSam Ravnborg  */
2038d125562SAndres Salomon int prom_nodematch(phandle node, const char *name)
2045de18cdeSSam Ravnborg {
2055de18cdeSSam Ravnborg 	char namebuf[128];
2065de18cdeSSam Ravnborg 	prom_getproperty(node, "name", namebuf, sizeof(namebuf));
20725edd694SDavid S. Miller 	if (strcmp(namebuf, name) == 0)
20825edd694SDavid S. Miller 		return 1;
2095de18cdeSSam Ravnborg 	return 0;
2105de18cdeSSam Ravnborg }
2115de18cdeSSam Ravnborg 
2125de18cdeSSam Ravnborg /* Search siblings at 'node_start' for a node with name
2135de18cdeSSam Ravnborg  * 'nodename'.  Return node if successful, zero if not.
2145de18cdeSSam Ravnborg  */
2158d125562SAndres Salomon phandle prom_searchsiblings(phandle node_start, const char *nodename)
2165de18cdeSSam Ravnborg {
2178d125562SAndres Salomon 	phandle thisnode;
2188d125562SAndres Salomon 	int error;
2195de18cdeSSam Ravnborg 	char promlib_buf[128];
2205de18cdeSSam Ravnborg 
2215de18cdeSSam Ravnborg 	for(thisnode = node_start; thisnode;
2225de18cdeSSam Ravnborg 	    thisnode=prom_getsibling(thisnode)) {
2235de18cdeSSam Ravnborg 		error = prom_getproperty(thisnode, "name", promlib_buf,
2245de18cdeSSam Ravnborg 					 sizeof(promlib_buf));
2255de18cdeSSam Ravnborg 		/* Should this ever happen? */
2265de18cdeSSam Ravnborg 		if(error == -1) continue;
2275de18cdeSSam Ravnborg 		if(strcmp(nodename, promlib_buf)==0) return thisnode;
2285de18cdeSSam Ravnborg 	}
2295de18cdeSSam Ravnborg 
2305de18cdeSSam Ravnborg 	return 0;
2315de18cdeSSam Ravnborg }
232917c3660SSam Ravnborg EXPORT_SYMBOL(prom_searchsiblings);
2335de18cdeSSam Ravnborg 
23425edd694SDavid S. Miller static const char *prom_nextprop_name = "nextprop";
23525edd694SDavid S. Miller 
2365de18cdeSSam Ravnborg /* Return the first property type for node 'node'.
2375de18cdeSSam Ravnborg  * buffer should be at least 32B in length
2385de18cdeSSam Ravnborg  */
239dbebe0daSDenis Efremov char *prom_firstprop(phandle node, char *buffer)
2405de18cdeSSam Ravnborg {
24125edd694SDavid S. Miller 	unsigned long args[7];
24225edd694SDavid S. Miller 
2435de18cdeSSam Ravnborg 	*buffer = 0;
2444a3a2552SAndres Salomon 	if ((s32)node == -1)
24525edd694SDavid S. Miller 		return buffer;
24625edd694SDavid S. Miller 
24725edd694SDavid S. Miller 	args[0] = (unsigned long) prom_nextprop_name;
24825edd694SDavid S. Miller 	args[1] = 3;
24925edd694SDavid S. Miller 	args[2] = 1;
25025edd694SDavid S. Miller 	args[3] = (unsigned int) node;
25125edd694SDavid S. Miller 	args[4] = 0;
25225edd694SDavid S. Miller 	args[5] = (unsigned long) buffer;
25325edd694SDavid S. Miller 	args[6] = (unsigned long) -1;
25425edd694SDavid S. Miller 
25525edd694SDavid S. Miller 	p1275_cmd_direct(args);
25625edd694SDavid S. Miller 
2575de18cdeSSam Ravnborg 	return buffer;
2585de18cdeSSam Ravnborg }
259917c3660SSam Ravnborg EXPORT_SYMBOL(prom_firstprop);
2605de18cdeSSam Ravnborg 
2615de18cdeSSam Ravnborg /* Return the property type string after property type 'oprop'
2625de18cdeSSam Ravnborg  * at node 'node' .  Returns NULL string if no more
2635de18cdeSSam Ravnborg  * property types for this node.
2645de18cdeSSam Ravnborg  */
265dbebe0daSDenis Efremov char *prom_nextprop(phandle node, const char *oprop, char *buffer)
2665de18cdeSSam Ravnborg {
26725edd694SDavid S. Miller 	unsigned long args[7];
2685de18cdeSSam Ravnborg 	char buf[32];
2695de18cdeSSam Ravnborg 
2704a3a2552SAndres Salomon 	if ((s32)node == -1) {
2715de18cdeSSam Ravnborg 		*buffer = 0;
2725de18cdeSSam Ravnborg 		return buffer;
2735de18cdeSSam Ravnborg 	}
2745de18cdeSSam Ravnborg 	if (oprop == buffer) {
2755de18cdeSSam Ravnborg 		strcpy (buf, oprop);
2765de18cdeSSam Ravnborg 		oprop = buf;
2775de18cdeSSam Ravnborg 	}
27825edd694SDavid S. Miller 
27925edd694SDavid S. Miller 	args[0] = (unsigned long) prom_nextprop_name;
28025edd694SDavid S. Miller 	args[1] = 3;
28125edd694SDavid S. Miller 	args[2] = 1;
28225edd694SDavid S. Miller 	args[3] = (unsigned int) node;
28325edd694SDavid S. Miller 	args[4] = (unsigned long) oprop;
28425edd694SDavid S. Miller 	args[5] = (unsigned long) buffer;
28525edd694SDavid S. Miller 	args[6] = (unsigned long) -1;
28625edd694SDavid S. Miller 
28725edd694SDavid S. Miller 	p1275_cmd_direct(args);
28825edd694SDavid S. Miller 
2895de18cdeSSam Ravnborg 	return buffer;
2905de18cdeSSam Ravnborg }
291917c3660SSam Ravnborg EXPORT_SYMBOL(prom_nextprop);
2925de18cdeSSam Ravnborg 
2938d125562SAndres Salomon phandle prom_finddevice(const char *name)
2945de18cdeSSam Ravnborg {
29525edd694SDavid S. Miller 	unsigned long args[5];
29625edd694SDavid S. Miller 
2975de18cdeSSam Ravnborg 	if (!name)
2985de18cdeSSam Ravnborg 		return 0;
29925edd694SDavid S. Miller 	args[0] = (unsigned long) "finddevice";
30025edd694SDavid S. Miller 	args[1] = 1;
30125edd694SDavid S. Miller 	args[2] = 1;
30225edd694SDavid S. Miller 	args[3] = (unsigned long) name;
30325edd694SDavid S. Miller 	args[4] = (unsigned long) -1;
30425edd694SDavid S. Miller 
30525edd694SDavid S. Miller 	p1275_cmd_direct(args);
30625edd694SDavid S. Miller 
30725edd694SDavid S. Miller 	return (int) args[4];
3085de18cdeSSam Ravnborg }
309917c3660SSam Ravnborg EXPORT_SYMBOL(prom_finddevice);
3105de18cdeSSam Ravnborg 
3118d125562SAndres Salomon int prom_node_has_property(phandle node, const char *prop)
3125de18cdeSSam Ravnborg {
3135de18cdeSSam Ravnborg 	char buf [32];
3145de18cdeSSam Ravnborg 
3155de18cdeSSam Ravnborg 	*buf = 0;
3165de18cdeSSam Ravnborg 	do {
3175de18cdeSSam Ravnborg 		prom_nextprop(node, buf, buf);
3185de18cdeSSam Ravnborg 		if (!strcmp(buf, prop))
3195de18cdeSSam Ravnborg 			return 1;
3205de18cdeSSam Ravnborg 	} while (*buf);
3215de18cdeSSam Ravnborg 	return 0;
3225de18cdeSSam Ravnborg }
323917c3660SSam Ravnborg EXPORT_SYMBOL(prom_node_has_property);
3245de18cdeSSam Ravnborg 
3255de18cdeSSam Ravnborg /* Set property 'pname' at node 'node' to value 'value' which has a length
3265de18cdeSSam Ravnborg  * of 'size' bytes.  Return the number of bytes the prom accepted.
3275de18cdeSSam Ravnborg  */
3285de18cdeSSam Ravnborg int
3298d125562SAndres Salomon prom_setprop(phandle node, const char *pname, char *value, int size)
3305de18cdeSSam Ravnborg {
33125edd694SDavid S. Miller 	unsigned long args[8];
33225edd694SDavid S. Miller 
3335de18cdeSSam Ravnborg 	if (size == 0)
3345de18cdeSSam Ravnborg 		return 0;
335*c7933eaeSThorsten Blum 	if ((pname == NULL) || (value == NULL))
3365de18cdeSSam Ravnborg 		return 0;
3375de18cdeSSam Ravnborg 
3385de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS
3395de18cdeSSam Ravnborg 	if (ldom_domaining_enabled) {
3405de18cdeSSam Ravnborg 		ldom_set_var(pname, value);
3415de18cdeSSam Ravnborg 		return 0;
3425de18cdeSSam Ravnborg 	}
3435de18cdeSSam Ravnborg #endif
34425edd694SDavid S. Miller 	args[0] = (unsigned long) "setprop";
34525edd694SDavid S. Miller 	args[1] = 4;
34625edd694SDavid S. Miller 	args[2] = 1;
34725edd694SDavid S. Miller 	args[3] = (unsigned int) node;
34825edd694SDavid S. Miller 	args[4] = (unsigned long) pname;
34925edd694SDavid S. Miller 	args[5] = (unsigned long) value;
35025edd694SDavid S. Miller 	args[6] = size;
35125edd694SDavid S. Miller 	args[7] = (unsigned long) -1;
35225edd694SDavid S. Miller 
35325edd694SDavid S. Miller 	p1275_cmd_direct(args);
35425edd694SDavid S. Miller 
35525edd694SDavid S. Miller 	return (int) args[7];
3565de18cdeSSam Ravnborg }
357917c3660SSam Ravnborg EXPORT_SYMBOL(prom_setprop);
3585de18cdeSSam Ravnborg 
3598d125562SAndres Salomon inline phandle prom_inst2pkg(int inst)
3605de18cdeSSam Ravnborg {
36125edd694SDavid S. Miller 	unsigned long args[5];
3628d125562SAndres Salomon 	phandle node;
3635de18cdeSSam Ravnborg 
36425edd694SDavid S. Miller 	args[0] = (unsigned long) "instance-to-package";
36525edd694SDavid S. Miller 	args[1] = 1;
36625edd694SDavid S. Miller 	args[2] = 1;
36725edd694SDavid S. Miller 	args[3] = (unsigned int) inst;
36825edd694SDavid S. Miller 	args[4] = (unsigned long) -1;
36925edd694SDavid S. Miller 
37025edd694SDavid S. Miller 	p1275_cmd_direct(args);
37125edd694SDavid S. Miller 
37225edd694SDavid S. Miller 	node = (int) args[4];
3734a3a2552SAndres Salomon 	if ((s32)node == -1)
37425edd694SDavid S. Miller 		return 0;
3755de18cdeSSam Ravnborg 	return node;
3765de18cdeSSam Ravnborg }
3775de18cdeSSam Ravnborg 
3785de18cdeSSam Ravnborg int prom_ihandle2path(int handle, char *buffer, int bufsize)
3795de18cdeSSam Ravnborg {
38025edd694SDavid S. Miller 	unsigned long args[7];
38125edd694SDavid S. Miller 
38225edd694SDavid S. Miller 	args[0] = (unsigned long) "instance-to-path";
38325edd694SDavid S. Miller 	args[1] = 3;
38425edd694SDavid S. Miller 	args[2] = 1;
38525edd694SDavid S. Miller 	args[3] = (unsigned int) handle;
38625edd694SDavid S. Miller 	args[4] = (unsigned long) buffer;
38725edd694SDavid S. Miller 	args[5] = bufsize;
38825edd694SDavid S. Miller 	args[6] = (unsigned long) -1;
38925edd694SDavid S. Miller 
39025edd694SDavid S. Miller 	p1275_cmd_direct(args);
39125edd694SDavid S. Miller 
39225edd694SDavid S. Miller 	return (int) args[6];
3935de18cdeSSam Ravnborg }
394