This adds the applicable libfdt source files (unmodified) and a README to explain where the source came from.master
parent
7cd5da0fe8
commit
35748177c6
@ -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; |
||||
} |
@ -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; |
||||
} |
@ -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; |
||||
} |
@ -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; |
||||
} |
Loading…
Reference in new issue