summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/of_property.c1
-rw-r--r--drivers/of/base.c107
-rw-r--r--drivers/of/fdt.c36
-rw-r--r--drivers/pinctrl/pinctrl.c18
-rw-r--r--include/of.h5
5 files changed, 132 insertions, 35 deletions
diff --git a/commands/of_property.c b/commands/of_property.c
index ae6bfd4211..2bc08f2dad 100644
--- a/commands/of_property.c
+++ b/commands/of_property.c
@@ -278,6 +278,7 @@ static int do_of_property(int argc, char *argv[])
if (pp) {
free(pp->value);
+ pp->value_const = NULL;
/* limit property data to the actual size */
if (len) {
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 23e5e22ffe..152dbe7a4f 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -129,6 +129,11 @@ struct property *of_find_property(const struct device_node *np,
}
EXPORT_SYMBOL(of_find_property);
+const void *of_property_get_value(struct property *pp)
+{
+ return pp->value ? pp->value : pp->value_const;
+}
+
static void of_alias_add(struct alias_prop *ap, struct device_node *np,
int id, const char *stem, int stem_len)
{
@@ -178,7 +183,7 @@ void of_alias_scan(void)
!of_prop_cmp(pp->name, "linux,phandle"))
continue;
- np = of_find_node_by_path(pp->value);
+ np = of_find_node_by_path(of_property_get_value(pp));
if (!np)
continue;
@@ -374,7 +379,10 @@ const void *of_get_property(const struct device_node *np, const char *name,
{
struct property *pp = of_find_property(np, name, lenp);
- return pp ? pp->value : NULL;
+ if (!pp)
+ return NULL;
+
+ return of_property_get_value(pp);
}
EXPORT_SYMBOL(of_get_property);
@@ -678,19 +686,21 @@ EXPORT_SYMBOL(of_match);
* property data isn't large enough.
*
*/
-static void *of_find_property_value_of_size(const struct device_node *np,
+static const void *of_find_property_value_of_size(const struct device_node *np,
const char *propname, u32 len)
{
struct property *prop = of_find_property(np, propname, NULL);
+ const void *value;
if (!prop)
return ERR_PTR(-EINVAL);
- if (!prop->value)
+ value = of_property_get_value(prop);
+ if (!value)
return ERR_PTR(-ENODATA);
if (len > prop->length)
return ERR_PTR(-EOVERFLOW);
- return prop->value;
+ return value;
}
/**
@@ -867,13 +877,16 @@ int of_property_read_string(struct device_node *np, const char *propname,
const char **out_string)
{
struct property *prop = of_find_property(np, propname, NULL);
+ const void *value;
+
if (!prop)
return -EINVAL;
- if (!prop->value)
+ value = of_property_get_value(prop);
+ if (!value)
return -ENODATA;
- if (strnlen(prop->value, prop->length) >= prop->length)
+ if (strnlen(value, prop->length) >= prop->length)
return -EILSEQ;
- *out_string = prop->value;
+ *out_string = value;
return 0;
}
EXPORT_SYMBOL_GPL(of_property_read_string);
@@ -903,15 +916,17 @@ int of_property_read_string_index(struct device_node *np, const char *propname,
int i = 0;
size_t l = 0, total = 0;
const char *p;
+ const void *value;
if (!prop)
return -EINVAL;
- if (!prop->value)
+ value = of_property_get_value(prop);
+ if (!value)
return -ENODATA;
- if (strnlen(prop->value, prop->length) >= prop->length)
+ if (strnlen(value, prop->length) >= prop->length)
return -EILSEQ;
- p = prop->value;
+ p = value;
for (i = 0; total < prop->length; total += l, p += l) {
l = strlen(p) + 1;
@@ -943,10 +958,11 @@ int of_property_match_string(struct device_node *np, const char *propname,
if (!prop)
return -EINVAL;
- if (!prop->value)
+
+ p = of_property_get_value(prop);
+ if (!p)
return -ENODATA;
- p = prop->value;
end = p + prop->length;
for (i = 0; p < end; i++, p += l) {
@@ -979,15 +995,17 @@ int of_property_count_strings(struct device_node *np, const char *propname)
int i = 0;
size_t l = 0, total = 0;
const char *p;
+ const void *value;
if (!prop)
return -EINVAL;
- if (!prop->value)
+ value = of_property_get_value(prop);
+ if (!value)
return -ENODATA;
- if (strnlen(prop->value, prop->length) >= prop->length)
+ if (strnlen(value, prop->length) >= prop->length)
return -EILSEQ;
- p = prop->value;
+ p = value;
for (i = 0; total < prop->length; total += l, p += l, i++)
l = strlen(p) + 1;
@@ -1000,17 +1018,20 @@ const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
u32 *pu)
{
const void *curv = cur;
+ const void *value;
if (!prop)
return NULL;
+ value = of_property_get_value(prop);
+
if (!cur) {
- curv = prop->value;
+ curv = value;
goto out_val;
}
curv += sizeof(*cur);
- if (curv >= prop->value + prop->length)
+ if (curv >= value + prop->length)
return NULL;
out_val:
@@ -1022,15 +1043,18 @@ EXPORT_SYMBOL_GPL(of_prop_next_u32);
const char *of_prop_next_string(struct property *prop, const char *cur)
{
const void *curv = cur;
+ const void *value;
if (!prop)
return NULL;
+ value = of_property_get_value(prop);
+
if (!cur)
- return prop->value;
+ return value;
curv += strlen(cur) + 1;
- if (curv >= prop->value + prop->length)
+ if (curv >= value + prop->length)
return NULL;
return curv;
@@ -1777,7 +1801,7 @@ void of_print_nodes(struct device_node *node, int indent)
printf("%s", p->name);
if (p->length) {
printf(" = ");
- of_print_property(p->value, p->length);
+ of_print_property(of_property_get_value(p), p->length);
}
printf(";\n");
}
@@ -1817,6 +1841,18 @@ struct device_node *of_new_node(struct device_node *parent, const char *name)
return node;
}
+/**
+ * of_new_property - Add a new property to a node
+ * @node: device node to which the property is added
+ * @name: Name of the new property
+ * @data: Value of the property (can be NULL)
+ * @len: Length of the value
+ *
+ * This adds a new property to a device node. @data is copied and no longer needed
+ * after calling this function.
+ *
+ * Return: A pointer to the new property
+ */
struct property *of_new_property(struct device_node *node, const char *name,
const void *data, int len)
{
@@ -1835,6 +1871,35 @@ struct property *of_new_property(struct device_node *node, const char *name,
return prop;
}
+/**
+ * of_new_property_const - Add a new property to a node
+ * @node: device node to which the property is added
+ * @name: Name of the new property
+ * @data: Value of the property (can be NULL)
+ * @len: Length of the value
+ *
+ * This adds a new property to a device node. @data is used directly in the
+ * property and must be valid until the property is deleted again or set to
+ * another value. Normally you shouldn't use this function, use of_new_property()
+ * instead.
+ *
+ * Return: A pointer to the new property
+ */
+struct property *of_new_property_const(struct device_node *node, const char *name,
+ const void *data, int len)
+{
+ struct property *prop;
+
+ prop = xzalloc(sizeof(*prop));
+ prop->name = xstrdup(name);
+ prop->length = len;
+ prop->value_const = data;
+
+ list_add_tail(&prop->list, &node->properties);
+
+ return prop;
+}
+
void of_delete_property(struct property *pp)
{
if (!pp)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 614e136de6..1edb35f3d6 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -117,7 +117,7 @@ static int of_unflatten_reservemap(struct device_node *root,
* Parse a flat device tree binary blob and return a pointer to the
* unflattened tree.
*/
-struct device_node *of_unflatten_dtb(const void *infdt)
+struct device_node *__of_unflatten_dtb(const void *infdt, bool constprops)
{
const void *nodep; /* property node pointer */
uint32_t tag; /* tag */
@@ -221,7 +221,11 @@ struct device_node *of_unflatten_dtb(const void *infdt)
goto err;
}
- p = of_new_property(node, name, nodep, len);
+ if (constprops)
+ p = of_new_property_const(node, name, nodep, len);
+ else
+ p = of_new_property(node, name, nodep, len);
+
if (!strcmp(name, "phandle") && len == 4)
node->phandle = be32_to_cpup(p->value);
@@ -255,6 +259,34 @@ err:
return ERR_PTR(ret);
}
+/**
+ * of_unflatten_dtb - unflatten a dtb binary blob
+ * @infdt - the fdt blob to unflatten
+ *
+ * Parse a flat device tree binary blob and return a pointer to the unflattened
+ * tree. The tree must be freed after use with of_delete_node().
+ */
+struct device_node *of_unflatten_dtb(const void *infdt)
+{
+ return __of_unflatten_dtb(infdt, false);
+}
+
+/**
+ * of_unflatten_dtb_const - unflatten a dtb binary blob
+ * @infdt - the fdt blob to unflatten
+ *
+ * Parse a flat device tree binary blob and return a pointer to the unflattened
+ * tree. The tree must be freed after use with of_delete_node(). Unlike the
+ * above version this function uses the property data directly from the input
+ * flattened tree instead of copying the data, thus @infdt must be valid for the
+ * whole lifetime of the returned tree. This is normally not what you want, so
+ * use of_unflatten_dtb() instead.
+ */
+struct device_node *of_unflatten_dtb_const(const void *infdt)
+{
+ return __of_unflatten_dtb(infdt, true);
+}
+
struct fdt {
void *dt;
uint32_t dt_nextofs;
diff --git a/drivers/pinctrl/pinctrl.c b/drivers/pinctrl/pinctrl.c
index bef4fcdba1..0e42a31474 100644
--- a/drivers/pinctrl/pinctrl.c
+++ b/drivers/pinctrl/pinctrl.c
@@ -99,8 +99,7 @@ static int pinctrl_config_one(struct device_node *np)
int of_pinctrl_select_state(struct device_node *np, const char *name)
{
int state, ret;
- char *propname;
- struct property *prop;
+ char propname[sizeof("pinctrl-4294967295")];
const __be32 *list;
int size, config;
phandle phandle;
@@ -113,18 +112,13 @@ int of_pinctrl_select_state(struct device_node *np, const char *name)
/* For each defined state ID */
for (state = 0; ; state++) {
/* Retrieve the pinctrl-* property */
- propname = basprintf("pinctrl-%d", state);
- prop = of_find_property(np, propname, NULL);
- free(propname);
-
- if (!prop) {
+ sprintf(propname, "pinctrl-%d", state);
+ list = of_get_property(np, propname, &size);
+ if (!list) {
ret = -ENODEV;
break;
}
- size = prop->length;
-
- list = prop->value;
size /= sizeof(*list);
/* Determine whether pinctrl-names property names the state */
@@ -137,7 +131,7 @@ int of_pinctrl_select_state(struct device_node *np, const char *name)
*/
if (ret < 0) {
/* strlen("pinctrl-") == 8 */
- statename = prop->name + 8;
+ statename = &propname[8];
}
if (strcmp(name, statename))
@@ -151,7 +145,7 @@ int of_pinctrl_select_state(struct device_node *np, const char *name)
np_config = of_find_node_by_phandle(phandle);
if (!np_config) {
pr_err("prop %s %s index %i invalid phandle\n",
- np->full_name, prop->name, config);
+ np->full_name, propname, config);
ret = -EINVAL;
goto err;
}
diff --git a/include/of.h b/include/of.h
index 4564f48514..fec51bb94f 100644
--- a/include/of.h
+++ b/include/of.h
@@ -20,6 +20,7 @@ struct property {
char *name;
int length;
void *value;
+ const void *value_const;
struct list_head list;
};
@@ -100,6 +101,7 @@ void of_print_nodes(struct device_node *node, int indent);
int of_probe(void);
int of_parse_dtb(struct fdt_header *fdt);
struct device_node *of_unflatten_dtb(const void *fdt);
+struct device_node *of_unflatten_dtb_const(const void *infdt);
struct cdev;
@@ -117,6 +119,9 @@ extern int of_set_property(struct device_node *node, const char *p,
const void *val, int len, int create);
extern struct property *of_new_property(struct device_node *node,
const char *name, const void *data, int len);
+extern struct property *of_new_property_const(struct device_node *node,
+ const char *name,
+ const void *data, int len);
extern void of_delete_property(struct property *pp);
extern struct device_node *of_find_node_by_name(struct device_node *from,