usb: gadget: uvc: Allow linking XUs to string descriptors
authorDaniel Scally <dan.scally@ideasonboard.com>
Mon, 6 Feb 2023 16:17:59 +0000 (16:17 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 7 Feb 2023 07:46:37 +0000 (08:46 +0100)
Add .allow_link() and .drop_link() callbacks to allow users to link
an extension unit descriptor to a string descriptor.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Link: https://lore.kernel.org/r/20230206161802.892954-9-dan.scally@ideasonboard.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/gadget/function/uvc_configfs.h

index c365f323af45ac810d6a3a838c7bcd6cfd703b29..3ac27838514c6da8f4b4bf3f791a924736672a8c 100644 (file)
@@ -1064,8 +1064,60 @@ static void uvcg_extension_release(struct config_item *item)
        kfree(xu);
 }
 
+static int uvcg_extension_allow_link(struct config_item *src, struct config_item *tgt)
+{
+       struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+       struct uvcg_extension *xu = to_uvcg_extension(src);
+       struct config_item *gadget_item;
+       struct gadget_string *string;
+       struct config_item *strings;
+       int ret = 0;
+
+       mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+       /* Validate that the target of the link is an entry in strings/<langid> */
+       gadget_item = src->ci_parent->ci_parent->ci_parent->ci_parent->ci_parent;
+       strings = config_group_find_item(to_config_group(gadget_item), "strings");
+       if (!strings || tgt->ci_parent->ci_parent != strings) {
+               ret = -EINVAL;
+               goto put_strings;
+       }
+
+       string = to_gadget_string(tgt);
+       xu->string_descriptor_index = string->usb_string.id;
+
+put_strings:
+       config_item_put(strings);
+       mutex_unlock(su_mutex);
+
+       return ret;
+}
+
+static void uvcg_extension_drop_link(struct config_item *src, struct config_item *tgt)
+{
+       struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+       struct uvcg_extension *xu = to_uvcg_extension(src);
+       struct config_item *opts_item;
+       struct f_uvc_opts *opts;
+
+       mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+       opts_item = src->ci_parent->ci_parent->ci_parent;
+       opts = to_f_uvc_opts(opts_item);
+
+       mutex_lock(&opts->lock);
+
+       xu->string_descriptor_index = 0;
+
+       mutex_unlock(&opts->lock);
+
+       mutex_unlock(su_mutex);
+}
+
 static struct configfs_item_operations uvcg_extension_item_ops = {
        .release        = uvcg_extension_release,
+       .allow_link     = uvcg_extension_allow_link,
+       .drop_link      = uvcg_extension_drop_link,
 };
 
 static const struct config_item_type uvcg_extension_type = {
index 5557813bcca9edf0fb2a2fa3e851ef08e478d3b0..c6a690158138fea9dcda2aaf9aa47f521096a770 100644 (file)
@@ -163,6 +163,7 @@ struct uvcg_extension_unit_descriptor {
 struct uvcg_extension {
        struct config_item item;
        struct list_head list;
+       u8 string_descriptor_index;
        struct uvcg_extension_unit_descriptor desc;
 };