symbian-qemu-0.9.1-12/dtc-trunk/libfdt/fdt_ro.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * libfdt - Flat Device Tree manipulation
       
     3  * Copyright (C) 2006 David Gibson, IBM Corporation.
       
     4  *
       
     5  * libfdt is dual licensed: you can use it either under the terms of
       
     6  * the GPL, or the BSD license, at your option.
       
     7  *
       
     8  *  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.
       
    12  *
       
    13  *     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.
       
    50  */
       
    51 #include "libfdt_env.h"
       
    52 
       
    53 #include <fdt.h>
       
    54 #include <libfdt.h>
       
    55 
       
    56 #include "libfdt_internal.h"
       
    57 
       
    58 static int _fdt_nodename_eq(const void *fdt, int offset,
       
    59 			    const char *s, int len)
       
    60 {
       
    61 	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
       
    62 
       
    63 	if (! p)
       
    64 		/* short match */
       
    65 		return 0;
       
    66 
       
    67 	if (memcmp(p, s, len) != 0)
       
    68 		return 0;
       
    69 
       
    70 	if (p[len] == '\0')
       
    71 		return 1;
       
    72 	else if (!memchr(s, '@', len) && (p[len] == '@'))
       
    73 		return 1;
       
    74 	else
       
    75 		return 0;
       
    76 }
       
    77 
       
    78 const char *fdt_string(const void *fdt, int stroffset)
       
    79 {
       
    80 	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
       
    81 }
       
    82 
       
    83 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
       
    84 {
       
    85 	FDT_CHECK_HEADER(fdt);
       
    86 	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
       
    87 	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
       
    88 	return 0;
       
    89 }
       
    90 
       
    91 int fdt_num_mem_rsv(const void *fdt)
       
    92 {
       
    93 	int i = 0;
       
    94 
       
    95 	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
       
    96 		i++;
       
    97 	return i;
       
    98 }
       
    99 
       
   100 int fdt_subnode_offset_namelen(const void *fdt, int offset,
       
   101 			       const char *name, int namelen)
       
   102 {
       
   103 	int depth;
       
   104 
       
   105 	FDT_CHECK_HEADER(fdt);
       
   106 
       
   107 	for (depth = 0;
       
   108 	     offset >= 0;
       
   109 	     offset = fdt_next_node(fdt, offset, &depth)) {
       
   110 		if (depth < 0)
       
   111 			return -FDT_ERR_NOTFOUND;
       
   112 		else if ((depth == 1)
       
   113 			 && _fdt_nodename_eq(fdt, offset, name, namelen))
       
   114 			return offset;
       
   115 	}
       
   116 
       
   117 	return offset; /* error */
       
   118 }
       
   119 
       
   120 int fdt_subnode_offset(const void *fdt, int parentoffset,
       
   121 		       const char *name)
       
   122 {
       
   123 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
       
   124 }
       
   125 
       
   126 int fdt_path_offset(const void *fdt, const char *path)
       
   127 {
       
   128 	const char *end = path + strlen(path);
       
   129 	const char *p = path;
       
   130 	int offset = 0;
       
   131 
       
   132 	FDT_CHECK_HEADER(fdt);
       
   133 
       
   134 	if (*path != '/')
       
   135 		return -FDT_ERR_BADPATH;
       
   136 
       
   137 	while (*p) {
       
   138 		const char *q;
       
   139 
       
   140 		while (*p == '/')
       
   141 			p++;
       
   142 		if (! *p)
       
   143 			return offset;
       
   144 		q = strchr(p, '/');
       
   145 		if (! q)
       
   146 			q = end;
       
   147 
       
   148 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
       
   149 		if (offset < 0)
       
   150 			return offset;
       
   151 
       
   152 		p = q;
       
   153 	}
       
   154 
       
   155 	return offset;
       
   156 }
       
   157 
       
   158 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
       
   159 {
       
   160 	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
       
   161 	int err;
       
   162 
       
   163 	if (((err = fdt_check_header(fdt)) != 0)
       
   164 	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
       
   165 			goto fail;
       
   166 
       
   167 	if (len)
       
   168 		*len = strlen(nh->name);
       
   169 
       
   170 	return nh->name;
       
   171 
       
   172  fail:
       
   173 	if (len)
       
   174 		*len = err;
       
   175 	return NULL;
       
   176 }
       
   177 
       
   178 const struct fdt_property *fdt_get_property(const void *fdt,
       
   179 					    int nodeoffset,
       
   180 					    const char *name, int *lenp)
       
   181 {
       
   182 	uint32_t tag;
       
   183 	const struct fdt_property *prop;
       
   184 	int namestroff;
       
   185 	int offset, nextoffset;
       
   186 	int err;
       
   187 
       
   188 	if (((err = fdt_check_header(fdt)) != 0)
       
   189 	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
       
   190 			goto fail;
       
   191 
       
   192 	nextoffset = err;
       
   193 	do {
       
   194 		offset = nextoffset;
       
   195 
       
   196 		tag = fdt_next_tag(fdt, offset, &nextoffset);
       
   197 		switch (tag) {
       
   198 		case FDT_END:
       
   199 			err = -FDT_ERR_TRUNCATED;
       
   200 			goto fail;
       
   201 
       
   202 		case FDT_BEGIN_NODE:
       
   203 		case FDT_END_NODE:
       
   204 		case FDT_NOP:
       
   205 			break;
       
   206 
       
   207 		case FDT_PROP:
       
   208 			err = -FDT_ERR_BADSTRUCTURE;
       
   209 			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
       
   210 			if (! prop)
       
   211 				goto fail;
       
   212 			namestroff = fdt32_to_cpu(prop->nameoff);
       
   213 			if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
       
   214 				/* Found it! */
       
   215 				int len = fdt32_to_cpu(prop->len);
       
   216 				prop = fdt_offset_ptr(fdt, offset,
       
   217 						      sizeof(*prop)+len);
       
   218 				if (! prop)
       
   219 					goto fail;
       
   220 
       
   221 				if (lenp)
       
   222 					*lenp = len;
       
   223 
       
   224 				return prop;
       
   225 			}
       
   226 			break;
       
   227 
       
   228 		default:
       
   229 			err = -FDT_ERR_BADSTRUCTURE;
       
   230 			goto fail;
       
   231 		}
       
   232 	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
       
   233 
       
   234 	err = -FDT_ERR_NOTFOUND;
       
   235  fail:
       
   236 	if (lenp)
       
   237 		*lenp = err;
       
   238 	return NULL;
       
   239 }
       
   240 
       
   241 const void *fdt_getprop(const void *fdt, int nodeoffset,
       
   242 		  const char *name, int *lenp)
       
   243 {
       
   244 	const struct fdt_property *prop;
       
   245 
       
   246 	prop = fdt_get_property(fdt, nodeoffset, name, lenp);
       
   247 	if (! prop)
       
   248 		return NULL;
       
   249 
       
   250 	return prop->data;
       
   251 }
       
   252 
       
   253 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
       
   254 {
       
   255 	const uint32_t *php;
       
   256 	int len;
       
   257 
       
   258 	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
       
   259 	if (!php || (len != sizeof(*php)))
       
   260 		return 0;
       
   261 
       
   262 	return fdt32_to_cpu(*php);
       
   263 }
       
   264 
       
   265 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
       
   266 {
       
   267 	int pdepth = 0, p = 0;
       
   268 	int offset, depth, namelen;
       
   269 	const char *name;
       
   270 
       
   271 	FDT_CHECK_HEADER(fdt);
       
   272 
       
   273 	if (buflen < 2)
       
   274 		return -FDT_ERR_NOSPACE;
       
   275 
       
   276 	for (offset = 0, depth = 0;
       
   277 	     (offset >= 0) && (offset <= nodeoffset);
       
   278 	     offset = fdt_next_node(fdt, offset, &depth)) {
       
   279 		if (pdepth < depth)
       
   280 			continue; /* overflowed buffer */
       
   281 
       
   282 		while (pdepth > depth) {
       
   283 			do {
       
   284 				p--;
       
   285 			} while (buf[p-1] != '/');
       
   286 			pdepth--;
       
   287 		}
       
   288 
       
   289 		name = fdt_get_name(fdt, offset, &namelen);
       
   290 		if (!name)
       
   291 			return namelen;
       
   292 		if ((p + namelen + 1) <= buflen) {
       
   293 			memcpy(buf + p, name, namelen);
       
   294 			p += namelen;
       
   295 			buf[p++] = '/';
       
   296 			pdepth++;
       
   297 		}
       
   298 
       
   299 		if (offset == nodeoffset) {
       
   300 			if (pdepth < (depth + 1))
       
   301 				return -FDT_ERR_NOSPACE;
       
   302 
       
   303 			if (p > 1) /* special case so that root path is "/", not "" */
       
   304 				p--;
       
   305 			buf[p] = '\0';
       
   306 			return p;
       
   307 		}
       
   308 	}
       
   309 
       
   310 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
       
   311 		return -FDT_ERR_BADOFFSET;
       
   312 	else if (offset == -FDT_ERR_BADOFFSET)
       
   313 		return -FDT_ERR_BADSTRUCTURE;
       
   314 
       
   315 	return offset; /* error from fdt_next_node() */
       
   316 }
       
   317 
       
   318 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
       
   319 				 int supernodedepth, int *nodedepth)
       
   320 {
       
   321 	int offset, depth;
       
   322 	int supernodeoffset = -FDT_ERR_INTERNAL;
       
   323 
       
   324 	FDT_CHECK_HEADER(fdt);
       
   325 
       
   326 	if (supernodedepth < 0)
       
   327 		return -FDT_ERR_NOTFOUND;
       
   328 
       
   329 	for (offset = 0, depth = 0;
       
   330 	     (offset >= 0) && (offset <= nodeoffset);
       
   331 	     offset = fdt_next_node(fdt, offset, &depth)) {
       
   332 		if (depth == supernodedepth)
       
   333 			supernodeoffset = offset;
       
   334 
       
   335 		if (offset == nodeoffset) {
       
   336 			if (nodedepth)
       
   337 				*nodedepth = depth;
       
   338 
       
   339 			if (supernodedepth > depth)
       
   340 				return -FDT_ERR_NOTFOUND;
       
   341 			else
       
   342 				return supernodeoffset;
       
   343 		}
       
   344 	}
       
   345 
       
   346 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
       
   347 		return -FDT_ERR_BADOFFSET;
       
   348 	else if (offset == -FDT_ERR_BADOFFSET)
       
   349 		return -FDT_ERR_BADSTRUCTURE;
       
   350 
       
   351 	return offset; /* error from fdt_next_node() */
       
   352 }
       
   353 
       
   354 int fdt_node_depth(const void *fdt, int nodeoffset)
       
   355 {
       
   356 	int nodedepth;
       
   357 	int err;
       
   358 
       
   359 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
       
   360 	if (err)
       
   361 		return (err < 0) ? err : -FDT_ERR_INTERNAL;
       
   362 	return nodedepth;
       
   363 }
       
   364 
       
   365 int fdt_parent_offset(const void *fdt, int nodeoffset)
       
   366 {
       
   367 	int nodedepth = fdt_node_depth(fdt, nodeoffset);
       
   368 
       
   369 	if (nodedepth < 0)
       
   370 		return nodedepth;
       
   371 	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
       
   372 					    nodedepth - 1, NULL);
       
   373 }
       
   374 
       
   375 int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
       
   376 				  const char *propname,
       
   377 				  const void *propval, int proplen)
       
   378 {
       
   379 	int offset;
       
   380 	const void *val;
       
   381 	int len;
       
   382 
       
   383 	FDT_CHECK_HEADER(fdt);
       
   384 
       
   385 	/* FIXME: The algorithm here is pretty horrible: we scan each
       
   386 	 * property of a node in fdt_getprop(), then if that didn't
       
   387 	 * find what we want, we scan over them again making our way
       
   388 	 * to the next node.  Still it's the easiest to implement
       
   389 	 * approach; performance can come later. */
       
   390 	for (offset = fdt_next_node(fdt, startoffset, NULL);
       
   391 	     offset >= 0;
       
   392 	     offset = fdt_next_node(fdt, offset, NULL)) {
       
   393 		val = fdt_getprop(fdt, offset, propname, &len);
       
   394 		if (val && (len == proplen)
       
   395 		    && (memcmp(val, propval, len) == 0))
       
   396 			return offset;
       
   397 	}
       
   398 
       
   399 	return offset; /* error from fdt_next_node() */
       
   400 }
       
   401 
       
   402 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
       
   403 {
       
   404 	if ((phandle == 0) || (phandle == -1))
       
   405 		return -FDT_ERR_BADPHANDLE;
       
   406 	phandle = cpu_to_fdt32(phandle);
       
   407 	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
       
   408 					     &phandle, sizeof(phandle));
       
   409 }
       
   410 
       
   411 int _stringlist_contains(const char *strlist, int listlen, const char *str)
       
   412 {
       
   413 	int len = strlen(str);
       
   414 	const char *p;
       
   415 
       
   416 	while (listlen >= len) {
       
   417 		if (memcmp(str, strlist, len+1) == 0)
       
   418 			return 1;
       
   419 		p = memchr(strlist, '\0', listlen);
       
   420 		if (!p)
       
   421 			return 0; /* malformed strlist.. */
       
   422 		listlen -= (p-strlist) + 1;
       
   423 		strlist = p + 1;
       
   424 	}
       
   425 	return 0;
       
   426 }
       
   427 
       
   428 int fdt_node_check_compatible(const void *fdt, int nodeoffset,
       
   429 			      const char *compatible)
       
   430 {
       
   431 	const void *prop;
       
   432 	int len;
       
   433 
       
   434 	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
       
   435 	if (!prop)
       
   436 		return len;
       
   437 	if (_stringlist_contains(prop, len, compatible))
       
   438 		return 0;
       
   439 	else
       
   440 		return 1;
       
   441 }
       
   442 
       
   443 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
       
   444 				  const char *compatible)
       
   445 {
       
   446 	int offset, err;
       
   447 
       
   448 	FDT_CHECK_HEADER(fdt);
       
   449 
       
   450 	/* FIXME: The algorithm here is pretty horrible: we scan each
       
   451 	 * property of a node in fdt_node_check_compatible(), then if
       
   452 	 * that didn't find what we want, we scan over them again
       
   453 	 * making our way to the next node.  Still it's the easiest to
       
   454 	 * implement approach; performance can come later. */
       
   455 	for (offset = fdt_next_node(fdt, startoffset, NULL);
       
   456 	     offset >= 0;
       
   457 	     offset = fdt_next_node(fdt, offset, NULL)) {
       
   458 		err = fdt_node_check_compatible(fdt, offset, compatible);
       
   459 		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
       
   460 			return err;
       
   461 		else if (err == 0)
       
   462 			return offset;
       
   463 	}
       
   464 
       
   465 	return offset; /* error from fdt_next_node() */
       
   466 }