mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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:
		
							parent
							
								
									dfb05b5dc3
								
							
						
					
					
						commit
						993a44fa85
					
				
					 4 changed files with 49 additions and 1 deletions
				
			
		| 
						 | 
					@ -32,4 +32,5 @@ Description:
 | 
				
			||||||
					(in 1/256 dB)
 | 
										(in 1/256 dB)
 | 
				
			||||||
		req_number		the number of pre-allocated requests
 | 
							req_number		the number of pre-allocated requests
 | 
				
			||||||
					for both capture and playback
 | 
										for both capture and playback
 | 
				
			||||||
 | 
							function_name		name of the interface
 | 
				
			||||||
		=====================	=======================================
 | 
							=====================	=======================================
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
						p_volume_res     playback volume control resolution (in 1/256 dB)
 | 
				
			||||||
	req_number       the number of pre-allocated requests for both capture
 | 
						req_number       the number of pre-allocated requests for both capture
 | 
				
			||||||
	                 and playback
 | 
						                 and playback
 | 
				
			||||||
 | 
						function_name    name of the interface
 | 
				
			||||||
	================ ====================================================
 | 
						================ ====================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The attributes have sane default values.
 | 
					The attributes have sane default values.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ enum {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct usb_string strings_fn[] = {
 | 
					static struct usb_string strings_fn[] = {
 | 
				
			||||||
	[STR_ASSOC].s = "Source/Sink",
 | 
						/* [STR_ASSOC].s = DYNAMIC, */
 | 
				
			||||||
	[STR_IF_CTRL].s = "Topology Control",
 | 
						[STR_IF_CTRL].s = "Topology Control",
 | 
				
			||||||
	[STR_CLKSRC_IN].s = "Input Clock",
 | 
						[STR_CLKSRC_IN].s = "Input Clock",
 | 
				
			||||||
	[STR_CLKSRC_OUT].s = "Output Clock",
 | 
						[STR_CLKSRC_OUT].s = "Output Clock",
 | 
				
			||||||
| 
						 | 
					@ -984,6 +984,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						strings_fn[STR_ASSOC].s = uac2_opts->function_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
 | 
						us = usb_gstrings_attach(cdev, fn_strings, ARRAY_SIZE(strings_fn));
 | 
				
			||||||
	if (IS_ERR(us))
 | 
						if (IS_ERR(us))
 | 
				
			||||||
		return PTR_ERR(us);
 | 
							return PTR_ERR(us);
 | 
				
			||||||
| 
						 | 
					@ -1963,6 +1965,42 @@ end:									\
 | 
				
			||||||
									\
 | 
														\
 | 
				
			||||||
CONFIGFS_ATTR(f_uac2_opts_, name)
 | 
					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_ATTRIBUTE(u32, p_chmask);
 | 
				
			||||||
UAC2_RATE_ATTRIBUTE(p_srate);
 | 
					UAC2_RATE_ATTRIBUTE(p_srate);
 | 
				
			||||||
UAC2_ATTRIBUTE(u32, p_ssize);
 | 
					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_max);
 | 
				
			||||||
UAC2_ATTRIBUTE(s16, c_volume_res);
 | 
					UAC2_ATTRIBUTE(s16, c_volume_res);
 | 
				
			||||||
UAC2_ATTRIBUTE(u32, fb_max);
 | 
					UAC2_ATTRIBUTE(u32, fb_max);
 | 
				
			||||||
 | 
					UAC2_ATTRIBUTE_STRING(function_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct configfs_attribute *f_uac2_attrs[] = {
 | 
					static struct configfs_attribute *f_uac2_attrs[] = {
 | 
				
			||||||
	&f_uac2_opts_attr_p_chmask,
 | 
						&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_max,
 | 
				
			||||||
	&f_uac2_opts_attr_c_volume_res,
 | 
						&f_uac2_opts_attr_c_volume_res,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						&f_uac2_opts_attr_function_name,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NULL,
 | 
						NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2061,6 +2102,9 @@ static struct usb_function_instance *afunc_alloc_inst(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opts->req_number = UAC2_DEF_REQ_NUM;
 | 
						opts->req_number = UAC2_DEF_REQ_NUM;
 | 
				
			||||||
	opts->fb_max = FBACK_FAST_MAX;
 | 
						opts->fb_max = FBACK_FAST_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &opts->func_inst;
 | 
						return &opts->func_inst;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,8 @@ struct f_uac2_opts {
 | 
				
			||||||
	int				fb_max;
 | 
						int				fb_max;
 | 
				
			||||||
	bool			bound;
 | 
						bool			bound;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						char			function_name[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct mutex			lock;
 | 
						struct mutex			lock;
 | 
				
			||||||
	int				refcnt;
 | 
						int				refcnt;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue