usb: gadget: f_uac2: allow changing interface name via configfs

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>
This commit is contained in:
Yunhao Tian 2022-01-22 19:24:41 +08:00 committed by Greg Kroah-Hartman
parent dfb05b5dc3
commit 993a44fa85
4 changed files with 49 additions and 1 deletions

View 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
===================== =======================================

View 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.

View 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;
}

View File

@ -59,6 +59,8 @@ struct f_uac2_opts {
int fb_max;
bool bound;
char function_name[32];
struct mutex lock;
int refcnt;
};