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