1/* prom_common.c: OF device tree support common code. 2 * 3 * Paul Mackerras August 1996. 4 * Copyright (C) 1996-2005 Paul Mackerras. 5 * 6 * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. 7 * {engebret|bergner}@us.ibm.com 8 * 9 * Adapted for sparc by David S. Miller davem@davemloft.net 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/errno.h> 20#include <linux/mutex.h> 21#include <linux/slab.h> 22#include <linux/of.h> 23#include <asm/prom.h> 24#include <asm/oplib.h> 25#include <asm/leon.h> 26 27#include "prom.h" 28 29void (*prom_build_more)(struct device_node *dp, struct device_node ***nextp); 30 31struct device_node *of_console_device; 32EXPORT_SYMBOL(of_console_device); 33 34char *of_console_path; 35EXPORT_SYMBOL(of_console_path); 36 37char *of_console_options; 38EXPORT_SYMBOL(of_console_options); 39 40int of_getintprop_default(struct device_node *np, const char *name, int def) 41{ 42 struct property *prop; 43 int len; 44 45 prop = of_find_property(np, name, &len); 46 if (!prop || len != 4) 47 return def; 48 49 return *(int *) prop->value; 50} 51EXPORT_SYMBOL(of_getintprop_default); 52 53DEFINE_MUTEX(of_set_property_mutex); 54EXPORT_SYMBOL(of_set_property_mutex); 55 56int of_set_property(struct device_node *dp, const char *name, void *val, int len) 57{ 58 struct property **prevp; 59 void *new_val; 60 int err; 61 62 new_val = kmalloc(len, GFP_KERNEL); 63 if (!new_val) 64 return -ENOMEM; 65 66 memcpy(new_val, val, len); 67 68 err = -ENODEV; 69 70 mutex_lock(&of_set_property_mutex); 71 write_lock(&devtree_lock); 72 prevp = &dp->properties; 73 while (*prevp) { 74 struct property *prop = *prevp; 75 76 if (!strcasecmp(prop->name, name)) { 77 void *old_val = prop->value; 78 int ret; 79 80 ret = prom_setprop(dp->phandle, name, val, len); 81 82 err = -EINVAL; 83 if (ret >= 0) { 84 prop->value = new_val; 85 prop->length = len; 86 87 if (OF_IS_DYNAMIC(prop)) 88 kfree(old_val); 89 90 OF_MARK_DYNAMIC(prop); 91 92 err = 0; 93 } 94 break; 95 } 96 prevp = &(*prevp)->next; 97 } 98 write_unlock(&devtree_lock); 99 mutex_unlock(&of_set_property_mutex); 100 101 102 return err; 103} 104EXPORT_SYMBOL(of_set_property); 105 106int of_find_in_proplist(const char *list, const char *match, int len) 107{ 108 while (len > 0) { 109 int l; 110 111 if (!strcmp(list, match)) 112 return 1; 113 l = strlen(list) + 1; 114 list += l; 115 len -= l; 116 } 117 return 0; 118} 119EXPORT_SYMBOL(of_find_in_proplist); 120 121unsigned int prom_unique_id; 122 123static struct property * __init build_one_prop(phandle node, char *prev, 124 char *special_name, 125 void *special_val, 126 int special_len) 127{ 128 static struct property *tmp = NULL; 129 struct property *p; 130 const char *name; 131 132 if (tmp) { 133 p = tmp; 134 memset(p, 0, sizeof(*p) + 32); 135 tmp = NULL; 136 } else { 137 p = prom_early_alloc(sizeof(struct property) + 32); 138 p->unique_id = prom_unique_id++; 139 } 140 141 p->name = (char *) (p + 1); 142 if (special_name) { 143 strcpy(p->name, special_name); 144 p->length = special_len; 145 p->value = prom_early_alloc(special_len); 146 memcpy(p->value, special_val, special_len); 147 } else { 148 if (prev == NULL) { 149 name = prom_firstprop(node, p->name); 150 } else { 151 name = prom_nextprop(node, prev, p->name); 152 } 153 154 if (!name || strlen(name) == 0) { 155 tmp = p; 156 return NULL; 157 } 158#ifdef CONFIG_SPARC32 159 strcpy(p->name, name); 160#endif 161 p->length = prom_getproplen(node, p->name); 162 if (p->length <= 0) { 163 p->length = 0; 164 } else { 165 int len; 166 167 p->value = prom_early_alloc(p->length + 1); 168 len = prom_getproperty(node, p->name, p->value, 169 p->length); 170 if (len <= 0) 171 p->length = 0; 172 ((unsigned char *)p->value)[p->length] = '\0'; 173 } 174 } 175 return p; 176} 177 178static struct property * __init build_prop_list(phandle node) 179{ 180 struct property *head, *tail; 181 182 head = tail = build_one_prop(node, NULL, 183 ".node", &node, sizeof(node)); 184 185 tail->next = build_one_prop(node, NULL, NULL, NULL, 0); 186 tail = tail->next; 187 while(tail) { 188 tail->next = build_one_prop(node, tail->name, 189 NULL, NULL, 0); 190 tail = tail->next; 191 } 192 193 return head; 194} 195 196static char * __init get_one_property(phandle node, const char *name) 197{ 198 char *buf = "<NULL>"; 199 int len; 200 201 len = prom_getproplen(node, name); 202 if (len > 0) { 203 buf = prom_early_alloc(len); 204 len = prom_getproperty(node, name, buf, len); 205 } 206 207 return buf; 208} 209 210static struct device_node * __init prom_create_node(phandle node, 211 struct device_node *parent) 212{ 213 struct device_node *dp; 214 215 if (!node) 216 return NULL; 217 218 dp = prom_early_alloc(sizeof(*dp)); 219 dp->unique_id = prom_unique_id++; 220 dp->parent = parent; 221 222 kref_init(&dp->kref); 223 224 dp->name = get_one_property(node, "name"); 225 dp->type = get_one_property(node, "device_type"); 226 dp->phandle = node; 227 228 dp->properties = build_prop_list(node); 229 230 irq_trans_init(dp); 231 232 return dp; 233} 234 235char * __init build_full_name(struct device_node *dp) 236{ 237 int len, ourlen, plen; 238 char *n; 239 240 plen = strlen(dp->parent->full_name); 241 ourlen = strlen(dp->path_component_name); 242 len = ourlen + plen + 2; 243 244 n = prom_early_alloc(len); 245 strcpy(n, dp->parent->full_name); 246 if (!of_node_is_root(dp->parent)) { 247 strcpy(n + plen, "/"); 248 plen++; 249 } 250 strcpy(n + plen, dp->path_component_name); 251 252 return n; 253} 254 255static struct device_node * __init prom_build_tree(struct device_node *parent, 256 phandle node, 257 struct device_node ***nextp) 258{ 259 struct device_node *ret = NULL, *prev_sibling = NULL; 260 struct device_node *dp; 261 262 while (1) { 263 dp = prom_create_node(node, parent); 264 if (!dp) 265 break; 266 267 if (prev_sibling) 268 prev_sibling->sibling = dp; 269 270 if (!ret) 271 ret = dp; 272 prev_sibling = dp; 273 274 *(*nextp) = dp; 275 *nextp = &dp->allnext; 276 277 dp->path_component_name = build_path_component(dp); 278 dp->full_name = build_full_name(dp); 279 280 dp->child = prom_build_tree(dp, prom_getchild(node), nextp); 281 282 if (prom_build_more) 283 prom_build_more(dp, nextp); 284 285 node = prom_getsibling(node); 286 } 287 288 return ret; 289} 290 291unsigned int prom_early_allocated __initdata; 292 293void __init prom_build_devicetree(void) 294{ 295 struct device_node **nextp; 296 297 allnodes = prom_create_node(prom_root_node, NULL); 298 allnodes->path_component_name = ""; 299 allnodes->full_name = "/"; 300 301 nextp = &allnodes->allnext; 302 allnodes->child = prom_build_tree(allnodes, 303 prom_getchild(allnodes->phandle), 304 &nextp); 305 of_console_init(); 306 307 printk("PROM: Built device tree with %u bytes of memory.\n", 308 prom_early_allocated); 309} 310