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