1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * tree.c: Basic device tree traversal/scanning for the Linux |
4 | * prom library. |
5 | * |
6 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) |
7 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
8 | */ |
9 | |
10 | #include <linux/string.h> |
11 | #include <linux/types.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/sched.h> |
14 | #include <linux/module.h> |
15 | |
16 | #include <asm/openprom.h> |
17 | #include <asm/oplib.h> |
18 | #include <asm/ldc.h> |
19 | |
20 | static phandle prom_node_to_node(const char *type, phandle node) |
21 | { |
22 | unsigned long args[5]; |
23 | |
24 | args[0] = (unsigned long) type; |
25 | args[1] = 1; |
26 | args[2] = 1; |
27 | args[3] = (unsigned int) node; |
28 | args[4] = (unsigned long) -1; |
29 | |
30 | p1275_cmd_direct(args); |
31 | |
32 | return (phandle) args[4]; |
33 | } |
34 | |
35 | /* Return the child of node 'node' or zero if no this node has no |
36 | * direct descendent. |
37 | */ |
38 | inline phandle __prom_getchild(phandle node) |
39 | { |
40 | return prom_node_to_node("child" , node); |
41 | } |
42 | |
43 | phandle prom_getchild(phandle node) |
44 | { |
45 | phandle cnode; |
46 | |
47 | if ((s32)node == -1) |
48 | return 0; |
49 | cnode = __prom_getchild(node); |
50 | if ((s32)cnode == -1) |
51 | return 0; |
52 | return cnode; |
53 | } |
54 | EXPORT_SYMBOL(prom_getchild); |
55 | |
56 | inline phandle prom_getparent(phandle node) |
57 | { |
58 | phandle cnode; |
59 | |
60 | if ((s32)node == -1) |
61 | return 0; |
62 | cnode = prom_node_to_node("parent" , node); |
63 | if ((s32)cnode == -1) |
64 | return 0; |
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 | inline phandle __prom_getsibling(phandle node) |
72 | { |
73 | return prom_node_to_node(prom_peer_name, node); |
74 | } |
75 | |
76 | phandle prom_getsibling(phandle node) |
77 | { |
78 | phandle sibnode; |
79 | |
80 | if ((s32)node == -1) |
81 | return 0; |
82 | sibnode = __prom_getsibling(node); |
83 | if ((s32)sibnode == -1) |
84 | return 0; |
85 | |
86 | return sibnode; |
87 | } |
88 | EXPORT_SYMBOL(prom_getsibling); |
89 | |
90 | /* Return the length in bytes of property 'prop' at node 'node'. |
91 | * Return -1 on error. |
92 | */ |
93 | int prom_getproplen(phandle node, const char *prop) |
94 | { |
95 | unsigned long args[6]; |
96 | |
97 | if (!node || !prop) |
98 | return -1; |
99 | |
100 | args[0] = (unsigned long) "getproplen" ; |
101 | args[1] = 2; |
102 | args[2] = 1; |
103 | args[3] = (unsigned int) node; |
104 | args[4] = (unsigned long) prop; |
105 | args[5] = (unsigned long) -1; |
106 | |
107 | p1275_cmd_direct(args); |
108 | |
109 | return (int) args[5]; |
110 | } |
111 | EXPORT_SYMBOL(prom_getproplen); |
112 | |
113 | /* Acquire a property 'prop' at node 'node' and place it in |
114 | * 'buffer' which has a size of 'bufsize'. If the acquisition |
115 | * was successful the length will be returned, else -1 is returned. |
116 | */ |
117 | int prom_getproperty(phandle node, const char *prop, |
118 | char *buffer, int bufsize) |
119 | { |
120 | unsigned long args[8]; |
121 | int plen; |
122 | |
123 | plen = prom_getproplen(node, prop); |
124 | if ((plen > bufsize) || (plen == 0) || (plen == -1)) |
125 | return -1; |
126 | |
127 | args[0] = (unsigned long) prom_getprop_name; |
128 | args[1] = 4; |
129 | args[2] = 1; |
130 | args[3] = (unsigned int) node; |
131 | args[4] = (unsigned long) prop; |
132 | args[5] = (unsigned long) buffer; |
133 | args[6] = bufsize; |
134 | args[7] = (unsigned long) -1; |
135 | |
136 | p1275_cmd_direct(args); |
137 | |
138 | return (int) args[7]; |
139 | } |
140 | EXPORT_SYMBOL(prom_getproperty); |
141 | |
142 | /* Acquire an integer property and return its value. Returns -1 |
143 | * on failure. |
144 | */ |
145 | int prom_getint(phandle node, const char *prop) |
146 | { |
147 | int intprop; |
148 | |
149 | if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) |
150 | return intprop; |
151 | |
152 | return -1; |
153 | } |
154 | EXPORT_SYMBOL(prom_getint); |
155 | |
156 | /* Acquire an integer property, upon error return the passed default |
157 | * integer. |
158 | */ |
159 | |
160 | int prom_getintdefault(phandle node, const char *property, int deflt) |
161 | { |
162 | int retval; |
163 | |
164 | retval = prom_getint(node, property); |
165 | if (retval == -1) |
166 | return deflt; |
167 | |
168 | return retval; |
169 | } |
170 | EXPORT_SYMBOL(prom_getintdefault); |
171 | |
172 | /* Acquire a boolean property, 1=TRUE 0=FALSE. */ |
173 | int prom_getbool(phandle node, const char *prop) |
174 | { |
175 | int retval; |
176 | |
177 | retval = prom_getproplen(node, prop); |
178 | if (retval == -1) |
179 | return 0; |
180 | return 1; |
181 | } |
182 | EXPORT_SYMBOL(prom_getbool); |
183 | |
184 | /* Acquire a property whose value is a string, returns a null |
185 | * string on error. The char pointer is the user supplied string |
186 | * buffer. |
187 | */ |
188 | void prom_getstring(phandle node, const char *prop, char *user_buf, |
189 | int ubuf_size) |
190 | { |
191 | int len; |
192 | |
193 | len = prom_getproperty(node, prop, user_buf, ubuf_size); |
194 | if (len != -1) |
195 | return; |
196 | user_buf[0] = 0; |
197 | } |
198 | EXPORT_SYMBOL(prom_getstring); |
199 | |
200 | /* Does the device at node 'node' have name 'name'? |
201 | * YES = 1 NO = 0 |
202 | */ |
203 | int prom_nodematch(phandle node, const char *name) |
204 | { |
205 | char namebuf[128]; |
206 | prom_getproperty(node, "name" , namebuf, sizeof(namebuf)); |
207 | if (strcmp(namebuf, name) == 0) |
208 | return 1; |
209 | return 0; |
210 | } |
211 | |
212 | /* Search siblings at 'node_start' for a node with name |
213 | * 'nodename'. Return node if successful, zero if not. |
214 | */ |
215 | phandle prom_searchsiblings(phandle node_start, const char *nodename) |
216 | { |
217 | phandle thisnode; |
218 | int error; |
219 | char promlib_buf[128]; |
220 | |
221 | for(thisnode = node_start; thisnode; |
222 | thisnode=prom_getsibling(thisnode)) { |
223 | error = prom_getproperty(thisnode, "name" , promlib_buf, |
224 | sizeof(promlib_buf)); |
225 | /* Should this ever happen? */ |
226 | if(error == -1) continue; |
227 | if(strcmp(nodename, promlib_buf)==0) return thisnode; |
228 | } |
229 | |
230 | return 0; |
231 | } |
232 | EXPORT_SYMBOL(prom_searchsiblings); |
233 | |
234 | static const char *prom_nextprop_name = "nextprop" ; |
235 | |
236 | /* Return the first property type for node 'node'. |
237 | * buffer should be at least 32B in length |
238 | */ |
239 | char *prom_firstprop(phandle node, char *buffer) |
240 | { |
241 | unsigned long args[7]; |
242 | |
243 | *buffer = 0; |
244 | if ((s32)node == -1) |
245 | return buffer; |
246 | |
247 | args[0] = (unsigned long) prom_nextprop_name; |
248 | args[1] = 3; |
249 | args[2] = 1; |
250 | args[3] = (unsigned int) node; |
251 | args[4] = 0; |
252 | args[5] = (unsigned long) buffer; |
253 | args[6] = (unsigned long) -1; |
254 | |
255 | p1275_cmd_direct(args); |
256 | |
257 | return buffer; |
258 | } |
259 | EXPORT_SYMBOL(prom_firstprop); |
260 | |
261 | /* Return the property type string after property type 'oprop' |
262 | * at node 'node' . Returns NULL string if no more |
263 | * property types for this node. |
264 | */ |
265 | char *prom_nextprop(phandle node, const char *oprop, char *buffer) |
266 | { |
267 | unsigned long args[7]; |
268 | char buf[32]; |
269 | |
270 | if ((s32)node == -1) { |
271 | *buffer = 0; |
272 | return buffer; |
273 | } |
274 | if (oprop == buffer) { |
275 | strcpy (p: buf, q: oprop); |
276 | oprop = buf; |
277 | } |
278 | |
279 | args[0] = (unsigned long) prom_nextprop_name; |
280 | args[1] = 3; |
281 | args[2] = 1; |
282 | args[3] = (unsigned int) node; |
283 | args[4] = (unsigned long) oprop; |
284 | args[5] = (unsigned long) buffer; |
285 | args[6] = (unsigned long) -1; |
286 | |
287 | p1275_cmd_direct(args); |
288 | |
289 | return buffer; |
290 | } |
291 | EXPORT_SYMBOL(prom_nextprop); |
292 | |
293 | phandle prom_finddevice(const char *name) |
294 | { |
295 | unsigned long args[5]; |
296 | |
297 | if (!name) |
298 | return 0; |
299 | args[0] = (unsigned long) "finddevice" ; |
300 | args[1] = 1; |
301 | args[2] = 1; |
302 | args[3] = (unsigned long) name; |
303 | args[4] = (unsigned long) -1; |
304 | |
305 | p1275_cmd_direct(args); |
306 | |
307 | return (int) args[4]; |
308 | } |
309 | EXPORT_SYMBOL(prom_finddevice); |
310 | |
311 | int prom_node_has_property(phandle node, const char *prop) |
312 | { |
313 | char buf [32]; |
314 | |
315 | *buf = 0; |
316 | do { |
317 | prom_nextprop(node, buf, buf); |
318 | if (!strcmp(buf, prop)) |
319 | return 1; |
320 | } while (*buf); |
321 | return 0; |
322 | } |
323 | EXPORT_SYMBOL(prom_node_has_property); |
324 | |
325 | /* Set property 'pname' at node 'node' to value 'value' which has a length |
326 | * of 'size' bytes. Return the number of bytes the prom accepted. |
327 | */ |
328 | int |
329 | prom_setprop(phandle node, const char *pname, char *value, int size) |
330 | { |
331 | unsigned long args[8]; |
332 | |
333 | if (size == 0) |
334 | return 0; |
335 | if ((pname == 0) || (value == 0)) |
336 | return 0; |
337 | |
338 | #ifdef CONFIG_SUN_LDOMS |
339 | if (ldom_domaining_enabled) { |
340 | ldom_set_var(pname, value); |
341 | return 0; |
342 | } |
343 | #endif |
344 | args[0] = (unsigned long) "setprop" ; |
345 | args[1] = 4; |
346 | args[2] = 1; |
347 | args[3] = (unsigned int) node; |
348 | args[4] = (unsigned long) pname; |
349 | args[5] = (unsigned long) value; |
350 | args[6] = size; |
351 | args[7] = (unsigned long) -1; |
352 | |
353 | p1275_cmd_direct(args); |
354 | |
355 | return (int) args[7]; |
356 | } |
357 | EXPORT_SYMBOL(prom_setprop); |
358 | |
359 | inline phandle prom_inst2pkg(int inst) |
360 | { |
361 | unsigned long args[5]; |
362 | phandle node; |
363 | |
364 | args[0] = (unsigned long) "instance-to-package" ; |
365 | args[1] = 1; |
366 | args[2] = 1; |
367 | args[3] = (unsigned int) inst; |
368 | args[4] = (unsigned long) -1; |
369 | |
370 | p1275_cmd_direct(args); |
371 | |
372 | node = (int) args[4]; |
373 | if ((s32)node == -1) |
374 | return 0; |
375 | return node; |
376 | } |
377 | |
378 | int prom_ihandle2path(int handle, char *buffer, int bufsize) |
379 | { |
380 | unsigned long args[7]; |
381 | |
382 | args[0] = (unsigned long) "instance-to-path" ; |
383 | args[1] = 3; |
384 | args[2] = 1; |
385 | args[3] = (unsigned int) handle; |
386 | args[4] = (unsigned long) buffer; |
387 | args[5] = bufsize; |
388 | args[6] = (unsigned long) -1; |
389 | |
390 | p1275_cmd_direct(args); |
391 | |
392 | return (int) args[6]; |
393 | } |
394 | |