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

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

 



Hi Andrzej,

Thank you for the patch.

git am complains with

Applying: usb/gadget: f_uvc: add configfs support
/home/laurent/src/kernel/media.git/.git/rebase-apply/patch:40: trailing 
whitespace.
        boolean "USB Webcam function"     
warning: 1 line adds whitespace errors.

Could you please fix that ?

On Friday 28 February 2014 10:32:30 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/Makefile                       |    2 +-
>  drivers/usb/gadget/f_uvc.c                        |   97 +-
>  drivers/usb/gadget/u_uvc.h                        |   19 +
>  drivers/usb/gadget/uvc_configfs.c                 | 2928 ++++++++++++++++++
>  drivers/usb/gadget/uvc_configfs.h                 |  283 ++
>  7 files changed, 3348 insertions(+), 3 deletions(-)
>  create mode 100644 Documentation/ABI/testing/configfs-usb-gadget-uvc
>  create mode 100644 drivers/usb/gadget/uvc_configfs.c
>  create mode 100644 drivers/usb/gadget/uvc_configfs.h

[snip]

> diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
> index bbadc0a..31e8bed 100644
> --- a/drivers/usb/gadget/f_uvc.c
> +++ b/drivers/usb/gadget/f_uvc.c
> @@ -31,6 +31,7 @@
>  #include "u_uvc.h"
>  #include "uvc_video.h"
>  #include "uvc_v4l2.h"
> +#include "uvc_configfs.h"

Please keep the headers sorted alphabetically.

>  unsigned int uvc_gadget_trace_param;
> 
> @@ -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);
> +

Is this a configfs-specific problem ? If not it should be moved to a separate 
patch.

>  	/* Descriptors layout
>  	 *
>  	 * uvc_iad
> @@ -658,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;
> +	}

Same comment here. Should't you also handle the case where 
uvc_copy_descriptors() returns NULL ? It seems a pretty fatal error too.

> 
>  	/* Preallocate control endpoint request. */
>  	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
> @@ -738,17 +757,88 @@ 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;
> +	struct f_uvc_opts *opts;
> 
>  	uvc = to_uvc(f);
> +	opts = container_of(f->fi, struct f_uvc_opts, func_inst);
>  	kfree(uvc);
> +	mutex_lock(&opts->lock);
> +	--opts->refcnt;
> +	mutex_unlock(&opts->lock);
>  }
> 
>  static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
> @@ -778,14 +868,17 @@ struct usb_function *uvc_alloc(struct
> usb_function_instance *fi) if (uvc == NULL)
>  		return ERR_PTR(-ENOMEM);
> 
> -	uvc->state = UVC_STATE_DISCONNECTED;
>  	opts = container_of(fi, struct f_uvc_opts, func_inst);
> -
> +	mutex_lock(&opts->lock);
> +	++opts->refcnt;
>  	uvc->desc.fs_control = opts->fs_control;
>  	uvc->desc.ss_control = opts->ss_control;
>  	uvc->desc.fs_streaming = opts->fs_streaming;
>  	uvc->desc.hs_streaming = opts->hs_streaming;
>  	uvc->desc.ss_streaming = opts->ss_streaming;
> +	mutex_unlock(&opts->lock);
> +
> +	uvc->state = UVC_STATE_DISCONNECTED;
> 
>  	/* Register the function. */
>  	uvc->func.name = "uvc";
> diff --git a/drivers/usb/gadget/u_uvc.h b/drivers/usb/gadget/u_uvc.h
> index 1909ad5..8277fdf 100644
> --- a/drivers/usb/gadget/u_uvc.h
> +++ b/drivers/usb/gadget/u_uvc.h
> @@ -29,6 +29,25 @@ struct f_uvc_opts {
>  	const struct uvc_descriptor_header * const	*fs_streaming;
>  	const struct uvc_descriptor_header * const	*hs_streaming;
>  	const struct uvc_descriptor_header * const	*ss_streaming;
> +
> +	/*
> +	 * Read/write access to configfs attributes is handled by configfs.
> +	 *
> +	 * This is to protect the data from concurrent access by read/write
> +	 * and create symlink/remove symlink.

This sounds like a pretty common problem to me, shouldn't it be handled by the 
configfs core ?

> +	 */
> +	struct mutex			lock;
> +	int				refcnt;
> +	/*
> +	 * In uvc function's configfs directory there will be symbolic links.
> +	 * The allowed targets are in the "known_targets" list.
> +	 */
> +	struct list_head		known_targets;
> +	struct config_item		*fs_class;
> +	struct config_item		*ss_class;
> +	struct config_item		*fs_streaming_class;
> +	struct config_item		*ss_streaming_class;
> +	struct config_item		*hs_streaming_class;
>  };
> 
>  void uvc_set_trace_param(unsigned int uvc_gadget_trace_param_webcam);
> diff --git a/drivers/usb/gadget/uvc_configfs.c
> b/drivers/usb/gadget/uvc_configfs.c new file mode 100644
> index 0000000..2031114
> --- /dev/null
> +++ b/drivers/usb/gadget/uvc_configfs.c
> @@ -0,0 +1,2928 @@
> +/*
> + * uvc_configfs.c
> + *
> + * Configfs hierarchy definitions for the uvc function
> + *
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Author: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include "uvc_configfs.h"
> +#include "configfs.h"
> +#include "u_uvc.h"

Please sort the headers here too.

I'll have to learn about configfs to understand the code below, that will take 
a bit more time. I propose sorting out the rest of the issues I've pointed out 
for the patch set and work on getting patches 1/8 to 7/8 mainlined in the 
meantime.

> diff --git a/drivers/usb/gadget/uvc_configfs.h
> b/drivers/usb/gadget/uvc_configfs.h new file mode 100644
> index 0000000..13f554f
> --- /dev/null
> +++ b/drivers/usb/gadget/uvc_configfs.h
> @@ -0,0 +1,283 @@
> +/*
> + * uvc_configfs.h
> + *
> + * Configfs hierarchy definitions for the uvc function
> + *
> + * Copyright (c) 2014 Samsung Electronics Co., Ltd.
> + *		http://www.samsung.com
> + *
> + * Author: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef UVC_CONFIGFS_H
> +#define UVC_CONFIGFS_H

The UVC gadget headers are guarded by

_F_UVC_H_
U_UVC_H
_UVC_GADGET_H_
UVC_CONFIGFS_H
_UVC_QUEUE_H_
__UVC__V4L2__H__
__UVC__VIDEO__H__

I propose standardizing it to

__F_UVC_H__
__U_UVC_H__
__UVC_GADGET_H__
__UVC_CONFIGFS_H__
__UVC_QUEUE_H__
__UVC_V4L2_H__
__UVC_VIDEO_H__

or

_F_UVC_H_
_U_UVC_H_
_UVC_GADGET_H_
_UVC_CONFIGFS_H_
_UVC_QUEUE_H_
_UVC_V4L2_H_
_UVC_VIDEO_H_

> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/configfs.h>
> +#include <linux/usb/video.h>

Usual comment :-)

[snip]

> +
> +#endif /* UVC_CONFIGFS_H */

-- 
Regards,

Laurent Pinchart

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