mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	usb: gadget: uvc: allow changing interface name via configfs
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>
This commit is contained in:
		
							parent
							
								
									3123109284
								
							
						
					
					
						commit
						324e4f8507
					
				
					 5 changed files with 47 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue