[alsa-devel] [PATCH 1/2] usbtv: split core and video implementation

Lubomir Rintel lkundrak at v3.sk
Sun Jan 5 17:37:05 CET 2014


Hi Federico,

please apply this patch (and I guess the other one too) against the
Linux kernel tree (so that the filenames are not usbtv.c, but
drivers/media/usb/usbtv.c instead). They will likely get into mainline
via the media tree (the other one still needs to be cc-ed to alsa list)
and therefore need to be send to the linux media list too.

Once you apply the patches to the Linux tree, scripts/get_maintainer.pl
is very helpful in finding out where to send the patches.

Thank you!
Lubo

On Sun, 2014-01-05 at 16:38 +0100, Federico Simoncelli wrote:
> Signed-off-by: Federico Simoncelli <fsimonce at redhat.com>
> Reviewed-by: Lubomir Rintel <lkundrak at v3.sk>
> ---
>  Makefile                 |   3 +
>  usbtv-core.c             | 136 +++++++++++++++++++++++++++++++++++++++
>  usbtv.c => usbtv-video.c | 163 +++--------------------------------------------
>  usbtv.h                  |  98 ++++++++++++++++++++++++++++
>  4 files changed, 246 insertions(+), 154 deletions(-)
>  create mode 100644 usbtv-core.c
>  rename usbtv.c => usbtv-video.c (82%)
>  create mode 100644 usbtv.h
> 
> diff --git a/Makefile b/Makefile
> index 28b872f..775316a 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1 +1,4 @@
> +usbtv-y := usbtv-core.o \
> +	usbtv-video.o
> +
>  obj-$(CONFIG_VIDEO_USBTV) += usbtv.o
> diff --git a/usbtv-core.c b/usbtv-core.c
> new file mode 100644
> index 0000000..e89e48b
> --- /dev/null
> +++ b/usbtv-core.c
> @@ -0,0 +1,136 @@
> +/*
> + * Fushicai USBTV007 Video Grabber Driver
> + *
> + * Product web site:
> + * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
> + *
> + * Following LWN articles were very useful in construction of this driver:
> + * Video4Linux2 API series: http://lwn.net/Articles/203924/
> + * videobuf2 API explanation: http://lwn.net/Articles/447435/
> + * Thanks go to Jonathan Corbet for providing this quality documentation.
> + * He is awesome.
> + *
> + * Copyright (c) 2013 Lubomir Rintel
> + * All rights reserved.
> + * No physical hardware was harmed running Windows during the
> + * reverse-engineering activity
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions, and the following disclaimer,
> + *    without modification.
> + * 2. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * Alternatively, this software may be distributed under the terms of the
> + * GNU General Public License ("GPL").
> + */
> +
> +#include <linux/module.h>
> +
> +#include "usbtv.h"
> +
> +int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
> +{
> +	int ret;
> +	int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
> +	int i;
> +
> +	for (i = 0; i < size; i++) {
> +		u16 index = regs[i][0];
> +		u16 value = regs[i][1];
> +
> +		ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
> +			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
> +			value, index, NULL, 0, 0);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int usbtv_probe(struct usb_interface *intf,
> +	const struct usb_device_id *id)
> +{
> +	int ret;
> +	int size;
> +	struct device *dev = &intf->dev;
> +	struct usbtv *usbtv;
> +
> +	/* Checks that the device is what we think it is. */
> +	if (intf->num_altsetting != 2)
> +		return -ENODEV;
> +	if (intf->altsetting[1].desc.bNumEndpoints != 4)
> +		return -ENODEV;
> +
> +	/* Packet size is split into 11 bits of base size and count of
> +	 * extra multiplies of it.*/
> +	size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
> +	size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
> +
> +	/* Device structure */
> +	usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
> +	if (usbtv == NULL)
> +		return -ENOMEM;
> +	usbtv->dev = dev;
> +	usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
> +
> +	usbtv->iso_size = size;
> +
> +	usb_set_intfdata(intf, usbtv);
> +
> +	ret = usbtv_video_init(usbtv);
> +	if (ret < 0)
> +		goto usbtv_video_fail;
> +
> +	/* for simplicity we exploit the v4l2_device reference counting */
> +	v4l2_device_get(&usbtv->v4l2_dev);
> +
> +	dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
> +	return 0;
> +
> +usbtv_video_fail:
> +	kfree(usbtv);
> +
> +	return ret;
> +}
> +
> +static void usbtv_disconnect(struct usb_interface *intf)
> +{
> +	struct usbtv *usbtv = usb_get_intfdata(intf);
> +	usb_set_intfdata(intf, NULL);
> +
> +	if (!usbtv)
> +		return;
> +
> +	usbtv_video_free(usbtv);
> +
> +	usb_put_dev(usbtv->udev);
> +	usbtv->udev = NULL;
> +
> +	/* the usbtv structure will be deallocated when v4l2 will be
> +	   done using it */
> +	v4l2_device_put(&usbtv->v4l2_dev);
> +}
> +
> +struct usb_device_id usbtv_id_table[] = {
> +	{ USB_DEVICE(0x1b71, 0x3002) },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(usb, usbtv_id_table);
> +
> +MODULE_AUTHOR("Lubomir Rintel");
> +MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
> +MODULE_LICENSE("Dual BSD/GPL");
> +
> +struct usb_driver usbtv_usb_driver = {
> +	.name = "usbtv",
> +	.id_table = usbtv_id_table,
> +	.probe = usbtv_probe,
> +	.disconnect = usbtv_disconnect,
> +};
> +
> +module_usb_driver(usbtv_usb_driver);
> diff --git a/usbtv.c b/usbtv-video.c
> similarity index 82%
> rename from usbtv.c
> rename to usbtv-video.c
> index 6222a4a..496bc2e 100644
> --- a/usbtv.c
> +++ b/usbtv-video.c
> @@ -28,45 +28,10 @@
>   * GNU General Public License ("GPL").
>   */
>  
> -#include <linux/init.h>
> -#include <linux/list.h>
> -#include <linux/module.h>
> -#include <linux/slab.h>
> -#include <linux/usb.h>
> -#include <linux/videodev2.h>
> -
> -#include <media/v4l2-device.h>
>  #include <media/v4l2-ioctl.h>
>  #include <media/videobuf2-core.h>
> -#include <media/videobuf2-vmalloc.h>
> -
> -/* Hardware. */
> -#define USBTV_VIDEO_ENDP	0x81
> -#define USBTV_BASE		0xc000
> -#define USBTV_REQUEST_REG	12
> -
> -/* Number of concurrent isochronous urbs submitted.
> - * Higher numbers was seen to overly saturate the USB bus. */
> -#define USBTV_ISOC_TRANSFERS	16
> -#define USBTV_ISOC_PACKETS	8
> -
> -#define USBTV_CHUNK_SIZE	256
> -#define USBTV_CHUNK		240
> -
> -/* Chunk header. */
> -#define USBTV_MAGIC_OK(chunk)	((be32_to_cpu(chunk[0]) & 0xff000000) \
> -							== 0x88000000)
> -#define USBTV_FRAME_ID(chunk)	((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
> -#define USBTV_ODD(chunk)	((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
> -#define USBTV_CHUNK_NO(chunk)	(be32_to_cpu(chunk[0]) & 0x00000fff)
> -
> -#define USBTV_TV_STD  (V4L2_STD_525_60 | V4L2_STD_PAL)
> -
> -/* parameters for supported TV norms */
> -struct usbtv_norm_params {
> -	v4l2_std_id norm;
> -	int cap_width, cap_height;
> -};
> +
> +#include "usbtv.h"
>  
>  static struct usbtv_norm_params norm_params[] = {
>  	{
> @@ -81,43 +46,6 @@ static struct usbtv_norm_params norm_params[] = {
>  	}
>  };
>  
> -/* A single videobuf2 frame buffer. */
> -struct usbtv_buf {
> -	struct vb2_buffer vb;
> -	struct list_head list;
> -};
> -
> -/* Per-device structure. */
> -struct usbtv {
> -	struct device *dev;
> -	struct usb_device *udev;
> -	struct v4l2_device v4l2_dev;
> -	struct video_device vdev;
> -	struct vb2_queue vb2q;
> -	struct mutex v4l2_lock;
> -	struct mutex vb2q_lock;
> -
> -	/* List of videobuf2 buffers protected by a lock. */
> -	spinlock_t buflock;
> -	struct list_head bufs;
> -
> -	/* Number of currently processed frame, useful find
> -	 * out when a new one begins. */
> -	u32 frame_id;
> -	int chunks_done;
> -
> -	enum {
> -		USBTV_COMPOSITE_INPUT,
> -		USBTV_SVIDEO_INPUT,
> -	} input;
> -	v4l2_std_id norm;
> -	int width, height;
> -	int n_chunks;
> -	int iso_size;
> -	unsigned int sequence;
> -	struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
> -};
> -
>  static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm)
>  {
>  	int i, ret = 0;
> @@ -142,26 +70,6 @@ static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm)
>  	return ret;
>  }
>  
> -static int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size)
> -{
> -	int ret;
> -	int pipe = usb_rcvctrlpipe(usbtv->udev, 0);
> -	int i;
> -
> -	for (i = 0; i < size; i++) {
> -		u16 index = regs[i][0];
> -		u16 value = regs[i][1];
> -
> -		ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG,
> -			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
> -			value, index, NULL, 0, 0);
> -		if (ret < 0)
> -			return ret;
> -	}
> -
> -	return 0;
> -}
> -
>  static int usbtv_select_input(struct usbtv *usbtv, int input)
>  {
>  	int ret;
> @@ -560,12 +468,6 @@ start_fail:
>  	return ret;
>  }
>  
> -struct usb_device_id usbtv_id_table[] = {
> -	{ USB_DEVICE(0x1b71, 0x3002) },
> -	{}
> -};
> -MODULE_DEVICE_TABLE(usb, usbtv_id_table);
> -
>  static int usbtv_querycap(struct file *file, void *priv,
>  				struct v4l2_capability *cap)
>  {
> @@ -759,33 +661,9 @@ static void usbtv_release(struct v4l2_device *v4l2_dev)
>  	kfree(usbtv);
>  }
>  
> -static int usbtv_probe(struct usb_interface *intf,
> -	const struct usb_device_id *id)
> +int usbtv_video_init(struct usbtv *usbtv)
>  {
>  	int ret;
> -	int size;
> -	struct device *dev = &intf->dev;
> -	struct usbtv *usbtv;
> -
> -	/* Checks that the device is what we think it is. */
> -	if (intf->num_altsetting != 2)
> -		return -ENODEV;
> -	if (intf->altsetting[1].desc.bNumEndpoints != 4)
> -		return -ENODEV;
> -
> -	/* Packet size is split into 11 bits of base size and count of
> -	 * extra multiplies of it.*/
> -	size = usb_endpoint_maxp(&intf->altsetting[1].endpoint[0].desc);
> -	size = (size & 0x07ff) * (((size & 0x1800) >> 11) + 1);
> -
> -	/* Device structure */
> -	usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL);
> -	if (usbtv == NULL)
> -		return -ENOMEM;
> -	usbtv->dev = dev;
> -	usbtv->udev = usb_get_dev(interface_to_usbdev(intf));
> -
> -	usbtv->iso_size = size;
>  
>  	(void)usbtv_configure_for_norm(usbtv, V4L2_STD_525_60);
>  
> @@ -805,20 +683,18 @@ static int usbtv_probe(struct usb_interface *intf,
>  	usbtv->vb2q.lock = &usbtv->vb2q_lock;
>  	ret = vb2_queue_init(&usbtv->vb2q);
>  	if (ret < 0) {
> -		dev_warn(dev, "Could not initialize videobuf2 queue\n");
> -		goto usbtv_fail;
> +		dev_warn(usbtv->dev, "Could not initialize videobuf2 queue\n");
> +		return ret;
>  	}
>  
>  	/* v4l2 structure */
>  	usbtv->v4l2_dev.release = usbtv_release;
> -	ret = v4l2_device_register(dev, &usbtv->v4l2_dev);
> +	ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev);
>  	if (ret < 0) {
> -		dev_warn(dev, "Could not register v4l2 device\n");
> +		dev_warn(usbtv->dev, "Could not register v4l2 device\n");
>  		goto v4l2_fail;
>  	}
>  
> -	usb_set_intfdata(intf, usbtv);
> -
>  	/* Video structure */
>  	strlcpy(usbtv->vdev.name, "usbtv", sizeof(usbtv->vdev.name));
>  	usbtv->vdev.v4l2_dev = &usbtv->v4l2_dev;
> @@ -832,52 +708,31 @@ static int usbtv_probe(struct usb_interface *intf,
>  	video_set_drvdata(&usbtv->vdev, usbtv);
>  	ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1);
>  	if (ret < 0) {
> -		dev_warn(dev, "Could not register video device\n");
> +		dev_warn(usbtv->dev, "Could not register video device\n");
>  		goto vdev_fail;
>  	}
>  
> -	dev_info(dev, "Fushicai USBTV007 Video Grabber\n");
>  	return 0;
>  
>  vdev_fail:
>  	v4l2_device_unregister(&usbtv->v4l2_dev);
>  v4l2_fail:
>  	vb2_queue_release(&usbtv->vb2q);
> -usbtv_fail:
> -	kfree(usbtv);
>  
>  	return ret;
>  }
>  
> -static void usbtv_disconnect(struct usb_interface *intf)
> +void usbtv_video_free(struct usbtv *usbtv)
>  {
> -	struct usbtv *usbtv = usb_get_intfdata(intf);
> -
>  	mutex_lock(&usbtv->vb2q_lock);
>  	mutex_lock(&usbtv->v4l2_lock);
>  
>  	usbtv_stop(usbtv);
> -	usb_set_intfdata(intf, NULL);
>  	video_unregister_device(&usbtv->vdev);
>  	v4l2_device_disconnect(&usbtv->v4l2_dev);
> -	usb_put_dev(usbtv->udev);
> -	usbtv->udev = NULL;
>  
>  	mutex_unlock(&usbtv->v4l2_lock);
>  	mutex_unlock(&usbtv->vb2q_lock);
>  
>  	v4l2_device_put(&usbtv->v4l2_dev);
>  }
> -
> -MODULE_AUTHOR("Lubomir Rintel");
> -MODULE_DESCRIPTION("Fushicai USBTV007 Video Grabber Driver");
> -MODULE_LICENSE("Dual BSD/GPL");
> -
> -struct usb_driver usbtv_usb_driver = {
> -	.name = "usbtv",
> -	.id_table = usbtv_id_table,
> -	.probe = usbtv_probe,
> -	.disconnect = usbtv_disconnect,
> -};
> -
> -module_usb_driver(usbtv_usb_driver);
> diff --git a/usbtv.h b/usbtv.h
> new file mode 100644
> index 0000000..536343d
> --- /dev/null
> +++ b/usbtv.h
> @@ -0,0 +1,98 @@
> +/*
> + * Fushicai USBTV007 Video Grabber Driver
> + *
> + * Copyright (c) 2013 Lubomir Rintel
> + * All rights reserved.
> + * No physical hardware was harmed running Windows during the
> + * reverse-engineering activity
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions, and the following disclaimer,
> + *    without modification.
> + * 2. The name of the author may not be used to endorse or promote products
> + *    derived from this software without specific prior written permission.
> + *
> + * Alternatively, this software may be distributed under the terms of the
> + * GNU General Public License ("GPL").
> + */
> +
> +#include <linux/slab.h>
> +#include <linux/usb.h>
> +
> +#include <media/v4l2-device.h>
> +#include <media/videobuf2-vmalloc.h>
> +
> +/* Hardware. */
> +#define USBTV_VIDEO_ENDP	0x81
> +#define USBTV_BASE		0xc000
> +#define USBTV_REQUEST_REG	12
> +
> +/* Number of concurrent isochronous urbs submitted.
> + * Higher numbers was seen to overly saturate the USB bus. */
> +#define USBTV_ISOC_TRANSFERS	16
> +#define USBTV_ISOC_PACKETS	8
> +
> +#define USBTV_CHUNK_SIZE	256
> +#define USBTV_CHUNK		240
> +
> +/* Chunk header. */
> +#define USBTV_MAGIC_OK(chunk)	((be32_to_cpu(chunk[0]) & 0xff000000) \
> +							== 0x88000000)
> +#define USBTV_FRAME_ID(chunk)	((be32_to_cpu(chunk[0]) & 0x00ff0000) >> 16)
> +#define USBTV_ODD(chunk)	((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
> +#define USBTV_CHUNK_NO(chunk)	(be32_to_cpu(chunk[0]) & 0x00000fff)
> +
> +#define USBTV_TV_STD  (V4L2_STD_525_60 | V4L2_STD_PAL)
> +
> +/* parameters for supported TV norms */
> +struct usbtv_norm_params {
> +	v4l2_std_id norm;
> +	int cap_width, cap_height;
> +};
> +
> +/* A single videobuf2 frame buffer. */
> +struct usbtv_buf {
> +	struct vb2_buffer vb;
> +	struct list_head list;
> +};
> +
> +/* Per-device structure. */
> +struct usbtv {
> +	struct device *dev;
> +	struct usb_device *udev;
> +
> +	/* video */
> +	struct v4l2_device v4l2_dev;
> +	struct video_device vdev;
> +	struct vb2_queue vb2q;
> +	struct mutex v4l2_lock;
> +	struct mutex vb2q_lock;
> +
> +	/* List of videobuf2 buffers protected by a lock. */
> +	spinlock_t buflock;
> +	struct list_head bufs;
> +
> +	/* Number of currently processed frame, useful find
> +	 * out when a new one begins. */
> +	u32 frame_id;
> +	int chunks_done;
> +
> +	enum {
> +		USBTV_COMPOSITE_INPUT,
> +		USBTV_SVIDEO_INPUT,
> +	} input;
> +	v4l2_std_id norm;
> +	int width, height;
> +	int n_chunks;
> +	int iso_size;
> +	unsigned int sequence;
> +	struct urb *isoc_urbs[USBTV_ISOC_TRANSFERS];
> +};
> +
> +int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size);
> +
> +int usbtv_video_init(struct usbtv *usbtv);
> +void usbtv_video_free(struct usbtv *usbtv);




More information about the Alsa-devel mailing list