libfdt: Enhanced and published fdt_next_tag()

Enhanced the formerly private function _fdt_next_tag() to allow stepping
  through the tree, used to produce a human-readable dump, and made
  it part of the published interface.
Also added some comments.
This commit is contained in:
Gerald Van Baren 2007-03-31 12:13:43 -04:00
parent fa3a74cec7
commit 3af0d587d9
7 changed files with 119 additions and 52 deletions

View File

@ -81,6 +81,9 @@ struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp);
uint32_t fdt_next_tag(const void *fdt, int offset,
int *nextoffset, char **namep);
/* Write-in-place functions */
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len);

View File

@ -58,45 +58,6 @@ void *fdt_offset_ptr(const void *fdt, int offset, int len)
return p;
}
uint32_t _fdt_next_tag(const void *fdt, int offset, int *nextoffset)
{
const uint32_t *tagp, *lenp;
uint32_t tag;
const char *p;
if (offset % FDT_TAGSIZE)
return -1;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (! p)
return FDT_END;
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (! lenp)
return FDT_END;
/* skip name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
break;
}
if (nextoffset)
*nextoffset = ALIGN(offset, FDT_TAGSIZE);
return tag;
}
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;

View File

@ -48,11 +48,24 @@ static int offset_streq(const void *fdt, int offset,
return 1;
}
/*
* Return a pointer to the string at the given string offset.
*/
char *fdt_string(const void *fdt, int stroffset)
{
return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
/*
* Return the node offset of the node specified by:
* parentoffset - starting place (0 to start at the root)
* name - name being searched for
* namelen - length of the name: typically strlen(name)
*
* Notes:
* If the start node has subnodes, the subnodes are _not_ searched for the
* requested name.
*/
int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
const char *name, int namelen)
{
@ -62,13 +75,13 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
CHECK_HEADER(fdt);
tag = _fdt_next_tag(fdt, parentoffset, &nextoffset);
tag = fdt_next_tag(fdt, parentoffset, &nextoffset, NULL);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);
tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
switch (tag) {
case FDT_END:
@ -76,10 +89,15 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
case FDT_BEGIN_NODE:
level++;
/*
* If we are nested down levels, ignore the strings
* until we get back to the proper level.
*/
if (level != 1)
continue;
/* Return the offset if this is "our" string. */
if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen))
/* Found it! */
return offset;
break;
@ -99,12 +117,19 @@ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
return -FDT_ERR_NOTFOUND;
}
/*
* See fdt_subnode_offset_namelen()
*/
int fdt_subnode_offset(const void *fdt, int parentoffset,
const char *name)
{
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}
/*
* Searches for the node corresponding to the given path and returns the
* offset of that node.
*/
int fdt_path_offset(const void *fdt, const char *path)
{
const char *end = path + strlen(path);
@ -113,21 +138,33 @@ int fdt_path_offset(const void *fdt, const char *path)
CHECK_HEADER(fdt);
/* Paths must be absolute */
if (*path != '/')
return -FDT_ERR_BADPATH;
while (*p) {
const char *q;
/* Skip path separator(s) */
while (*p == '/')
p++;
if (! *p)
return -FDT_ERR_BADPATH;
/*
* Find the next path separator. The characters between
* p and q are the next segment of the the path to find.
*/
q = strchr(p, '/');
if (! q)
q = end;
/*
* Find the offset corresponding to the this path segment.
*/
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
/* Oops, error, abort abort abort */
if (offset < 0)
return offset;
@ -137,6 +174,10 @@ int fdt_path_offset(const void *fdt, const char *path)
return offset;
}
/*
* Given the offset of a node and a name of a property in that node, return
* a pointer to the property struct.
*/
struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
@ -155,14 +196,14 @@ struct fdt_property *fdt_get_property(const void *fdt,
if (nodeoffset % FDT_TAGSIZE)
goto fail;
tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL);
if (tag != FDT_BEGIN_NODE)
goto fail;
do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);
tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
switch (tag) {
case FDT_END:
err = -FDT_ERR_TRUNCATED;
@ -177,6 +218,10 @@ struct fdt_property *fdt_get_property(const void *fdt,
break;
case FDT_PROP:
/*
* If we are nested down levels, ignore the strings
* until we get back to the proper level.
*/
if (level != 0)
continue;
@ -216,6 +261,10 @@ struct fdt_property *fdt_get_property(const void *fdt,
return NULL;
}
/*
* Given the offset of a node and a name of a property in that node, return
* a pointer to the property data (ONLY).
*/
void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
@ -225,5 +274,60 @@ void *fdt_getprop(const void *fdt, int nodeoffset,
if (! prop)
return NULL;
return prop->data;
return (void *)prop->data;
}
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset, char **namep)
{
const uint32_t *tagp, *lenp;
uint32_t tag;
const char *p;
if (offset % FDT_TAGSIZE)
return -1;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
switch (tag) {
case FDT_BEGIN_NODE:
if(namep)
*namep = fdt_offset_ptr(fdt, offset, 1);
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (! p)
return FDT_END;
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (! lenp)
return FDT_END;
/*
* Get the property and set the namep to the name.
*/
if(namep) {
struct fdt_property *prop;
prop = fdt_offset_ptr_typed(fdt, offset - FDT_TAGSIZE, prop);
if (! prop)
return -FDT_ERR_BADSTRUCTURE;
*namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
}
/* skip name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
break;
}
if (nextoffset)
*nextoffset = ALIGN(offset, FDT_TAGSIZE);
return tag;
}

View File

@ -145,7 +145,7 @@ static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
int namestroff;
int err;
tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
@ -219,10 +219,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
return offset;
/* Try to place the new node after the parent's properties */
_fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
fdt_next_tag(fdt, parentoffset, &nextoffset, NULL); /* skip the BEGIN_NODE */
do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);
tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
} while (tag == FDT_PROP);
nh = _fdt_offset_ptr(fdt, offset);

View File

@ -203,7 +203,7 @@ int fdt_finish(void *fdt)
/* Walk the structure, correcting string offsets */
offset = 0;
while ((tag = _fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
while ((tag = fdt_next_tag(fdt, offset, &nextoffset, NULL)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop = fdt_offset_ptr(fdt, offset,
sizeof(*prop));

View File

@ -68,12 +68,12 @@ int _fdt_node_end_offset(void *fdt, int nodeoffset)
uint32_t tag;
int offset, nextoffset;
tag = _fdt_next_tag(fdt, nodeoffset, &nextoffset);
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
do {
offset = nextoffset;
tag = _fdt_next_tag(fdt, offset, &nextoffset);
tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
switch (tag) {
case FDT_END:

View File

@ -27,7 +27,6 @@
#define streq(p, q) (strcmp((p), (q)) == 0)
int _fdt_check_header(const void *fdt);
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);