diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2021-01-08 14:38:24 +0200 |
---|---|---|
committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2021-03-18 18:25:31 +0300 |
commit | 7d3084c0b77c6c417a16fc1c5bf3bc3149d20fab (patch) | |
tree | f0bb6a614b1a85b800b9547395a28d758dbbc4b2 | |
parent | 3bb163331e3acafb217f4259b1987e5f56b0456a (diff) | |
download | linux-7d3084c0b77c6c417a16fc1c5bf3bc3149d20fab.tar.gz linux-7d3084c0b77c6c417a16fc1c5bf3bc3149d20fab.tar.bz2 linux-7d3084c0b77c6c417a16fc1c5bf3bc3149d20fab.zip |
thunderbolt: Add tb_property_copy_dir()
This function takes a deep copy of the properties. We need this in order
to support more dynamic properties per XDomain connection as required by
the USB4 inter-domain service spec.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r-- | drivers/thunderbolt/property.c | 71 | ||||
-rw-r--r-- | include/linux/thunderbolt.h | 1 |
2 files changed, 72 insertions, 0 deletions
diff --git a/drivers/thunderbolt/property.c b/drivers/thunderbolt/property.c index d5b0cdb8f0b1..dc555cda98e6 100644 --- a/drivers/thunderbolt/property.c +++ b/drivers/thunderbolt/property.c @@ -502,6 +502,77 @@ 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 + * + * This function takes a deep copy of @dir and returns back the copy. In + * case of error returns %NULL. The resulting directory needs to be + * released by calling tb_property_free_dir(). + */ +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 diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index 7ec977161f5c..003a9ad29168 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -146,6 +146,7 @@ struct tb_property_dir *tb_property_parse_dir(const u32 *block, size_t block_len); ssize_t tb_property_format_dir(const struct tb_property_dir *dir, u32 *block, size_t block_len); +struct tb_property_dir *tb_property_copy_dir(const struct tb_property_dir *dir); struct tb_property_dir *tb_property_create_dir(const uuid_t *uuid); void tb_property_free_dir(struct tb_property_dir *dir); int tb_property_add_immediate(struct tb_property_dir *parent, const char *key, |