public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Jerry Van Baren <gerald.vanbaren@smiths-aerospace.com>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] LIBFDT: first version of fdt_find_compatible_node
Date: Wed, 25 Apr 2007 11:12:28 -0400	[thread overview]
Message-ID: <462F6FDC.8020804@smiths-aerospace.com> (raw)
In-Reply-To: <462F1831.7070902@grandegger.com>

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

  reply	other threads:[~2007-04-25 15:12 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-04-25  8:58 [U-Boot-Users] LIBFDT: first version of fdt_find_compatible_node Wolfgang Grandegger
2007-04-25 15:12 ` Jerry Van Baren [this message]
2007-04-25 19:37   ` Wolfgang Grandegger
2007-04-25 21:06     ` Jerry Van Baren
2007-04-26  7:39       ` Wolfgang Grandegger
2007-04-26  9:42         ` Wolfgang Grandegger
2007-04-26 10:45           ` Jerry Van Baren
2007-04-26 11:12             ` Wolfgang Grandegger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=462F6FDC.8020804@smiths-aerospace.com \
    --to=gerald.vanbaren@smiths-aerospace.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox