OF: Utility helper functions for dynamic nodes
Introduce helper functions for working with the live DT tree, all of them related to dynamically adding/removing nodes and properties. __of_prop_dup() copies a property dynamically __of_node_alloc() creates an empty node Bug fix about prop->len == 0 by Ionut Nicu <ioan.nicu.ext@nsn.com> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> [glikely: Added unittest for of_copy_property and dropped fine-grained allocations] [glikely: removed name, type and phandle arguments from __of_node_alloc] Signed-off-by: Grant Likely <grant.likely@linaro.org>
This commit is contained in:
Родитель
6afc0dc381
Коммит
698433963b
|
@ -214,3 +214,80 @@ void of_node_release(struct kobject *kobj)
|
|||
kfree(node->data);
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* __of_prop_dup - Copy a property dynamically.
|
||||
* @prop: Property to copy
|
||||
* @allocflags: Allocation flags (typically pass GFP_KERNEL)
|
||||
*
|
||||
* Copy a property by dynamically allocating the memory of both the
|
||||
* property stucture and the property name & contents. The property's
|
||||
* flags have the OF_DYNAMIC bit set so that we can differentiate between
|
||||
* dynamically allocated properties and not.
|
||||
* Returns the newly allocated property or NULL on out of memory error.
|
||||
*/
|
||||
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
|
||||
{
|
||||
struct property *new;
|
||||
|
||||
new = kzalloc(sizeof(*new), allocflags);
|
||||
if (!new)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* NOTE: There is no check for zero length value.
|
||||
* In case of a boolean property This will allocate a value
|
||||
* of zero bytes. We do this to work around the use
|
||||
* of of_get_property() calls on boolean values.
|
||||
*/
|
||||
new->name = kstrdup(prop->name, allocflags);
|
||||
new->value = kmemdup(prop->value, prop->length, allocflags);
|
||||
new->length = prop->length;
|
||||
if (!new->name || !new->value)
|
||||
goto err_free;
|
||||
|
||||
/* mark the property as dynamic */
|
||||
of_property_set_flag(new, OF_DYNAMIC);
|
||||
|
||||
return new;
|
||||
|
||||
err_free:
|
||||
kfree(new->name);
|
||||
kfree(new->value);
|
||||
kfree(new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* __of_node_alloc() - Create an empty device node dynamically.
|
||||
* @full_name: Full name of the new device node
|
||||
* @allocflags: Allocation flags (typically pass GFP_KERNEL)
|
||||
*
|
||||
* Create an empty device tree node, suitable for further modification.
|
||||
* The node data are dynamically allocated and all the node flags
|
||||
* have the OF_DYNAMIC & OF_DETACHED bits set.
|
||||
* Returns the newly allocated node or NULL on out of memory error.
|
||||
*/
|
||||
struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags)
|
||||
{
|
||||
struct device_node *node;
|
||||
|
||||
node = kzalloc(sizeof(*node), allocflags);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
node->full_name = kstrdup(full_name, allocflags);
|
||||
of_node_set_flag(node, OF_DYNAMIC);
|
||||
of_node_set_flag(node, OF_DETACHED);
|
||||
if (!node->full_name)
|
||||
goto err_free;
|
||||
|
||||
of_node_init(node);
|
||||
|
||||
return node;
|
||||
|
||||
err_free:
|
||||
kfree(node->full_name);
|
||||
kfree(node);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -51,4 +51,14 @@ static inline int of_property_notify(int action, struct device_node *np,
|
|||
}
|
||||
#endif /* CONFIG_OF_DYNAMIC */
|
||||
|
||||
/**
|
||||
* General utilities for working with live trees.
|
||||
*
|
||||
* All functions with two leading underscores operate
|
||||
* without taking node references, so you either have to
|
||||
* own the devtree lock or work on detached trees only.
|
||||
*/
|
||||
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
|
||||
struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
|
||||
|
||||
#endif /* _LINUX_OF_PRIVATE_H */
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "of_private.h"
|
||||
|
||||
static struct selftest_results {
|
||||
int passed;
|
||||
int failed;
|
||||
|
@ -266,6 +268,31 @@ static void __init of_selftest_property_match_string(void)
|
|||
selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc);
|
||||
}
|
||||
|
||||
#define propcmp(p1, p2) (((p1)->length == (p2)->length) && \
|
||||
(p1)->value && (p2)->value && \
|
||||
!memcmp((p1)->value, (p2)->value, (p1)->length) && \
|
||||
!strcmp((p1)->name, (p2)->name))
|
||||
static void __init of_selftest_property_copy(void)
|
||||
{
|
||||
#ifdef CONFIG_OF_DYNAMIC
|
||||
struct property p1 = { .name = "p1", .length = 0, .value = "" };
|
||||
struct property p2 = { .name = "p2", .length = 5, .value = "abcd" };
|
||||
struct property *new;
|
||||
|
||||
new = __of_prop_dup(&p1, GFP_KERNEL);
|
||||
selftest(new && propcmp(&p1, new), "empty property didn't copy correctly\n");
|
||||
kfree(new->value);
|
||||
kfree(new->name);
|
||||
kfree(new);
|
||||
|
||||
new = __of_prop_dup(&p2, GFP_KERNEL);
|
||||
selftest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n");
|
||||
kfree(new->value);
|
||||
kfree(new->name);
|
||||
kfree(new);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init of_selftest_parse_interrupts(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
@ -533,6 +560,7 @@ static int __init of_selftest(void)
|
|||
of_selftest_dynamic();
|
||||
of_selftest_parse_phandle_with_args();
|
||||
of_selftest_property_match_string();
|
||||
of_selftest_property_copy();
|
||||
of_selftest_parse_interrupts();
|
||||
of_selftest_parse_interrupts_extended();
|
||||
of_selftest_match_node();
|
||||
|
|
Загрузка…
Ссылка в новой задаче