usb: gadget: f_uac1: allow changing interface name via configfs
authorYunhao Tian <t123yh.xyz@gmail.com>
Sat, 22 Jan 2022 11:24:40 +0000 (19:24 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 26 Jan 2022 13:10:40 +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 "AC Interface" just as before if unchanged.

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

index 09725e273e9b846410ff7dc4e02c754e2997da37..c4ba92f004c313cf451e7ed9442c74eca0e78a93 100644 (file)
@@ -29,4 +29,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 046842b00c89ba9f0f625418e213fc3e8ac8b8cd..1792bd88f666018422f076275df36b7656a37a4a 100644 (file)
@@ -745,6 +745,7 @@ The uac2 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 request for both capture
                         and playback
+       function_name    name of the interface
        ================ ====================================================
 
 The attributes have sane default values.
index 1484e5c231d33893a01940311139cfa3afcb676e..6f0e1d803dc244d820905870dd6288bdbbd77832 100644 (file)
@@ -309,7 +309,7 @@ enum {
 };
 
 static struct usb_string strings_uac1[] = {
-       [STR_AC_IF].s = "AC Interface",
+       /* [STR_AC_IF].s = DYNAMIC, */
        [STR_USB_OUT_IT].s = "Playback Input terminal",
        [STR_USB_OUT_IT_CH_NAMES].s = "Playback Channels",
        [STR_IO_OUT_OT].s = "Playback Output terminal",
@@ -1192,6 +1192,8 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 
        audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
 
+       strings_uac1[STR_AC_IF].s = audio_opts->function_name;
+
        us = usb_gstrings_attach(cdev, uac1_strings, ARRAY_SIZE(strings_uac1));
        if (IS_ERR(us))
                return PTR_ERR(us);
@@ -1551,6 +1553,42 @@ end:                                                                     \
                                                                        \
 CONFIGFS_ATTR(f_uac1_opts_, name)
 
+#define UAC1_ATTRIBUTE_STRING(name)                                    \
+static ssize_t f_uac1_opts_##name##_show(struct config_item *item,     \
+                                        char *page)                    \
+{                                                                      \
+       struct f_uac1_opts *opts = to_f_uac1_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_uac1_opts_##name##_store(struct config_item *item,    \
+                                         const char *page, size_t len) \
+{                                                                      \
+       struct f_uac1_opts *opts = to_f_uac1_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_uac1_opts_, name)
+
 UAC1_ATTRIBUTE(u32, c_chmask);
 UAC1_RATE_ATTRIBUTE(c_srate);
 UAC1_ATTRIBUTE(u32, c_ssize);
@@ -1570,6 +1608,7 @@ UAC1_ATTRIBUTE(bool, c_volume_present);
 UAC1_ATTRIBUTE(s16, c_volume_min);
 UAC1_ATTRIBUTE(s16, c_volume_max);
 UAC1_ATTRIBUTE(s16, c_volume_res);
+UAC1_ATTRIBUTE_STRING(function_name);
 
 static struct configfs_attribute *f_uac1_attrs[] = {
        &f_uac1_opts_attr_c_chmask,
@@ -1592,6 +1631,8 @@ static struct configfs_attribute *f_uac1_attrs[] = {
        &f_uac1_opts_attr_c_volume_max,
        &f_uac1_opts_attr_c_volume_res,
 
+       &f_uac1_opts_attr_function_name,
+
        NULL,
 };
 
@@ -1643,6 +1684,9 @@ static struct usb_function_instance *f_audio_alloc_inst(void)
        opts->c_volume_res = UAC1_DEF_RES_DB;
 
        opts->req_number = UAC1_DEF_REQ_NUM;
+
+       snprintf(opts->function_name, sizeof(opts->function_name), "AC Interface");
+
        return &opts->func_inst;
 }
 
index b6cd6171d30626a5d7b4fe533b2c828fbfd51b49..f7a616760e314b0e57bdb211f0ce3bb578516925 100644 (file)
@@ -52,6 +52,8 @@ struct f_uac1_opts {
        int                             req_number;
        unsigned                        bound:1;
 
+       char                    function_name[32];
+
        struct mutex                    lock;
        int                             refcnt;
 };