usb: gadget: uvc: allow changing interface name via configfs
authorDan Vacura <w36195@motorola.com>
Fri, 1 Apr 2022 16:04:45 +0000 (11:04 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 21 Apr 2022 16:14:34 +0000 (18:14 +0200)
Add a configfs entry, "function_name", to change the iInterface field
for VideoControl. This name is used on host devices for user selection,
useful when multiple cameras are present. The default will remain "UVC
Camera".

Signed-off-by: Dan Vacura <w36195@motorola.com>
Link: https://lore.kernel.org/r/20220401160447.5919-1-w36195@motorola.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/configfs-usb-gadget-uvc
Documentation/usb/gadget-testing.rst
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/function/u_uvc.h
drivers/usb/gadget/function/uvc_configfs.c

index 889ed45..611b23e 100644 (file)
@@ -7,6 +7,7 @@ Description:    UVC function directory
                streaming_maxburst      0..15 (ss only)
                streaming_maxpacket     1..1023 (fs), 1..3072 (hs/ss)
                streaming_interval      1..16
+               function_name           string [32]
                ===================     =============================
 
 What:          /config/usb-gadget/gadget/functions/uvc.name/control
index c6d034a..1c37159 100644 (file)
@@ -787,6 +787,7 @@ The uvc function provides these attributes in its function directory:
        streaming_maxpacket maximum packet size this endpoint is capable of
                            sending or receiving when this configuration is
                            selected
+       function_name       name of the interface
        =================== ================================================
 
 There are also "control" and "streaming" subdirectories, each of which contain
index 71bb5e4..50e6e7a 100644 (file)
@@ -44,7 +44,7 @@ MODULE_PARM_DESC(trace, "Trace level bitmask");
 #define UVC_STRING_STREAMING_IDX               1
 
 static struct usb_string uvc_en_us_strings[] = {
-       [UVC_STRING_CONTROL_IDX].s = "UVC Camera",
+       /* [UVC_STRING_CONTROL_IDX].s = DYNAMIC, */
        [UVC_STRING_STREAMING_IDX].s = "Video Streaming",
        {  }
 };
@@ -676,6 +676,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
        uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
 
+       uvc_en_us_strings[UVC_STRING_CONTROL_IDX].s = opts->function_name;
        us = usb_gstrings_attach(cdev, uvc_function_strings,
                                 ARRAY_SIZE(uvc_en_us_strings));
        if (IS_ERR(us)) {
@@ -866,6 +867,7 @@ static struct usb_function_instance *uvc_alloc_inst(void)
 
        opts->streaming_interval = 1;
        opts->streaming_maxpacket = 1024;
+       snprintf(opts->function_name, sizeof(opts->function_name), "UVC Camera");
 
        ret = uvcg_attach_configfs(opts);
        if (ret < 0) {
index 9a01a7d..24b8681 100644 (file)
@@ -27,6 +27,7 @@ struct f_uvc_opts {
 
        unsigned int                                    control_interface;
        unsigned int                                    streaming_interface;
+       char                                            function_name[32];
 
        /*
         * Control descriptors array pointers for full-/high-speed and
index 77d6403..63b8d37 100644 (file)
@@ -2425,10 +2425,51 @@ UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
 
 #undef UVCG_OPTS_ATTR
 
+#define UVCG_OPTS_STRING_ATTR(cname, aname)                            \
+static ssize_t f_uvc_opts_string_##cname##_show(struct config_item *item,\
+                                        char *page)                    \
+{                                                                      \
+       struct f_uvc_opts *opts = to_f_uvc_opts(item);                  \
+       int result;                                                     \
+                                                                       \
+       mutex_lock(&opts->lock);                                        \
+       result = snprintf(page, sizeof(opts->aname), "%s", opts->aname);\
+       mutex_unlock(&opts->lock);                                      \
+                                                                       \
+       return result;                                                  \
+}                                                                      \
+                                                                       \
+static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
+                                         const char *page, size_t len) \
+{                                                                      \
+       struct f_uvc_opts *opts = to_f_uvc_opts(item);                  \
+       int ret = 0;                                                    \
+                                                                       \
+       mutex_lock(&opts->lock);                                        \
+       if (opts->refcnt) {                                             \
+               ret = -EBUSY;                                           \
+               goto end;                                               \
+       }                                                               \
+                                                                       \
+       ret = snprintf(opts->aname, min(sizeof(opts->aname), len),      \
+                       "%s", page);                                    \
+                                                                       \
+end:                                                                   \
+       mutex_unlock(&opts->lock);                                      \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+UVC_ATTR(f_uvc_opts_string_, cname, aname)
+
+UVCG_OPTS_STRING_ATTR(function_name, function_name);
+
+#undef UVCG_OPTS_STRING_ATTR
+
 static struct configfs_attribute *uvc_attrs[] = {
        &f_uvc_opts_attr_streaming_interval,
        &f_uvc_opts_attr_streaming_maxpacket,
        &f_uvc_opts_attr_streaming_maxburst,
+       &f_uvc_opts_string_attr_function_name,
        NULL,
 };