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:
parent
9963f7440f
commit
fe62575537
@ -82,6 +82,14 @@ struct f_uvc_opts {
|
|||||||
struct uvc_descriptor_header **uvc_hs_streaming_cls;
|
struct uvc_descriptor_header **uvc_hs_streaming_cls;
|
||||||
struct uvc_descriptor_header **uvc_ss_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.
|
* Read/write access to configfs attributes is handled by configfs.
|
||||||
*
|
*
|
||||||
|
@ -3174,8 +3174,68 @@ static void uvc_func_item_release(struct config_item *item)
|
|||||||
usb_put_function_instance(&opts->func_inst);
|
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 = {
|
static struct configfs_item_operations uvc_func_item_ops = {
|
||||||
.release = uvc_func_item_release,
|
.release = uvc_func_item_release,
|
||||||
|
.allow_link = uvc_func_allow_link,
|
||||||
|
.drop_link = uvc_func_drop_link,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UVCG_OPTS_ATTR(cname, aname, limit) \
|
#define UVCG_OPTS_ATTR(cname, aname, limit) \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user