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