Re: [RFC 3/3] usb/gadget: f_uvc: add configfs support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Andrzej,

On Thu, Jul 17, 2014 at 02:42:19PM +0200, Andrzej Pietrasiewicz wrote:
> Add support for using uvc as a component of a composite gadget
> set up with configfs.
> 
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
> ---
>  Documentation/ABI/testing/configfs-usb-gadget-uvc |   11 +
>  drivers/usb/gadget/Kconfig                        |   11 +
>  drivers/usb/gadget/function/Makefile              |    2 +-
>  drivers/usb/gadget/function/f_uvc.c               |   94 +
>  drivers/usb/gadget/function/u_uvc.h               |   19 +
>  drivers/usb/gadget/function/uvc_configfs.c        | 2928 +++++++++++++++++++++
>  drivers/usb/gadget/function/uvc_configfs.h        |  283 ++
>  7 files changed, 3347 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uvc
>  create mode 100644 drivers/usb/gadget/function/uvc_configfs.c
>  create mode 100644 drivers/usb/gadget/function/uvc_configfs.h
> 
> diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc
> new file mode 100644
> index 0000000..b3b4ba5
> --- /dev/null
> +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc
> @@ -0,0 +1,11 @@
> +What:		/config/usb-gadget/gadget/functions/uvc.name
> +Date:		Oct 2014
> +KenelVersion:	3.18
> +Description:
> +		The attributes:
> +
> +		streaming_interval	- 1..16
> +		streaming_maxpacket	- 1..1023 (fs), 1..3072 (hs/ss)
> +		streaming_maxburst	- 0..15 (ss only)
> +		trace			- trace level bitmask,
> +					  common for all uvc instances
> diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
> index 4b3d4e9..ce55234 100644
> --- a/drivers/usb/gadget/Kconfig
> +++ b/drivers/usb/gadget/Kconfig
> @@ -356,6 +356,17 @@ config USB_CONFIGFS_F_FS
>  	  implemented in kernel space (for instance Ethernet, serial or
>  	  mass storage) and other are implemented in user space.
>  
> +config USB_CONFIGFS_F_UVC
> +	boolean "USB Webcam function"	  
> +	depends on USB_CONFIGFS
> +	depends on VIDEO_DEV
> +	select VIDEOBUF2_VMALLOC
> +	select USB_F_UVC
> +	help
> +	  The Webcam function acts as a composite USB Audio and Video Class
> +	  device. It provides a userspace API to process UVC control requests
> +	  and stream video data to the host.
> +
>  source "drivers/usb/gadget/legacy/Kconfig"
>  
>  endchoice
> diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
> index ad80f21..94391f3 100644
> --- a/drivers/usb/gadget/function/Makefile
> +++ b/drivers/usb/gadget/function/Makefile
> @@ -32,5 +32,5 @@ usb_f_mass_storage-y		:= f_mass_storage.o storage_common.o
>  obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o
>  usb_f_fs-y			:= f_fs.o
>  obj-$(CONFIG_USB_F_FS)		+= usb_f_fs.o
> -usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
> +usb_f_uvc-y			:= f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
>  obj-$(CONFIG_USB_F_UVC)		+= usb_f_uvc.o
> diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
> index 9d22928..10ad916 100644
> --- a/drivers/usb/gadget/function/f_uvc.c
> +++ b/drivers/usb/gadget/function/f_uvc.c
> @@ -28,6 +28,7 @@
>  #include <media/v4l2-event.h>
>  
>  #include "uvc.h"
> +#include "uvc_configfs.h"
>  #include "uvc_v4l2.h"
>  #include "uvc_video.h"
>  #include "u_uvc.h"
> @@ -467,6 +468,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
>  		break;
>  	}
>  
> +	if (!uvc_control_desc || !uvc_streaming_cls)
> +		return ERR_PTR(-ENODEV);
> +
>  	/* Descriptors layout
>  	 *
>  	 * uvc_iad
> @@ -642,6 +646,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
>  	uvc_streaming_intf_alt0.iInterface = ret;
>  	uvc_streaming_intf_alt1.iInterface = ret;
>  
> +
>  	/* Allocate interface IDs. */
>  	if ((ret = usb_interface_id(c, f)) < 0)
>  		goto error;
> @@ -657,10 +662,25 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
>  
>  	/* Copy descriptors */
>  	f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
> +	if (IS_ERR(f->fs_descriptors)) {
> +		ret = PTR_ERR(f->fs_descriptors);
> +		f->fs_descriptors = NULL;
> +		goto error;
> +	}
>  	if (gadget_is_dualspeed(cdev->gadget))
>  		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
> +	if (IS_ERR(f->hs_descriptors)) {
> +		ret = PTR_ERR(f->hs_descriptors);
> +		f->hs_descriptors = NULL;
> +		goto error;
> +	}
>  	if (gadget_is_superspeed(c->cdev->gadget))
>  		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
> +	if (IS_ERR(f->ss_descriptors)) {
> +		ret = PTR_ERR(f->ss_descriptors);
> +		f->ss_descriptors = NULL;
> +		goto error;
> +	}
>  
>  	/* Preallocate control endpoint request. */
>  	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
> @@ -735,16 +755,87 @@ static struct usb_function_instance *uvc_alloc_inst(void)
>  	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
>  	if (!opts)
>  		return ERR_PTR(-ENOMEM);
> +	mutex_init(&opts->lock);
>  	opts->func_inst.free_func_inst = uvc_free_inst;
>  
> +	config_group_init_type_name(&f_uvc_header_group, "header",
> +				    &f_uvc_header_type);
> +	config_group_init_type_name(&f_uvc_processing_group, "processing",
> +				    &f_uvc_processing_type);
> +	config_group_init_type_name(&f_uvc_class_fs_group, "fs",
> +				    &f_uvc_class_fs_type);
> +	config_group_init_type_name(&f_uvc_class_ss_group, "ss",
> +				    &f_uvc_class_ss_type);
> +	f_uvc_class_group.default_groups = f_uvc_class_default_groups;
> +	config_group_init_type_name(&f_uvc_class_group, "class",
> +				    &f_uvc_class_type);
> +	config_group_init_type_name(&f_uvc_camera_group, "camera",
> +				    &f_uvc_camera_type);
> +	config_group_init_type_name(&f_uvc_output_group, "output",
> +				    &f_uvc_output_type);
> +	f_uvc_terminal_group.default_groups = f_uvc_terminal_default_groups;
> +	config_group_init_type_name(&f_uvc_terminal_group, "terminal",
> +				    &f_uvc_terminal_type);
> +	f_uvc_control_group.group.default_groups = f_uvc_control_default_groups;
> +	INIT_LIST_HEAD(&f_uvc_control_group.known_targets);
> +	config_group_init_type_name(&f_uvc_control_group.group, "control",
> +				    &f_uvc_control_type);
> +	config_group_init_type_name(&f_uvc_input_header_group, "input_header",
> +				    &f_uvc_input_header_type);
> +	config_group_init_type_name(&f_uvc_color_matching_group, "color_matching",
> +				    &f_uvc_color_matching_type);
> +	config_group_init_type_name(&f_uvc_streaming_fs_group, "fs",
> +				    &f_uvc_streaming_fs_type);
> +	config_group_init_type_name(&f_uvc_streaming_hs_group, "hs",
> +				    &f_uvc_streaming_hs_type);
> +	config_group_init_type_name(&f_uvc_streaming_ss_group, "ss",
> +				    &f_uvc_streaming_ss_type);
> +	f_uvc_streaming_class_group.default_groups =
> +		f_uvc_streaming_class_default_groups;
> +	config_group_init_type_name(&f_uvc_streaming_class_group, "class",
> +				    &f_uvc_streaming_class_type);
> +	config_group_init_type_name(&f_uvc_frame_yuv_group, "yuv",
> +				    &f_uvc_frame_yuv_type);
> +	config_group_init_type_name(&f_uvc_frame_mjpeg_group, "mjpeg",
> +				    &f_uvc_frame_mjpeg_type);
> +	f_uvc_frame_group.default_groups = f_uvc_frame_default_groups;
> +	config_group_init_type_name(&f_uvc_frame_group, "frame",
> +				    &f_uvc_frame_type);
> +	config_group_init_type_name(&f_uvc_format_yuv_group, "yuv",
> +				    &f_uvc_format_yuv_type);
> +	config_group_init_type_name(&f_uvc_format_mjpeg_group, "mjpeg",
> +				    &f_uvc_format_mjpeg_type);
> +	f_uvc_format_group.group.default_groups = f_uvc_format_default_groups;
> +	INIT_LIST_HEAD(&f_uvc_format_group.known_targets);
> +	config_group_init_type_name(&f_uvc_format_group.group, "format",
> +				    &f_uvc_format_type);
> +	f_uvc_streaming_group.group.default_groups = f_uvc_streaming_default_groups;
> +	INIT_LIST_HEAD(&f_uvc_streaming_group.known_targets);
> +	config_group_init_type_name(&f_uvc_streaming_group.group, "streaming",
> +				    &f_uvc_streaming_type);
> +	opts->func_inst.group.default_groups = f_uvc_default_groups;
> +	opts->fs_class = &f_uvc_class_fs_group.cg_item;
> +	opts->ss_class = &f_uvc_class_ss_group.cg_item;
> +	opts->fs_streaming_class = &f_uvc_streaming_fs_group.cg_item;
> +	opts->hs_streaming_class = &f_uvc_streaming_hs_group.cg_item;
> +	opts->ss_streaming_class = &f_uvc_streaming_ss_group.cg_item;
> +	INIT_LIST_HEAD(&opts->known_targets);
> +	config_group_init_type_name(&opts->func_inst.group, "",
> +				    &uvc_func_type);
> +
>  	return &opts->func_inst;
>  }
>  
>  static void uvc_free(struct usb_function *f)
>  {
>  	struct uvc_device *uvc = to_uvc(f);
> +	struct f_uvc_opts *opts;
>  
> +	opts = container_of(f->fi, struct f_uvc_opts, func_inst);
>  	kfree(uvc);

How about to_f_uvc_opts instead of container_of here?

[snip]

I am trying to work with your patches. It was possible
to compile and run this together with your other f_uvc series.

Now I tried the configfs instructions in the coverletter together
with the dummy_udc.0. On this udc it was possible to load
webcam.ko. But the configfs implementation does bailout on uvc_copy_descriptors:


        if (!uvc_control_desc || !uvc_streaming_cl)
               return ERR_PTR(-ENODEV);


root@virtual:/cfg/usb_gadget/g1 echo dummy_udc.0 > UDC
configfs-gadget gadget: uvc_function_bind
configfs-gadget dummy_udc.0: failed to start g1: -19
sh: write error: No such device

Regards,
Michael


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux