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