diff options
| author | Gerald Van Baren <vanbaren@cideas.com> | 2007-03-31 12:00:56 -0400 | 
|---|---|---|
| committer | Gerald Van Baren <vanbaren@cideas.com> | 2007-03-31 12:00:56 -0400 | 
| commit | 35748177c64a4a83a00057e93bb33e40278a2a96 (patch) | |
| tree | 4e02a9f0d02878be5cdf03e81a27cb39b898a7b9 | |
| parent | 7cd5da0fe877e7171a4cdd44880bce783132871a (diff) | |
| download | olio-uboot-2014.01-35748177c64a4a83a00057e93bb33e40278a2a96.tar.xz olio-uboot-2014.01-35748177c64a4a83a00057e93bb33e40278a2a96.zip | |
libfdt: Import libfdt source (2 of 2)
This adds the applicable libfdt source files (unmodified) and a README
to explain where the source came from.
| -rw-r--r-- | libfdt/fdt_ro.c | 229 | ||||
| -rw-r--r-- | libfdt/fdt_rw.c | 293 | ||||
| -rw-r--r-- | libfdt/fdt_sw.c | 226 | ||||
| -rw-r--r-- | libfdt/fdt_wip.c | 112 | 
4 files changed, 860 insertions, 0 deletions
| diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c new file mode 100644 index 000000000..9112c6a63 --- /dev/null +++ b/libfdt/fdt_ro.c @@ -0,0 +1,229 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +#define CHECK_HEADER(fdt) \ +	{ \ +		int err; \ +		if ((err = _fdt_check_header(fdt)) != 0) \ +			return err; \ +	} + +static int offset_streq(const void *fdt, int offset, +			const char *s, int len) +{ +	const char *p = fdt_offset_ptr(fdt, offset, len+1); + +	if (! p) +		/* short match */ +		return 0; + +	if (memcmp(p, s, len) != 0) +		return 0; + +	if (p[len] != '\0') +		return 0; + +	return 1; +} + +char *fdt_string(const void *fdt, int stroffset) +{ +	return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset; +} + +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, +			       const char *name, int namelen) +{ +	int level = 0; +	uint32_t tag; +	int offset, nextoffset; + +	CHECK_HEADER(fdt); + +	tag = _fdt_next_tag(fdt, parentoffset, &nextoffset); +	if (tag != FDT_BEGIN_NODE) +		return -FDT_ERR_BADOFFSET; + +	do { +		offset = nextoffset; +		tag = _fdt_next_tag(fdt, offset, &nextoffset); + +		switch (tag) { +		case FDT_END: +			return -FDT_ERR_TRUNCATED; + +		case FDT_BEGIN_NODE: +			level++; +			if (level != 1) +				continue; +			if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen)) +				/* Found it! */ +				return offset; +			break; + +		case FDT_END_NODE: +			level--; +			break; + +		case FDT_PROP: +		case FDT_NOP: +			break; + +		default: +			return -FDT_ERR_BADSTRUCTURE; +		} +	} while (level >= 0); + +	return -FDT_ERR_NOTFOUND; +} + +int fdt_subnode_offset(const void *fdt, int parentoffset, +		       const char *name) +{ +	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_path_offset(const void *fdt, const char *path) +{ +	const char *end = path + strlen(path); +	const char *p = path; +	int offset = 0; + +	CHECK_HEADER(fdt); + +	if (*path != '/') +		return -FDT_ERR_BADPATH; + +	while (*p) { +		const char *q; + +		while (*p == '/') +			p++; +		if (! *p) +			return -FDT_ERR_BADPATH; +		q = strchr(p, '/'); +		if (! q) +			q = end; + +		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); +		if (offset < 0) +			return offset; + +		p = q; +	} + +	return offset;	 +} + +struct fdt_property *fdt_get_property(const void *fdt, +				      int nodeoffset, +				      const char *name, int *lenp) +{ +	int level = 0; +	uint32_t tag; +	struct fdt_property *prop; +	int namestroff; +	int offset, nextoffset; +	int err; + +	if ((err = _fdt_check_header(fdt)) != 0) +		goto fail; + +	err = -FDT_ERR_BADOFFSET; +	if (nodeoffset % FDT_TAGSIZE) +		goto fail; + +	tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset); +	if (tag != FDT_BEGIN_NODE) +		goto fail; + +	do { +		offset = nextoffset; + +		tag = _fdt_next_tag(fdt, offset, &nextoffset); +		switch (tag) { +		case FDT_END: +			err = -FDT_ERR_TRUNCATED; +			goto fail; + +		case FDT_BEGIN_NODE: +			level++; +			break; + +		case FDT_END_NODE: +			level--; +			break; + +		case FDT_PROP: +			if (level != 0) +				continue; + +			err = -FDT_ERR_BADSTRUCTURE; +			prop = fdt_offset_ptr_typed(fdt, offset, prop); +			if (! prop) +				goto fail; +			namestroff = fdt32_to_cpu(prop->nameoff); +			if (streq(fdt_string(fdt, namestroff), name)) { +				/* Found it! */ +				int len = fdt32_to_cpu(prop->len); +				prop = fdt_offset_ptr(fdt, offset, +						      sizeof(*prop)+len); +				if (! prop) +					goto fail; + +				if (lenp) +					*lenp = len; +				 +				return prop; +			} +			break; + +		case FDT_NOP: +			break; + +		default: +			err = -FDT_ERR_BADSTRUCTURE; +			goto fail; +		} +	} while (level >= 0); + +	err = -FDT_ERR_NOTFOUND; + fail: +	if (lenp) +		*lenp = err; +	return NULL; +} + +void *fdt_getprop(const void *fdt, int nodeoffset, +		  const char *name, int *lenp) +{ +	const struct fdt_property *prop; + +	prop = fdt_get_property(fdt, nodeoffset, name, lenp); +	if (! prop) +		return NULL; + +	return prop->data; +} diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c new file mode 100644 index 000000000..7396645a6 --- /dev/null +++ b/libfdt/fdt_rw.c @@ -0,0 +1,293 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int rw_check_header(void *fdt) +{ +	int err; + +	if ((err = _fdt_check_header(fdt))) +		return err; +	if (fdt_version(fdt) < 0x11) +		return -FDT_ERR_BADVERSION; +	if (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8)) +		return -FDT_ERR_BADLAYOUT; +	if (fdt_off_dt_struct(fdt) < +	    (fdt_off_mem_rsvmap(fdt) + sizeof(struct fdt_reserve_entry))) +		return -FDT_ERR_BADLAYOUT; +	if (fdt_off_dt_strings(fdt) < +	    (fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt))) +		return -FDT_ERR_BADLAYOUT; +	if (fdt_totalsize(fdt) < +	    (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))) +		return -FDT_ERR_BADLAYOUT; +	return 0; +} + +#define RW_CHECK_HEADER(fdt) \ +	{ \ +		int err; \ +		if ((err = rw_check_header(fdt)) != 0) \ +			return err; \ +	} + +static inline int _blob_data_size(void *fdt) +{ +	return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +} + +static int _blob_splice(void *fdt, void *p, int oldlen, int newlen) +{ +	void *end = fdt + _blob_data_size(fdt); + +	if (((p + oldlen) < p) || ((p + oldlen) > end)) +		return -FDT_ERR_BADOFFSET; +	if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt))) +		return -FDT_ERR_NOSPACE; +	memmove(p + newlen, p + oldlen, end - p - oldlen); +	return 0; +} + +static int _blob_splice_struct(void *fdt, void *p, +			       int oldlen, int newlen) +{ +	int delta = newlen - oldlen; +	int err; + +	if ((err = _blob_splice(fdt, p, oldlen, newlen))) +		return err; + +	fdt_set_header(fdt, size_dt_struct, fdt_size_dt_struct(fdt) + delta); +	fdt_set_header(fdt, off_dt_strings, fdt_off_dt_strings(fdt) + delta); +	return 0; +} + +static int _blob_splice_string(void *fdt, int newlen) +{ +	void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); +	int err; + +	if ((err = _blob_splice(fdt, p, 0, newlen))) +		return err; + +	fdt_set_header(fdt, size_dt_strings, fdt_size_dt_strings(fdt) + newlen); +	return 0; +} + +static int _find_add_string(void *fdt, const char *s) +{ +	char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); +	const char *p; +	char *new; +	int len = strlen(s) + 1; +	int err; + +	p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s); +	if (p) +		/* found it */ +		return (p - strtab); + +	new = strtab + fdt_size_dt_strings(fdt); +	err = _blob_splice_string(fdt, len); +	if (err) +		return err; + +	memcpy(new, s, len); +	return (new - strtab); +} + +static int _resize_property(void *fdt, int nodeoffset, const char *name, int len, +			    struct fdt_property **prop) +{ +	int oldlen; +	int err; + +	*prop = fdt_get_property(fdt, nodeoffset, name, &oldlen); +	if (! (*prop)) +		return oldlen; + +	if ((err = _blob_splice_struct(fdt, (*prop)->data, +				       ALIGN(oldlen, FDT_TAGSIZE), +				       ALIGN(len, FDT_TAGSIZE)))) +		return err; + +	(*prop)->len = cpu_to_fdt32(len); +	return 0; +} + +static int _add_property(void *fdt, int nodeoffset, const char *name, int len, +			 struct fdt_property **prop) +{ +	uint32_t tag; +	int proplen; +	int nextoffset; +	int namestroff; +	int err; + +	tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset); +	if (tag != FDT_BEGIN_NODE) +		return -FDT_ERR_BADOFFSET; + +	namestroff = _find_add_string(fdt, name); +	if (namestroff < 0) +		return namestroff; + +	*prop = _fdt_offset_ptr(fdt, nextoffset); +	proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE); + +	err = _blob_splice_struct(fdt, *prop, 0, proplen); +	if (err) +		return err; + +	(*prop)->tag = cpu_to_fdt32(FDT_PROP); +	(*prop)->nameoff = cpu_to_fdt32(namestroff); +	(*prop)->len = cpu_to_fdt32(len); +	return 0; +} + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, +		const void *val, int len) +{ +	struct fdt_property *prop; +	int err; + +	if ((err = rw_check_header(fdt))) +		return err; + +	err = _resize_property(fdt, nodeoffset, name, len, &prop); +	if (err == -FDT_ERR_NOTFOUND) +		err = _add_property(fdt, nodeoffset, name, len, &prop); +	if (err) +		return err; + +	memcpy(prop->data, val, len); +	return 0; +} + +int fdt_delprop(void *fdt, int nodeoffset, const char *name) +{ +	struct fdt_property *prop; +	int len, proplen; + +	RW_CHECK_HEADER(fdt); + +	prop = fdt_get_property(fdt, nodeoffset, name, &len); +	if (! prop) +		return len; + +	proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE); +	return _blob_splice_struct(fdt, prop, proplen, 0); +} + +int fdt_add_subnode_namelen(void *fdt, int parentoffset, +			    const char *name, int namelen) +{ +	struct fdt_node_header *nh; +	int offset, nextoffset; +	int nodelen; +	int err; +	uint32_t tag; +	uint32_t *endtag; + +	RW_CHECK_HEADER(fdt); + +	offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); +	if (offset >= 0) +		return -FDT_ERR_EXISTS; +	else if (offset != -FDT_ERR_NOTFOUND) +		return offset; + +	/* Try to place the new node after the parent's properties */ +	_fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ +	do { +		offset = nextoffset; +		tag = _fdt_next_tag(fdt, offset, &nextoffset); +	} while (tag == FDT_PROP); + +	nh = _fdt_offset_ptr(fdt, offset); +	nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE; + +	err = _blob_splice_struct(fdt, nh, 0, nodelen); +	if (err) +		return err; + +	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); +	memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE)); +	memcpy(nh->name, name, namelen); +	endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE); +	*endtag = cpu_to_fdt32(FDT_END_NODE); + +	return offset; +} + +int fdt_add_subnode(void *fdt, int parentoffset, const char *name) +{ +	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); +} + +int fdt_del_node(void *fdt, int nodeoffset) +{ +	int endoffset; + +	endoffset = _fdt_node_end_offset(fdt, nodeoffset); +	if (endoffset < 0) +		return endoffset; + +	return _blob_splice_struct(fdt, _fdt_offset_ptr(fdt, nodeoffset), +				   endoffset - nodeoffset, 0); +} + +int fdt_open_into(void *fdt, void *buf, int bufsize) +{ +	int err; + +	err = fdt_move(fdt, buf, bufsize); +	if (err) +		return err; + +	fdt = buf; + +	fdt_set_header(fdt, totalsize, bufsize); + +	/* FIXME: re-order if necessary */ + +	err = rw_check_header(fdt); +	if (err) +		return err; + +	return 0; +} + +int fdt_pack(void *fdt) +{ +	int err; + +	err = rw_check_header(fdt); +	if (err) +		return err; + +	/* FIXME: pack components */ +	fdt_set_header(fdt, totalsize, _blob_data_size(fdt)); +	return 0; +} diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c new file mode 100644 index 000000000..41d4891bb --- /dev/null +++ b/libfdt/fdt_sw.c @@ -0,0 +1,226 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +static int check_header_sw(void *fdt) +{ +	if (fdt_magic(fdt) != SW_MAGIC) +		return -FDT_ERR_BADMAGIC; +	return 0; +} + +static void *grab_space(void *fdt, int len) +{ +	int offset = fdt_size_dt_struct(fdt); +	int spaceleft; + +	spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) +		- fdt_size_dt_strings(fdt); + +	if ((offset + len < offset) || (offset + len > spaceleft)) +		return NULL; + +	fdt_set_header(fdt, size_dt_struct, offset + len); +	return fdt_offset_ptr(fdt, offset, len); +} + +int fdt_create(void *buf, int bufsize) +{ +	void *fdt = buf; + +	if (bufsize < sizeof(struct fdt_header)) +		return -FDT_ERR_NOSPACE; + +	memset(buf, 0, bufsize); + +	fdt_set_header(fdt, magic, SW_MAGIC); +	fdt_set_header(fdt, version, FDT_LAST_SUPPORTED_VERSION); +	fdt_set_header(fdt, last_comp_version, FDT_FIRST_SUPPORTED_VERSION); +	fdt_set_header(fdt, totalsize, bufsize); + +	fdt_set_header(fdt, off_mem_rsvmap, ALIGN(sizeof(struct fdt_header), +					      sizeof(struct fdt_reserve_entry))); +	fdt_set_header(fdt, off_dt_struct, fdt_off_mem_rsvmap(fdt)); +	fdt_set_header(fdt, off_dt_strings, bufsize); + +	return 0; +} + +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) +{ +	struct fdt_reserve_entry *re; +	int err = check_header_sw(fdt); +	int offset; + +	if (err) +		return err; +	if (fdt_size_dt_struct(fdt)) +		return -FDT_ERR_BADSTATE; + +	offset = fdt_off_dt_struct(fdt); +	if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) +		return -FDT_ERR_NOSPACE; + +	re = (struct fdt_reserve_entry *)((void *)fdt + offset); +	re->address = cpu_to_fdt64(addr); +	re->size = cpu_to_fdt64(size); + +	fdt_set_header(fdt, off_dt_struct, offset + sizeof(*re)); + +	return 0; +} + +int fdt_finish_reservemap(void *fdt) +{ +	return fdt_add_reservemap_entry(fdt, 0, 0); +} + +int fdt_begin_node(void *fdt, const char *name) +{ +	struct fdt_node_header *nh; +	int err = check_header_sw(fdt); +	int namelen = strlen(name) + 1; + +	if (err) +		return err; + +	nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE)); +	if (! nh) +		return -FDT_ERR_NOSPACE; + +	nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); +	memcpy(nh->name, name, namelen); +	return 0; +} + +int fdt_end_node(void *fdt) +{ +	uint32_t *en; +	int err = check_header_sw(fdt); + +	if (err) +		return err; + +	en = grab_space(fdt, FDT_TAGSIZE); +	if (! en) +		return -FDT_ERR_NOSPACE; + +	*en = cpu_to_fdt32(FDT_END_NODE); +	return 0; +} + +static int find_add_string(void *fdt, const char *s) +{ +	char *strtab = (char *)fdt + fdt_totalsize(fdt); +	const char *p; +	int strtabsize = fdt_size_dt_strings(fdt); +	int len = strlen(s) + 1; +	int struct_top, offset; + +	p = _fdt_find_string(strtab - strtabsize, strtabsize, s); +	if (p) +		return p - strtab; + +	/* Add it */ +	offset = -strtabsize - len; +	struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); +	if (fdt_totalsize(fdt) + offset < struct_top) +		return 0; /* no more room :( */ + +	memcpy(strtab + offset, s, len); +	fdt_set_header(fdt, size_dt_strings, strtabsize + len); +	return offset; +} + +int fdt_property(void *fdt, const char *name, const void *val, int len) +{ +	struct fdt_property *prop; +	int err = check_header_sw(fdt); +	int nameoff; + +	if (err) +		return err; + +	nameoff = find_add_string(fdt, name); +	if (nameoff == 0) +		return -FDT_ERR_NOSPACE; + +	prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE)); +	if (! prop) +		return -FDT_ERR_NOSPACE; + +	prop->tag = cpu_to_fdt32(FDT_PROP); +	prop->nameoff = cpu_to_fdt32(nameoff); +	prop->len = cpu_to_fdt32(len); +	memcpy(prop->data, val, len); +	return 0; +} + +int fdt_finish(void *fdt) +{ +	int err = check_header_sw(fdt); +	char *p = (char *)fdt; +	uint32_t *end; +	int oldstroffset, newstroffset; +	uint32_t tag; +	int offset, nextoffset; + +	if (err) +		return err; + +	/* Add terminator */ +	end = grab_space(fdt, sizeof(*end)); +	if (! end) +		return -FDT_ERR_NOSPACE; +	*end = cpu_to_fdt32(FDT_END); + +	/* Relocate the string table */ +	oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); +	newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); +	memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); +	fdt_set_header(fdt, off_dt_strings, newstroffset); + +	/* Walk the structure, correcting string offsets */ +	offset = 0; +	while ((tag = _fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { +		if (tag == FDT_PROP) { +			struct fdt_property *prop = fdt_offset_ptr(fdt, offset, +								   sizeof(*prop)); +			int nameoff; + +			if (! prop) +				return -FDT_ERR_BADSTRUCTURE; + +			nameoff = fdt32_to_cpu(prop->nameoff); +			nameoff += fdt_size_dt_strings(fdt); +			prop->nameoff = cpu_to_fdt32(nameoff); +		} +		offset = nextoffset; +	} + +	/* Finally, adjust the header */ +	fdt_set_header(fdt, totalsize, newstroffset + fdt_size_dt_strings(fdt)); +	fdt_set_header(fdt, magic, FDT_MAGIC); +	return 0; +} diff --git a/libfdt/fdt_wip.c b/libfdt/fdt_wip.c new file mode 100644 index 000000000..0db7d259f --- /dev/null +++ b/libfdt/fdt_wip.c @@ -0,0 +1,112 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, +			const void *val, int len) +{ +	void *propval; +	int proplen; + +	propval = fdt_getprop(fdt, nodeoffset, name, &proplen); +	if (! propval) +		return proplen; + +	if (proplen != len) +		return -FDT_ERR_NOSPACE; + +	memcpy(propval, val, len); +	return 0; +} + +static void nop_region(void *start, int len) +{ +	uint32_t *p; + +	for (p = start; (void *)p < (start + len); p++) +		*p = cpu_to_fdt32(FDT_NOP); +} + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name) +{ +	struct fdt_property *prop; +	int len; + +	prop = fdt_get_property(fdt, nodeoffset, name, &len); +	if (! prop) +		return len; + +	nop_region(prop, len + sizeof(*prop)); + +	return 0; +} + +int _fdt_node_end_offset(void *fdt, int nodeoffset) +{ +	int level = 0; +	uint32_t tag; +	int offset, nextoffset; + +	tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset); +	if (tag != FDT_BEGIN_NODE) +		return -FDT_ERR_BADOFFSET; +	do { +		offset = nextoffset; +		tag = _fdt_next_tag(fdt, offset, &nextoffset); + +		switch (tag) { +		case FDT_END: +			return offset; + +		case FDT_BEGIN_NODE: +			level++; +			break; + +		case FDT_END_NODE: +			level--; +			break; + +		case FDT_PROP: +		case FDT_NOP: +			break; + +		default: +			return -FDT_ERR_BADSTRUCTURE; +		} +	} while (level >= 0); + +	return nextoffset; +} + +int fdt_nop_node(void *fdt, int nodeoffset) +{ +	int endoffset; + +	endoffset = _fdt_node_end_offset(fdt, nodeoffset); +	if (endoffset < 0) +		return endoffset; + +	nop_region(fdt_offset_ptr(fdt, nodeoffset, 0), endoffset - nodeoffset); +	return 0; +} |