diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/proc/proc_devtree.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/proc/proc_devtree.c')
-rw-r--r-- | fs/proc/proc_devtree.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c new file mode 100644 index 000000000000..67423c696c0a --- /dev/null +++ b/fs/proc/proc_devtree.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * proc_devtree.c - handles /proc/device-tree | ||
3 | * | ||
4 | * Copyright 1997 Paul Mackerras | ||
5 | */ | ||
6 | #include <linux/errno.h> | ||
7 | #include <linux/time.h> | ||
8 | #include <linux/proc_fs.h> | ||
9 | #include <linux/stat.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <asm/prom.h> | ||
12 | #include <asm/uaccess.h> | ||
13 | |||
14 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS | ||
15 | static inline void set_node_proc_entry(struct device_node *np, struct proc_dir_entry *de) | ||
16 | { | ||
17 | } | ||
18 | |||
19 | static void inline set_node_name_link(struct device_node *np, struct proc_dir_entry *de) | ||
20 | { | ||
21 | } | ||
22 | |||
23 | static void inline set_node_addr_link(struct device_node *np, struct proc_dir_entry *de) | ||
24 | { | ||
25 | } | ||
26 | #endif | ||
27 | |||
28 | static struct proc_dir_entry *proc_device_tree; | ||
29 | |||
30 | /* | ||
31 | * Supply data on a read from /proc/device-tree/node/property. | ||
32 | */ | ||
33 | static int property_read_proc(char *page, char **start, off_t off, | ||
34 | int count, int *eof, void *data) | ||
35 | { | ||
36 | struct property *pp = data; | ||
37 | int n; | ||
38 | |||
39 | if (off >= pp->length) { | ||
40 | *eof = 1; | ||
41 | return 0; | ||
42 | } | ||
43 | n = pp->length - off; | ||
44 | if (n > count) | ||
45 | n = count; | ||
46 | else | ||
47 | *eof = 1; | ||
48 | memcpy(page, pp->value + off, n); | ||
49 | *start = page; | ||
50 | return n; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * For a node with a name like "gc@10", we make symlinks called "gc" | ||
55 | * and "@10" to it. | ||
56 | */ | ||
57 | |||
58 | /* | ||
59 | * Process a node, adding entries for its children and its properties. | ||
60 | */ | ||
61 | void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *de) | ||
62 | { | ||
63 | struct property *pp; | ||
64 | struct proc_dir_entry *ent; | ||
65 | struct device_node *child, *sib; | ||
66 | const char *p, *at; | ||
67 | int l; | ||
68 | struct proc_dir_entry *list, **lastp, *al; | ||
69 | |||
70 | set_node_proc_entry(np, de); | ||
71 | lastp = &list; | ||
72 | for (pp = np->properties; pp != 0; pp = pp->next) { | ||
73 | /* | ||
74 | * Unfortunately proc_register puts each new entry | ||
75 | * at the beginning of the list. So we rearrange them. | ||
76 | */ | ||
77 | ent = create_proc_read_entry(pp->name, strncmp(pp->name, "security-", 9) ? | ||
78 | S_IRUGO : S_IRUSR, de, property_read_proc, pp); | ||
79 | if (ent == 0) | ||
80 | break; | ||
81 | if (!strncmp(pp->name, "security-", 9)) | ||
82 | ent->size = 0; /* don't leak number of password chars */ | ||
83 | else | ||
84 | ent->size = pp->length; | ||
85 | *lastp = ent; | ||
86 | lastp = &ent->next; | ||
87 | } | ||
88 | child = NULL; | ||
89 | while ((child = of_get_next_child(np, child))) { | ||
90 | p = strrchr(child->full_name, '/'); | ||
91 | if (!p) | ||
92 | p = child->full_name; | ||
93 | else | ||
94 | ++p; | ||
95 | /* chop off '@0' if the name ends with that */ | ||
96 | l = strlen(p); | ||
97 | if (l > 2 && p[l-2] == '@' && p[l-1] == '0') | ||
98 | l -= 2; | ||
99 | ent = proc_mkdir(p, de); | ||
100 | if (ent == 0) | ||
101 | break; | ||
102 | *lastp = ent; | ||
103 | lastp = &ent->next; | ||
104 | proc_device_tree_add_node(child, ent); | ||
105 | |||
106 | /* | ||
107 | * If we left the address part on the name, consider | ||
108 | * adding symlinks from the name and address parts. | ||
109 | */ | ||
110 | if (p[l] != 0 || (at = strchr(p, '@')) == 0) | ||
111 | continue; | ||
112 | |||
113 | /* | ||
114 | * If this is the first node with a given name property, | ||
115 | * add a symlink with the name property as its name. | ||
116 | */ | ||
117 | sib = NULL; | ||
118 | while ((sib = of_get_next_child(np, sib)) && sib != child) | ||
119 | if (sib->name && strcmp(sib->name, child->name) == 0) | ||
120 | break; | ||
121 | if (sib == child && strncmp(p, child->name, l) != 0) { | ||
122 | al = proc_symlink(child->name, de, ent->name); | ||
123 | if (al == 0) { | ||
124 | of_node_put(sib); | ||
125 | break; | ||
126 | } | ||
127 | set_node_name_link(child, al); | ||
128 | *lastp = al; | ||
129 | lastp = &al->next; | ||
130 | } | ||
131 | of_node_put(sib); | ||
132 | /* | ||
133 | * Add another directory with the @address part as its name. | ||
134 | */ | ||
135 | al = proc_symlink(at, de, ent->name); | ||
136 | if (al == 0) | ||
137 | break; | ||
138 | set_node_addr_link(child, al); | ||
139 | *lastp = al; | ||
140 | lastp = &al->next; | ||
141 | } | ||
142 | of_node_put(child); | ||
143 | *lastp = NULL; | ||
144 | de->subdir = list; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Called on initialization to set up the /proc/device-tree subtree | ||
149 | */ | ||
150 | void proc_device_tree_init(void) | ||
151 | { | ||
152 | struct device_node *root; | ||
153 | if ( !have_of ) | ||
154 | return; | ||
155 | proc_device_tree = proc_mkdir("device-tree", NULL); | ||
156 | if (proc_device_tree == 0) | ||
157 | return; | ||
158 | root = of_find_node_by_path("/"); | ||
159 | if (root == 0) { | ||
160 | printk(KERN_ERR "/proc/device-tree: can't find root\n"); | ||
161 | return; | ||
162 | } | ||
163 | proc_device_tree_add_node(root, proc_device_tree); | ||
164 | of_node_put(root); | ||
165 | } | ||