121fdc27aSRafal Jaworowski /*
221fdc27aSRafal Jaworowski * libfdt - Flat Device Tree manipulation
321fdc27aSRafal Jaworowski * Copyright (C) 2006 David Gibson, IBM Corporation.
421fdc27aSRafal Jaworowski *
521fdc27aSRafal Jaworowski * libfdt is dual licensed: you can use it either under the terms of
621fdc27aSRafal Jaworowski * the GPL, or the BSD license, at your option.
721fdc27aSRafal Jaworowski *
821fdc27aSRafal Jaworowski * a) This library is free software; you can redistribute it and/or
921fdc27aSRafal Jaworowski * modify it under the terms of the GNU General Public License as
1021fdc27aSRafal Jaworowski * published by the Free Software Foundation; either version 2 of the
1121fdc27aSRafal Jaworowski * License, or (at your option) any later version.
1221fdc27aSRafal Jaworowski *
1321fdc27aSRafal Jaworowski * This library is distributed in the hope that it will be useful,
1421fdc27aSRafal Jaworowski * but WITHOUT ANY WARRANTY; without even the implied warranty of
1521fdc27aSRafal Jaworowski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1621fdc27aSRafal Jaworowski * GNU General Public License for more details.
1721fdc27aSRafal Jaworowski *
1821fdc27aSRafal Jaworowski * You should have received a copy of the GNU General Public
1921fdc27aSRafal Jaworowski * License along with this library; if not, write to the Free
2021fdc27aSRafal Jaworowski * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
2121fdc27aSRafal Jaworowski * MA 02110-1301 USA
2221fdc27aSRafal Jaworowski *
2321fdc27aSRafal Jaworowski * Alternatively,
2421fdc27aSRafal Jaworowski *
2521fdc27aSRafal Jaworowski * b) Redistribution and use in source and binary forms, with or
2621fdc27aSRafal Jaworowski * without modification, are permitted provided that the following
2721fdc27aSRafal Jaworowski * conditions are met:
2821fdc27aSRafal Jaworowski *
2921fdc27aSRafal Jaworowski * 1. Redistributions of source code must retain the above
3021fdc27aSRafal Jaworowski * copyright notice, this list of conditions and the following
3121fdc27aSRafal Jaworowski * disclaimer.
3221fdc27aSRafal Jaworowski * 2. Redistributions in binary form must reproduce the above
3321fdc27aSRafal Jaworowski * copyright notice, this list of conditions and the following
3421fdc27aSRafal Jaworowski * disclaimer in the documentation and/or other materials
3521fdc27aSRafal Jaworowski * provided with the distribution.
3621fdc27aSRafal Jaworowski *
3721fdc27aSRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
3821fdc27aSRafal Jaworowski * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
3921fdc27aSRafal Jaworowski * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
4021fdc27aSRafal Jaworowski * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4121fdc27aSRafal Jaworowski * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
4221fdc27aSRafal Jaworowski * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4321fdc27aSRafal Jaworowski * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4421fdc27aSRafal Jaworowski * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4521fdc27aSRafal Jaworowski * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4621fdc27aSRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
4721fdc27aSRafal Jaworowski * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
4821fdc27aSRafal Jaworowski * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
4921fdc27aSRafal Jaworowski * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5021fdc27aSRafal Jaworowski */
5121fdc27aSRafal Jaworowski #include "libfdt_env.h"
5221fdc27aSRafal Jaworowski
5321fdc27aSRafal Jaworowski #include <fdt.h>
5421fdc27aSRafal Jaworowski #include <libfdt.h>
5521fdc27aSRafal Jaworowski
5621fdc27aSRafal Jaworowski #include "libfdt_internal.h"
5721fdc27aSRafal Jaworowski
fdt_nodename_eq_(const void * fdt,int offset,const char * s,int len)586780e684SKyle Evans static int fdt_nodename_eq_(const void *fdt, int offset,
5921fdc27aSRafal Jaworowski const char *s, int len)
6021fdc27aSRafal Jaworowski {
61*1a4529b5SKyle Evans int olen;
62*1a4529b5SKyle Evans const char *p = fdt_get_name(fdt, offset, &olen);
6321fdc27aSRafal Jaworowski
64*1a4529b5SKyle Evans if (!p || olen < len)
6521fdc27aSRafal Jaworowski /* short match */
6621fdc27aSRafal Jaworowski return 0;
6721fdc27aSRafal Jaworowski
6821fdc27aSRafal Jaworowski if (memcmp(p, s, len) != 0)
6921fdc27aSRafal Jaworowski return 0;
7021fdc27aSRafal Jaworowski
7121fdc27aSRafal Jaworowski if (p[len] == '\0')
7221fdc27aSRafal Jaworowski return 1;
7321fdc27aSRafal Jaworowski else if (!memchr(s, '@', len) && (p[len] == '@'))
7421fdc27aSRafal Jaworowski return 1;
7521fdc27aSRafal Jaworowski else
7621fdc27aSRafal Jaworowski return 0;
7721fdc27aSRafal Jaworowski }
7821fdc27aSRafal Jaworowski
fdt_string(const void * fdt,int stroffset)7921fdc27aSRafal Jaworowski const char *fdt_string(const void *fdt, int stroffset)
8021fdc27aSRafal Jaworowski {
8121fdc27aSRafal Jaworowski return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
8221fdc27aSRafal Jaworowski }
8321fdc27aSRafal Jaworowski
fdt_string_eq_(const void * fdt,int stroffset,const char * s,int len)846780e684SKyle Evans static int fdt_string_eq_(const void *fdt, int stroffset,
8521fdc27aSRafal Jaworowski const char *s, int len)
8621fdc27aSRafal Jaworowski {
8721fdc27aSRafal Jaworowski const char *p = fdt_string(fdt, stroffset);
8821fdc27aSRafal Jaworowski
8921fdc27aSRafal Jaworowski return (strlen(p) == len) && (memcmp(p, s, len) == 0);
9021fdc27aSRafal Jaworowski }
9121fdc27aSRafal Jaworowski
fdt_get_max_phandle(const void * fdt)926780e684SKyle Evans uint32_t fdt_get_max_phandle(const void *fdt)
936780e684SKyle Evans {
946780e684SKyle Evans uint32_t max_phandle = 0;
956780e684SKyle Evans int offset;
966780e684SKyle Evans
976780e684SKyle Evans for (offset = fdt_next_node(fdt, -1, NULL);;
986780e684SKyle Evans offset = fdt_next_node(fdt, offset, NULL)) {
996780e684SKyle Evans uint32_t phandle;
1006780e684SKyle Evans
1016780e684SKyle Evans if (offset == -FDT_ERR_NOTFOUND)
1026780e684SKyle Evans return max_phandle;
1036780e684SKyle Evans
1046780e684SKyle Evans if (offset < 0)
1056780e684SKyle Evans return (uint32_t)-1;
1066780e684SKyle Evans
1076780e684SKyle Evans phandle = fdt_get_phandle(fdt, offset);
1086780e684SKyle Evans if (phandle == (uint32_t)-1)
1096780e684SKyle Evans continue;
1106780e684SKyle Evans
1116780e684SKyle Evans if (phandle > max_phandle)
1126780e684SKyle Evans max_phandle = phandle;
1136780e684SKyle Evans }
1146780e684SKyle Evans
1156780e684SKyle Evans return 0;
1166780e684SKyle Evans }
1176780e684SKyle Evans
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)11821fdc27aSRafal Jaworowski int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
11921fdc27aSRafal Jaworowski {
12021fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
1216780e684SKyle Evans *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address);
1226780e684SKyle Evans *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size);
12321fdc27aSRafal Jaworowski return 0;
12421fdc27aSRafal Jaworowski }
12521fdc27aSRafal Jaworowski
fdt_num_mem_rsv(const void * fdt)12621fdc27aSRafal Jaworowski int fdt_num_mem_rsv(const void *fdt)
12721fdc27aSRafal Jaworowski {
12821fdc27aSRafal Jaworowski int i = 0;
12921fdc27aSRafal Jaworowski
1306780e684SKyle Evans while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0)
13121fdc27aSRafal Jaworowski i++;
13221fdc27aSRafal Jaworowski return i;
13321fdc27aSRafal Jaworowski }
13421fdc27aSRafal Jaworowski
nextprop_(const void * fdt,int offset)1356780e684SKyle Evans static int nextprop_(const void *fdt, int offset)
13652baf267SWarner Losh {
13752baf267SWarner Losh uint32_t tag;
13852baf267SWarner Losh int nextoffset;
13952baf267SWarner Losh
14052baf267SWarner Losh do {
14152baf267SWarner Losh tag = fdt_next_tag(fdt, offset, &nextoffset);
14252baf267SWarner Losh
14352baf267SWarner Losh switch (tag) {
14452baf267SWarner Losh case FDT_END:
14552baf267SWarner Losh if (nextoffset >= 0)
14652baf267SWarner Losh return -FDT_ERR_BADSTRUCTURE;
14752baf267SWarner Losh else
14852baf267SWarner Losh return nextoffset;
14952baf267SWarner Losh
15052baf267SWarner Losh case FDT_PROP:
15152baf267SWarner Losh return offset;
15252baf267SWarner Losh }
15352baf267SWarner Losh offset = nextoffset;
15452baf267SWarner Losh } while (tag == FDT_NOP);
15552baf267SWarner Losh
15652baf267SWarner Losh return -FDT_ERR_NOTFOUND;
15752baf267SWarner Losh }
15852baf267SWarner Losh
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)15921fdc27aSRafal Jaworowski int fdt_subnode_offset_namelen(const void *fdt, int offset,
16021fdc27aSRafal Jaworowski const char *name, int namelen)
16121fdc27aSRafal Jaworowski {
16221fdc27aSRafal Jaworowski int depth;
16321fdc27aSRafal Jaworowski
16421fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
16521fdc27aSRafal Jaworowski
16621fdc27aSRafal Jaworowski for (depth = 0;
16721fdc27aSRafal Jaworowski (offset >= 0) && (depth >= 0);
16821fdc27aSRafal Jaworowski offset = fdt_next_node(fdt, offset, &depth))
16921fdc27aSRafal Jaworowski if ((depth == 1)
1706780e684SKyle Evans && fdt_nodename_eq_(fdt, offset, name, namelen))
17121fdc27aSRafal Jaworowski return offset;
17221fdc27aSRafal Jaworowski
17321fdc27aSRafal Jaworowski if (depth < 0)
17421fdc27aSRafal Jaworowski return -FDT_ERR_NOTFOUND;
17521fdc27aSRafal Jaworowski return offset; /* error */
17621fdc27aSRafal Jaworowski }
17721fdc27aSRafal Jaworowski
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)17821fdc27aSRafal Jaworowski int fdt_subnode_offset(const void *fdt, int parentoffset,
17921fdc27aSRafal Jaworowski const char *name)
18021fdc27aSRafal Jaworowski {
18121fdc27aSRafal Jaworowski return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
18221fdc27aSRafal Jaworowski }
18321fdc27aSRafal Jaworowski
fdt_path_offset_namelen(const void * fdt,const char * path,int namelen)1846780e684SKyle Evans int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
18521fdc27aSRafal Jaworowski {
1866780e684SKyle Evans const char *end = path + namelen;
18721fdc27aSRafal Jaworowski const char *p = path;
18821fdc27aSRafal Jaworowski int offset = 0;
18921fdc27aSRafal Jaworowski
19021fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
19121fdc27aSRafal Jaworowski
19221fdc27aSRafal Jaworowski /* see if we have an alias */
19321fdc27aSRafal Jaworowski if (*path != '/') {
1946780e684SKyle Evans const char *q = memchr(path, '/', end - p);
19521fdc27aSRafal Jaworowski
19621fdc27aSRafal Jaworowski if (!q)
19721fdc27aSRafal Jaworowski q = end;
19821fdc27aSRafal Jaworowski
19921fdc27aSRafal Jaworowski p = fdt_get_alias_namelen(fdt, p, q - p);
20021fdc27aSRafal Jaworowski if (!p)
20121fdc27aSRafal Jaworowski return -FDT_ERR_BADPATH;
20221fdc27aSRafal Jaworowski offset = fdt_path_offset(fdt, p);
20321fdc27aSRafal Jaworowski
20421fdc27aSRafal Jaworowski p = q;
20521fdc27aSRafal Jaworowski }
20621fdc27aSRafal Jaworowski
2076780e684SKyle Evans while (p < end) {
20821fdc27aSRafal Jaworowski const char *q;
20921fdc27aSRafal Jaworowski
2106780e684SKyle Evans while (*p == '/') {
21121fdc27aSRafal Jaworowski p++;
2126780e684SKyle Evans if (p == end)
21321fdc27aSRafal Jaworowski return offset;
2146780e684SKyle Evans }
2156780e684SKyle Evans q = memchr(p, '/', end - p);
21621fdc27aSRafal Jaworowski if (! q)
21721fdc27aSRafal Jaworowski q = end;
21821fdc27aSRafal Jaworowski
21921fdc27aSRafal Jaworowski offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
22021fdc27aSRafal Jaworowski if (offset < 0)
22121fdc27aSRafal Jaworowski return offset;
22221fdc27aSRafal Jaworowski
22321fdc27aSRafal Jaworowski p = q;
22421fdc27aSRafal Jaworowski }
22521fdc27aSRafal Jaworowski
22621fdc27aSRafal Jaworowski return offset;
22721fdc27aSRafal Jaworowski }
22821fdc27aSRafal Jaworowski
fdt_path_offset(const void * fdt,const char * path)2296780e684SKyle Evans int fdt_path_offset(const void *fdt, const char *path)
2306780e684SKyle Evans {
2316780e684SKyle Evans return fdt_path_offset_namelen(fdt, path, strlen(path));
2326780e684SKyle Evans }
2336780e684SKyle Evans
fdt_get_name(const void * fdt,int nodeoffset,int * len)23421fdc27aSRafal Jaworowski const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
23521fdc27aSRafal Jaworowski {
2366780e684SKyle Evans const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
237*1a4529b5SKyle Evans const char *nameptr;
23821fdc27aSRafal Jaworowski int err;
23921fdc27aSRafal Jaworowski
24021fdc27aSRafal Jaworowski if (((err = fdt_check_header(fdt)) != 0)
2416780e684SKyle Evans || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
24221fdc27aSRafal Jaworowski goto fail;
24321fdc27aSRafal Jaworowski
244*1a4529b5SKyle Evans nameptr = nh->name;
24521fdc27aSRafal Jaworowski
246*1a4529b5SKyle Evans if (fdt_version(fdt) < 0x10) {
247*1a4529b5SKyle Evans /*
248*1a4529b5SKyle Evans * For old FDT versions, match the naming conventions of V16:
249*1a4529b5SKyle Evans * give only the leaf name (after all /). The actual tree
250*1a4529b5SKyle Evans * contents are loosely checked.
251*1a4529b5SKyle Evans */
252*1a4529b5SKyle Evans const char *leaf;
253*1a4529b5SKyle Evans leaf = strrchr(nameptr, '/');
254*1a4529b5SKyle Evans if (leaf == NULL) {
255*1a4529b5SKyle Evans err = -FDT_ERR_BADSTRUCTURE;
256*1a4529b5SKyle Evans goto fail;
257*1a4529b5SKyle Evans }
258*1a4529b5SKyle Evans nameptr = leaf+1;
259*1a4529b5SKyle Evans }
260*1a4529b5SKyle Evans
261*1a4529b5SKyle Evans if (len)
262*1a4529b5SKyle Evans *len = strlen(nameptr);
263*1a4529b5SKyle Evans
264*1a4529b5SKyle Evans return nameptr;
26521fdc27aSRafal Jaworowski
26621fdc27aSRafal Jaworowski fail:
26721fdc27aSRafal Jaworowski if (len)
26821fdc27aSRafal Jaworowski *len = err;
26921fdc27aSRafal Jaworowski return NULL;
27021fdc27aSRafal Jaworowski }
27121fdc27aSRafal Jaworowski
fdt_first_property_offset(const void * fdt,int nodeoffset)27252baf267SWarner Losh int fdt_first_property_offset(const void *fdt, int nodeoffset)
27321fdc27aSRafal Jaworowski {
27452baf267SWarner Losh int offset;
27552baf267SWarner Losh
2766780e684SKyle Evans if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
27752baf267SWarner Losh return offset;
27852baf267SWarner Losh
2796780e684SKyle Evans return nextprop_(fdt, offset);
28052baf267SWarner Losh }
28152baf267SWarner Losh
fdt_next_property_offset(const void * fdt,int offset)28252baf267SWarner Losh int fdt_next_property_offset(const void *fdt, int offset)
28352baf267SWarner Losh {
2846780e684SKyle Evans if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
28552baf267SWarner Losh return offset;
28652baf267SWarner Losh
2876780e684SKyle Evans return nextprop_(fdt, offset);
28852baf267SWarner Losh }
28952baf267SWarner Losh
fdt_get_property_by_offset_(const void * fdt,int offset,int * lenp)290*1a4529b5SKyle Evans static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
29152baf267SWarner Losh int offset,
29252baf267SWarner Losh int *lenp)
29352baf267SWarner Losh {
29421fdc27aSRafal Jaworowski int err;
29552baf267SWarner Losh const struct fdt_property *prop;
29621fdc27aSRafal Jaworowski
2976780e684SKyle Evans if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) {
29852baf267SWarner Losh if (lenp)
29952baf267SWarner Losh *lenp = err;
30052baf267SWarner Losh return NULL;
30152baf267SWarner Losh }
30221fdc27aSRafal Jaworowski
3036780e684SKyle Evans prop = fdt_offset_ptr_(fdt, offset);
30452baf267SWarner Losh
30521fdc27aSRafal Jaworowski if (lenp)
30621fdc27aSRafal Jaworowski *lenp = fdt32_to_cpu(prop->len);
30721fdc27aSRafal Jaworowski
30821fdc27aSRafal Jaworowski return prop;
30921fdc27aSRafal Jaworowski }
31052baf267SWarner Losh
fdt_get_property_by_offset(const void * fdt,int offset,int * lenp)311*1a4529b5SKyle Evans const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
312*1a4529b5SKyle Evans int offset,
313*1a4529b5SKyle Evans int *lenp)
314*1a4529b5SKyle Evans {
315*1a4529b5SKyle Evans /* Prior to version 16, properties may need realignment
316*1a4529b5SKyle Evans * and this API does not work. fdt_getprop_*() will, however. */
317*1a4529b5SKyle Evans
318*1a4529b5SKyle Evans if (fdt_version(fdt) < 0x10) {
319*1a4529b5SKyle Evans if (lenp)
320*1a4529b5SKyle Evans *lenp = -FDT_ERR_BADVERSION;
321*1a4529b5SKyle Evans return NULL;
322*1a4529b5SKyle Evans }
323*1a4529b5SKyle Evans
324*1a4529b5SKyle Evans return fdt_get_property_by_offset_(fdt, offset, lenp);
325*1a4529b5SKyle Evans }
326*1a4529b5SKyle Evans
fdt_get_property_namelen_(const void * fdt,int offset,const char * name,int namelen,int * lenp,int * poffset)327*1a4529b5SKyle Evans static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
32852baf267SWarner Losh int offset,
32952baf267SWarner Losh const char *name,
330*1a4529b5SKyle Evans int namelen,
331*1a4529b5SKyle Evans int *lenp,
332*1a4529b5SKyle Evans int *poffset)
33352baf267SWarner Losh {
33452baf267SWarner Losh for (offset = fdt_first_property_offset(fdt, offset);
33552baf267SWarner Losh (offset >= 0);
33652baf267SWarner Losh (offset = fdt_next_property_offset(fdt, offset))) {
33752baf267SWarner Losh const struct fdt_property *prop;
33852baf267SWarner Losh
339*1a4529b5SKyle Evans if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) {
34052baf267SWarner Losh offset = -FDT_ERR_INTERNAL;
34121fdc27aSRafal Jaworowski break;
34221fdc27aSRafal Jaworowski }
3436780e684SKyle Evans if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff),
344*1a4529b5SKyle Evans name, namelen)) {
345*1a4529b5SKyle Evans if (poffset)
346*1a4529b5SKyle Evans *poffset = offset;
34752baf267SWarner Losh return prop;
34852baf267SWarner Losh }
349*1a4529b5SKyle Evans }
35021fdc27aSRafal Jaworowski
35121fdc27aSRafal Jaworowski if (lenp)
35252baf267SWarner Losh *lenp = offset;
35321fdc27aSRafal Jaworowski return NULL;
35421fdc27aSRafal Jaworowski }
35521fdc27aSRafal Jaworowski
356*1a4529b5SKyle Evans
fdt_get_property_namelen(const void * fdt,int offset,const char * name,int namelen,int * lenp)357*1a4529b5SKyle Evans const struct fdt_property *fdt_get_property_namelen(const void *fdt,
358*1a4529b5SKyle Evans int offset,
359*1a4529b5SKyle Evans const char *name,
360*1a4529b5SKyle Evans int namelen, int *lenp)
361*1a4529b5SKyle Evans {
362*1a4529b5SKyle Evans /* Prior to version 16, properties may need realignment
363*1a4529b5SKyle Evans * and this API does not work. fdt_getprop_*() will, however. */
364*1a4529b5SKyle Evans if (fdt_version(fdt) < 0x10) {
365*1a4529b5SKyle Evans if (lenp)
366*1a4529b5SKyle Evans *lenp = -FDT_ERR_BADVERSION;
367*1a4529b5SKyle Evans return NULL;
368*1a4529b5SKyle Evans }
369*1a4529b5SKyle Evans
370*1a4529b5SKyle Evans return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
371*1a4529b5SKyle Evans NULL);
372*1a4529b5SKyle Evans }
373*1a4529b5SKyle Evans
374*1a4529b5SKyle Evans
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)37521fdc27aSRafal Jaworowski const struct fdt_property *fdt_get_property(const void *fdt,
37621fdc27aSRafal Jaworowski int nodeoffset,
37721fdc27aSRafal Jaworowski const char *name, int *lenp)
37821fdc27aSRafal Jaworowski {
37921fdc27aSRafal Jaworowski return fdt_get_property_namelen(fdt, nodeoffset, name,
38021fdc27aSRafal Jaworowski strlen(name), lenp);
38121fdc27aSRafal Jaworowski }
38221fdc27aSRafal Jaworowski
fdt_getprop_namelen(const void * fdt,int nodeoffset,const char * name,int namelen,int * lenp)38321fdc27aSRafal Jaworowski const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
38421fdc27aSRafal Jaworowski const char *name, int namelen, int *lenp)
38521fdc27aSRafal Jaworowski {
386*1a4529b5SKyle Evans int poffset;
38721fdc27aSRafal Jaworowski const struct fdt_property *prop;
38821fdc27aSRafal Jaworowski
389*1a4529b5SKyle Evans prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
390*1a4529b5SKyle Evans &poffset);
39121fdc27aSRafal Jaworowski if (!prop)
39221fdc27aSRafal Jaworowski return NULL;
39321fdc27aSRafal Jaworowski
394*1a4529b5SKyle Evans /* Handle realignment */
395*1a4529b5SKyle Evans if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 &&
396*1a4529b5SKyle Evans fdt32_to_cpu(prop->len) >= 8)
397*1a4529b5SKyle Evans return prop->data + 4;
39821fdc27aSRafal Jaworowski return prop->data;
39921fdc27aSRafal Jaworowski }
40021fdc27aSRafal Jaworowski
fdt_getprop_by_offset(const void * fdt,int offset,const char ** namep,int * lenp)40152baf267SWarner Losh const void *fdt_getprop_by_offset(const void *fdt, int offset,
40252baf267SWarner Losh const char **namep, int *lenp)
40352baf267SWarner Losh {
40452baf267SWarner Losh const struct fdt_property *prop;
40552baf267SWarner Losh
406*1a4529b5SKyle Evans prop = fdt_get_property_by_offset_(fdt, offset, lenp);
40752baf267SWarner Losh if (!prop)
40852baf267SWarner Losh return NULL;
40952baf267SWarner Losh if (namep)
41052baf267SWarner Losh *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
411*1a4529b5SKyle Evans
412*1a4529b5SKyle Evans /* Handle realignment */
413*1a4529b5SKyle Evans if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 &&
414*1a4529b5SKyle Evans fdt32_to_cpu(prop->len) >= 8)
415*1a4529b5SKyle Evans return prop->data + 4;
41652baf267SWarner Losh return prop->data;
41752baf267SWarner Losh }
41852baf267SWarner Losh
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)41921fdc27aSRafal Jaworowski const void *fdt_getprop(const void *fdt, int nodeoffset,
42021fdc27aSRafal Jaworowski const char *name, int *lenp)
42121fdc27aSRafal Jaworowski {
42221fdc27aSRafal Jaworowski return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
42321fdc27aSRafal Jaworowski }
42421fdc27aSRafal Jaworowski
fdt_get_phandle(const void * fdt,int nodeoffset)42521fdc27aSRafal Jaworowski uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
42621fdc27aSRafal Jaworowski {
4276780e684SKyle Evans const fdt32_t *php;
42821fdc27aSRafal Jaworowski int len;
42921fdc27aSRafal Jaworowski
43021fdc27aSRafal Jaworowski /* FIXME: This is a bit sub-optimal, since we potentially scan
43121fdc27aSRafal Jaworowski * over all the properties twice. */
43221fdc27aSRafal Jaworowski php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
43321fdc27aSRafal Jaworowski if (!php || (len != sizeof(*php))) {
43421fdc27aSRafal Jaworowski php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
43521fdc27aSRafal Jaworowski if (!php || (len != sizeof(*php)))
43621fdc27aSRafal Jaworowski return 0;
43721fdc27aSRafal Jaworowski }
43821fdc27aSRafal Jaworowski
43921fdc27aSRafal Jaworowski return fdt32_to_cpu(*php);
44021fdc27aSRafal Jaworowski }
44121fdc27aSRafal Jaworowski
fdt_get_alias_namelen(const void * fdt,const char * name,int namelen)44221fdc27aSRafal Jaworowski const char *fdt_get_alias_namelen(const void *fdt,
44321fdc27aSRafal Jaworowski const char *name, int namelen)
44421fdc27aSRafal Jaworowski {
44521fdc27aSRafal Jaworowski int aliasoffset;
44621fdc27aSRafal Jaworowski
44721fdc27aSRafal Jaworowski aliasoffset = fdt_path_offset(fdt, "/aliases");
44821fdc27aSRafal Jaworowski if (aliasoffset < 0)
44921fdc27aSRafal Jaworowski return NULL;
45021fdc27aSRafal Jaworowski
45121fdc27aSRafal Jaworowski return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
45221fdc27aSRafal Jaworowski }
45321fdc27aSRafal Jaworowski
fdt_get_alias(const void * fdt,const char * name)45421fdc27aSRafal Jaworowski const char *fdt_get_alias(const void *fdt, const char *name)
45521fdc27aSRafal Jaworowski {
45621fdc27aSRafal Jaworowski return fdt_get_alias_namelen(fdt, name, strlen(name));
45721fdc27aSRafal Jaworowski }
45821fdc27aSRafal Jaworowski
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)45921fdc27aSRafal Jaworowski int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
46021fdc27aSRafal Jaworowski {
46121fdc27aSRafal Jaworowski int pdepth = 0, p = 0;
46221fdc27aSRafal Jaworowski int offset, depth, namelen;
46321fdc27aSRafal Jaworowski const char *name;
46421fdc27aSRafal Jaworowski
46521fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
46621fdc27aSRafal Jaworowski
46721fdc27aSRafal Jaworowski if (buflen < 2)
46821fdc27aSRafal Jaworowski return -FDT_ERR_NOSPACE;
46921fdc27aSRafal Jaworowski
47021fdc27aSRafal Jaworowski for (offset = 0, depth = 0;
47121fdc27aSRafal Jaworowski (offset >= 0) && (offset <= nodeoffset);
47221fdc27aSRafal Jaworowski offset = fdt_next_node(fdt, offset, &depth)) {
47321fdc27aSRafal Jaworowski while (pdepth > depth) {
47421fdc27aSRafal Jaworowski do {
47521fdc27aSRafal Jaworowski p--;
47621fdc27aSRafal Jaworowski } while (buf[p-1] != '/');
47721fdc27aSRafal Jaworowski pdepth--;
47821fdc27aSRafal Jaworowski }
47921fdc27aSRafal Jaworowski
48021fdc27aSRafal Jaworowski if (pdepth >= depth) {
48121fdc27aSRafal Jaworowski name = fdt_get_name(fdt, offset, &namelen);
48221fdc27aSRafal Jaworowski if (!name)
48321fdc27aSRafal Jaworowski return namelen;
48421fdc27aSRafal Jaworowski if ((p + namelen + 1) <= buflen) {
48521fdc27aSRafal Jaworowski memcpy(buf + p, name, namelen);
48621fdc27aSRafal Jaworowski p += namelen;
48721fdc27aSRafal Jaworowski buf[p++] = '/';
48821fdc27aSRafal Jaworowski pdepth++;
48921fdc27aSRafal Jaworowski }
49021fdc27aSRafal Jaworowski }
49121fdc27aSRafal Jaworowski
49221fdc27aSRafal Jaworowski if (offset == nodeoffset) {
49321fdc27aSRafal Jaworowski if (pdepth < (depth + 1))
49421fdc27aSRafal Jaworowski return -FDT_ERR_NOSPACE;
49521fdc27aSRafal Jaworowski
49621fdc27aSRafal Jaworowski if (p > 1) /* special case so that root path is "/", not "" */
49721fdc27aSRafal Jaworowski p--;
49821fdc27aSRafal Jaworowski buf[p] = '\0';
49921fdc27aSRafal Jaworowski return 0;
50021fdc27aSRafal Jaworowski }
50121fdc27aSRafal Jaworowski }
50221fdc27aSRafal Jaworowski
50321fdc27aSRafal Jaworowski if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
50421fdc27aSRafal Jaworowski return -FDT_ERR_BADOFFSET;
50521fdc27aSRafal Jaworowski else if (offset == -FDT_ERR_BADOFFSET)
50621fdc27aSRafal Jaworowski return -FDT_ERR_BADSTRUCTURE;
50721fdc27aSRafal Jaworowski
50821fdc27aSRafal Jaworowski return offset; /* error from fdt_next_node() */
50921fdc27aSRafal Jaworowski }
51021fdc27aSRafal Jaworowski
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)51121fdc27aSRafal Jaworowski int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
51221fdc27aSRafal Jaworowski int supernodedepth, int *nodedepth)
51321fdc27aSRafal Jaworowski {
51421fdc27aSRafal Jaworowski int offset, depth;
51521fdc27aSRafal Jaworowski int supernodeoffset = -FDT_ERR_INTERNAL;
51621fdc27aSRafal Jaworowski
51721fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
51821fdc27aSRafal Jaworowski
51921fdc27aSRafal Jaworowski if (supernodedepth < 0)
52021fdc27aSRafal Jaworowski return -FDT_ERR_NOTFOUND;
52121fdc27aSRafal Jaworowski
52221fdc27aSRafal Jaworowski for (offset = 0, depth = 0;
52321fdc27aSRafal Jaworowski (offset >= 0) && (offset <= nodeoffset);
52421fdc27aSRafal Jaworowski offset = fdt_next_node(fdt, offset, &depth)) {
52521fdc27aSRafal Jaworowski if (depth == supernodedepth)
52621fdc27aSRafal Jaworowski supernodeoffset = offset;
52721fdc27aSRafal Jaworowski
52821fdc27aSRafal Jaworowski if (offset == nodeoffset) {
52921fdc27aSRafal Jaworowski if (nodedepth)
53021fdc27aSRafal Jaworowski *nodedepth = depth;
53121fdc27aSRafal Jaworowski
53221fdc27aSRafal Jaworowski if (supernodedepth > depth)
53321fdc27aSRafal Jaworowski return -FDT_ERR_NOTFOUND;
53421fdc27aSRafal Jaworowski else
53521fdc27aSRafal Jaworowski return supernodeoffset;
53621fdc27aSRafal Jaworowski }
53721fdc27aSRafal Jaworowski }
53821fdc27aSRafal Jaworowski
53921fdc27aSRafal Jaworowski if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
54021fdc27aSRafal Jaworowski return -FDT_ERR_BADOFFSET;
54121fdc27aSRafal Jaworowski else if (offset == -FDT_ERR_BADOFFSET)
54221fdc27aSRafal Jaworowski return -FDT_ERR_BADSTRUCTURE;
54321fdc27aSRafal Jaworowski
54421fdc27aSRafal Jaworowski return offset; /* error from fdt_next_node() */
54521fdc27aSRafal Jaworowski }
54621fdc27aSRafal Jaworowski
fdt_node_depth(const void * fdt,int nodeoffset)54721fdc27aSRafal Jaworowski int fdt_node_depth(const void *fdt, int nodeoffset)
54821fdc27aSRafal Jaworowski {
54921fdc27aSRafal Jaworowski int nodedepth;
55021fdc27aSRafal Jaworowski int err;
55121fdc27aSRafal Jaworowski
55221fdc27aSRafal Jaworowski err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
55321fdc27aSRafal Jaworowski if (err)
55421fdc27aSRafal Jaworowski return (err < 0) ? err : -FDT_ERR_INTERNAL;
55521fdc27aSRafal Jaworowski return nodedepth;
55621fdc27aSRafal Jaworowski }
55721fdc27aSRafal Jaworowski
fdt_parent_offset(const void * fdt,int nodeoffset)55821fdc27aSRafal Jaworowski int fdt_parent_offset(const void *fdt, int nodeoffset)
55921fdc27aSRafal Jaworowski {
56021fdc27aSRafal Jaworowski int nodedepth = fdt_node_depth(fdt, nodeoffset);
56121fdc27aSRafal Jaworowski
56221fdc27aSRafal Jaworowski if (nodedepth < 0)
56321fdc27aSRafal Jaworowski return nodedepth;
56421fdc27aSRafal Jaworowski return fdt_supernode_atdepth_offset(fdt, nodeoffset,
56521fdc27aSRafal Jaworowski nodedepth - 1, NULL);
56621fdc27aSRafal Jaworowski }
56721fdc27aSRafal Jaworowski
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)56821fdc27aSRafal Jaworowski int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
56921fdc27aSRafal Jaworowski const char *propname,
57021fdc27aSRafal Jaworowski const void *propval, int proplen)
57121fdc27aSRafal Jaworowski {
57221fdc27aSRafal Jaworowski int offset;
57321fdc27aSRafal Jaworowski const void *val;
57421fdc27aSRafal Jaworowski int len;
57521fdc27aSRafal Jaworowski
57621fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
57721fdc27aSRafal Jaworowski
57821fdc27aSRafal Jaworowski /* FIXME: The algorithm here is pretty horrible: we scan each
57921fdc27aSRafal Jaworowski * property of a node in fdt_getprop(), then if that didn't
58021fdc27aSRafal Jaworowski * find what we want, we scan over them again making our way
58121fdc27aSRafal Jaworowski * to the next node. Still it's the easiest to implement
58221fdc27aSRafal Jaworowski * approach; performance can come later. */
58321fdc27aSRafal Jaworowski for (offset = fdt_next_node(fdt, startoffset, NULL);
58421fdc27aSRafal Jaworowski offset >= 0;
58521fdc27aSRafal Jaworowski offset = fdt_next_node(fdt, offset, NULL)) {
58621fdc27aSRafal Jaworowski val = fdt_getprop(fdt, offset, propname, &len);
58721fdc27aSRafal Jaworowski if (val && (len == proplen)
58821fdc27aSRafal Jaworowski && (memcmp(val, propval, len) == 0))
58921fdc27aSRafal Jaworowski return offset;
59021fdc27aSRafal Jaworowski }
59121fdc27aSRafal Jaworowski
59221fdc27aSRafal Jaworowski return offset; /* error from fdt_next_node() */
59321fdc27aSRafal Jaworowski }
59421fdc27aSRafal Jaworowski
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)59521fdc27aSRafal Jaworowski int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
59621fdc27aSRafal Jaworowski {
59721fdc27aSRafal Jaworowski int offset;
59821fdc27aSRafal Jaworowski
59921fdc27aSRafal Jaworowski if ((phandle == 0) || (phandle == -1))
60021fdc27aSRafal Jaworowski return -FDT_ERR_BADPHANDLE;
60121fdc27aSRafal Jaworowski
60221fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
60321fdc27aSRafal Jaworowski
60421fdc27aSRafal Jaworowski /* FIXME: The algorithm here is pretty horrible: we
60521fdc27aSRafal Jaworowski * potentially scan each property of a node in
60621fdc27aSRafal Jaworowski * fdt_get_phandle(), then if that didn't find what
60721fdc27aSRafal Jaworowski * we want, we scan over them again making our way to the next
60821fdc27aSRafal Jaworowski * node. Still it's the easiest to implement approach;
60921fdc27aSRafal Jaworowski * performance can come later. */
61021fdc27aSRafal Jaworowski for (offset = fdt_next_node(fdt, -1, NULL);
61121fdc27aSRafal Jaworowski offset >= 0;
61221fdc27aSRafal Jaworowski offset = fdt_next_node(fdt, offset, NULL)) {
61321fdc27aSRafal Jaworowski if (fdt_get_phandle(fdt, offset) == phandle)
61421fdc27aSRafal Jaworowski return offset;
61521fdc27aSRafal Jaworowski }
61621fdc27aSRafal Jaworowski
61721fdc27aSRafal Jaworowski return offset; /* error from fdt_next_node() */
61821fdc27aSRafal Jaworowski }
61921fdc27aSRafal Jaworowski
fdt_stringlist_contains(const char * strlist,int listlen,const char * str)6206780e684SKyle Evans int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
62121fdc27aSRafal Jaworowski {
62221fdc27aSRafal Jaworowski int len = strlen(str);
62321fdc27aSRafal Jaworowski const char *p;
62421fdc27aSRafal Jaworowski
62521fdc27aSRafal Jaworowski while (listlen >= len) {
62621fdc27aSRafal Jaworowski if (memcmp(str, strlist, len+1) == 0)
62721fdc27aSRafal Jaworowski return 1;
62821fdc27aSRafal Jaworowski p = memchr(strlist, '\0', listlen);
62921fdc27aSRafal Jaworowski if (!p)
63021fdc27aSRafal Jaworowski return 0; /* malformed strlist.. */
63121fdc27aSRafal Jaworowski listlen -= (p-strlist) + 1;
63221fdc27aSRafal Jaworowski strlist = p + 1;
63321fdc27aSRafal Jaworowski }
63421fdc27aSRafal Jaworowski return 0;
63521fdc27aSRafal Jaworowski }
63621fdc27aSRafal Jaworowski
fdt_stringlist_count(const void * fdt,int nodeoffset,const char * property)6376780e684SKyle Evans int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
6386780e684SKyle Evans {
6396780e684SKyle Evans const char *list, *end;
6406780e684SKyle Evans int length, count = 0;
6416780e684SKyle Evans
6426780e684SKyle Evans list = fdt_getprop(fdt, nodeoffset, property, &length);
6436780e684SKyle Evans if (!list)
6446780e684SKyle Evans return length;
6456780e684SKyle Evans
6466780e684SKyle Evans end = list + length;
6476780e684SKyle Evans
6486780e684SKyle Evans while (list < end) {
6496780e684SKyle Evans length = strnlen(list, end - list) + 1;
6506780e684SKyle Evans
6516780e684SKyle Evans /* Abort if the last string isn't properly NUL-terminated. */
6526780e684SKyle Evans if (list + length > end)
6536780e684SKyle Evans return -FDT_ERR_BADVALUE;
6546780e684SKyle Evans
6556780e684SKyle Evans list += length;
6566780e684SKyle Evans count++;
6576780e684SKyle Evans }
6586780e684SKyle Evans
6596780e684SKyle Evans return count;
6606780e684SKyle Evans }
6616780e684SKyle Evans
fdt_stringlist_search(const void * fdt,int nodeoffset,const char * property,const char * string)6626780e684SKyle Evans int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
6636780e684SKyle Evans const char *string)
6646780e684SKyle Evans {
6656780e684SKyle Evans int length, len, idx = 0;
6666780e684SKyle Evans const char *list, *end;
6676780e684SKyle Evans
6686780e684SKyle Evans list = fdt_getprop(fdt, nodeoffset, property, &length);
6696780e684SKyle Evans if (!list)
6706780e684SKyle Evans return length;
6716780e684SKyle Evans
6726780e684SKyle Evans len = strlen(string) + 1;
6736780e684SKyle Evans end = list + length;
6746780e684SKyle Evans
6756780e684SKyle Evans while (list < end) {
6766780e684SKyle Evans length = strnlen(list, end - list) + 1;
6776780e684SKyle Evans
6786780e684SKyle Evans /* Abort if the last string isn't properly NUL-terminated. */
6796780e684SKyle Evans if (list + length > end)
6806780e684SKyle Evans return -FDT_ERR_BADVALUE;
6816780e684SKyle Evans
6826780e684SKyle Evans if (length == len && memcmp(list, string, length) == 0)
6836780e684SKyle Evans return idx;
6846780e684SKyle Evans
6856780e684SKyle Evans list += length;
6866780e684SKyle Evans idx++;
6876780e684SKyle Evans }
6886780e684SKyle Evans
6896780e684SKyle Evans return -FDT_ERR_NOTFOUND;
6906780e684SKyle Evans }
6916780e684SKyle Evans
fdt_stringlist_get(const void * fdt,int nodeoffset,const char * property,int idx,int * lenp)6926780e684SKyle Evans const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
6936780e684SKyle Evans const char *property, int idx,
6946780e684SKyle Evans int *lenp)
6956780e684SKyle Evans {
6966780e684SKyle Evans const char *list, *end;
6976780e684SKyle Evans int length;
6986780e684SKyle Evans
6996780e684SKyle Evans list = fdt_getprop(fdt, nodeoffset, property, &length);
7006780e684SKyle Evans if (!list) {
7016780e684SKyle Evans if (lenp)
7026780e684SKyle Evans *lenp = length;
7036780e684SKyle Evans
7046780e684SKyle Evans return NULL;
7056780e684SKyle Evans }
7066780e684SKyle Evans
7076780e684SKyle Evans end = list + length;
7086780e684SKyle Evans
7096780e684SKyle Evans while (list < end) {
7106780e684SKyle Evans length = strnlen(list, end - list) + 1;
7116780e684SKyle Evans
7126780e684SKyle Evans /* Abort if the last string isn't properly NUL-terminated. */
7136780e684SKyle Evans if (list + length > end) {
7146780e684SKyle Evans if (lenp)
7156780e684SKyle Evans *lenp = -FDT_ERR_BADVALUE;
7166780e684SKyle Evans
7176780e684SKyle Evans return NULL;
7186780e684SKyle Evans }
7196780e684SKyle Evans
7206780e684SKyle Evans if (idx == 0) {
7216780e684SKyle Evans if (lenp)
7226780e684SKyle Evans *lenp = length - 1;
7236780e684SKyle Evans
7246780e684SKyle Evans return list;
7256780e684SKyle Evans }
7266780e684SKyle Evans
7276780e684SKyle Evans list += length;
7286780e684SKyle Evans idx--;
7296780e684SKyle Evans }
7306780e684SKyle Evans
7316780e684SKyle Evans if (lenp)
7326780e684SKyle Evans *lenp = -FDT_ERR_NOTFOUND;
7336780e684SKyle Evans
7346780e684SKyle Evans return NULL;
7356780e684SKyle Evans }
7366780e684SKyle Evans
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)73721fdc27aSRafal Jaworowski int fdt_node_check_compatible(const void *fdt, int nodeoffset,
73821fdc27aSRafal Jaworowski const char *compatible)
73921fdc27aSRafal Jaworowski {
74021fdc27aSRafal Jaworowski const void *prop;
74121fdc27aSRafal Jaworowski int len;
74221fdc27aSRafal Jaworowski
74321fdc27aSRafal Jaworowski prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
74421fdc27aSRafal Jaworowski if (!prop)
74521fdc27aSRafal Jaworowski return len;
7466780e684SKyle Evans
7476780e684SKyle Evans return !fdt_stringlist_contains(prop, len, compatible);
74821fdc27aSRafal Jaworowski }
74921fdc27aSRafal Jaworowski
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)75021fdc27aSRafal Jaworowski int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
75121fdc27aSRafal Jaworowski const char *compatible)
75221fdc27aSRafal Jaworowski {
75321fdc27aSRafal Jaworowski int offset, err;
75421fdc27aSRafal Jaworowski
75521fdc27aSRafal Jaworowski FDT_CHECK_HEADER(fdt);
75621fdc27aSRafal Jaworowski
75721fdc27aSRafal Jaworowski /* FIXME: The algorithm here is pretty horrible: we scan each
75821fdc27aSRafal Jaworowski * property of a node in fdt_node_check_compatible(), then if
75921fdc27aSRafal Jaworowski * that didn't find what we want, we scan over them again
76021fdc27aSRafal Jaworowski * making our way to the next node. Still it's the easiest to
76121fdc27aSRafal Jaworowski * implement approach; performance can come later. */
76221fdc27aSRafal Jaworowski for (offset = fdt_next_node(fdt, startoffset, NULL);
76321fdc27aSRafal Jaworowski offset >= 0;
76421fdc27aSRafal Jaworowski offset = fdt_next_node(fdt, offset, NULL)) {
76521fdc27aSRafal Jaworowski err = fdt_node_check_compatible(fdt, offset, compatible);
76621fdc27aSRafal Jaworowski if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
76721fdc27aSRafal Jaworowski return err;
76821fdc27aSRafal Jaworowski else if (err == 0)
76921fdc27aSRafal Jaworowski return offset;
77021fdc27aSRafal Jaworowski }
77121fdc27aSRafal Jaworowski
77221fdc27aSRafal Jaworowski return offset; /* error from fdt_next_node() */
77321fdc27aSRafal Jaworowski }
774