xref: /freebsd-src/sys/contrib/libfdt/fdt_ro.c (revision 1a4529b5e5cd270938c89a6c329894c2abcdd1f7)
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