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 <[email protected]>
> ---
> 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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html