aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of/dynamic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/dynamic.c')
-rw-r--r--drivers/of/dynamic.c195
1 files changed, 187 insertions, 8 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 49b16f76d78e..1f9ad0132b88 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -27,7 +27,7 @@ static struct device_node *kobj_to_device_node(struct kobject *kobj)
* @node: Node to inc refcount, NULL is supported to simplify writing of
* callers
*
- * Returns node.
+ * Return: The node with refcount incremented.
*/
struct device_node *of_node_get(struct device_node *node)
{
@@ -104,8 +104,10 @@ int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p)
* @arg - argument of the of notifier
*
* Returns the new state of a device based on the notifier used.
- * Returns 0 on device going from enabled to disabled, 1 on device
- * going from disabled to enabled and -1 on no change.
+ *
+ * Return: OF_RECONFIG_CHANGE_REMOVE on device going from enabled to
+ * disabled, OF_RECONFIG_CHANGE_ADD on device going from disabled to
+ * enabled and OF_RECONFIG_NO_CHANGE on no change.
*/
int of_reconfig_get_state_change(unsigned long action, struct of_reconfig_data *pr)
{
@@ -372,7 +374,8 @@ void of_node_release(struct kobject *kobj)
* property structure 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.
+ *
+ * Return: The newly allocated property or NULL on out of memory error.
*/
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
{
@@ -415,7 +418,7 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
* another node. 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.
+ * Return: The newly allocated node or NULL on out of memory error.
*/
struct device_node *__of_node_dup(const struct device_node *np,
const char *full_name)
@@ -781,7 +784,8 @@ static int __of_changeset_apply(struct of_changeset *ocs)
* Any side-effects of live tree state changes are applied here on
* success, like creation/destruction of devices and side-effects
* like creation of sysfs properties and directories.
- * Returns 0 on success, a negative error value in case of an error.
+ *
+ * Return: 0 on success, a negative error value in case of an error.
* On error the partially applied effects are reverted.
*/
int of_changeset_apply(struct of_changeset *ocs)
@@ -875,7 +879,8 @@ static int __of_changeset_revert(struct of_changeset *ocs)
* was before the application.
* Any side-effects like creation/destruction of devices and
* removal of sysfs properties and directories are applied.
- * Returns 0 on success, a negative error value in case of an error.
+ *
+ * Return: 0 on success, a negative error value in case of an error.
*/
int of_changeset_revert(struct of_changeset *ocs)
{
@@ -903,7 +908,8 @@ EXPORT_SYMBOL_GPL(of_changeset_revert);
* + OF_RECONFIG_ADD_PROPERTY
* + OF_RECONFIG_REMOVE_PROPERTY,
* + OF_RECONFIG_UPDATE_PROPERTY
- * Returns 0 on success, a negative error value in case of an error.
+ *
+ * Return: 0 on success, a negative error value in case of an error.
*/
int of_changeset_action(struct of_changeset *ocs, unsigned long action,
struct device_node *np, struct property *prop)
@@ -927,3 +933,176 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action,
return 0;
}
EXPORT_SYMBOL_GPL(of_changeset_action);
+
+/* changeset helpers */
+
+/**
+ * __of_changeset_add_property_copy - Create/update a new property copying
+ * name & value
+ *
+ * @ocs: changeset pointer
+ * @np: device node pointer
+ * @name: name of the property
+ * @value: pointer to the value data
+ * @length: length of the value in bytes
+ * @update: True on update operation
+ *
+ * Adds/updates a property to the changeset by making copies of the name & value
+ * entries. The @update parameter controls whether an add or update takes place.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int __of_changeset_add_update_property_copy(struct of_changeset *ocs,
+ struct device_node *np, const char *name, const void *value,
+ int length, bool update)
+{
+ struct property *prop;
+ char *new_name;
+ void *new_value;
+ int ret = -ENOMEM;
+
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return -ENOMEM;
+
+ new_name = kstrdup(name, GFP_KERNEL);
+ if (!new_name)
+ goto out_err;
+
+ /*
+ * 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_value = kmemdup(value, length, GFP_KERNEL);
+ if (!new_value)
+ goto out_err;
+
+ of_property_set_flag(prop, OF_DYNAMIC);
+
+ prop->name = new_name;
+ prop->value = new_value;
+ prop->length = length;
+
+ if (!update)
+ ret = of_changeset_add_property(ocs, np, prop);
+ else
+ ret = of_changeset_update_property(ocs, np, prop);
+
+ if (!ret)
+ return 0;
+
+out_err:
+ kfree(prop->value);
+ kfree(prop->name);
+ kfree(prop);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_copy);
+
+/**
+ * of_changeset_add_property_stringf - Create a new formatted string property
+ *
+ * @ocs: changeset pointer
+ * @np: device node pointer
+ * @name: name of the property
+ * @fmt: format of string property
+ * ... arguments of the format string
+ *
+ * Adds a string property to the changeset by making copies of the name
+ * and the formatted value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+__printf(4, 5) int of_changeset_add_property_stringf(
+ struct of_changeset *ocs, struct device_node *np,
+ const char *name, const char *fmt, ...)
+{
+ va_list vargs;
+ int ret;
+
+ va_start(vargs, fmt);
+ ret = __of_changeset_add_update_property_stringv(ocs, np, name, fmt,
+ vargs, false);
+ va_end(vargs);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_changeset_add_property_stringf);
+
+/**
+ * of_changeset_update_property_stringf - Update formatted string property
+ *
+ * @ocs: changeset pointer
+ * @np: device node pointer
+ * @name: name of the property
+ * @fmt: format of string property
+ * ... arguments of the format string
+ *
+ * Updates a string property to the changeset by making copies of the name
+ * and the formatted value.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int of_changeset_update_property_stringf(
+ struct of_changeset *ocs, struct device_node *np,
+ const char *name, const char *fmt, ...)
+{
+ va_list vargs;
+ int ret;
+
+ va_start(vargs, fmt);
+ ret = __of_changeset_add_update_property_stringv(ocs, np, name, fmt,
+ vargs, true);
+ va_end(vargs);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_changeset_update_property_stringf);
+
+/**
+ * __of_changeset_add_update_property_string_list - Create/update a string
+ * list property
+ *
+ * @ocs: changeset pointer
+ * @np: device node pointer
+ * @name: name of the property
+ * @strs: pointer to the string list
+ * @count: string count
+ * @update: True on update operation
+ *
+ * Adds a string list property to the changeset.
+ *
+ * Returns zero on success, a negative error value otherwise.
+ */
+int __of_changeset_add_update_property_string_list(
+ struct of_changeset *ocs, struct device_node *np,
+ const char *name, const char **strs, int count, bool update)
+{
+ int total = 0, i, ret;
+ char *value, *s;
+
+ for (i = 0; i < count; i++) {
+ /* check if it's NULL */
+ if (!strs[i])
+ return -EINVAL;
+ total += strlen(strs[i]) + 1;
+ }
+
+ value = kmalloc(total, GFP_KERNEL);
+ if (!value)
+ return -ENOMEM;
+
+ for (i = 0, s = value; i < count; i++) {
+ /* no need to check for NULL, check above */
+ strcpy(s, strs[i]);
+ s += strlen(strs[i]) + 1;
+ }
+
+ ret = __of_changeset_add_update_property_copy(ocs, np, name, value,
+ total, update);
+
+ kfree(value);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__of_changeset_add_update_property_string_list);