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