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