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