|
@@ -21,7 +21,7 @@
|
|
|
|
|
|
struct property_set {
|
|
|
struct fwnode_handle fwnode;
|
|
|
- struct property_entry *properties;
|
|
|
+ const struct property_entry *properties;
|
|
|
};
|
|
|
|
|
|
static inline bool is_pset_node(struct fwnode_handle *fwnode)
|
|
@@ -35,10 +35,10 @@ static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode)
|
|
|
container_of(fwnode, struct property_set, fwnode) : NULL;
|
|
|
}
|
|
|
|
|
|
-static struct property_entry *pset_prop_get(struct property_set *pset,
|
|
|
- const char *name)
|
|
|
+static const struct property_entry *pset_prop_get(struct property_set *pset,
|
|
|
+ const char *name)
|
|
|
{
|
|
|
- struct property_entry *prop;
|
|
|
+ const struct property_entry *prop;
|
|
|
|
|
|
if (!pset || !pset->properties)
|
|
|
return NULL;
|
|
@@ -50,11 +50,11 @@ static struct property_entry *pset_prop_get(struct property_set *pset,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static void *pset_prop_find(struct property_set *pset, const char *propname,
|
|
|
- size_t length)
|
|
|
+static const void *pset_prop_find(struct property_set *pset,
|
|
|
+ const char *propname, size_t length)
|
|
|
{
|
|
|
- struct property_entry *prop;
|
|
|
- void *pointer;
|
|
|
+ const struct property_entry *prop;
|
|
|
+ const void *pointer;
|
|
|
|
|
|
prop = pset_prop_get(pset, propname);
|
|
|
if (!prop)
|
|
@@ -74,7 +74,7 @@ static int pset_prop_read_u8_array(struct property_set *pset,
|
|
|
const char *propname,
|
|
|
u8 *values, size_t nval)
|
|
|
{
|
|
|
- void *pointer;
|
|
|
+ const void *pointer;
|
|
|
size_t length = nval * sizeof(*values);
|
|
|
|
|
|
pointer = pset_prop_find(pset, propname, length);
|
|
@@ -89,7 +89,7 @@ static int pset_prop_read_u16_array(struct property_set *pset,
|
|
|
const char *propname,
|
|
|
u16 *values, size_t nval)
|
|
|
{
|
|
|
- void *pointer;
|
|
|
+ const void *pointer;
|
|
|
size_t length = nval * sizeof(*values);
|
|
|
|
|
|
pointer = pset_prop_find(pset, propname, length);
|
|
@@ -104,7 +104,7 @@ static int pset_prop_read_u32_array(struct property_set *pset,
|
|
|
const char *propname,
|
|
|
u32 *values, size_t nval)
|
|
|
{
|
|
|
- void *pointer;
|
|
|
+ const void *pointer;
|
|
|
size_t length = nval * sizeof(*values);
|
|
|
|
|
|
pointer = pset_prop_find(pset, propname, length);
|
|
@@ -119,7 +119,7 @@ static int pset_prop_read_u64_array(struct property_set *pset,
|
|
|
const char *propname,
|
|
|
u64 *values, size_t nval)
|
|
|
{
|
|
|
- void *pointer;
|
|
|
+ const void *pointer;
|
|
|
size_t length = nval * sizeof(*values);
|
|
|
|
|
|
pointer = pset_prop_find(pset, propname, length);
|
|
@@ -133,7 +133,7 @@ static int pset_prop_read_u64_array(struct property_set *pset,
|
|
|
static int pset_prop_count_elems_of_size(struct property_set *pset,
|
|
|
const char *propname, size_t length)
|
|
|
{
|
|
|
- struct property_entry *prop;
|
|
|
+ const struct property_entry *prop;
|
|
|
|
|
|
prop = pset_prop_get(pset, propname);
|
|
|
if (!prop)
|
|
@@ -146,7 +146,7 @@ static int pset_prop_read_string_array(struct property_set *pset,
|
|
|
const char *propname,
|
|
|
const char **strings, size_t nval)
|
|
|
{
|
|
|
- void *pointer;
|
|
|
+ const void *pointer;
|
|
|
size_t length = nval * sizeof(*strings);
|
|
|
|
|
|
pointer = pset_prop_find(pset, propname, length);
|
|
@@ -160,8 +160,8 @@ static int pset_prop_read_string_array(struct property_set *pset,
|
|
|
static int pset_prop_read_string(struct property_set *pset,
|
|
|
const char *propname, const char **strings)
|
|
|
{
|
|
|
- struct property_entry *prop;
|
|
|
- const char **pointer;
|
|
|
+ const struct property_entry *prop;
|
|
|
+ const char * const *pointer;
|
|
|
|
|
|
prop = pset_prop_get(pset, propname);
|
|
|
if (!prop)
|
|
@@ -682,77 +682,64 @@ out:
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(fwnode_property_match_string);
|
|
|
|
|
|
-/**
|
|
|
- * pset_free_set - releases memory allocated for copied property set
|
|
|
- * @pset: Property set to release
|
|
|
- *
|
|
|
- * Function takes previously copied property set and releases all the
|
|
|
- * memory allocated to it.
|
|
|
- */
|
|
|
-static void pset_free_set(struct property_set *pset)
|
|
|
+static int property_copy_string_array(struct property_entry *dst,
|
|
|
+ const struct property_entry *src)
|
|
|
{
|
|
|
- const struct property_entry *prop;
|
|
|
- size_t i, nval;
|
|
|
+ char **d;
|
|
|
+ size_t nval = src->length / sizeof(*d);
|
|
|
+ int i;
|
|
|
|
|
|
- if (!pset)
|
|
|
- return;
|
|
|
+ d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
|
|
|
+ if (!d)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- for (prop = pset->properties; prop->name; prop++) {
|
|
|
- if (prop->is_array) {
|
|
|
- if (prop->is_string && prop->pointer.str) {
|
|
|
- nval = prop->length / sizeof(const char *);
|
|
|
- for (i = 0; i < nval; i++)
|
|
|
- kfree(prop->pointer.str[i]);
|
|
|
- }
|
|
|
- kfree(prop->pointer.raw_data);
|
|
|
- } else if (prop->is_string) {
|
|
|
- kfree(prop->value.str);
|
|
|
+ for (i = 0; i < nval; i++) {
|
|
|
+ d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
|
|
|
+ if (!d[i] && src->pointer.str[i]) {
|
|
|
+ while (--i >= 0)
|
|
|
+ kfree(d[i]);
|
|
|
+ kfree(d);
|
|
|
+ return -ENOMEM;
|
|
|
}
|
|
|
- kfree(prop->name);
|
|
|
}
|
|
|
|
|
|
- kfree(pset->properties);
|
|
|
- kfree(pset);
|
|
|
+ dst->pointer.raw_data = d;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static int pset_copy_entry(struct property_entry *dst,
|
|
|
- const struct property_entry *src)
|
|
|
+static int property_entry_copy_data(struct property_entry *dst,
|
|
|
+ const struct property_entry *src)
|
|
|
{
|
|
|
- const char **d, **s;
|
|
|
- size_t i, nval;
|
|
|
+ int error;
|
|
|
|
|
|
dst->name = kstrdup(src->name, GFP_KERNEL);
|
|
|
if (!dst->name)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
if (src->is_array) {
|
|
|
- if (!src->length)
|
|
|
- return -ENODATA;
|
|
|
+ if (!src->length) {
|
|
|
+ error = -ENODATA;
|
|
|
+ goto out_free_name;
|
|
|
+ }
|
|
|
|
|
|
if (src->is_string) {
|
|
|
- nval = src->length / sizeof(const char *);
|
|
|
- dst->pointer.str = kcalloc(nval, sizeof(const char *),
|
|
|
- GFP_KERNEL);
|
|
|
- if (!dst->pointer.str)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- d = dst->pointer.str;
|
|
|
- s = src->pointer.str;
|
|
|
- for (i = 0; i < nval; i++) {
|
|
|
- d[i] = kstrdup(s[i], GFP_KERNEL);
|
|
|
- if (!d[i] && s[i])
|
|
|
- return -ENOMEM;
|
|
|
- }
|
|
|
+ error = property_copy_string_array(dst, src);
|
|
|
+ if (error)
|
|
|
+ goto out_free_name;
|
|
|
} else {
|
|
|
dst->pointer.raw_data = kmemdup(src->pointer.raw_data,
|
|
|
src->length, GFP_KERNEL);
|
|
|
- if (!dst->pointer.raw_data)
|
|
|
- return -ENOMEM;
|
|
|
+ if (!dst->pointer.raw_data) {
|
|
|
+ error = -ENOMEM;
|
|
|
+ goto out_free_name;
|
|
|
+ }
|
|
|
}
|
|
|
} else if (src->is_string) {
|
|
|
dst->value.str = kstrdup(src->value.str, GFP_KERNEL);
|
|
|
- if (!dst->value.str && src->value.str)
|
|
|
- return -ENOMEM;
|
|
|
+ if (!dst->value.str && src->value.str) {
|
|
|
+ error = -ENOMEM;
|
|
|
+ goto out_free_name;
|
|
|
+ }
|
|
|
} else {
|
|
|
dst->value.raw_data = src->value.raw_data;
|
|
|
}
|
|
@@ -762,6 +749,95 @@ static int pset_copy_entry(struct property_entry *dst,
|
|
|
dst->is_string = src->is_string;
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+out_free_name:
|
|
|
+ kfree(dst->name);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+static void property_entry_free_data(const struct property_entry *p)
|
|
|
+{
|
|
|
+ size_t i, nval;
|
|
|
+
|
|
|
+ if (p->is_array) {
|
|
|
+ if (p->is_string && p->pointer.str) {
|
|
|
+ nval = p->length / sizeof(const char *);
|
|
|
+ for (i = 0; i < nval; i++)
|
|
|
+ kfree(p->pointer.str[i]);
|
|
|
+ }
|
|
|
+ kfree(p->pointer.raw_data);
|
|
|
+ } else if (p->is_string) {
|
|
|
+ kfree(p->value.str);
|
|
|
+ }
|
|
|
+ kfree(p->name);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * property_entries_dup - duplicate array of properties
|
|
|
+ * @properties: array of properties to copy
|
|
|
+ *
|
|
|
+ * This function creates a deep copy of the given NULL-terminated array
|
|
|
+ * of property entries.
|
|
|
+ */
|
|
|
+struct property_entry *
|
|
|
+property_entries_dup(const struct property_entry *properties)
|
|
|
+{
|
|
|
+ struct property_entry *p;
|
|
|
+ int i, n = 0;
|
|
|
+
|
|
|
+ while (properties[n].name)
|
|
|
+ n++;
|
|
|
+
|
|
|
+ p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
|
|
|
+ if (!p)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
|
+ for (i = 0; i < n; i++) {
|
|
|
+ int ret = property_entry_copy_data(&p[i], &properties[i]);
|
|
|
+ if (ret) {
|
|
|
+ while (--i >= 0)
|
|
|
+ property_entry_free_data(&p[i]);
|
|
|
+ kfree(p);
|
|
|
+ return ERR_PTR(ret);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return p;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(property_entries_dup);
|
|
|
+
|
|
|
+/**
|
|
|
+ * property_entries_free - free previously allocated array of properties
|
|
|
+ * @properties: array of properties to destroy
|
|
|
+ *
|
|
|
+ * This function frees given NULL-terminated array of property entries,
|
|
|
+ * along with their data.
|
|
|
+ */
|
|
|
+void property_entries_free(const struct property_entry *properties)
|
|
|
+{
|
|
|
+ const struct property_entry *p;
|
|
|
+
|
|
|
+ for (p = properties; p->name; p++)
|
|
|
+ property_entry_free_data(p);
|
|
|
+
|
|
|
+ kfree(properties);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(property_entries_free);
|
|
|
+
|
|
|
+/**
|
|
|
+ * pset_free_set - releases memory allocated for copied property set
|
|
|
+ * @pset: Property set to release
|
|
|
+ *
|
|
|
+ * Function takes previously copied property set and releases all the
|
|
|
+ * memory allocated to it.
|
|
|
+ */
|
|
|
+static void pset_free_set(struct property_set *pset)
|
|
|
+{
|
|
|
+ if (!pset)
|
|
|
+ return;
|
|
|
+
|
|
|
+ property_entries_free(pset->properties);
|
|
|
+ kfree(pset);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -776,32 +852,20 @@ static int pset_copy_entry(struct property_entry *dst,
|
|
|
*/
|
|
|
static struct property_set *pset_copy_set(const struct property_set *pset)
|
|
|
{
|
|
|
- const struct property_entry *entry;
|
|
|
+ struct property_entry *properties;
|
|
|
struct property_set *p;
|
|
|
- size_t i, n = 0;
|
|
|
|
|
|
p = kzalloc(sizeof(*p), GFP_KERNEL);
|
|
|
if (!p)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
- while (pset->properties[n].name)
|
|
|
- n++;
|
|
|
-
|
|
|
- p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL);
|
|
|
- if (!p->properties) {
|
|
|
+ properties = property_entries_dup(pset->properties);
|
|
|
+ if (IS_ERR(properties)) {
|
|
|
kfree(p);
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
- }
|
|
|
-
|
|
|
- for (i = 0; i < n; i++) {
|
|
|
- int ret = pset_copy_entry(&p->properties[i],
|
|
|
- &pset->properties[i]);
|
|
|
- if (ret) {
|
|
|
- pset_free_set(p);
|
|
|
- return ERR_PTR(ret);
|
|
|
- }
|
|
|
+ return ERR_CAST(properties);
|
|
|
}
|
|
|
|
|
|
+ p->properties = properties;
|
|
|
return p;
|
|
|
}
|
|
|
|
|
@@ -847,7 +911,8 @@ EXPORT_SYMBOL_GPL(device_remove_properties);
|
|
|
* @dev as its secondary firmware node. The function takes a copy of
|
|
|
* @properties.
|
|
|
*/
|
|
|
-int device_add_properties(struct device *dev, struct property_entry *properties)
|
|
|
+int device_add_properties(struct device *dev,
|
|
|
+ const struct property_entry *properties)
|
|
|
{
|
|
|
struct property_set *p, pset;
|
|
|
|