Hi all - apologies, meant to add this discussion point before sending
On 21/11/2022 09:25, Daniel Scally wrote:
Currently the string descriptors for the IAD, VideoControl Interface
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@xxxxxxxxxxxxxxxx>
---
Changes in v2:
- New patch
drivers/usb/gadget/function/u_uvc.h | 8 +++
drivers/usb/gadget/function/uvc_configfs.c | 59 ++++++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index c1c9ea5931d3..331cdf5ba9c8 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -88,6 +88,14 @@ struct f_uvc_opts {
struct list_head languages;
unsigned int nlangs;
+ /*
+ * 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.
*
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 5c51862150c4..e8faa31998fa 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -3197,8 +3197,67 @@ 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 config_item *strings;
+ struct uvcg_string *string;
+ 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), "strings");
+ if (!strings || tgt->ci_parent->ci_parent != strings) {
+ ret = -EINVAL;
+ goto put_strings;
+ }
+
+ string = to_uvcg_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;
Is this reliance on the name of the target to set the right internal
index an acceptable method? I wasn't quite sure, but it seemed like the
simplest way to do it.
+
+ 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) \