at v3.8 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 if (!oldprop) { 105 proc_device_tree_add_prop(pde, newprop); 106 return; 107 } 108 109 for (ent = pde->subdir; ent != NULL; ent = ent->next) 110 if (ent->data == oldprop) 111 break; 112 if (ent == NULL) { 113 printk(KERN_WARNING "device-tree: property \"%s\" " 114 " does not exist\n", oldprop->name); 115 } else { 116 ent->data = newprop; 117 ent->size = newprop->length; 118 } 119} 120 121/* 122 * Various dodgy firmware might give us nodes and/or properties with 123 * conflicting names. That's generally ok, except for exporting via /proc, 124 * so munge names here to ensure they're unique. 125 */ 126 127static int duplicate_name(struct proc_dir_entry *de, const char *name) 128{ 129 struct proc_dir_entry *ent; 130 int found = 0; 131 132 spin_lock(&proc_subdir_lock); 133 134 for (ent = de->subdir; ent != NULL; ent = ent->next) { 135 if (strcmp(ent->name, name) == 0) { 136 found = 1; 137 break; 138 } 139 } 140 141 spin_unlock(&proc_subdir_lock); 142 143 return found; 144} 145 146static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, 147 const char *name) 148{ 149 char *fixed_name; 150 int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */ 151 int i = 1, size; 152 153realloc: 154 fixed_name = kmalloc(fixup_len, GFP_KERNEL); 155 if (fixed_name == NULL) { 156 printk(KERN_ERR "device-tree: Out of memory trying to fixup " 157 "name \"%s\"\n", name); 158 return name; 159 } 160 161retry: 162 size = snprintf(fixed_name, fixup_len, "%s#%d", name, i); 163 size++; /* account for NULL */ 164 165 if (size > fixup_len) { 166 /* We ran out of space, free and reallocate. */ 167 kfree(fixed_name); 168 fixup_len = size; 169 goto realloc; 170 } 171 172 if (duplicate_name(de, fixed_name)) { 173 /* Multiple duplicates. Retry with a different offset. */ 174 i++; 175 goto retry; 176 } 177 178 printk(KERN_WARNING "device-tree: Duplicate name in %s, " 179 "renamed to \"%s\"\n", np->full_name, fixed_name); 180 181 return fixed_name; 182} 183 184/* 185 * Process a node, adding entries for its children and its properties. 186 */ 187void proc_device_tree_add_node(struct device_node *np, 188 struct proc_dir_entry *de) 189{ 190 struct property *pp; 191 struct proc_dir_entry *ent; 192 struct device_node *child; 193 const char *p; 194 195 set_node_proc_entry(np, de); 196 for (child = NULL; (child = of_get_next_child(np, child));) { 197 /* Use everything after the last slash, or the full name */ 198 p = kbasename(child->full_name); 199 200 if (duplicate_name(de, p)) 201 p = fixup_name(np, de, p); 202 203 ent = proc_mkdir(p, de); 204 if (ent == NULL) 205 break; 206 proc_device_tree_add_node(child, ent); 207 } 208 of_node_put(child); 209 210 for (pp = np->properties; pp != NULL; pp = pp->next) { 211 p = pp->name; 212 213 if (strchr(p, '/')) 214 continue; 215 216 if (duplicate_name(de, p)) 217 p = fixup_name(np, de, p); 218 219 ent = __proc_device_tree_add_prop(de, pp, p); 220 if (ent == NULL) 221 break; 222 } 223} 224 225/* 226 * Called on initialization to set up the /proc/device-tree subtree 227 */ 228void __init proc_device_tree_init(void) 229{ 230 struct device_node *root; 231 232 proc_device_tree = proc_mkdir("device-tree", NULL); 233 if (proc_device_tree == NULL) 234 return; 235 root = of_find_node_by_path("/"); 236 if (root == NULL) { 237 pr_debug("/proc/device-tree: can't find root\n"); 238 return; 239 } 240 proc_device_tree_add_node(root, proc_device_tree); 241 of_node_put(root); 242}