diff options
Diffstat (limited to 'libfdt/fdt_ro.c')
| -rw-r--r-- | libfdt/fdt_ro.c | 116 | 
1 files changed, 110 insertions, 6 deletions
| diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c index 9112c6a63..f88408395 100644 --- a/libfdt/fdt_ro.c +++ b/libfdt/fdt_ro.c @@ -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; +} + |