]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
b00dc837 | 2 | /* |
1da177e4 LT |
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> | |
917c3660 | 14 | #include <linux/module.h> |
1da177e4 LT |
15 | |
16 | #include <asm/openprom.h> | |
17 | #include <asm/oplib.h> | |
b3e13fbe | 18 | #include <asm/ldc.h> |
1da177e4 | 19 | |
8d125562 | 20 | static phandle prom_node_to_node(const char *type, phandle node) |
25edd694 DM |
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 | ||
8d125562 | 32 | return (phandle) args[4]; |
25edd694 DM |
33 | } |
34 | ||
1da177e4 LT |
35 | /* Return the child of node 'node' or zero if no this node has no |
36 | * direct descendent. | |
37 | */ | |
8d125562 | 38 | inline phandle __prom_getchild(phandle node) |
1da177e4 | 39 | { |
25edd694 | 40 | return prom_node_to_node("child", node); |
1da177e4 LT |
41 | } |
42 | ||
dbebe0da | 43 | phandle prom_getchild(phandle node) |
1da177e4 | 44 | { |
8d125562 | 45 | phandle cnode; |
1da177e4 | 46 | |
4a3a2552 | 47 | if ((s32)node == -1) |
25edd694 | 48 | return 0; |
1da177e4 | 49 | cnode = __prom_getchild(node); |
4a3a2552 | 50 | if ((s32)cnode == -1) |
25edd694 DM |
51 | return 0; |
52 | return cnode; | |
1da177e4 | 53 | } |
917c3660 | 54 | EXPORT_SYMBOL(prom_getchild); |
1da177e4 | 55 | |
8d125562 | 56 | inline phandle prom_getparent(phandle node) |
1da177e4 | 57 | { |
8d125562 | 58 | phandle cnode; |
1da177e4 | 59 | |
4a3a2552 | 60 | if ((s32)node == -1) |
25edd694 DM |
61 | return 0; |
62 | cnode = prom_node_to_node("parent", node); | |
4a3a2552 | 63 | if ((s32)cnode == -1) |
25edd694 DM |
64 | return 0; |
65 | return cnode; | |
1da177e4 LT |
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 | */ | |
8d125562 | 71 | inline phandle __prom_getsibling(phandle node) |
1da177e4 | 72 | { |
25edd694 | 73 | return prom_node_to_node(prom_peer_name, node); |
1da177e4 LT |
74 | } |
75 | ||
dbebe0da | 76 | phandle prom_getsibling(phandle node) |
1da177e4 | 77 | { |
8d125562 | 78 | phandle sibnode; |
1da177e4 | 79 | |
4a3a2552 | 80 | if ((s32)node == -1) |
d82ace7d | 81 | return 0; |
1da177e4 | 82 | sibnode = __prom_getsibling(node); |
4a3a2552 | 83 | if ((s32)sibnode == -1) |
d82ace7d DM |
84 | return 0; |
85 | ||
1da177e4 LT |
86 | return sibnode; |
87 | } | |
917c3660 | 88 | EXPORT_SYMBOL(prom_getsibling); |
1da177e4 LT |
89 | |
90 | /* Return the length in bytes of property 'prop' at node 'node'. | |
91 | * Return -1 on error. | |
92 | */ | |
dbebe0da | 93 | int prom_getproplen(phandle node, const char *prop) |
1da177e4 | 94 | { |
25edd694 DM |
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]; | |
1da177e4 | 110 | } |
917c3660 | 111 | EXPORT_SYMBOL(prom_getproplen); |
1da177e4 LT |
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 | */ | |
dbebe0da DE |
117 | int prom_getproperty(phandle node, const char *prop, |
118 | char *buffer, int bufsize) | |
1da177e4 | 119 | { |
25edd694 | 120 | unsigned long args[8]; |
1da177e4 LT |
121 | int plen; |
122 | ||
123 | plen = prom_getproplen(node, prop); | |
25edd694 | 124 | if ((plen > bufsize) || (plen == 0) || (plen == -1)) |
1da177e4 | 125 | return -1; |
25edd694 DM |
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]; | |
1da177e4 | 139 | } |
917c3660 | 140 | EXPORT_SYMBOL(prom_getproperty); |
1da177e4 LT |
141 | |
142 | /* Acquire an integer property and return its value. Returns -1 | |
143 | * on failure. | |
144 | */ | |
dbebe0da | 145 | int prom_getint(phandle node, const char *prop) |
1da177e4 LT |
146 | { |
147 | int intprop; | |
148 | ||
25edd694 | 149 | if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) |
1da177e4 LT |
150 | return intprop; |
151 | ||
152 | return -1; | |
153 | } | |
917c3660 | 154 | EXPORT_SYMBOL(prom_getint); |
1da177e4 LT |
155 | |
156 | /* Acquire an integer property, upon error return the passed default | |
157 | * integer. | |
158 | */ | |
159 | ||
8d125562 | 160 | int prom_getintdefault(phandle node, const char *property, int deflt) |
1da177e4 LT |
161 | { |
162 | int retval; | |
163 | ||
164 | retval = prom_getint(node, property); | |
25edd694 DM |
165 | if (retval == -1) |
166 | return deflt; | |
1da177e4 LT |
167 | |
168 | return retval; | |
169 | } | |
917c3660 | 170 | EXPORT_SYMBOL(prom_getintdefault); |
1da177e4 LT |
171 | |
172 | /* Acquire a boolean property, 1=TRUE 0=FALSE. */ | |
8d125562 | 173 | int prom_getbool(phandle node, const char *prop) |
1da177e4 LT |
174 | { |
175 | int retval; | |
176 | ||
177 | retval = prom_getproplen(node, prop); | |
25edd694 DM |
178 | if (retval == -1) |
179 | return 0; | |
1da177e4 LT |
180 | return 1; |
181 | } | |
917c3660 | 182 | EXPORT_SYMBOL(prom_getbool); |
1da177e4 LT |
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 | */ | |
8d125562 AS |
188 | void prom_getstring(phandle node, const char *prop, char *user_buf, |
189 | int ubuf_size) | |
1da177e4 LT |
190 | { |
191 | int len; | |
192 | ||
193 | len = prom_getproperty(node, prop, user_buf, ubuf_size); | |
25edd694 DM |
194 | if (len != -1) |
195 | return; | |
1da177e4 | 196 | user_buf[0] = 0; |
1da177e4 | 197 | } |
917c3660 | 198 | EXPORT_SYMBOL(prom_getstring); |
1da177e4 LT |
199 | |
200 | /* Does the device at node 'node' have name 'name'? | |
201 | * YES = 1 NO = 0 | |
202 | */ | |
8d125562 | 203 | int prom_nodematch(phandle node, const char *name) |
1da177e4 LT |
204 | { |
205 | char namebuf[128]; | |
206 | prom_getproperty(node, "name", namebuf, sizeof(namebuf)); | |
25edd694 DM |
207 | if (strcmp(namebuf, name) == 0) |
208 | return 1; | |
1da177e4 LT |
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 | */ | |
8d125562 | 215 | phandle prom_searchsiblings(phandle node_start, const char *nodename) |
1da177e4 | 216 | { |
8d125562 AS |
217 | phandle thisnode; |
218 | int error; | |
1da177e4 LT |
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 | } | |
917c3660 | 232 | EXPORT_SYMBOL(prom_searchsiblings); |
1da177e4 | 233 | |
25edd694 DM |
234 | static const char *prom_nextprop_name = "nextprop"; |
235 | ||
1da177e4 LT |
236 | /* Return the first property type for node 'node'. |
237 | * buffer should be at least 32B in length | |
238 | */ | |
dbebe0da | 239 | char *prom_firstprop(phandle node, char *buffer) |
1da177e4 | 240 | { |
25edd694 DM |
241 | unsigned long args[7]; |
242 | ||
1da177e4 | 243 | *buffer = 0; |
4a3a2552 | 244 | if ((s32)node == -1) |
25edd694 DM |
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 | ||
1da177e4 LT |
257 | return buffer; |
258 | } | |
917c3660 | 259 | EXPORT_SYMBOL(prom_firstprop); |
1da177e4 LT |
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 | */ | |
dbebe0da | 265 | char *prom_nextprop(phandle node, const char *oprop, char *buffer) |
1da177e4 | 266 | { |
25edd694 | 267 | unsigned long args[7]; |
1da177e4 LT |
268 | char buf[32]; |
269 | ||
4a3a2552 | 270 | if ((s32)node == -1) { |
1da177e4 LT |
271 | *buffer = 0; |
272 | return buffer; | |
273 | } | |
274 | if (oprop == buffer) { | |
275 | strcpy (buf, oprop); | |
276 | oprop = buf; | |
277 | } | |
25edd694 DM |
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 | ||
1da177e4 LT |
289 | return buffer; |
290 | } | |
917c3660 | 291 | EXPORT_SYMBOL(prom_nextprop); |
1da177e4 | 292 | |
8d125562 | 293 | phandle prom_finddevice(const char *name) |
1da177e4 | 294 | { |
25edd694 DM |
295 | unsigned long args[5]; |
296 | ||
bff06d55 DM |
297 | if (!name) |
298 | return 0; | |
25edd694 DM |
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]; | |
1da177e4 | 308 | } |
917c3660 | 309 | EXPORT_SYMBOL(prom_finddevice); |
1da177e4 | 310 | |
8d125562 | 311 | int prom_node_has_property(phandle node, const char *prop) |
1da177e4 LT |
312 | { |
313 | char buf [32]; | |
314 | ||
315 | *buf = 0; | |
316 | do { | |
317 | prom_nextprop(node, buf, buf); | |
25edd694 | 318 | if (!strcmp(buf, prop)) |
1da177e4 LT |
319 | return 1; |
320 | } while (*buf); | |
321 | return 0; | |
322 | } | |
917c3660 SR |
323 | EXPORT_SYMBOL(prom_node_has_property); |
324 | ||
1da177e4 LT |
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 | |
8d125562 | 329 | prom_setprop(phandle node, const char *pname, char *value, int size) |
1da177e4 | 330 | { |
25edd694 DM |
331 | unsigned long args[8]; |
332 | ||
b3e13fbe DM |
333 | if (size == 0) |
334 | return 0; | |
335 | if ((pname == 0) || (value == 0)) | |
336 | return 0; | |
1da177e4 | 337 | |
b3e13fbe DM |
338 | #ifdef CONFIG_SUN_LDOMS |
339 | if (ldom_domaining_enabled) { | |
340 | ldom_set_var(pname, value); | |
341 | return 0; | |
342 | } | |
343 | #endif | |
25edd694 DM |
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]; | |
1da177e4 | 356 | } |
917c3660 | 357 | EXPORT_SYMBOL(prom_setprop); |
1da177e4 | 358 | |
8d125562 | 359 | inline phandle prom_inst2pkg(int inst) |
1da177e4 | 360 | { |
25edd694 | 361 | unsigned long args[5]; |
8d125562 | 362 | phandle node; |
1da177e4 | 363 | |
25edd694 DM |
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]; | |
4a3a2552 | 373 | if ((s32)node == -1) |
25edd694 | 374 | return 0; |
1da177e4 LT |
375 | return node; |
376 | } | |
377 | ||
c73fcc84 DM |
378 | int prom_ihandle2path(int handle, char *buffer, int bufsize) |
379 | { | |
25edd694 DM |
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]; | |
c73fcc84 | 393 | } |