15de18cdeSSam Ravnborg /* 25de18cdeSSam Ravnborg * tree.c: Basic device tree traversal/scanning for the Linux 35de18cdeSSam Ravnborg * prom library. 45de18cdeSSam Ravnborg * 55de18cdeSSam Ravnborg * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 65de18cdeSSam Ravnborg * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 75de18cdeSSam Ravnborg */ 85de18cdeSSam Ravnborg 95de18cdeSSam Ravnborg #include <linux/string.h> 105de18cdeSSam Ravnborg #include <linux/types.h> 115de18cdeSSam Ravnborg #include <linux/kernel.h> 125de18cdeSSam Ravnborg #include <linux/sched.h> 13917c3660SSam Ravnborg #include <linux/module.h> 145de18cdeSSam Ravnborg 155de18cdeSSam Ravnborg #include <asm/openprom.h> 165de18cdeSSam Ravnborg #include <asm/oplib.h> 175de18cdeSSam Ravnborg #include <asm/ldc.h> 185de18cdeSSam Ravnborg 19*25edd694SDavid S. Miller static int prom_node_to_node(const char *type, int node) 20*25edd694SDavid S. Miller { 21*25edd694SDavid S. Miller unsigned long args[5]; 22*25edd694SDavid S. Miller 23*25edd694SDavid S. Miller args[0] = (unsigned long) type; 24*25edd694SDavid S. Miller args[1] = 1; 25*25edd694SDavid S. Miller args[2] = 1; 26*25edd694SDavid S. Miller args[3] = (unsigned int) node; 27*25edd694SDavid S. Miller args[4] = (unsigned long) -1; 28*25edd694SDavid S. Miller 29*25edd694SDavid S. Miller p1275_cmd_direct(args); 30*25edd694SDavid S. Miller 31*25edd694SDavid S. Miller return (int) args[4]; 32*25edd694SDavid S. Miller } 33*25edd694SDavid S. Miller 345de18cdeSSam Ravnborg /* Return the child of node 'node' or zero if no this node has no 355de18cdeSSam Ravnborg * direct descendent. 365de18cdeSSam Ravnborg */ 375de18cdeSSam Ravnborg inline int __prom_getchild(int node) 385de18cdeSSam Ravnborg { 39*25edd694SDavid S. Miller return prom_node_to_node("child", node); 405de18cdeSSam Ravnborg } 415de18cdeSSam Ravnborg 425de18cdeSSam Ravnborg inline int prom_getchild(int node) 435de18cdeSSam Ravnborg { 445de18cdeSSam Ravnborg int cnode; 455de18cdeSSam Ravnborg 46*25edd694SDavid S. Miller if (node == -1) 47*25edd694SDavid S. Miller return 0; 485de18cdeSSam Ravnborg cnode = __prom_getchild(node); 49*25edd694SDavid S. Miller if (cnode == -1) 50*25edd694SDavid S. Miller return 0; 51*25edd694SDavid S. Miller return cnode; 525de18cdeSSam Ravnborg } 53917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getchild); 545de18cdeSSam Ravnborg 555de18cdeSSam Ravnborg inline int prom_getparent(int node) 565de18cdeSSam Ravnborg { 575de18cdeSSam Ravnborg int cnode; 585de18cdeSSam Ravnborg 59*25edd694SDavid S. Miller if (node == -1) 60*25edd694SDavid S. Miller return 0; 61*25edd694SDavid S. Miller cnode = prom_node_to_node("parent", node); 62*25edd694SDavid S. Miller if (cnode == -1) 63*25edd694SDavid S. Miller return 0; 64*25edd694SDavid S. Miller return cnode; 655de18cdeSSam Ravnborg } 665de18cdeSSam Ravnborg 675de18cdeSSam Ravnborg /* Return the next sibling of node 'node' or zero if no more siblings 685de18cdeSSam Ravnborg * at this level of depth in the tree. 695de18cdeSSam Ravnborg */ 705de18cdeSSam Ravnborg inline int __prom_getsibling(int node) 715de18cdeSSam Ravnborg { 72*25edd694SDavid S. Miller return prom_node_to_node(prom_peer_name, node); 735de18cdeSSam Ravnborg } 745de18cdeSSam Ravnborg 755de18cdeSSam Ravnborg inline int prom_getsibling(int node) 765de18cdeSSam Ravnborg { 775de18cdeSSam Ravnborg int sibnode; 785de18cdeSSam Ravnborg 795de18cdeSSam Ravnborg if (node == -1) 805de18cdeSSam Ravnborg return 0; 815de18cdeSSam Ravnborg sibnode = __prom_getsibling(node); 825de18cdeSSam Ravnborg if (sibnode == -1) 835de18cdeSSam Ravnborg return 0; 845de18cdeSSam Ravnborg 855de18cdeSSam Ravnborg return sibnode; 865de18cdeSSam Ravnborg } 87917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getsibling); 885de18cdeSSam Ravnborg 895de18cdeSSam Ravnborg /* Return the length in bytes of property 'prop' at node 'node'. 905de18cdeSSam Ravnborg * Return -1 on error. 915de18cdeSSam Ravnborg */ 925de18cdeSSam Ravnborg inline int prom_getproplen(int node, const char *prop) 935de18cdeSSam Ravnborg { 94*25edd694SDavid S. Miller unsigned long args[6]; 95*25edd694SDavid S. Miller 96*25edd694SDavid S. Miller if (!node || !prop) 97*25edd694SDavid S. Miller return -1; 98*25edd694SDavid S. Miller 99*25edd694SDavid S. Miller args[0] = (unsigned long) "getproplen"; 100*25edd694SDavid S. Miller args[1] = 2; 101*25edd694SDavid S. Miller args[2] = 1; 102*25edd694SDavid S. Miller args[3] = (unsigned int) node; 103*25edd694SDavid S. Miller args[4] = (unsigned long) prop; 104*25edd694SDavid S. Miller args[5] = (unsigned long) -1; 105*25edd694SDavid S. Miller 106*25edd694SDavid S. Miller p1275_cmd_direct(args); 107*25edd694SDavid S. Miller 108*25edd694SDavid S. Miller return (int) args[5]; 1095de18cdeSSam Ravnborg } 110917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproplen); 1115de18cdeSSam Ravnborg 1125de18cdeSSam Ravnborg /* Acquire a property 'prop' at node 'node' and place it in 1135de18cdeSSam Ravnborg * 'buffer' which has a size of 'bufsize'. If the acquisition 1145de18cdeSSam Ravnborg * was successful the length will be returned, else -1 is returned. 1155de18cdeSSam Ravnborg */ 1165de18cdeSSam Ravnborg inline int prom_getproperty(int node, const char *prop, 1175de18cdeSSam Ravnborg char *buffer, int bufsize) 1185de18cdeSSam Ravnborg { 119*25edd694SDavid S. Miller unsigned long args[8]; 1205de18cdeSSam Ravnborg int plen; 1215de18cdeSSam Ravnborg 1225de18cdeSSam Ravnborg plen = prom_getproplen(node, prop); 123*25edd694SDavid S. Miller if ((plen > bufsize) || (plen == 0) || (plen == -1)) 1245de18cdeSSam Ravnborg return -1; 125*25edd694SDavid S. Miller 126*25edd694SDavid S. Miller args[0] = (unsigned long) prom_getprop_name; 127*25edd694SDavid S. Miller args[1] = 4; 128*25edd694SDavid S. Miller args[2] = 1; 129*25edd694SDavid S. Miller args[3] = (unsigned int) node; 130*25edd694SDavid S. Miller args[4] = (unsigned long) prop; 131*25edd694SDavid S. Miller args[5] = (unsigned long) buffer; 132*25edd694SDavid S. Miller args[6] = bufsize; 133*25edd694SDavid S. Miller args[7] = (unsigned long) -1; 134*25edd694SDavid S. Miller 135*25edd694SDavid S. Miller p1275_cmd_direct(args); 136*25edd694SDavid S. Miller 137*25edd694SDavid S. Miller return (int) args[7]; 1385de18cdeSSam Ravnborg } 139917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getproperty); 1405de18cdeSSam Ravnborg 1415de18cdeSSam Ravnborg /* Acquire an integer property and return its value. Returns -1 1425de18cdeSSam Ravnborg * on failure. 1435de18cdeSSam Ravnborg */ 1445de18cdeSSam Ravnborg inline int prom_getint(int node, const char *prop) 1455de18cdeSSam Ravnborg { 1465de18cdeSSam Ravnborg int intprop; 1475de18cdeSSam Ravnborg 1485de18cdeSSam Ravnborg if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) 1495de18cdeSSam Ravnborg return intprop; 1505de18cdeSSam Ravnborg 1515de18cdeSSam Ravnborg return -1; 1525de18cdeSSam Ravnborg } 153917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getint); 1545de18cdeSSam Ravnborg 1555de18cdeSSam Ravnborg /* Acquire an integer property, upon error return the passed default 1565de18cdeSSam Ravnborg * integer. 1575de18cdeSSam Ravnborg */ 1585de18cdeSSam Ravnborg 1595de18cdeSSam Ravnborg int prom_getintdefault(int node, const char *property, int deflt) 1605de18cdeSSam Ravnborg { 1615de18cdeSSam Ravnborg int retval; 1625de18cdeSSam Ravnborg 1635de18cdeSSam Ravnborg retval = prom_getint(node, property); 164*25edd694SDavid S. Miller if (retval == -1) 165*25edd694SDavid S. Miller return deflt; 1665de18cdeSSam Ravnborg 1675de18cdeSSam Ravnborg return retval; 1685de18cdeSSam Ravnborg } 169917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getintdefault); 1705de18cdeSSam Ravnborg 1715de18cdeSSam Ravnborg /* Acquire a boolean property, 1=TRUE 0=FALSE. */ 1725de18cdeSSam Ravnborg int prom_getbool(int node, const char *prop) 1735de18cdeSSam Ravnborg { 1745de18cdeSSam Ravnborg int retval; 1755de18cdeSSam Ravnborg 1765de18cdeSSam Ravnborg retval = prom_getproplen(node, prop); 177*25edd694SDavid S. Miller if (retval == -1) 178*25edd694SDavid S. Miller return 0; 1795de18cdeSSam Ravnborg return 1; 1805de18cdeSSam Ravnborg } 181917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getbool); 1825de18cdeSSam Ravnborg 1835de18cdeSSam Ravnborg /* Acquire a property whose value is a string, returns a null 1845de18cdeSSam Ravnborg * string on error. The char pointer is the user supplied string 1855de18cdeSSam Ravnborg * buffer. 1865de18cdeSSam Ravnborg */ 1875de18cdeSSam Ravnborg void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) 1885de18cdeSSam Ravnborg { 1895de18cdeSSam Ravnborg int len; 1905de18cdeSSam Ravnborg 1915de18cdeSSam Ravnborg len = prom_getproperty(node, prop, user_buf, ubuf_size); 192*25edd694SDavid S. Miller if (len != -1) 193*25edd694SDavid S. Miller return; 1945de18cdeSSam Ravnborg user_buf[0] = 0; 1955de18cdeSSam Ravnborg } 196917c3660SSam Ravnborg EXPORT_SYMBOL(prom_getstring); 1975de18cdeSSam Ravnborg 1985de18cdeSSam Ravnborg /* Does the device at node 'node' have name 'name'? 1995de18cdeSSam Ravnborg * YES = 1 NO = 0 2005de18cdeSSam Ravnborg */ 2015de18cdeSSam Ravnborg int prom_nodematch(int node, const char *name) 2025de18cdeSSam Ravnborg { 2035de18cdeSSam Ravnborg char namebuf[128]; 2045de18cdeSSam Ravnborg prom_getproperty(node, "name", namebuf, sizeof(namebuf)); 205*25edd694SDavid S. Miller if (strcmp(namebuf, name) == 0) 206*25edd694SDavid S. Miller return 1; 2075de18cdeSSam Ravnborg return 0; 2085de18cdeSSam Ravnborg } 2095de18cdeSSam Ravnborg 2105de18cdeSSam Ravnborg /* Search siblings at 'node_start' for a node with name 2115de18cdeSSam Ravnborg * 'nodename'. Return node if successful, zero if not. 2125de18cdeSSam Ravnborg */ 2135de18cdeSSam Ravnborg int prom_searchsiblings(int node_start, const char *nodename) 2145de18cdeSSam Ravnborg { 2155de18cdeSSam Ravnborg 2165de18cdeSSam Ravnborg int thisnode, error; 2175de18cdeSSam Ravnborg char promlib_buf[128]; 2185de18cdeSSam Ravnborg 2195de18cdeSSam Ravnborg for(thisnode = node_start; thisnode; 2205de18cdeSSam Ravnborg thisnode=prom_getsibling(thisnode)) { 2215de18cdeSSam Ravnborg error = prom_getproperty(thisnode, "name", promlib_buf, 2225de18cdeSSam Ravnborg sizeof(promlib_buf)); 2235de18cdeSSam Ravnborg /* Should this ever happen? */ 2245de18cdeSSam Ravnborg if(error == -1) continue; 2255de18cdeSSam Ravnborg if(strcmp(nodename, promlib_buf)==0) return thisnode; 2265de18cdeSSam Ravnborg } 2275de18cdeSSam Ravnborg 2285de18cdeSSam Ravnborg return 0; 2295de18cdeSSam Ravnborg } 230917c3660SSam Ravnborg EXPORT_SYMBOL(prom_searchsiblings); 2315de18cdeSSam Ravnborg 232*25edd694SDavid S. Miller static const char *prom_nextprop_name = "nextprop"; 233*25edd694SDavid S. Miller 2345de18cdeSSam Ravnborg /* Return the first property type for node 'node'. 2355de18cdeSSam Ravnborg * buffer should be at least 32B in length 2365de18cdeSSam Ravnborg */ 2375de18cdeSSam Ravnborg inline char *prom_firstprop(int node, char *buffer) 2385de18cdeSSam Ravnborg { 239*25edd694SDavid S. Miller unsigned long args[7]; 240*25edd694SDavid S. Miller 2415de18cdeSSam Ravnborg *buffer = 0; 242*25edd694SDavid S. Miller if (node == -1) 243*25edd694SDavid S. Miller return buffer; 244*25edd694SDavid S. Miller 245*25edd694SDavid S. Miller args[0] = (unsigned long) prom_nextprop_name; 246*25edd694SDavid S. Miller args[1] = 3; 247*25edd694SDavid S. Miller args[2] = 1; 248*25edd694SDavid S. Miller args[3] = (unsigned int) node; 249*25edd694SDavid S. Miller args[4] = 0; 250*25edd694SDavid S. Miller args[5] = (unsigned long) buffer; 251*25edd694SDavid S. Miller args[6] = (unsigned long) -1; 252*25edd694SDavid S. Miller 253*25edd694SDavid S. Miller p1275_cmd_direct(args); 254*25edd694SDavid S. Miller 2555de18cdeSSam Ravnborg return buffer; 2565de18cdeSSam Ravnborg } 257917c3660SSam Ravnborg EXPORT_SYMBOL(prom_firstprop); 2585de18cdeSSam Ravnborg 2595de18cdeSSam Ravnborg /* Return the property type string after property type 'oprop' 2605de18cdeSSam Ravnborg * at node 'node' . Returns NULL string if no more 2615de18cdeSSam Ravnborg * property types for this node. 2625de18cdeSSam Ravnborg */ 2635de18cdeSSam Ravnborg inline char *prom_nextprop(int node, const char *oprop, char *buffer) 2645de18cdeSSam Ravnborg { 265*25edd694SDavid S. Miller unsigned long args[7]; 2665de18cdeSSam Ravnborg char buf[32]; 2675de18cdeSSam Ravnborg 2685de18cdeSSam Ravnborg if (node == -1) { 2695de18cdeSSam Ravnborg *buffer = 0; 2705de18cdeSSam Ravnborg return buffer; 2715de18cdeSSam Ravnborg } 2725de18cdeSSam Ravnborg if (oprop == buffer) { 2735de18cdeSSam Ravnborg strcpy (buf, oprop); 2745de18cdeSSam Ravnborg oprop = buf; 2755de18cdeSSam Ravnborg } 276*25edd694SDavid S. Miller 277*25edd694SDavid S. Miller args[0] = (unsigned long) prom_nextprop_name; 278*25edd694SDavid S. Miller args[1] = 3; 279*25edd694SDavid S. Miller args[2] = 1; 280*25edd694SDavid S. Miller args[3] = (unsigned int) node; 281*25edd694SDavid S. Miller args[4] = (unsigned long) oprop; 282*25edd694SDavid S. Miller args[5] = (unsigned long) buffer; 283*25edd694SDavid S. Miller args[6] = (unsigned long) -1; 284*25edd694SDavid S. Miller 285*25edd694SDavid S. Miller p1275_cmd_direct(args); 286*25edd694SDavid S. Miller 2875de18cdeSSam Ravnborg return buffer; 2885de18cdeSSam Ravnborg } 289917c3660SSam Ravnborg EXPORT_SYMBOL(prom_nextprop); 2905de18cdeSSam Ravnborg 2915de18cdeSSam Ravnborg int 2925de18cdeSSam Ravnborg prom_finddevice(const char *name) 2935de18cdeSSam Ravnborg { 294*25edd694SDavid S. Miller unsigned long args[5]; 295*25edd694SDavid S. Miller 2965de18cdeSSam Ravnborg if (!name) 2975de18cdeSSam Ravnborg return 0; 298*25edd694SDavid S. Miller args[0] = (unsigned long) "finddevice"; 299*25edd694SDavid S. Miller args[1] = 1; 300*25edd694SDavid S. Miller args[2] = 1; 301*25edd694SDavid S. Miller args[3] = (unsigned long) name; 302*25edd694SDavid S. Miller args[4] = (unsigned long) -1; 303*25edd694SDavid S. Miller 304*25edd694SDavid S. Miller p1275_cmd_direct(args); 305*25edd694SDavid S. Miller 306*25edd694SDavid S. Miller return (int) args[4]; 3075de18cdeSSam Ravnborg } 308917c3660SSam Ravnborg EXPORT_SYMBOL(prom_finddevice); 3095de18cdeSSam Ravnborg 3105de18cdeSSam Ravnborg int prom_node_has_property(int node, const char *prop) 3115de18cdeSSam Ravnborg { 3125de18cdeSSam Ravnborg char buf [32]; 3135de18cdeSSam Ravnborg 3145de18cdeSSam Ravnborg *buf = 0; 3155de18cdeSSam Ravnborg do { 3165de18cdeSSam Ravnborg prom_nextprop(node, buf, buf); 3175de18cdeSSam Ravnborg if (!strcmp(buf, prop)) 3185de18cdeSSam Ravnborg return 1; 3195de18cdeSSam Ravnborg } while (*buf); 3205de18cdeSSam Ravnborg return 0; 3215de18cdeSSam Ravnborg } 322917c3660SSam Ravnborg EXPORT_SYMBOL(prom_node_has_property); 3235de18cdeSSam Ravnborg 3245de18cdeSSam Ravnborg /* Set property 'pname' at node 'node' to value 'value' which has a length 3255de18cdeSSam Ravnborg * of 'size' bytes. Return the number of bytes the prom accepted. 3265de18cdeSSam Ravnborg */ 3275de18cdeSSam Ravnborg int 3285de18cdeSSam Ravnborg prom_setprop(int node, const char *pname, char *value, int size) 3295de18cdeSSam Ravnborg { 330*25edd694SDavid S. Miller unsigned long args[8]; 331*25edd694SDavid S. Miller 3325de18cdeSSam Ravnborg if (size == 0) 3335de18cdeSSam Ravnborg return 0; 3345de18cdeSSam Ravnborg if ((pname == 0) || (value == 0)) 3355de18cdeSSam Ravnborg return 0; 3365de18cdeSSam Ravnborg 3375de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS 3385de18cdeSSam Ravnborg if (ldom_domaining_enabled) { 3395de18cdeSSam Ravnborg ldom_set_var(pname, value); 3405de18cdeSSam Ravnborg return 0; 3415de18cdeSSam Ravnborg } 3425de18cdeSSam Ravnborg #endif 343*25edd694SDavid S. Miller args[0] = (unsigned long) "setprop"; 344*25edd694SDavid S. Miller args[1] = 4; 345*25edd694SDavid S. Miller args[2] = 1; 346*25edd694SDavid S. Miller args[3] = (unsigned int) node; 347*25edd694SDavid S. Miller args[4] = (unsigned long) pname; 348*25edd694SDavid S. Miller args[5] = (unsigned long) value; 349*25edd694SDavid S. Miller args[6] = size; 350*25edd694SDavid S. Miller args[7] = (unsigned long) -1; 351*25edd694SDavid S. Miller 352*25edd694SDavid S. Miller p1275_cmd_direct(args); 353*25edd694SDavid S. Miller 354*25edd694SDavid S. Miller return (int) args[7]; 3555de18cdeSSam Ravnborg } 356917c3660SSam Ravnborg EXPORT_SYMBOL(prom_setprop); 3575de18cdeSSam Ravnborg 3585de18cdeSSam Ravnborg inline int prom_inst2pkg(int inst) 3595de18cdeSSam Ravnborg { 360*25edd694SDavid S. Miller unsigned long args[5]; 3615de18cdeSSam Ravnborg int node; 3625de18cdeSSam Ravnborg 363*25edd694SDavid S. Miller args[0] = (unsigned long) "instance-to-package"; 364*25edd694SDavid S. Miller args[1] = 1; 365*25edd694SDavid S. Miller args[2] = 1; 366*25edd694SDavid S. Miller args[3] = (unsigned int) inst; 367*25edd694SDavid S. Miller args[4] = (unsigned long) -1; 368*25edd694SDavid S. Miller 369*25edd694SDavid S. Miller p1275_cmd_direct(args); 370*25edd694SDavid S. Miller 371*25edd694SDavid S. Miller node = (int) args[4]; 372*25edd694SDavid S. Miller if (node == -1) 373*25edd694SDavid S. Miller return 0; 3745de18cdeSSam Ravnborg return node; 3755de18cdeSSam Ravnborg } 3765de18cdeSSam Ravnborg 3775de18cdeSSam Ravnborg /* Return 'node' assigned to a particular prom 'path' 3785de18cdeSSam Ravnborg * FIXME: Should work for v0 as well 3795de18cdeSSam Ravnborg */ 3805de18cdeSSam Ravnborg int 3815de18cdeSSam Ravnborg prom_pathtoinode(const char *path) 3825de18cdeSSam Ravnborg { 3835de18cdeSSam Ravnborg int node, inst; 3845de18cdeSSam Ravnborg 3855de18cdeSSam Ravnborg inst = prom_devopen (path); 386*25edd694SDavid S. Miller if (inst == 0) 387*25edd694SDavid S. Miller return 0; 3885de18cdeSSam Ravnborg node = prom_inst2pkg(inst); 3895de18cdeSSam Ravnborg prom_devclose(inst); 390*25edd694SDavid S. Miller if (node == -1) 391*25edd694SDavid S. Miller return 0; 3925de18cdeSSam Ravnborg return node; 3935de18cdeSSam Ravnborg } 3945de18cdeSSam Ravnborg 3955de18cdeSSam Ravnborg int prom_ihandle2path(int handle, char *buffer, int bufsize) 3965de18cdeSSam Ravnborg { 397*25edd694SDavid S. Miller unsigned long args[7]; 398*25edd694SDavid S. Miller 399*25edd694SDavid S. Miller args[0] = (unsigned long) "instance-to-path"; 400*25edd694SDavid S. Miller args[1] = 3; 401*25edd694SDavid S. Miller args[2] = 1; 402*25edd694SDavid S. Miller args[3] = (unsigned int) handle; 403*25edd694SDavid S. Miller args[4] = (unsigned long) buffer; 404*25edd694SDavid S. Miller args[5] = bufsize; 405*25edd694SDavid S. Miller args[6] = (unsigned long) -1; 406*25edd694SDavid S. Miller 407*25edd694SDavid S. Miller p1275_cmd_direct(args); 408*25edd694SDavid S. Miller 409*25edd694SDavid S. Miller return (int) args[6]; 4105de18cdeSSam Ravnborg } 411