at v2.6.21 5.1 kB view raw
1/* 2 * proc_devtree.c - handles /proc/device-tree 3 * 4 * Copyright 1997 Paul Mackerras 5 */ 6#include <linux/errno.h> 7#include <linux/time.h> 8#include <linux/proc_fs.h> 9#include <linux/stat.h> 10#include <linux/string.h> 11#include <asm/prom.h> 12#include <asm/uaccess.h> 13 14#ifndef HAVE_ARCH_DEVTREE_FIXUPS 15static inline void set_node_proc_entry(struct device_node *np, 16 struct proc_dir_entry *de) 17{ 18} 19#endif 20 21static struct proc_dir_entry *proc_device_tree; 22 23/* 24 * Supply data on a read from /proc/device-tree/node/property. 25 */ 26static int property_read_proc(char *page, char **start, off_t off, 27 int count, int *eof, void *data) 28{ 29 struct property *pp = data; 30 int n; 31 32 if (off >= pp->length) { 33 *eof = 1; 34 return 0; 35 } 36 n = pp->length - off; 37 if (n > count) 38 n = count; 39 else 40 *eof = 1; 41 memcpy(page, pp->value + off, n); 42 *start = page; 43 return n; 44} 45 46/* 47 * For a node with a name like "gc@10", we make symlinks called "gc" 48 * and "@10" to it. 49 */ 50 51/* 52 * Add a property to a node 53 */ 54static struct proc_dir_entry * 55__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, 56 const char *name) 57{ 58 struct proc_dir_entry *ent; 59 60 /* 61 * Unfortunately proc_register puts each new entry 62 * at the beginning of the list. So we rearrange them. 63 */ 64 ent = create_proc_read_entry(name, 65 strncmp(name, "security-", 9) 66 ? S_IRUGO : S_IRUSR, de, 67 property_read_proc, pp); 68 if (ent == NULL) 69 return NULL; 70 71 if (!strncmp(name, "security-", 9)) 72 ent->size = 0; /* don't leak number of password chars */ 73 else 74 ent->size = pp->length; 75 76 return ent; 77} 78 79 80void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) 81{ 82 __proc_device_tree_add_prop(pde, prop, prop->name); 83} 84 85void proc_device_tree_remove_prop(struct proc_dir_entry *pde, 86 struct property *prop) 87{ 88 remove_proc_entry(prop->name, pde); 89} 90 91void proc_device_tree_update_prop(struct proc_dir_entry *pde, 92 struct property *newprop, 93 struct property *oldprop) 94{ 95 struct proc_dir_entry *ent; 96 97 for (ent = pde->subdir; ent != NULL; ent = ent->next) 98 if (ent->data == oldprop) 99 break; 100 if (ent == NULL) { 101 printk(KERN_WARNING "device-tree: property \"%s\" " 102 " does not exist\n", oldprop->name); 103 } else { 104 ent->data = newprop; 105 ent->size = newprop->length; 106 } 107} 108 109/* 110 * Various dodgy firmware might give us nodes and/or properties with 111 * conflicting names. That's generally ok, except for exporting via /proc, 112 * so munge names here to ensure they're unique. 113 */ 114 115static int duplicate_name(struct proc_dir_entry *de, const char *name) 116{ 117 struct proc_dir_entry *ent; 118 int found = 0; 119 120 spin_lock(&proc_subdir_lock); 121 122 for (ent = de->subdir; ent != NULL; ent = ent->next) { 123 if (strcmp(ent->name, name) == 0) { 124 found = 1; 125 break; 126 } 127 } 128 129 spin_unlock(&proc_subdir_lock); 130 131 return found; 132} 133 134static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, 135 const char *name) 136{ 137 char *fixed_name; 138 int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */ 139 int i = 1, size; 140 141realloc: 142 fixed_name = kmalloc(fixup_len, GFP_KERNEL); 143 if (fixed_name == NULL) { 144 printk(KERN_ERR "device-tree: Out of memory trying to fixup " 145 "name \"%s\"\n", name); 146 return name; 147 } 148 149retry: 150 size = snprintf(fixed_name, fixup_len, "%s#%d", name, i); 151 size++; /* account for NULL */ 152 153 if (size > fixup_len) { 154 /* We ran out of space, free and reallocate. */ 155 kfree(fixed_name); 156 fixup_len = size; 157 goto realloc; 158 } 159 160 if (duplicate_name(de, fixed_name)) { 161 /* Multiple duplicates. Retry with a different offset. */ 162 i++; 163 goto retry; 164 } 165 166 printk(KERN_WARNING "device-tree: Duplicate name in %s, " 167 "renamed to \"%s\"\n", np->full_name, fixed_name); 168 169 return fixed_name; 170} 171 172/* 173 * Process a node, adding entries for its children and its properties. 174 */ 175void proc_device_tree_add_node(struct device_node *np, 176 struct proc_dir_entry *de) 177{ 178 struct property *pp; 179 struct proc_dir_entry *ent; 180 struct device_node *child; 181 const char *p; 182 183 set_node_proc_entry(np, de); 184 for (child = NULL; (child = of_get_next_child(np, child));) { 185 /* Use everything after the last slash, or the full name */ 186 p = strrchr(child->full_name, '/'); 187 if (!p) 188 p = child->full_name; 189 else 190 ++p; 191 192 if (duplicate_name(de, p)) 193 p = fixup_name(np, de, p); 194 195 ent = proc_mkdir(p, de); 196 if (ent == 0) 197 break; 198 proc_device_tree_add_node(child, ent); 199 } 200 of_node_put(child); 201 202 for (pp = np->properties; pp != 0; pp = pp->next) { 203 p = pp->name; 204 205 if (duplicate_name(de, p)) 206 p = fixup_name(np, de, p); 207 208 ent = __proc_device_tree_add_prop(de, pp, p); 209 if (ent == 0) 210 break; 211 } 212} 213 214/* 215 * Called on initialization to set up the /proc/device-tree subtree 216 */ 217void proc_device_tree_init(void) 218{ 219 struct device_node *root; 220 if ( !have_of ) 221 return; 222 proc_device_tree = proc_mkdir("device-tree", NULL); 223 if (proc_device_tree == 0) 224 return; 225 root = of_find_node_by_path("/"); 226 if (root == 0) { 227 printk(KERN_ERR "/proc/device-tree: can't find root\n"); 228 return; 229 } 230 proc_device_tree_add_node(root, proc_device_tree); 231 of_node_put(root); 232}