diff options
author | Sam Ravnborg <sam@ravnborg.org> | 2008-11-30 01:15:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-04 12:17:16 -0500 |
commit | 708d4f09647106d549c646dc459c7ccf2c237cc8 (patch) | |
tree | 23657862535d88fcb71bc416c51c27cd480a93c4 /arch/sparc/prom/tree_32.c | |
parent | 5e53879008b9acefe9f43498fd36db7376e08739 (diff) |
sparc: prepare prom/ for unification
- rename files where sparc64 uses identical names to *_32.c
- refactor Makefile (but keep linking order)
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/prom/tree_32.c')
-rw-r--r-- | arch/sparc/prom/tree_32.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/arch/sparc/prom/tree_32.c b/arch/sparc/prom/tree_32.c new file mode 100644 index 000000000000..f228fe057b24 --- /dev/null +++ b/arch/sparc/prom/tree_32.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * tree.c: Basic device tree traversal/scanning for the Linux | ||
3 | * prom library. | ||
4 | * | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | */ | ||
7 | |||
8 | #define PROMLIB_INTERNAL | ||
9 | |||
10 | #include <linux/string.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/ctype.h> | ||
15 | |||
16 | #include <asm/openprom.h> | ||
17 | #include <asm/oplib.h> | ||
18 | |||
19 | extern void restore_current(void); | ||
20 | |||
21 | static char promlib_buf[128]; | ||
22 | |||
23 | /* Internal version of prom_getchild that does not alter return values. */ | ||
24 | int __prom_getchild(int node) | ||
25 | { | ||
26 | unsigned long flags; | ||
27 | int cnode; | ||
28 | |||
29 | spin_lock_irqsave(&prom_lock, flags); | ||
30 | cnode = prom_nodeops->no_child(node); | ||
31 | restore_current(); | ||
32 | spin_unlock_irqrestore(&prom_lock, flags); | ||
33 | |||
34 | return cnode; | ||
35 | } | ||
36 | |||
37 | /* Return the child of node 'node' or zero if no this node has no | ||
38 | * direct descendent. | ||
39 | */ | ||
40 | int prom_getchild(int node) | ||
41 | { | ||
42 | int cnode; | ||
43 | |||
44 | if (node == -1) | ||
45 | return 0; | ||
46 | |||
47 | cnode = __prom_getchild(node); | ||
48 | if (cnode == 0 || cnode == -1) | ||
49 | return 0; | ||
50 | |||
51 | return cnode; | ||
52 | } | ||
53 | |||
54 | /* Internal version of prom_getsibling that does not alter return values. */ | ||
55 | int __prom_getsibling(int node) | ||
56 | { | ||
57 | unsigned long flags; | ||
58 | int cnode; | ||
59 | |||
60 | spin_lock_irqsave(&prom_lock, flags); | ||
61 | cnode = prom_nodeops->no_nextnode(node); | ||
62 | restore_current(); | ||
63 | spin_unlock_irqrestore(&prom_lock, flags); | ||
64 | |||
65 | return cnode; | ||
66 | } | ||
67 | |||
68 | /* Return the next sibling of node 'node' or zero if no more siblings | ||
69 | * at this level of depth in the tree. | ||
70 | */ | ||
71 | int prom_getsibling(int node) | ||
72 | { | ||
73 | int sibnode; | ||
74 | |||
75 | if (node == -1) | ||
76 | return 0; | ||
77 | |||
78 | sibnode = __prom_getsibling(node); | ||
79 | if (sibnode == 0 || sibnode == -1) | ||
80 | return 0; | ||
81 | |||
82 | return sibnode; | ||
83 | } | ||
84 | |||
85 | /* Return the length in bytes of property 'prop' at node 'node'. | ||
86 | * Return -1 on error. | ||
87 | */ | ||
88 | int prom_getproplen(int node, char *prop) | ||
89 | { | ||
90 | int ret; | ||
91 | unsigned long flags; | ||
92 | |||
93 | if((!node) || (!prop)) | ||
94 | return -1; | ||
95 | |||
96 | spin_lock_irqsave(&prom_lock, flags); | ||
97 | ret = prom_nodeops->no_proplen(node, prop); | ||
98 | restore_current(); | ||
99 | spin_unlock_irqrestore(&prom_lock, flags); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* Acquire a property 'prop' at node 'node' and place it in | ||
104 | * 'buffer' which has a size of 'bufsize'. If the acquisition | ||
105 | * was successful the length will be returned, else -1 is returned. | ||
106 | */ | ||
107 | int prom_getproperty(int node, char *prop, char *buffer, int bufsize) | ||
108 | { | ||
109 | int plen, ret; | ||
110 | unsigned long flags; | ||
111 | |||
112 | plen = prom_getproplen(node, prop); | ||
113 | if((plen > bufsize) || (plen == 0) || (plen == -1)) | ||
114 | return -1; | ||
115 | /* Ok, things seem all right. */ | ||
116 | spin_lock_irqsave(&prom_lock, flags); | ||
117 | ret = prom_nodeops->no_getprop(node, prop, buffer); | ||
118 | restore_current(); | ||
119 | spin_unlock_irqrestore(&prom_lock, flags); | ||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | /* Acquire an integer property and return its value. Returns -1 | ||
124 | * on failure. | ||
125 | */ | ||
126 | int prom_getint(int node, char *prop) | ||
127 | { | ||
128 | static int intprop; | ||
129 | |||
130 | if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) | ||
131 | return intprop; | ||
132 | |||
133 | return -1; | ||
134 | } | ||
135 | |||
136 | /* Acquire an integer property, upon error return the passed default | ||
137 | * integer. | ||
138 | */ | ||
139 | int prom_getintdefault(int node, char *property, int deflt) | ||
140 | { | ||
141 | int retval; | ||
142 | |||
143 | retval = prom_getint(node, property); | ||
144 | if(retval == -1) return deflt; | ||
145 | |||
146 | return retval; | ||
147 | } | ||
148 | |||
149 | /* Acquire a boolean property, 1=TRUE 0=FALSE. */ | ||
150 | int prom_getbool(int node, char *prop) | ||
151 | { | ||
152 | int retval; | ||
153 | |||
154 | retval = prom_getproplen(node, prop); | ||
155 | if(retval == -1) return 0; | ||
156 | return 1; | ||
157 | } | ||
158 | |||
159 | /* Acquire a property whose value is a string, returns a null | ||
160 | * string on error. The char pointer is the user supplied string | ||
161 | * buffer. | ||
162 | */ | ||
163 | void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size) | ||
164 | { | ||
165 | int len; | ||
166 | |||
167 | len = prom_getproperty(node, prop, user_buf, ubuf_size); | ||
168 | if(len != -1) return; | ||
169 | user_buf[0] = 0; | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | |||
174 | /* Does the device at node 'node' have name 'name'? | ||
175 | * YES = 1 NO = 0 | ||
176 | */ | ||
177 | int prom_nodematch(int node, char *name) | ||
178 | { | ||
179 | int error; | ||
180 | |||
181 | static char namebuf[128]; | ||
182 | error = prom_getproperty(node, "name", namebuf, sizeof(namebuf)); | ||
183 | if (error == -1) return 0; | ||
184 | if(strcmp(namebuf, name) == 0) return 1; | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /* Search siblings at 'node_start' for a node with name | ||
189 | * 'nodename'. Return node if successful, zero if not. | ||
190 | */ | ||
191 | int prom_searchsiblings(int node_start, char *nodename) | ||
192 | { | ||
193 | |||
194 | int thisnode, error; | ||
195 | |||
196 | for(thisnode = node_start; thisnode; | ||
197 | thisnode=prom_getsibling(thisnode)) { | ||
198 | error = prom_getproperty(thisnode, "name", promlib_buf, | ||
199 | sizeof(promlib_buf)); | ||
200 | /* Should this ever happen? */ | ||
201 | if(error == -1) continue; | ||
202 | if(strcmp(nodename, promlib_buf)==0) return thisnode; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* Interal version of nextprop that does not alter return values. */ | ||
209 | char * __prom_nextprop(int node, char * oprop) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | char *prop; | ||
213 | |||
214 | spin_lock_irqsave(&prom_lock, flags); | ||
215 | prop = prom_nodeops->no_nextprop(node, oprop); | ||
216 | restore_current(); | ||
217 | spin_unlock_irqrestore(&prom_lock, flags); | ||
218 | |||
219 | return prop; | ||
220 | } | ||
221 | |||
222 | /* Return the first property name for node 'node'. */ | ||
223 | /* buffer is unused argument, but as v9 uses it, we need to have the same interface */ | ||
224 | char * prom_firstprop(int node, char *bufer) | ||
225 | { | ||
226 | if (node == 0 || node == -1) | ||
227 | return ""; | ||
228 | |||
229 | return __prom_nextprop(node, ""); | ||
230 | } | ||
231 | |||
232 | /* Return the property type string after property type 'oprop' | ||
233 | * at node 'node' . Returns empty string if no more | ||
234 | * property types for this node. | ||
235 | */ | ||
236 | char * prom_nextprop(int node, char *oprop, char *buffer) | ||
237 | { | ||
238 | if (node == 0 || node == -1) | ||
239 | return ""; | ||
240 | |||
241 | return __prom_nextprop(node, oprop); | ||
242 | } | ||
243 | |||
244 | int prom_finddevice(char *name) | ||
245 | { | ||
246 | char nbuf[128]; | ||
247 | char *s = name, *d; | ||
248 | int node = prom_root_node, node2; | ||
249 | unsigned int which_io, phys_addr; | ||
250 | struct linux_prom_registers reg[PROMREG_MAX]; | ||
251 | |||
252 | while (*s++) { | ||
253 | if (!*s) return node; /* path '.../' is legal */ | ||
254 | node = prom_getchild(node); | ||
255 | |||
256 | for (d = nbuf; *s != 0 && *s != '@' && *s != '/';) | ||
257 | *d++ = *s++; | ||
258 | *d = 0; | ||
259 | |||
260 | node = prom_searchsiblings(node, nbuf); | ||
261 | if (!node) | ||
262 | return 0; | ||
263 | |||
264 | if (*s == '@') { | ||
265 | if (isxdigit(s[1]) && s[2] == ',') { | ||
266 | which_io = simple_strtoul(s+1, NULL, 16); | ||
267 | phys_addr = simple_strtoul(s+3, &d, 16); | ||
268 | if (d != s + 3 && (!*d || *d == '/') | ||
269 | && d <= s + 3 + 8) { | ||
270 | node2 = node; | ||
271 | while (node2 && node2 != -1) { | ||
272 | if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { | ||
273 | if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { | ||
274 | node = node2; | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | node2 = prom_getsibling(node2); | ||
279 | if (!node2 || node2 == -1) | ||
280 | break; | ||
281 | node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | while (*s != 0 && *s != '/') s++; | ||
286 | } | ||
287 | } | ||
288 | return node; | ||
289 | } | ||
290 | |||
291 | int prom_node_has_property(int node, char *prop) | ||
292 | { | ||
293 | char *current_property = ""; | ||
294 | |||
295 | do { | ||
296 | current_property = prom_nextprop(node, current_property, NULL); | ||
297 | if(!strcmp(current_property, prop)) | ||
298 | return 1; | ||
299 | } while (*current_property); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* Set property 'pname' at node 'node' to value 'value' which has a length | ||
304 | * of 'size' bytes. Return the number of bytes the prom accepted. | ||
305 | */ | ||
306 | int prom_setprop(int node, char *pname, char *value, int size) | ||
307 | { | ||
308 | unsigned long flags; | ||
309 | int ret; | ||
310 | |||
311 | if(size == 0) return 0; | ||
312 | if((pname == 0) || (value == 0)) return 0; | ||
313 | spin_lock_irqsave(&prom_lock, flags); | ||
314 | ret = prom_nodeops->no_setprop(node, pname, value, size); | ||
315 | restore_current(); | ||
316 | spin_unlock_irqrestore(&prom_lock, flags); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | int prom_inst2pkg(int inst) | ||
321 | { | ||
322 | int node; | ||
323 | unsigned long flags; | ||
324 | |||
325 | spin_lock_irqsave(&prom_lock, flags); | ||
326 | node = (*romvec->pv_v2devops.v2_inst2pkg)(inst); | ||
327 | restore_current(); | ||
328 | spin_unlock_irqrestore(&prom_lock, flags); | ||
329 | if (node == -1) return 0; | ||
330 | return node; | ||
331 | } | ||
332 | |||
333 | /* Return 'node' assigned to a particular prom 'path' | ||
334 | * FIXME: Should work for v0 as well | ||
335 | */ | ||
336 | int prom_pathtoinode(char *path) | ||
337 | { | ||
338 | int node, inst; | ||
339 | |||
340 | inst = prom_devopen (path); | ||
341 | if (inst == -1) return 0; | ||
342 | node = prom_inst2pkg (inst); | ||
343 | prom_devclose (inst); | ||
344 | if (node == -1) return 0; | ||
345 | return node; | ||
346 | } | ||