[U-Boot-Users] LIBFDT: first version of fdt_find_compatible_node
Jerry Van Baren
gerald.vanbaren at smiths-aerospace.com
Wed Apr 25 17:12:28 CEST 2007
Wolfgang Grandegger wrote:
> Hello,
>
> attached you can find a patch implementing fdt_find_compatible_node():
Yeeee-ha! :-)
> /*
> * Find a node based on its device type and one of the tokens in
> * its its "compatible" property. On success, the offset of that
> * node is returned or an error code:
> *
> * startoffset - the node to start searching from or 0, the node
> * you pass will not be searched, only the next one
> * will; typically, you pass 0 to start the search
> * and then what the previous call returned.
> * type - the device type string to match against
> * compat - the string to match to one of the tokens
> * in the "compatible" list.
> */
>
> It should be used as shown below:
>
> offset = 0;
> do {
> offset = fdt_find_compatible_node(fdt, offset, "type", "comp");
> } while (offset >= 0);
>
> This first hack also implements a cached version as alternative, because
> tag re-scanning might take quite long. In principle, the cache could
> also be used for other functions, like fdt_path_offset(), and could be
> invalidated in case the FDT gets updated.
>
> What do you think?
>
> Thanks.
>
> Wolfgang.
Looks good. In the real patch, I would like to see the cache addition
split from the fdt_node_is_compatible() fdt_find_compatible_node() and
addition.
> ------------------------------------------------------------------------
>
> diff --git a/include/libfdt.h b/include/libfdt.h
> index f8bac73..3fd7c9f 100644
> --- a/include/libfdt.h
> +++ b/include/libfdt.h
> @@ -89,6 +89,12 @@ uint32_t fdt_next_tag(const void *fdt, int offset,
> int fdt_num_reservemap(void *fdt, int *used, int *total);
> int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re);
>
> +int fdt_node_is_compatible(const void *fdt, int nodeoffset,
> + const char *compat);
> +
> +int fdt_find_compatible_node(const void *fdt, int startoffset,
> + const char *type, const char *compat);
> +
> /* Write-in-place functions */
> int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
> const void *val, int len);
> diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
> index 4e2c325..65ede88 100644
> --- a/libfdt/fdt_ro.c
> +++ b/libfdt/fdt_ro.c
> @@ -55,6 +55,236 @@ char *fdt_string(const void *fdt, int stroffset)
> return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
> }
>
> +#define CONFIG_OF_LIBFDT_TABLE 64
> +#if CONFIG_OF_LIBFDT_TABLE > 0
[snip]
> +#endif /* CONFIG_OF_LIBFDT_TABLE > 0 */
> +
> +/*
> + * Check if the specified node is compatible by comparing the
> + * tokens in its "compatible" property with the specified string:
> + *
> + * nodeoffset - starting place of the node
> + * compat - the string to match to one of the tokens
> + * in the "compatible" list.
> + */
> +int fdt_node_is_compatible(const void *fdt, int nodeoffset,
> + const char *compat)
> +{
> + const char* cp;
> + int cplen, l;
> +
> + cp = fdt_getprop(fdt, nodeoffset, "compatible", &cplen);
> + if (cp == NULL)
> + return 0;
> + while (cplen > 0) {
> + if (strncmp(cp, compat, strlen(compat)) == 0)
> + return 1;
> + l = strlen(cp) + 1;
> + cp += l;
> + cplen -= l;
> + }
> +
> + return 0;
> +}
I see this came directly from arch/powerpc/kernel/prom.c, but using "l"
for a variable is evil. For a minute, I was wondering how the compiler
was compiling "1" (one) as a lvalue. I would prefer it to be "len" or
something more descriptive.
> +/*
> + * Find a node based on its device type and one of the tokens in
> + * its its "compatible" property. On success, the offset of that
> + * node is return or an error code:
> + *
> + * startoffset - the node to start searching from or 0, the node
> + * you pass will not be searched, only the next one
> + * will; typically, you pass 0 to start the search
> + * and then what the previous call returned.
> + * type - the device type string to match against
> + * compat - the string to match to one of the tokens
> + * in the "compatible" list.
> + */
> +#if CONFIG_OF_LIBFDT_TABLE > 0
[snip]
> +#else /* CONFIG_OF_LIBFDT_TABLE <= 0 */
> +int fdt_find_compatible_node(const void *fdt, int startoffset,
> + const char *type, const char *compat)
> +{
> + static int level, typefound;
> + static int nodeoffset, nextoffset;
> + int offset, namestroff;
> + struct fdt_property *prop;
> + uint32_t tag;
> +
> + CHECK_HEADER(fdt);
> +
> + if (startoffset == 0) {
> + level = 0;
> + tag = fdt_next_tag(fdt, 0, &nextoffset, NULL);
> + if (tag != FDT_BEGIN_NODE)
> + return -FDT_ERR_BADOFFSET;
> + } else if (startoffset != nodeoffset)
> + return -FDT_ERR_BADOFFSET;
> +
> + do {
> + offset = nextoffset;
> + tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
> +
> + switch (tag) {
> + case FDT_END:
> + return -FDT_ERR_TRUNCATED;
> +
> + case FDT_BEGIN_NODE:
> + level++;
> + nodeoffset = offset;
> + typefound = 0;
> + break;
> +
> + case FDT_END_NODE:
> + level--;
> + break;
> +
> + case FDT_PROP:
> + if (typefound)
> + continue;
> +
> + prop = fdt_offset_ptr_typed(fdt, offset, prop);
> + if (! prop)
> + continue;
> + namestroff = fdt32_to_cpu(prop->nameoff);
> + if (streq(fdt_string(fdt, namestroff), "device_type")) {
> + int len = fdt32_to_cpu(prop->len);
> + typefound = 0;
> + prop = fdt_offset_ptr(fdt, offset,
> + sizeof(*prop)+len);
> + if (! prop)
> + continue;
> + if (strncasecmp(prop->data, type, len - 1) == 0 &&
> + fdt_node_is_compatible(fdt, nodeoffset, compat))
> + return nodeoffset;
> + }
> + break;
> +
> + case FDT_NOP:
> + break;
> +
> + default:
> + return -FDT_ERR_BADSTRUCTURE;
> + }
> + } while (level >= 0);
> +
> + return -FDT_ERR_NOTFOUND;
> +}
> +#endif /* CONFIG_OF_LIBFDT_TABLE > 0 */
> +
> /*
> * Return the node offset of the node specified by:
> * parentoffset - starting place (0 to start at the root)
For the above version of fdt_find_compatible_node(), as well as the one
that fills the cache table (snipped), I'm thinking it would be better to
use the function I added:
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset, char
**namep)
I added this to step through the nodes and properties for dumping the
tree. Rather than having Yet Another (slightly modified) Copy of the
loop & switch, you should be able to use fdt_next_tag() to step through
the nodes and properties, doing the
if (streq(fdt_string(fdt, namestroff), "device_type"))
on the **namep parameter on every call to find the device_type
properties. Does this make sense?
Thanks,
gvb
More information about the U-Boot
mailing list