File: /usr/src/linux/arch/sparc64/prom/tree.c

1     /* $Id: tree.c,v 1.10 1998/01/10 22:39:00 ecd Exp $
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      * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
7      */
8     
9     #include <linux/string.h>
10     #include <linux/types.h>
11     #include <linux/kernel.h>
12     #include <linux/sched.h>
13     
14     #include <asm/openprom.h>
15     #include <asm/oplib.h>
16     
17     /* Return the child of node 'node' or zero if no this node has no
18      * direct descendent.
19      */
20     __inline__ int
21     __prom_getchild(int node)
22     {
23     	return p1275_cmd ("child", P1275_INOUT(1, 1), node);
24     }
25     
26     __inline__ int
27     prom_getchild(int node)
28     {
29     	int cnode;
30     
31     	if(node == -1) return 0;
32     	cnode = __prom_getchild(node);
33     	if(cnode == -1) return 0;
34     	return (int)cnode;
35     }
36     
37     __inline__ int
38     prom_getparent(int node)
39     {
40     	int cnode;
41     
42     	if(node == -1) return 0;
43     	cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
44     	if(cnode == -1) return 0;
45     	return (int)cnode;
46     }
47     
48     /* Return the next sibling of node 'node' or zero if no more siblings
49      * at this level of depth in the tree.
50      */
51     __inline__ int
52     __prom_getsibling(int node)
53     {
54     	return p1275_cmd ("peer", P1275_INOUT(1, 1), node);
55     }
56     
57     __inline__ int
58     prom_getsibling(int node)
59     {
60     	int sibnode;
61     
62     	if(node == -1) return 0;
63     	sibnode = __prom_getsibling(node);
64     	if(sibnode == -1) return 0;
65     	return sibnode;
66     }
67     
68     /* Return the length in bytes of property 'prop' at node 'node'.
69      * Return -1 on error.
70      */
71     __inline__ int
72     prom_getproplen(int node, char *prop)
73     {
74     	if((!node) || (!prop)) return -1;
75     	return p1275_cmd ("getproplen", 
76     			  P1275_ARG(1,P1275_ARG_IN_STRING)|
77     			  P1275_INOUT(2, 1), 
78     			  node, prop);
79     }
80     
81     /* Acquire a property 'prop' at node 'node' and place it in
82      * 'buffer' which has a size of 'bufsize'.  If the acquisition
83      * was successful the length will be returned, else -1 is returned.
84      */
85     __inline__ int
86     prom_getproperty(int node, char *prop, char *buffer, int bufsize)
87     {
88     	int plen;
89     
90     	plen = prom_getproplen(node, prop);
91     	if((plen > bufsize) || (plen == 0) || (plen == -1))
92     		return -1;
93     	else {
94     		/* Ok, things seem all right. */
95     		return p1275_cmd ("getprop", 
96     				  P1275_ARG(1,P1275_ARG_IN_STRING)|
97     				  P1275_ARG(2,P1275_ARG_OUT_BUF)|
98     				  P1275_INOUT(4, 1), 
99     				  node, prop, buffer, P1275_SIZE(plen));
100     	}
101     }
102     
103     /* Acquire an integer property and return its value.  Returns -1
104      * on failure.
105      */
106     __inline__ int
107     prom_getint(int node, char *prop)
108     {
109     	int intprop;
110     
111     	if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
112     		return intprop;
113     
114     	return -1;
115     }
116     
117     /* Acquire an integer property, upon error return the passed default
118      * integer.
119      */
120     
121     int
122     prom_getintdefault(int node, char *property, int deflt)
123     {
124     	int retval;
125     
126     	retval = prom_getint(node, property);
127     	if(retval == -1) return deflt;
128     
129     	return retval;
130     }
131     
132     /* Acquire a boolean property, 1=TRUE 0=FALSE. */
133     int
134     prom_getbool(int node, char *prop)
135     {
136     	int retval;
137     
138     	retval = prom_getproplen(node, prop);
139     	if(retval == -1) return 0;
140     	return 1;
141     }
142     
143     /* Acquire a property whose value is a string, returns a null
144      * string on error.  The char pointer is the user supplied string
145      * buffer.
146      */
147     void
148     prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
149     {
150     	int len;
151     
152     	len = prom_getproperty(node, prop, user_buf, ubuf_size);
153     	if(len != -1) return;
154     	user_buf[0] = 0;
155     	return;
156     }
157     
158     
159     /* Does the device at node 'node' have name 'name'?
160      * YES = 1   NO = 0
161      */
162     int
163     prom_nodematch(int node, char *name)
164     {
165     	char namebuf[128];
166     	prom_getproperty(node, "name", namebuf, sizeof(namebuf));
167     	if(strcmp(namebuf, name) == 0) return 1;
168     	return 0;
169     }
170     
171     /* Search siblings at 'node_start' for a node with name
172      * 'nodename'.  Return node if successful, zero if not.
173      */
174     int
175     prom_searchsiblings(int node_start, char *nodename)
176     {
177     
178     	int thisnode, error;
179     	char promlib_buf[128];
180     
181     	for(thisnode = node_start; thisnode;
182     	    thisnode=prom_getsibling(thisnode)) {
183     		error = prom_getproperty(thisnode, "name", promlib_buf,
184     					 sizeof(promlib_buf));
185     		/* Should this ever happen? */
186     		if(error == -1) continue;
187     		if(strcmp(nodename, promlib_buf)==0) return thisnode;
188     	}
189     
190     	return 0;
191     }
192     
193     /* Gets name in the {name@x,yyyyy|name (if no reg)} form */
194     int 
195     prom_getname (int node, char *buffer, int len)
196     {
197     	int i, sbus = 0;
198     	int pci = 0, ebus = 0, ide = 0;
199     	struct linux_prom_registers *reg;
200     	struct linux_prom64_registers reg64[PROMREG_MAX];
201     	
202     	for (sbus = prom_getparent (node); sbus; sbus = prom_getparent (sbus)) {
203     		i = prom_getproperty (sbus, "name", buffer, len);
204     		if (i > 0) {
205     			buffer [i] = 0;
206     			if (!strcmp (buffer, "sbus"))
207     				goto getit;
208     		}
209     	}
210     	if ((pci = prom_getparent (node))) {
211     		i = prom_getproperty (pci, "name", buffer, len);
212     		if (i > 0) {
213     			buffer [i] = 0;
214     			if (!strcmp (buffer, "pci"))
215     				goto getit;
216     		}
217     		pci = 0;
218     	}
219     	if ((ebus = prom_getparent (node))) {
220     		i = prom_getproperty (ebus, "name", buffer, len);
221     		if (i > 0) {
222     			buffer[i] = 0;
223     			if (!strcmp (buffer, "ebus"))
224     				goto getit;
225     		}
226     		ebus = 0;
227     	}
228     	if ((ide = prom_getparent (node))) {
229     		i = prom_getproperty (ide, "name", buffer, len);
230     		if (i > 0) {
231     			buffer [i] = 0;
232     			if (!strcmp (buffer, "ide"))
233     				goto getit;
234     		}
235     		ide = 0;
236     	}
237     getit:
238     	i = prom_getproperty (node, "name", buffer, len);
239     	if (i <= 0) {
240     		buffer [0] = 0;
241     		return -1;
242     	}
243     	buffer [i] = 0;
244     	len -= i;
245     	i = prom_getproperty (node, "reg", (char *)reg64, sizeof (reg64));
246     	if (i <= 0) return 0;
247     	if (len < 16) return -1;
248     	buffer = strchr (buffer, 0);
249     	if (sbus) {
250     		reg = (struct linux_prom_registers *)reg64;
251     		sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr);
252     	} else if (pci) {
253     		int dev, fn;
254     		reg = (struct linux_prom_registers *)reg64;
255     		fn = (reg[0].which_io >> 8) & 0x07;
256     		dev = (reg[0].which_io >> 11) & 0x1f;
257     		if (fn)
258     			sprintf (buffer, "@%x,%x", dev, fn);
259     		else
260     			sprintf (buffer, "@%x", dev);
261     	} else if (ebus) {
262     		reg = (struct linux_prom_registers *)reg64;
263     		sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr);
264     	} else if (ide) {
265     		reg = (struct linux_prom_registers *)reg64;
266     		sprintf (buffer, "@%x,%x", reg[0].which_io, reg[0].phys_addr);
267     	} else if (i == 4) {	/* Happens on 8042's children on Ultra/PCI. */
268     		reg = (struct linux_prom_registers *)reg64;
269     		sprintf (buffer, "@%x", reg[0].which_io);
270     	} else {
271     		sprintf (buffer, "@%x,%x",
272     			 (unsigned int)(reg64[0].phys_addr >> 36),
273     			 (unsigned int)(reg64[0].phys_addr));
274     	}
275     	return 0;
276     }
277     
278     /* Return the first property type for node 'node'.
279      * buffer should be at least 32B in length
280      */
281     __inline__ char *
282     prom_firstprop(int node, char *buffer)
283     {
284     	*buffer = 0;
285     	if(node == -1) return buffer;
286     	p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)|
287     			       P1275_INOUT(3, 0), 
288     			       node, (char *) 0x0, buffer);
289     	return buffer;
290     }
291     
292     /* Return the property type string after property type 'oprop'
293      * at node 'node' .  Returns NULL string if no more
294      * property types for this node.
295      */
296     __inline__ char *
297     prom_nextprop(int node, char *oprop, char *buffer)
298     {
299     	char buf[32];
300     
301     	if(node == -1) {
302     		*buffer = 0;
303     		return buffer;
304     	}
305     	if (oprop == buffer) {
306     		strcpy (buf, oprop);
307     		oprop = buf;
308     	}
309     	p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
310     				    P1275_ARG(2,P1275_ARG_OUT_32B)|
311     				    P1275_INOUT(3, 0), 
312     				    node, oprop, buffer); 
313     	return buffer;
314     }
315     
316     int
317     prom_finddevice(char *name)
318     {
319     	if(!name) return 0;
320     	return p1275_cmd ("finddevice", P1275_ARG(0,P1275_ARG_IN_STRING)|
321     				        P1275_INOUT(1, 1), 
322     				        name);
323     }
324     
325     int prom_node_has_property(int node, char *prop)
326     {
327     	char buf [32];
328             
329     	*buf = 0;
330     	do {
331     		prom_nextprop(node, buf, buf);
332     		if(!strcmp(buf, prop))
333     			return 1;
334     	} while (*buf);
335     	return 0;
336     }
337                                                                                                
338     /* Set property 'pname' at node 'node' to value 'value' which has a length
339      * of 'size' bytes.  Return the number of bytes the prom accepted.
340      */
341     int
342     prom_setprop(int node, char *pname, char *value, int size)
343     {
344     	if(size == 0) return 0;
345     	if((pname == 0) || (value == 0)) return 0;
346     	
347     	return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
348     					  P1275_ARG(2,P1275_ARG_IN_BUF)|
349     					  P1275_INOUT(4, 1), 
350     					  node, pname, value, P1275_SIZE(size));
351     }
352     
353     __inline__ int
354     prom_inst2pkg(int inst)
355     {
356     	int node;
357     	
358     	node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst);
359     	if (node == -1) return 0;
360     	return node;
361     }
362     
363     /* Return 'node' assigned to a particular prom 'path'
364      * FIXME: Should work for v0 as well
365      */
366     int
367     prom_pathtoinode(char *path)
368     {
369     	int node, inst;
370     
371     	inst = prom_devopen (path);
372     	if (inst == 0) return 0;
373     	node = prom_inst2pkg (inst);
374     	prom_devclose (inst);
375     	if (node == -1) return 0;
376     	return node;
377     }
378