blob: fdc9c29d2f1be93bda4de8679ab04f73d9ac4074 [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 *
Kumar Galac8ab7052007-10-24 11:04:22 -05005 * libfdt is dual licensed: you can use it either under the terms of
6 * the GPL, or the BSD license, at your option.
Gerald Van Baren9e61ed82007-03-31 12:00:56 -04007 *
Kumar Galac8ab7052007-10-24 11:04:22 -05008 * a) This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040012 *
Kumar Galac8ab7052007-10-24 11:04:22 -050013 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 * MA 02110-1301 USA
22 *
23 * Alternatively,
24 *
25 * b) Redistribution and use in source and binary forms, with or
26 * without modification, are permitted provided that the following
27 * conditions are met:
28 *
29 * 1. Redistributions of source code must retain the above
30 * copyright notice, this list of conditions and the following
31 * disclaimer.
32 * 2. Redistributions in binary form must reproduce the above
33 * copyright notice, this list of conditions and the following
34 * disclaimer in the documentation and/or other materials
35 * provided with the distribution.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040050 */
51#include "libfdt_env.h"
52
Bartlomiej Sieka61250862008-02-29 16:00:24 +010053#ifndef USE_HOSTCC
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040054#include <fdt.h>
55#include <libfdt.h>
Bartlomiej Sieka61250862008-02-29 16:00:24 +010056#else
57#include "fdt_host.h"
58#endif
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040059
60#include "libfdt_internal.h"
61
David Gibson9457d9d2008-07-09 14:10:24 +100062static int _fdt_nodename_eq(const void *fdt, int offset,
63 const char *s, int len)
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040064{
David Gibsond9d793c2008-02-12 11:58:31 +110065 const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040066
67 if (! p)
68 /* short match */
69 return 0;
70
71 if (memcmp(p, s, len) != 0)
72 return 0;
73
Kumar Galac8ab7052007-10-24 11:04:22 -050074 if (p[len] == '\0')
75 return 1;
76 else if (!memchr(s, '@', len) && (p[len] == '@'))
77 return 1;
78 else
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040079 return 0;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -040080}
81
Kumar Galac8ab7052007-10-24 11:04:22 -050082const char *fdt_string(const void *fdt, int stroffset)
Gerald Van Baren18c75c62007-05-17 23:54:36 -040083{
David Gibson870fa472008-07-07 10:14:15 +100084 return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
Kumar Galac8ab7052007-10-24 11:04:22 -050085}
Gerald Van Baren18c75c62007-05-17 23:54:36 -040086
David Gibsonc5b130e2008-08-06 14:50:49 +100087static int _fdt_string_eq(const void *fdt, int stroffset,
88 const char *s, int len)
89{
90 const char *p = fdt_string(fdt, stroffset);
91
92 return (strlen(p) == len) && (memcmp(p, s, len) == 0);
93}
94
Kumar Galac8ab7052007-10-24 11:04:22 -050095int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
96{
David Gibson9457d9d2008-07-09 14:10:24 +100097 FDT_CHECK_HEADER(fdt);
Kumar Galac8ab7052007-10-24 11:04:22 -050098 *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
99 *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
Gerald Van Baren18c75c62007-05-17 23:54:36 -0400100 return 0;
101}
102
Kumar Galac8ab7052007-10-24 11:04:22 -0500103int fdt_num_mem_rsv(const void *fdt)
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400104{
Kumar Galac8ab7052007-10-24 11:04:22 -0500105 int i = 0;
106
107 while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
108 i++;
109 return i;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400110}
111
David Gibsond9d793c2008-02-12 11:58:31 +1100112int fdt_subnode_offset_namelen(const void *fdt, int offset,
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400113 const char *name, int namelen)
114{
David Gibson1c0320e2008-10-29 23:27:45 -0500115 int depth = 0;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400116
David Gibson9457d9d2008-07-09 14:10:24 +1000117 FDT_CHECK_HEADER(fdt);
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400118
David Gibson1c0320e2008-10-29 23:27:45 -0500119 for (depth = 0, offset = fdt_next_node(fdt, offset, &depth);
120 (offset >= 0) && (depth > 0);
David Gibsond9d793c2008-02-12 11:58:31 +1100121 offset = fdt_next_node(fdt, offset, &depth)) {
122 if (depth < 0)
123 return -FDT_ERR_NOTFOUND;
124 else if ((depth == 1)
David Gibson9457d9d2008-07-09 14:10:24 +1000125 && _fdt_nodename_eq(fdt, offset, name, namelen))
David Gibsond9d793c2008-02-12 11:58:31 +1100126 return offset;
127 }
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400128
David Gibson1c0320e2008-10-29 23:27:45 -0500129 if (offset < 0)
130 return offset; /* error */
131 else
132 return -FDT_ERR_NOTFOUND;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400133}
134
135int fdt_subnode_offset(const void *fdt, int parentoffset,
136 const char *name)
137{
138 return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
139}
140
Kumar Galac8ab7052007-10-24 11:04:22 -0500141int fdt_path_offset(const void *fdt, const char *path)
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400142{
143 const char *end = path + strlen(path);
144 const char *p = path;
145 int offset = 0;
146
David Gibson9457d9d2008-07-09 14:10:24 +1000147 FDT_CHECK_HEADER(fdt);
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400148
Kumar Galaeb45e032008-08-14 08:28:19 -0500149 /* see if we have an alias */
150 if (*path != '/') {
David Gibsond6656ea2008-08-20 16:55:14 +1000151 const char *q = strchr(path, '/');
Kumar Galaeb45e032008-08-14 08:28:19 -0500152
Kumar Galaeb45e032008-08-14 08:28:19 -0500153 if (!q)
154 q = end;
155
David Gibsond6656ea2008-08-20 16:55:14 +1000156 p = fdt_get_alias_namelen(fdt, p, q - p);
Kumar Galaeb45e032008-08-14 08:28:19 -0500157 if (!p)
158 return -FDT_ERR_BADPATH;
159 offset = fdt_path_offset(fdt, p);
160
161 p = q;
162 }
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400163
164 while (*p) {
165 const char *q;
166
167 while (*p == '/')
168 p++;
169 if (! *p)
Kumar Galac8ab7052007-10-24 11:04:22 -0500170 return offset;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400171 q = strchr(p, '/');
172 if (! q)
173 q = end;
174
175 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
176 if (offset < 0)
177 return offset;
178
179 p = q;
180 }
181
Gerald Van Baren32480892007-03-31 14:30:53 -0400182 return offset;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400183}
184
Kumar Galac8ab7052007-10-24 11:04:22 -0500185const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400186{
David Gibson148a49b2008-05-20 17:19:11 +1000187 const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
Kumar Galac8ab7052007-10-24 11:04:22 -0500188 int err;
189
David Gibson148a49b2008-05-20 17:19:11 +1000190 if (((err = fdt_check_header(fdt)) != 0)
191 || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
192 goto fail;
Kumar Galac8ab7052007-10-24 11:04:22 -0500193
194 if (len)
195 *len = strlen(nh->name);
196
197 return nh->name;
198
199 fail:
200 if (len)
201 *len = err;
202 return NULL;
203}
204
David Gibsonc5b130e2008-08-06 14:50:49 +1000205const struct fdt_property *fdt_get_property_namelen(const void *fdt,
206 int nodeoffset,
207 const char *name,
208 int namelen, int *lenp)
Kumar Galac8ab7052007-10-24 11:04:22 -0500209{
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400210 uint32_t tag;
Kumar Galac8ab7052007-10-24 11:04:22 -0500211 const struct fdt_property *prop;
212 int namestroff;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400213 int offset, nextoffset;
214 int err;
215
David Gibson148a49b2008-05-20 17:19:11 +1000216 if (((err = fdt_check_header(fdt)) != 0)
217 || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
218 goto fail;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400219
David Gibson148a49b2008-05-20 17:19:11 +1000220 nextoffset = err;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400221 do {
222 offset = nextoffset;
223
Kumar Galac8ab7052007-10-24 11:04:22 -0500224 tag = fdt_next_tag(fdt, offset, &nextoffset);
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400225 switch (tag) {
226 case FDT_END:
227 err = -FDT_ERR_TRUNCATED;
228 goto fail;
229
230 case FDT_BEGIN_NODE:
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400231 case FDT_END_NODE:
Kumar Galac8ab7052007-10-24 11:04:22 -0500232 case FDT_NOP:
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400233 break;
234
235 case FDT_PROP:
Kumar Galac8ab7052007-10-24 11:04:22 -0500236 err = -FDT_ERR_BADSTRUCTURE;
237 prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
238 if (! prop)
Gerald Van Baren18c75c62007-05-17 23:54:36 -0400239 goto fail;
Kumar Galac8ab7052007-10-24 11:04:22 -0500240 namestroff = fdt32_to_cpu(prop->nameoff);
David Gibsonc5b130e2008-08-06 14:50:49 +1000241 if (_fdt_string_eq(fdt, namestroff, name, namelen)) {
Kumar Galac8ab7052007-10-24 11:04:22 -0500242 /* Found it! */
243 int len = fdt32_to_cpu(prop->len);
244 prop = fdt_offset_ptr(fdt, offset,
245 sizeof(*prop)+len);
246 if (! prop)
247 goto fail;
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400248
Kumar Galac8ab7052007-10-24 11:04:22 -0500249 if (lenp)
250 *lenp = len;
251
252 return prop;
253 }
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400254 break;
255
256 default:
257 err = -FDT_ERR_BADSTRUCTURE;
258 goto fail;
259 }
Kumar Galac8ab7052007-10-24 11:04:22 -0500260 } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400261
262 err = -FDT_ERR_NOTFOUND;
Kumar Galac8ab7052007-10-24 11:04:22 -0500263 fail:
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400264 if (lenp)
265 *lenp = err;
266 return NULL;
267}
268
David Gibsonc5b130e2008-08-06 14:50:49 +1000269const struct fdt_property *fdt_get_property(const void *fdt,
270 int nodeoffset,
271 const char *name, int *lenp)
272{
273 return fdt_get_property_namelen(fdt, nodeoffset, name,
274 strlen(name), lenp);
275}
276
277const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
278 const char *name, int namelen, int *lenp)
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400279{
280 const struct fdt_property *prop;
281
David Gibsonc5b130e2008-08-06 14:50:49 +1000282 prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400283 if (! prop)
284 return NULL;
285
Kumar Galac8ab7052007-10-24 11:04:22 -0500286 return prop->data;
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400287}
288
David Gibsonc5b130e2008-08-06 14:50:49 +1000289const void *fdt_getprop(const void *fdt, int nodeoffset,
290 const char *name, int *lenp)
291{
292 return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
293}
294
Kumar Galac8ab7052007-10-24 11:04:22 -0500295uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
296{
297 const uint32_t *php;
298 int len;
299
300 php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
301 if (!php || (len != sizeof(*php)))
302 return 0;
303
304 return fdt32_to_cpu(*php);
305}
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400306
David Gibsond6656ea2008-08-20 16:55:14 +1000307const char *fdt_get_alias_namelen(const void *fdt,
308 const char *name, int namelen)
309{
310 int aliasoffset;
311
312 aliasoffset = fdt_path_offset(fdt, "/aliases");
313 if (aliasoffset < 0)
314 return NULL;
315
316 return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
317}
318
319const char *fdt_get_alias(const void *fdt, const char *name)
320{
321 return fdt_get_alias_namelen(fdt, name, strlen(name));
322}
323
Kumar Galac8ab7052007-10-24 11:04:22 -0500324int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400325{
David Gibsond9d793c2008-02-12 11:58:31 +1100326 int pdepth = 0, p = 0;
327 int offset, depth, namelen;
Kumar Galac8ab7052007-10-24 11:04:22 -0500328 const char *name;
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400329
David Gibson9457d9d2008-07-09 14:10:24 +1000330 FDT_CHECK_HEADER(fdt);
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400331
Kumar Galac8ab7052007-10-24 11:04:22 -0500332 if (buflen < 2)
333 return -FDT_ERR_NOSPACE;
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400334
David Gibsond9d793c2008-02-12 11:58:31 +1100335 for (offset = 0, depth = 0;
336 (offset >= 0) && (offset <= nodeoffset);
337 offset = fdt_next_node(fdt, offset, &depth)) {
David Gibsond9d793c2008-02-12 11:58:31 +1100338 while (pdepth > depth) {
339 do {
340 p--;
341 } while (buf[p-1] != '/');
342 pdepth--;
343 }
344
David Gibson8d2810d2008-08-29 14:19:13 +1000345 if (pdepth >= depth) {
346 name = fdt_get_name(fdt, offset, &namelen);
347 if (!name)
348 return namelen;
349 if ((p + namelen + 1) <= buflen) {
350 memcpy(buf + p, name, namelen);
351 p += namelen;
352 buf[p++] = '/';
353 pdepth++;
354 }
David Gibsond9d793c2008-02-12 11:58:31 +1100355 }
Kumar Galac8ab7052007-10-24 11:04:22 -0500356
David Gibsond9d793c2008-02-12 11:58:31 +1100357 if (offset == nodeoffset) {
358 if (pdepth < (depth + 1))
359 return -FDT_ERR_NOSPACE;
Kumar Galac8ab7052007-10-24 11:04:22 -0500360
David Gibsond9d793c2008-02-12 11:58:31 +1100361 if (p > 1) /* special case so that root path is "/", not "" */
362 p--;
363 buf[p] = '\0';
David Gibson8d2810d2008-08-29 14:19:13 +1000364 return 0;
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400365 }
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400366 }
367
David Gibsond9d793c2008-02-12 11:58:31 +1100368 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
369 return -FDT_ERR_BADOFFSET;
370 else if (offset == -FDT_ERR_BADOFFSET)
371 return -FDT_ERR_BADSTRUCTURE;
Gerald Van Barenca8d8a62007-03-31 12:13:43 -0400372
David Gibsond9d793c2008-02-12 11:58:31 +1100373 return offset; /* error from fdt_next_node() */
Gerald Van Baren9e61ed82007-03-31 12:00:56 -0400374}
Gerald Van Barenc077a132007-04-14 22:46:41 -0400375
Kumar Galac8ab7052007-10-24 11:04:22 -0500376int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
377 int supernodedepth, int *nodedepth)
Gerald Van Barenc077a132007-04-14 22:46:41 -0400378{
David Gibsond9d793c2008-02-12 11:58:31 +1100379 int offset, depth;
Kumar Galac8ab7052007-10-24 11:04:22 -0500380 int supernodeoffset = -FDT_ERR_INTERNAL;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400381
David Gibson9457d9d2008-07-09 14:10:24 +1000382 FDT_CHECK_HEADER(fdt);
Gerald Van Barenc077a132007-04-14 22:46:41 -0400383
Kumar Galac8ab7052007-10-24 11:04:22 -0500384 if (supernodedepth < 0)
385 return -FDT_ERR_NOTFOUND;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400386
David Gibsond9d793c2008-02-12 11:58:31 +1100387 for (offset = 0, depth = 0;
388 (offset >= 0) && (offset <= nodeoffset);
389 offset = fdt_next_node(fdt, offset, &depth)) {
390 if (depth == supernodedepth)
391 supernodeoffset = offset;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400392
David Gibsond9d793c2008-02-12 11:58:31 +1100393 if (offset == nodeoffset) {
394 if (nodedepth)
395 *nodedepth = depth;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400396
David Gibsond9d793c2008-02-12 11:58:31 +1100397 if (supernodedepth > depth)
398 return -FDT_ERR_NOTFOUND;
399 else
400 return supernodeoffset;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400401 }
David Gibsond9d793c2008-02-12 11:58:31 +1100402 }
Kumar Galac8ab7052007-10-24 11:04:22 -0500403
David Gibsond9d793c2008-02-12 11:58:31 +1100404 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
405 return -FDT_ERR_BADOFFSET;
406 else if (offset == -FDT_ERR_BADOFFSET)
407 return -FDT_ERR_BADSTRUCTURE;
Kumar Galac8ab7052007-10-24 11:04:22 -0500408
David Gibsond9d793c2008-02-12 11:58:31 +1100409 return offset; /* error from fdt_next_node() */
Kumar Galac8ab7052007-10-24 11:04:22 -0500410}
411
412int fdt_node_depth(const void *fdt, int nodeoffset)
413{
414 int nodedepth;
415 int err;
416
417 err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
418 if (err)
419 return (err < 0) ? err : -FDT_ERR_INTERNAL;
420 return nodedepth;
421}
422
423int fdt_parent_offset(const void *fdt, int nodeoffset)
424{
425 int nodedepth = fdt_node_depth(fdt, nodeoffset);
426
427 if (nodedepth < 0)
428 return nodedepth;
429 return fdt_supernode_atdepth_offset(fdt, nodeoffset,
430 nodedepth - 1, NULL);
431}
432
433int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
434 const char *propname,
435 const void *propval, int proplen)
436{
David Gibsond9d793c2008-02-12 11:58:31 +1100437 int offset;
Kumar Galac8ab7052007-10-24 11:04:22 -0500438 const void *val;
439 int len;
440
David Gibson9457d9d2008-07-09 14:10:24 +1000441 FDT_CHECK_HEADER(fdt);
Kumar Galac8ab7052007-10-24 11:04:22 -0500442
Kumar Galac8ab7052007-10-24 11:04:22 -0500443 /* FIXME: The algorithm here is pretty horrible: we scan each
444 * property of a node in fdt_getprop(), then if that didn't
445 * find what we want, we scan over them again making our way
446 * to the next node. Still it's the easiest to implement
447 * approach; performance can come later. */
David Gibsond9d793c2008-02-12 11:58:31 +1100448 for (offset = fdt_next_node(fdt, startoffset, NULL);
449 offset >= 0;
450 offset = fdt_next_node(fdt, offset, NULL)) {
451 val = fdt_getprop(fdt, offset, propname, &len);
452 if (val && (len == proplen)
453 && (memcmp(val, propval, len) == 0))
454 return offset;
455 }
Kumar Galac8ab7052007-10-24 11:04:22 -0500456
David Gibsond9d793c2008-02-12 11:58:31 +1100457 return offset; /* error from fdt_next_node() */
Gerald Van Barenc077a132007-04-14 22:46:41 -0400458}
459
Kumar Galac8ab7052007-10-24 11:04:22 -0500460int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
Gerald Van Barenc077a132007-04-14 22:46:41 -0400461{
Kumar Galac8ab7052007-10-24 11:04:22 -0500462 if ((phandle == 0) || (phandle == -1))
463 return -FDT_ERR_BADPHANDLE;
464 phandle = cpu_to_fdt32(phandle);
465 return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
466 &phandle, sizeof(phandle));
467}
Gerald Van Barenc077a132007-04-14 22:46:41 -0400468
David Gibson0a1617a2008-07-29 14:51:22 +1000469static int _fdt_stringlist_contains(const char *strlist, int listlen,
470 const char *str)
Kumar Galac8ab7052007-10-24 11:04:22 -0500471{
472 int len = strlen(str);
David Gibsonb4141b82008-07-07 10:10:48 +1000473 const char *p;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400474
Kumar Galac8ab7052007-10-24 11:04:22 -0500475 while (listlen >= len) {
476 if (memcmp(str, strlist, len+1) == 0)
477 return 1;
478 p = memchr(strlist, '\0', listlen);
479 if (!p)
480 return 0; /* malformed strlist.. */
481 listlen -= (p-strlist) + 1;
482 strlist = p + 1;
Gerald Van Barenc077a132007-04-14 22:46:41 -0400483 }
484 return 0;
485}
Kumar Galac8ab7052007-10-24 11:04:22 -0500486
487int fdt_node_check_compatible(const void *fdt, int nodeoffset,
488 const char *compatible)
489{
490 const void *prop;
491 int len;
492
493 prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
494 if (!prop)
495 return len;
David Gibson0a1617a2008-07-29 14:51:22 +1000496 if (_fdt_stringlist_contains(prop, len, compatible))
Kumar Galac8ab7052007-10-24 11:04:22 -0500497 return 0;
498 else
499 return 1;
500}
501
502int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
503 const char *compatible)
504{
David Gibsone8f3f7f2008-02-18 18:09:04 +1100505 int offset, err;
Kumar Galac8ab7052007-10-24 11:04:22 -0500506
David Gibson9457d9d2008-07-09 14:10:24 +1000507 FDT_CHECK_HEADER(fdt);
Kumar Galac8ab7052007-10-24 11:04:22 -0500508
Kumar Galac8ab7052007-10-24 11:04:22 -0500509 /* FIXME: The algorithm here is pretty horrible: we scan each
510 * property of a node in fdt_node_check_compatible(), then if
511 * that didn't find what we want, we scan over them again
512 * making our way to the next node. Still it's the easiest to
513 * implement approach; performance can come later. */
David Gibsond9d793c2008-02-12 11:58:31 +1100514 for (offset = fdt_next_node(fdt, startoffset, NULL);
515 offset >= 0;
516 offset = fdt_next_node(fdt, offset, NULL)) {
517 err = fdt_node_check_compatible(fdt, offset, compatible);
518 if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
519 return err;
520 else if (err == 0)
521 return offset;
522 }
Kumar Galac8ab7052007-10-24 11:04:22 -0500523
David Gibsond9d793c2008-02-12 11:58:31 +1100524 return offset; /* error from fdt_next_node() */
Kumar Galac8ab7052007-10-24 11:04:22 -0500525}