1dfa76060SDavid S. Miller /* prom_common.c: OF device tree support common code. 2dfa76060SDavid S. Miller * 3dfa76060SDavid S. Miller * Paul Mackerras August 1996. 4dfa76060SDavid S. Miller * Copyright (C) 1996-2005 Paul Mackerras. 5dfa76060SDavid S. Miller * 6dfa76060SDavid S. Miller * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. 7dfa76060SDavid S. Miller * {engebret|bergner}@us.ibm.com 8dfa76060SDavid S. Miller * 9dfa76060SDavid S. Miller * Adapted for sparc by David S. Miller davem@davemloft.net 10dfa76060SDavid S. Miller * 11dfa76060SDavid S. Miller * This program is free software; you can redistribute it and/or 12dfa76060SDavid S. Miller * modify it under the terms of the GNU General Public License 13dfa76060SDavid S. Miller * as published by the Free Software Foundation; either version 14dfa76060SDavid S. Miller * 2 of the License, or (at your option) any later version. 15dfa76060SDavid S. Miller */ 16dfa76060SDavid S. Miller 17dfa76060SDavid S. Miller #include <linux/kernel.h> 18dfa76060SDavid S. Miller #include <linux/module.h> 19dfa76060SDavid S. Miller #include <linux/errno.h> 20dfa76060SDavid S. Miller #include <linux/mutex.h> 21dfa76060SDavid S. Miller #include <linux/slab.h> 22dfa76060SDavid S. Miller #include <linux/of.h> 23dfa76060SDavid S. Miller #include <asm/prom.h> 24dfa76060SDavid S. Miller #include <asm/oplib.h> 25dfa76060SDavid S. Miller 26dfa76060SDavid S. Miller #include "prom.h" 27dfa76060SDavid S. Miller 28dfa76060SDavid S. Miller struct device_node *of_find_node_by_phandle(phandle handle) 29dfa76060SDavid S. Miller { 30dfa76060SDavid S. Miller struct device_node *np; 31dfa76060SDavid S. Miller 32dfa76060SDavid S. Miller for (np = allnodes; np; np = np->allnext) 33dfa76060SDavid S. Miller if (np->node == handle) 34dfa76060SDavid S. Miller break; 35dfa76060SDavid S. Miller 36dfa76060SDavid S. Miller return np; 37dfa76060SDavid S. Miller } 38dfa76060SDavid S. Miller EXPORT_SYMBOL(of_find_node_by_phandle); 39dfa76060SDavid S. Miller 40dfa76060SDavid S. Miller int of_getintprop_default(struct device_node *np, const char *name, int def) 41dfa76060SDavid S. Miller { 42dfa76060SDavid S. Miller struct property *prop; 43dfa76060SDavid S. Miller int len; 44dfa76060SDavid S. Miller 45dfa76060SDavid S. Miller prop = of_find_property(np, name, &len); 46dfa76060SDavid S. Miller if (!prop || len != 4) 47dfa76060SDavid S. Miller return def; 48dfa76060SDavid S. Miller 49dfa76060SDavid S. Miller return *(int *) prop->value; 50dfa76060SDavid S. Miller } 51dfa76060SDavid S. Miller EXPORT_SYMBOL(of_getintprop_default); 52dfa76060SDavid S. Miller 53dfa76060SDavid S. Miller DEFINE_MUTEX(of_set_property_mutex); 54dfa76060SDavid S. Miller EXPORT_SYMBOL(of_set_property_mutex); 55dfa76060SDavid S. Miller 56dfa76060SDavid S. Miller int of_set_property(struct device_node *dp, const char *name, void *val, int len) 57dfa76060SDavid S. Miller { 58dfa76060SDavid S. Miller struct property **prevp; 59dfa76060SDavid S. Miller void *new_val; 60dfa76060SDavid S. Miller int err; 61dfa76060SDavid S. Miller 62dfa76060SDavid S. Miller new_val = kmalloc(len, GFP_KERNEL); 63dfa76060SDavid S. Miller if (!new_val) 64dfa76060SDavid S. Miller return -ENOMEM; 65dfa76060SDavid S. Miller 66dfa76060SDavid S. Miller memcpy(new_val, val, len); 67dfa76060SDavid S. Miller 68dfa76060SDavid S. Miller err = -ENODEV; 69dfa76060SDavid S. Miller 70dfa76060SDavid S. Miller write_lock(&devtree_lock); 71dfa76060SDavid S. Miller prevp = &dp->properties; 72dfa76060SDavid S. Miller while (*prevp) { 73dfa76060SDavid S. Miller struct property *prop = *prevp; 74dfa76060SDavid S. Miller 75dfa76060SDavid S. Miller if (!strcasecmp(prop->name, name)) { 76dfa76060SDavid S. Miller void *old_val = prop->value; 77dfa76060SDavid S. Miller int ret; 78dfa76060SDavid S. Miller 79dfa76060SDavid S. Miller mutex_lock(&of_set_property_mutex); 80dfa76060SDavid S. Miller ret = prom_setprop(dp->node, name, val, len); 81dfa76060SDavid S. Miller mutex_unlock(&of_set_property_mutex); 82dfa76060SDavid S. Miller 83dfa76060SDavid S. Miller err = -EINVAL; 84dfa76060SDavid S. Miller if (ret >= 0) { 85dfa76060SDavid S. Miller prop->value = new_val; 86dfa76060SDavid S. Miller prop->length = len; 87dfa76060SDavid S. Miller 88dfa76060SDavid S. Miller if (OF_IS_DYNAMIC(prop)) 89dfa76060SDavid S. Miller kfree(old_val); 90dfa76060SDavid S. Miller 91dfa76060SDavid S. Miller OF_MARK_DYNAMIC(prop); 92dfa76060SDavid S. Miller 93dfa76060SDavid S. Miller err = 0; 94dfa76060SDavid S. Miller } 95dfa76060SDavid S. Miller break; 96dfa76060SDavid S. Miller } 97dfa76060SDavid S. Miller prevp = &(*prevp)->next; 98dfa76060SDavid S. Miller } 99dfa76060SDavid S. Miller write_unlock(&devtree_lock); 100dfa76060SDavid S. Miller 101dfa76060SDavid S. Miller /* XXX Upate procfs if necessary... */ 102dfa76060SDavid S. Miller 103dfa76060SDavid S. Miller return err; 104dfa76060SDavid S. Miller } 105dfa76060SDavid S. Miller EXPORT_SYMBOL(of_set_property); 106dfa76060SDavid S. Miller 107dfa76060SDavid S. Miller int of_find_in_proplist(const char *list, const char *match, int len) 108dfa76060SDavid S. Miller { 109dfa76060SDavid S. Miller while (len > 0) { 110dfa76060SDavid S. Miller int l; 111dfa76060SDavid S. Miller 112dfa76060SDavid S. Miller if (!strcmp(list, match)) 113dfa76060SDavid S. Miller return 1; 114dfa76060SDavid S. Miller l = strlen(list) + 1; 115dfa76060SDavid S. Miller list += l; 116dfa76060SDavid S. Miller len -= l; 117dfa76060SDavid S. Miller } 118dfa76060SDavid S. Miller return 0; 119dfa76060SDavid S. Miller } 120dfa76060SDavid S. Miller EXPORT_SYMBOL(of_find_in_proplist); 121dfa76060SDavid S. Miller 122e5ff0fe3SDavid S. Miller unsigned int prom_unique_id; 123b9e5567cSDavid S. Miller 124b9e5567cSDavid S. Miller static struct property * __init build_one_prop(phandle node, char *prev, 125b9e5567cSDavid S. Miller char *special_name, 126b9e5567cSDavid S. Miller void *special_val, 127b9e5567cSDavid S. Miller int special_len) 128b9e5567cSDavid S. Miller { 129b9e5567cSDavid S. Miller static struct property *tmp = NULL; 130b9e5567cSDavid S. Miller struct property *p; 131b9e5567cSDavid S. Miller const char *name; 132b9e5567cSDavid S. Miller 133b9e5567cSDavid S. Miller if (tmp) { 134b9e5567cSDavid S. Miller p = tmp; 135b9e5567cSDavid S. Miller memset(p, 0, sizeof(*p) + 32); 136b9e5567cSDavid S. Miller tmp = NULL; 137b9e5567cSDavid S. Miller } else { 138b9e5567cSDavid S. Miller p = prom_early_alloc(sizeof(struct property) + 32); 139b9e5567cSDavid S. Miller p->unique_id = prom_unique_id++; 140b9e5567cSDavid S. Miller } 141b9e5567cSDavid S. Miller 142b9e5567cSDavid S. Miller p->name = (char *) (p + 1); 143b9e5567cSDavid S. Miller if (special_name) { 144b9e5567cSDavid S. Miller strcpy(p->name, special_name); 145b9e5567cSDavid S. Miller p->length = special_len; 146b9e5567cSDavid S. Miller p->value = prom_early_alloc(special_len); 147b9e5567cSDavid S. Miller memcpy(p->value, special_val, special_len); 148b9e5567cSDavid S. Miller } else { 149b9e5567cSDavid S. Miller #ifdef CONFIG_SPARC32 150b9e5567cSDavid S. Miller if (prev == NULL) { 151b9e5567cSDavid S. Miller name = prom_firstprop(node, NULL); 152b9e5567cSDavid S. Miller } else { 153b9e5567cSDavid S. Miller name = prom_nextprop(node, prev, NULL); 154b9e5567cSDavid S. Miller } 155b9e5567cSDavid S. Miller #else 156b9e5567cSDavid S. Miller if (prev == NULL) { 157b9e5567cSDavid S. Miller prom_firstprop(node, p->name); 158b9e5567cSDavid S. Miller } else { 159b9e5567cSDavid S. Miller prom_nextprop(node, prev, p->name); 160b9e5567cSDavid S. Miller } 161b9e5567cSDavid S. Miller name = p->name; 162b9e5567cSDavid S. Miller #endif 163b9e5567cSDavid S. Miller if (strlen(name) == 0) { 164b9e5567cSDavid S. Miller tmp = p; 165b9e5567cSDavid S. Miller return NULL; 166b9e5567cSDavid S. Miller } 167b9e5567cSDavid S. Miller #ifdef CONFIG_SPARC32 168b9e5567cSDavid S. Miller strcpy(p->name, name); 169b9e5567cSDavid S. Miller #endif 170b9e5567cSDavid S. Miller p->length = prom_getproplen(node, p->name); 171b9e5567cSDavid S. Miller if (p->length <= 0) { 172b9e5567cSDavid S. Miller p->length = 0; 173b9e5567cSDavid S. Miller } else { 174b9e5567cSDavid S. Miller int len; 175b9e5567cSDavid S. Miller 176b9e5567cSDavid S. Miller p->value = prom_early_alloc(p->length + 1); 177b9e5567cSDavid S. Miller len = prom_getproperty(node, p->name, p->value, 178b9e5567cSDavid S. Miller p->length); 179b9e5567cSDavid S. Miller if (len <= 0) 180b9e5567cSDavid S. Miller p->length = 0; 181b9e5567cSDavid S. Miller ((unsigned char *)p->value)[p->length] = '\0'; 182b9e5567cSDavid S. Miller } 183b9e5567cSDavid S. Miller } 184b9e5567cSDavid S. Miller return p; 185b9e5567cSDavid S. Miller } 186b9e5567cSDavid S. Miller 187*7d9439d5SDavid S. Miller static struct property * __init build_prop_list(phandle node) 188b9e5567cSDavid S. Miller { 189b9e5567cSDavid S. Miller struct property *head, *tail; 190b9e5567cSDavid S. Miller 191b9e5567cSDavid S. Miller head = tail = build_one_prop(node, NULL, 192b9e5567cSDavid S. Miller ".node", &node, sizeof(node)); 193b9e5567cSDavid S. Miller 194b9e5567cSDavid S. Miller tail->next = build_one_prop(node, NULL, NULL, NULL, 0); 195b9e5567cSDavid S. Miller tail = tail->next; 196b9e5567cSDavid S. Miller while(tail) { 197b9e5567cSDavid S. Miller tail->next = build_one_prop(node, tail->name, 198b9e5567cSDavid S. Miller NULL, NULL, 0); 199b9e5567cSDavid S. Miller tail = tail->next; 200b9e5567cSDavid S. Miller } 201b9e5567cSDavid S. Miller 202b9e5567cSDavid S. Miller return head; 203b9e5567cSDavid S. Miller } 204*7d9439d5SDavid S. Miller 205*7d9439d5SDavid S. Miller static char * __init get_one_property(phandle node, const char *name) 206*7d9439d5SDavid S. Miller { 207*7d9439d5SDavid S. Miller char *buf = "<NULL>"; 208*7d9439d5SDavid S. Miller int len; 209*7d9439d5SDavid S. Miller 210*7d9439d5SDavid S. Miller len = prom_getproplen(node, name); 211*7d9439d5SDavid S. Miller if (len > 0) { 212*7d9439d5SDavid S. Miller buf = prom_early_alloc(len); 213*7d9439d5SDavid S. Miller len = prom_getproperty(node, name, buf, len); 214*7d9439d5SDavid S. Miller } 215*7d9439d5SDavid S. Miller 216*7d9439d5SDavid S. Miller return buf; 217*7d9439d5SDavid S. Miller } 218*7d9439d5SDavid S. Miller 219*7d9439d5SDavid S. Miller struct device_node * __init create_node(phandle node, 220*7d9439d5SDavid S. Miller struct device_node *parent) 221*7d9439d5SDavid S. Miller { 222*7d9439d5SDavid S. Miller struct device_node *dp; 223*7d9439d5SDavid S. Miller 224*7d9439d5SDavid S. Miller if (!node) 225*7d9439d5SDavid S. Miller return NULL; 226*7d9439d5SDavid S. Miller 227*7d9439d5SDavid S. Miller dp = prom_early_alloc(sizeof(*dp)); 228*7d9439d5SDavid S. Miller dp->unique_id = prom_unique_id++; 229*7d9439d5SDavid S. Miller dp->parent = parent; 230*7d9439d5SDavid S. Miller 231*7d9439d5SDavid S. Miller kref_init(&dp->kref); 232*7d9439d5SDavid S. Miller 233*7d9439d5SDavid S. Miller dp->name = get_one_property(node, "name"); 234*7d9439d5SDavid S. Miller dp->type = get_one_property(node, "device_type"); 235*7d9439d5SDavid S. Miller dp->node = node; 236*7d9439d5SDavid S. Miller 237*7d9439d5SDavid S. Miller /* Build interrupts later... */ 238*7d9439d5SDavid S. Miller 239*7d9439d5SDavid S. Miller dp->properties = build_prop_list(node); 240*7d9439d5SDavid S. Miller 241*7d9439d5SDavid S. Miller return dp; 242*7d9439d5SDavid S. Miller } 243