Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tree_32.c
Go to the documentation of this file.
1 /*
2  * tree.c: Basic device tree traversal/scanning for the Linux
3  * prom library.
4  *
5  * Copyright (C) 1995 David S. Miller ([email protected])
6  */
7 
8 #include <linux/string.h>
9 #include <linux/types.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/ctype.h>
13 #include <linux/module.h>
14 
15 #include <asm/openprom.h>
16 #include <asm/oplib.h>
17 
18 extern void restore_current(void);
19 
20 static char promlib_buf[128];
21 
22 /* Internal version of prom_getchild that does not alter return values. */
24 {
25  unsigned long flags;
26  phandle cnode;
27 
28  spin_lock_irqsave(&prom_lock, flags);
29  cnode = prom_nodeops->no_child(node);
31  spin_unlock_irqrestore(&prom_lock, flags);
32 
33  return cnode;
34 }
35 
36 /* Return the child of node 'node' or zero if no this node has no
37  * direct descendent.
38  */
40 {
41  phandle cnode;
42 
43  if ((s32)node == -1)
44  return 0;
45 
46  cnode = __prom_getchild(node);
47  if (cnode == 0 || (s32)cnode == -1)
48  return 0;
49 
50  return cnode;
51 }
53 
54 /* Internal version of prom_getsibling that does not alter return values. */
56 {
57  unsigned long flags;
58  phandle cnode;
59 
60  spin_lock_irqsave(&prom_lock, flags);
61  cnode = prom_nodeops->no_nextnode(node);
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  */
72 {
73  phandle sibnode;
74 
75  if ((s32)node == -1)
76  return 0;
77 
78  sibnode = __prom_getsibling(node);
79  if (sibnode == 0 || (s32)sibnode == -1)
80  return 0;
81 
82  return sibnode;
83 }
85 
86 /* Return the length in bytes of property 'prop' at node 'node'.
87  * Return -1 on error.
88  */
89 int prom_getproplen(phandle node, const char *prop)
90 {
91  int ret;
92  unsigned long flags;
93 
94  if((!node) || (!prop))
95  return -1;
96 
98  ret = prom_nodeops->no_proplen(node, prop);
100  spin_unlock_irqrestore(&prom_lock, flags);
101  return ret;
102 }
104 
105 /* Acquire a property 'prop' at node 'node' and place it in
106  * 'buffer' which has a size of 'bufsize'. If the acquisition
107  * was successful the length will be returned, else -1 is returned.
108  */
109 int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize)
110 {
111  int plen, ret;
112  unsigned long flags;
113 
114  plen = prom_getproplen(node, prop);
115  if((plen > bufsize) || (plen == 0) || (plen == -1))
116  return -1;
117  /* Ok, things seem all right. */
118  spin_lock_irqsave(&prom_lock, flags);
119  ret = prom_nodeops->no_getprop(node, prop, buffer);
120  restore_current();
121  spin_unlock_irqrestore(&prom_lock, flags);
122  return ret;
123 }
125 
126 /* Acquire an integer property and return its value. Returns -1
127  * on failure.
128  */
129 int prom_getint(phandle node, char *prop)
130 {
131  static int intprop;
132 
133  if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
134  return intprop;
135 
136  return -1;
137 }
139 
140 /* Acquire an integer property, upon error return the passed default
141  * integer.
142  */
144 {
145  int retval;
146 
147  retval = prom_getint(node, property);
148  if(retval == -1) return deflt;
149 
150  return retval;
151 }
153 
154 /* Acquire a boolean property, 1=TRUE 0=FALSE. */
155 int prom_getbool(phandle node, char *prop)
156 {
157  int retval;
158 
159  retval = prom_getproplen(node, prop);
160  if(retval == -1) return 0;
161  return 1;
162 }
164 
165 /* Acquire a property whose value is a string, returns a null
166  * string on error. The char pointer is the user supplied string
167  * buffer.
168  */
169 void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size)
170 {
171  int len;
172 
173  len = prom_getproperty(node, prop, user_buf, ubuf_size);
174  if(len != -1) return;
175  user_buf[0] = 0;
176 }
178 
179 
180 /* Search siblings at 'node_start' for a node with name
181  * 'nodename'. Return node if successful, zero if not.
182  */
183 phandle prom_searchsiblings(phandle node_start, char *nodename)
184 {
185 
186  phandle thisnode;
187  int error;
188 
189  for(thisnode = node_start; thisnode;
190  thisnode=prom_getsibling(thisnode)) {
191  error = prom_getproperty(thisnode, "name", promlib_buf,
192  sizeof(promlib_buf));
193  /* Should this ever happen? */
194  if(error == -1) continue;
195  if(strcmp(nodename, promlib_buf)==0) return thisnode;
196  }
197 
198  return 0;
199 }
201 
202 /* Interal version of nextprop that does not alter return values. */
203 static char *__prom_nextprop(phandle node, char * oprop)
204 {
205  unsigned long flags;
206  char *prop;
207 
208  spin_lock_irqsave(&prom_lock, flags);
209  prop = prom_nodeops->no_nextprop(node, oprop);
210  restore_current();
211  spin_unlock_irqrestore(&prom_lock, flags);
212 
213  return prop;
214 }
215 
216 /* Return the property type string after property type 'oprop'
217  * at node 'node' . Returns empty string if no more
218  * property types for this node.
219  */
220 char *prom_nextprop(phandle node, char *oprop, char *buffer)
221 {
222  if (node == 0 || (s32)node == -1)
223  return "";
224 
225  return __prom_nextprop(node, oprop);
226 }
228 
230 {
231  char nbuf[128];
232  char *s = name, *d;
233  phandle node = prom_root_node, node2;
234  unsigned int which_io, phys_addr;
235  struct linux_prom_registers reg[PROMREG_MAX];
236 
237  while (*s++) {
238  if (!*s) return node; /* path '.../' is legal */
239  node = prom_getchild(node);
240 
241  for (d = nbuf; *s != 0 && *s != '@' && *s != '/';)
242  *d++ = *s++;
243  *d = 0;
244 
245  node = prom_searchsiblings(node, nbuf);
246  if (!node)
247  return 0;
248 
249  if (*s == '@') {
250  if (isxdigit(s[1]) && s[2] == ',') {
251  which_io = simple_strtoul(s+1, NULL, 16);
252  phys_addr = simple_strtoul(s+3, &d, 16);
253  if (d != s + 3 && (!*d || *d == '/')
254  && d <= s + 3 + 8) {
255  node2 = node;
256  while (node2 && (s32)node2 != -1) {
257  if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
258  if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
259  node = node2;
260  break;
261  }
262  }
263  node2 = prom_getsibling(node2);
264  if (!node2 || (s32)node2 == -1)
265  break;
266  node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
267  }
268  }
269  }
270  while (*s != 0 && *s != '/') s++;
271  }
272  }
273  return node;
274 }
276 
277 /* Set property 'pname' at node 'node' to value 'value' which has a length
278  * of 'size' bytes. Return the number of bytes the prom accepted.
279  */
280 int prom_setprop(phandle node, const char *pname, char *value, int size)
281 {
282  unsigned long flags;
283  int ret;
284 
285  if (size == 0)
286  return 0;
287  if ((pname == NULL) || (value == NULL))
288  return 0;
289  spin_lock_irqsave(&prom_lock, flags);
290  ret = prom_nodeops->no_setprop(node, pname, value, size);
291  restore_current();
292  spin_unlock_irqrestore(&prom_lock, flags);
293  return ret;
294 }
296 
298 {
299  phandle node;
300  unsigned long flags;
301 
302  spin_lock_irqsave(&prom_lock, flags);
303  node = (*romvec->pv_v2devops.v2_inst2pkg)(inst);
304  restore_current();
305  spin_unlock_irqrestore(&prom_lock, flags);
306  if ((s32)node == -1)
307  return 0;
308  return node;
309 }