summaryrefslogtreecommitdiff
path: root/drivers/thunderbolt/property.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thunderbolt/property.c')
-rw-r--r--drivers/thunderbolt/property.c119
1 files changed, 111 insertions, 8 deletions
diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c
index b2f0d6386cee..31aa0516932a 100644
--- a/drivers/thunderbolt/property.c
+++ b/drivers/thunderbolt/property.c
@@ -176,6 +176,10 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
} else {
dir->uuid = kmemdup(&block[dir_offset], sizeof(*dir->uuid),
GFP_KERNEL);
+ if (!dir->uuid) {
+ tb_property_free_dir(dir);
+ return NULL;
+ }
content_offset = dir_offset + 4;
content_len = dir_len - 4; /* Length includes UUID */
}
@@ -207,11 +211,13 @@ static struct tb_property_dir *__tb_property_parse_dir(const u32 *block,
*
* This function parses the XDomain properties data block into format that
* can be traversed using the helper functions provided by this module.
- * Upon success returns the parsed directory. In case of error returns
- * %NULL. The resulting &struct tb_property_dir needs to be released by
+ *
+ * The resulting &struct tb_property_dir needs to be released by
* calling tb_property_free_dir() when not needed anymore.
*
* The @block is expected to be root directory.
+ *
+ * Return: Pointer to &struct tb_property_dir, %NULL in case of failure.
*/
struct tb_property_dir *tb_property_parse_dir(const u32 *block,
size_t block_len)
@@ -234,6 +240,8 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block,
*
* Creates new, empty property directory. If @uuid is %NULL then the
* directory is assumed to be root directory.
+ *
+ * Return: Pointer to &struct tb_property_dir, %NULL in case of failure.
*/
struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid)
{
@@ -477,9 +485,11 @@ static ssize_t __tb_property_format_dir(const struct tb_property_dir *dir,
* @block_len: Length of the property block
*
* This function formats the directory to the packed format that can be
- * then send over the thunderbolt fabric to receiving host. Returns %0 in
- * case of success and negative errno on faulure. Passing %NULL in @block
- * returns number of entries the block takes.
+ * then sent over the thunderbolt fabric to receiving host.
+ *
+ * Passing %NULL in @block returns number of entries the block takes.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
size_t block_len)
@@ -498,10 +508,83 @@ ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block,
}
/**
+ * tb_property_copy_dir() - Take a deep copy of directory
+ * @dir: Directory to copy
+ *
+ * The resulting directory needs to be released by calling tb_property_free_dir().
+ *
+ * Return: Pointer to &struct tb_property_dir, %NULL in case of failure.
+ */
+struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir)
+{
+ struct tb_property *property, *p = NULL;
+ struct tb_property_dir *d;
+
+ if (!dir)
+ return NULL;
+
+ d = tb_property_create_dir(dir->uuid);
+ if (!d)
+ return NULL;
+
+ list_for_each_entry(property, &dir->properties, list) {
+ struct tb_property *p;
+
+ p = tb_property_alloc(property->key, property->type);
+ if (!p)
+ goto err_free;
+
+ p->length = property->length;
+
+ switch (property->type) {
+ case TB_PROPERTY_TYPE_DIRECTORY:
+ p->value.dir = tb_property_copy_dir(property->value.dir);
+ if (!p->value.dir)
+ goto err_free;
+ break;
+
+ case TB_PROPERTY_TYPE_DATA:
+ p->value.data = kmemdup(property->value.data,
+ property->length * 4,
+ GFP_KERNEL);
+ if (!p->value.data)
+ goto err_free;
+ break;
+
+ case TB_PROPERTY_TYPE_TEXT:
+ p->value.text = kzalloc(p->length * 4, GFP_KERNEL);
+ if (!p->value.text)
+ goto err_free;
+ strcpy(p->value.text, property->value.text);
+ break;
+
+ case TB_PROPERTY_TYPE_VALUE:
+ p->value.immediate = property->value.immediate;
+ break;
+
+ default:
+ break;
+ }
+
+ list_add_tail(&p->list, &d->properties);
+ }
+
+ return d;
+
+err_free:
+ kfree(p);
+ tb_property_free_dir(d);
+
+ return NULL;
+}
+
+/**
* tb_property_add_immediate() - Add immediate property to directory
* @parent: Directory to add the property
* @key: Key for the property
* @value: Immediate value to store with the property
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int tb_property_add_immediate(struct tb_property_dir *parent, const char *key,
u32 value)
@@ -531,6 +614,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_immediate);
* @buflen: Number of bytes in the data buffer
*
* Function takes a copy of @buf and adds it to the directory.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int tb_property_add_data(struct tb_property_dir *parent, const char *key,
const void *buf, size_t buflen)
@@ -548,6 +633,11 @@ int tb_property_add_data(struct tb_property_dir *parent, const char *key,
property->length = size / 4;
property->value.data = kzalloc(size, GFP_KERNEL);
+ if (!property->value.data) {
+ kfree(property);
+ return -ENOMEM;
+ }
+
memcpy(property->value.data, buf, buflen);
list_add_tail(&property->list, &parent->properties);
@@ -562,6 +652,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_data);
* @text: String to add
*
* Function takes a copy of @text and adds it to the directory.
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int tb_property_add_text(struct tb_property_dir *parent, const char *key,
const char *text)
@@ -578,7 +670,12 @@ int tb_property_add_text(struct tb_property_dir *parent, const char *key,
return -ENOMEM;
property->length = size / 4;
- property->value.data = kzalloc(size, GFP_KERNEL);
+ property->value.text = kzalloc(size, GFP_KERNEL);
+ if (!property->value.text) {
+ kfree(property);
+ return -ENOMEM;
+ }
+
strcpy(property->value.text, text);
list_add_tail(&property->list, &parent->properties);
@@ -591,6 +688,8 @@ EXPORT_SYMBOL_GPL(tb_property_add_text);
* @parent: Directory to add the property
* @key: Key for the property
* @dir: Directory to add
+ *
+ * Return: %0 on success, negative errno otherwise.
*/
int tb_property_add_dir(struct tb_property_dir *parent, const char *key,
struct tb_property_dir *dir)
@@ -631,8 +730,10 @@ EXPORT_SYMBOL_GPL(tb_property_remove);
* @key: Key to look for
* @type: Type of the property
*
- * Finds and returns property from the given directory. Does not recurse
- * into sub-directories. Returns %NULL if the property was not found.
+ * Finds and returns property from the given directory. Does not
+ * recurse into sub-directories.
+ *
+ * Return: Pointer to &struct tb_property, %NULL if the property was not found.
*/
struct tb_property *tb_property_find(struct tb_property_dir *dir,
const char *key, enum tb_property_type type)
@@ -652,6 +753,8 @@ EXPORT_SYMBOL_GPL(tb_property_find);
* tb_property_get_next() - Get next property from directory
* @dir: Directory holding properties
* @prev: Previous property in the directory (%NULL returns the first)
+ *
+ * Return: Pointer to &struct tb_property, %NULL if property was not found.
*/
struct tb_property *tb_property_get_next(struct tb_property_dir *dir,
struct tb_property *prev)