usb: gadget: uvc: Allow linking function to string descs

Currently the string descriptors for the IAD and VideoStreaming
Interfaces are hardcoded into f_uvc. Now that we can create arbitrary
string descriptors, add a mechanism to define string descriptors for
the IAD, VC and VS interfaces by linking to the appropriate directory
at function level.

Signed-off-by: Daniel Scally <dan.scally@ideasonboard.com>
Link: https://lore.kernel.org/r/20230206161802.892954-11-dan.scally@ideasonboard.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Daniel Scally 2023-02-06 16:18:01 +00:00 committed by Greg Kroah-Hartman
parent 9963f7440f
commit fe62575537
2 changed files with 68 additions and 0 deletions

View file

@ -82,6 +82,14 @@ struct f_uvc_opts {
struct uvc_descriptor_header **uvc_hs_streaming_cls;
struct uvc_descriptor_header **uvc_ss_streaming_cls;
/*
* Indexes into the function's string descriptors allowing users to set
* custom descriptions rather than the hard-coded defaults.
*/
u8 iad_index;
u8 vs0_index;
u8 vs1_index;
/*
* Read/write access to configfs attributes is handled by configfs.
*

View file

@ -3174,8 +3174,68 @@ static void uvc_func_item_release(struct config_item *item)
usb_put_function_instance(&opts->func_inst);
}
static int uvc_func_allow_link(struct config_item *src, struct config_item *tgt)
{
struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
struct gadget_string *string;
struct config_item *strings;
struct f_uvc_opts *opts;
int ret = 0;
mutex_lock(su_mutex); /* for navigating configfs hierarchy */
/* Validate that the target is an entry in strings/<langid> */
strings = config_group_find_item(to_config_group(src->ci_parent->ci_parent),
"strings");
if (!strings || tgt->ci_parent->ci_parent != strings) {
ret = -EINVAL;
goto put_strings;
}
string = to_gadget_string(tgt);
opts = to_f_uvc_opts(src);
mutex_lock(&opts->lock);
if (!strcmp(tgt->ci_name, "iad_desc"))
opts->iad_index = string->usb_string.id;
else if (!strcmp(tgt->ci_name, "vs0_desc"))
opts->vs0_index = string->usb_string.id;
else if (!strcmp(tgt->ci_name, "vs1_desc"))
opts->vs1_index = string->usb_string.id;
else
ret = -EINVAL;
mutex_unlock(&opts->lock);
put_strings:
config_item_put(strings);
mutex_unlock(su_mutex);
return ret;
}
static void uvc_func_drop_link(struct config_item *src, struct config_item *tgt)
{
struct f_uvc_opts *opts;
opts = to_f_uvc_opts(src);
mutex_lock(&opts->lock);
if (!strcmp(tgt->ci_name, "iad_desc"))
opts->iad_index = 0;
else if (!strcmp(tgt->ci_name, "vs0_desc"))
opts->vs0_index = 0;
else if (!strcmp(tgt->ci_name, "vs1_desc"))
opts->vs1_index = 0;
mutex_unlock(&opts->lock);
}
static struct configfs_item_operations uvc_func_item_ops = {
.release = uvc_func_item_release,
.allow_link = uvc_func_allow_link,
.drop_link = uvc_func_drop_link,
};
#define UVCG_OPTS_ATTR(cname, aname, limit) \