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