usb: gadget: f_uac2: allow changing interface name via configfs
authorYunhao Tian <t123yh.xyz@gmail.com>
Sat, 22 Jan 2022 11:24:41 +0000 (19:24 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Jan 2022 13:10:44 +0000 (14:10 +0100)
This adds "function_name" configfs entry to change string value
of the iInterface field. This field will be shown in Windows' audio
settings panel, so being able to change it is useful. It will default
to "Source/Sink" just as before.

Signed-off-by: Yunhao Tian <t123yh.xyz@gmail.com>
Link: https://lore.kernel.org/r/20220122112446.1415547-2-t123yh.xyz@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/configfs-usb-gadget-uac2
Documentation/usb/gadget-testing.rst
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/function/u_uac2.h

index 9d2f59ab9701f88c82f7691d677909c1de4bb9de..4c6bf63fcb224b720d4eceb567c3b7b970d7966f 100644 (file)
@@ -32,4 +32,5 @@ Description:
                                        (in 1/256 dB)
                req_number              the number of pre-allocated requests
                                        for both capture and playback
+               function_name           name of the interface
                =====================   =======================================
index 1792bd88f666018422f076275df36b7656a37a4a..6e8fdfaf19e7bd3215ea186e7a5d56baa32e4eb6 100644 (file)
@@ -934,6 +934,7 @@ The uac1 function provides these attributes in its function directory:
        p_volume_res     playback volume control resolution (in 1/256 dB)
        req_number       the number of pre-allocated requests for both capture
                         and playback
+       function_name    name of the interface
        ================ ====================================================
 
 The attributes have sane default values.
index 3e6339439b887948e9884ca69986988a2e4cac8e..d874e0d341886a805e018f23bec687acef87a477 100644 (file)
@@ -107,7 +107,7 @@ enum {
 };
 
 static struct usb_string strings_fn[] = {
-       [STR_ASSOC].s = "Source/Sink",
+       /* [STR_ASSOC].s = DYNAMIC, */
        [STR_IF_CTRL].s = "Topology Control",
        [STR_CLKSRC_IN].s = "Input Clock",
        [STR_CLKSRC_OUT].s = "Output Clock",
@@ -984,6 +984,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
        if (ret)
                return ret;
 
+       strings_fn[STR_ASSOC].s = uac2_opts->function_name;
+
        us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
        if (IS_ERR(us))
                return PTR_ERR(us);
@@ -1963,6 +1965,42 @@ end:                                                                     \
                                                                        \
 CONFIGFS_ATTR(f_uac2_opts_, name)
 
+#define UAC2_ATTRIBUTE_STRING(name)                                    \
+static ssize_t f_uac2_opts_##name##_show(struct config_item *item,     \
+                                        char *page)                    \
+{                                                                      \
+       struct f_uac2_opts *opts = to_f_uac2_opts(item);                \
+       int result;                                                     \
+                                                                       \
+       mutex_lock(&opts->lock);                                        \
+       result = snprintf(page, sizeof(opts->name), "%s", opts->name);  \
+       mutex_unlock(&opts->lock);                                      \
+                                                                       \
+       return result;                                                  \
+}                                                                      \
+                                                                       \
+static ssize_t f_uac2_opts_##name##_store(struct config_item *item,    \
+                                         const char *page, size_t len) \
+{                                                                      \
+       struct f_uac2_opts *opts = to_f_uac2_opts(item);                \
+       int ret = 0;                                                    \
+                                                                       \
+       mutex_lock(&opts->lock);                                        \
+       if (opts->refcnt) {                                             \
+               ret = -EBUSY;                                           \
+               goto end;                                               \
+       }                                                               \
+                                                                       \
+       ret = snprintf(opts->name, min(sizeof(opts->name), len),        \
+                       "%s", page);                                    \
+                                                                       \
+end:                                                                   \
+       mutex_unlock(&opts->lock);                                      \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+CONFIGFS_ATTR(f_uac2_opts_, name)
+
 UAC2_ATTRIBUTE(u32, p_chmask);
 UAC2_RATE_ATTRIBUTE(p_srate);
 UAC2_ATTRIBUTE(u32, p_ssize);
@@ -1984,6 +2022,7 @@ UAC2_ATTRIBUTE(s16, c_volume_min);
 UAC2_ATTRIBUTE(s16, c_volume_max);
 UAC2_ATTRIBUTE(s16, c_volume_res);
 UAC2_ATTRIBUTE(u32, fb_max);
+UAC2_ATTRIBUTE_STRING(function_name);
 
 static struct configfs_attribute *f_uac2_attrs[] = {
        &f_uac2_opts_attr_p_chmask,
@@ -2008,6 +2047,8 @@ static struct configfs_attribute *f_uac2_attrs[] = {
        &f_uac2_opts_attr_c_volume_max,
        &f_uac2_opts_attr_c_volume_res,
 
+       &f_uac2_opts_attr_function_name,
+
        NULL,
 };
 
@@ -2061,6 +2102,9 @@ static struct usb_function_instance *afunc_alloc_inst(void)
 
        opts->req_number = UAC2_DEF_REQ_NUM;
        opts->fb_max = FBACK_FAST_MAX;
+
+       snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
+
        return &opts->func_inst;
 }
 
index 6bfcf6d0e863b817e7a5543434f9bb4d7a9a0b1a..ed96c7c853e452ecce34d5f8e80cf1c1cb59f053 100644 (file)
@@ -59,6 +59,8 @@ struct f_uac2_opts {
        int                             fb_max;
        bool                    bound;
 
+       char                    function_name[32];
+
        struct mutex                    lock;
        int                             refcnt;
 };