blob: 9112c6a63935e78b5418af233d16b5b8e9d280fe [file] [log] [blame]
Gerald Van Baren9e61ed82007-03-31 12:00:56 -04001/*
2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include "libfdt_env.h"
20
21#include <fdt.h>
22#include <libfdt.h>
23
24#include "libfdt_internal.h"
25
26#define CHECK_HEADER(fdt) \
27 { \
28 int err; \
29 if ((err = _fdt_check_header(fdt)) != 0) \
30 return err; \
31 }
32
33static int offset_streq(const void *fdt, int offset,
34 const char *s, int len)
35{
36 const char *p = fdt_offset_ptr(fdt, offset, len+1);
37
38 if (! p)
39 /* short match */
40 return 0;
41
42 if (memcmp(p, s, len) != 0)
43 return 0;
44
45 if (p[len] != '\0')
46 return 0;
47
48 return 1;
49}
50
51char *fdt_string(const void *fdt, int stroffset)
52{
53 return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
54}
55
56int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
57 const char *name, int namelen)
58{
59 int level = 0;
60 uint32_t tag;
61 int offset, nextoffset;
62
63 CHECK_HEADER(fdt);
64
65 tag = _fdt_next_tag(fdt, parentoffset, &nextoffset);
66 if (tag != FDT_BEGIN_NODE)
67 return -FDT_ERR_BADOFFSET;
68
69 do {
70 offset = nextoffset;
71 tag = _fdt_next_tag(fdt, offset, &nextoffset);
72
73 switch (tag) {
74 case FDT_END:
75 return -FDT_ERR_TRUNCATED;
76
77 case FDT_BEGIN_NODE:
78 level++;
79 if (level != 1)
80 continue;
81 if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen))
82 /* Found it! */
83 return offset;
84 break;
85
86 case FDT_END_NODE:
87 level--;
88 break;
89
90 case FDT_PROP:
91 case FDT_NOP:
92 break;
93
94 default:
95 return -FDT_ERR_BADSTRUCTURE;
96 }
97 } while (level >= 0);
98
99 return -FDT_ERR_NOTFOUND;
100}
101
102int fdt_subnode_offset(const void *fdt, int parentoffset,
103 const char *name)
104{
105 return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
106}
107
108int fdt_path_offset(const void *fdt, const char *path)
109{
110 const char *end = path + strlen(path);
111 const char *p = path;
112 int offset = 0;
113
114 CHECK_HEADER(fdt);
115
116 if (*path != '/')
117 return -FDT_ERR_BADPATH;
118
119 while (*p) {
120 const char *q;
121
122 while (*p == '/')
123 p++;
124 if (! *p)
125 return -FDT_ERR_BADPATH;
126 q = strchr(p, '/');
127 if (! q)
128 q = end;
129
130 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
131 if (offset < 0)
132 return offset;
133
134 p = q;
135 }
136
137 return offset;
138}
139
140struct fdt_property *fdt_get_property(const void *fdt,
141 int nodeoffset,
142 const char *name, int *lenp)
143{
144 int level = 0;
145 uint32_t tag;
146 struct fdt_property *prop;
147 int namestroff;
148 int offset, nextoffset;
149 int err;
150
151 if ((err = _fdt_check_header(fdt)) != 0)
152 goto fail;
153
154 err = -FDT_ERR_BADOFFSET;
155 if (nodeoffset % FDT_TAGSIZE)
156 goto fail;
157
158 tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
159 if (tag != FDT_BEGIN_NODE)
160 goto fail;
161
162 do {
163 offset = nextoffset;
164
165 tag = _fdt_next_tag(fdt, offset, &nextoffset);
166 switch (tag) {
167 case FDT_END:
168 err = -FDT_ERR_TRUNCATED;
169 goto fail;
170
171 case FDT_BEGIN_NODE:
172 level++;
173 break;
174
175 case FDT_END_NODE:
176 level--;
177 break;
178
179 case FDT_PROP:
180 if (level != 0)
181 continue;
182
183 err = -FDT_ERR_BADSTRUCTURE;
184 prop = fdt_offset_ptr_typed(fdt, offset, prop);
185 if (! prop)
186 goto fail;
187 namestroff = fdt32_to_cpu(prop->nameoff);
188 if (streq(fdt_string(fdt, namestroff), name)) {
189 /* Found it! */
190 int len = fdt32_to_cpu(prop->len);
191 prop = fdt_offset_ptr(fdt, offset,
192 sizeof(*prop)+len);
193 if (! prop)
194 goto fail;
195
196 if (lenp)
197 *lenp = len;
198
199 return prop;
200 }
201 break;
202
203 case FDT_NOP:
204 break;
205
206 default:
207 err = -FDT_ERR_BADSTRUCTURE;
208 goto fail;
209 }
210 } while (level >= 0);
211
212 err = -FDT_ERR_NOTFOUND;
213 fail:
214 if (lenp)
215 *lenp = err;
216 return NULL;
217}
218
219void *fdt_getprop(const void *fdt, int nodeoffset,
220 const char *name, int *lenp)
221{
222 const struct fdt_property *prop;
223
224 prop = fdt_get_property(fdt, nodeoffset, name, lenp);
225 if (! prop)
226 return NULL;
227
228 return prop->data;
229}