From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lubomir Rintel Subject: Re: [PATCH 1/2] usbtv: split core and video implementation Date: Sun, 05 Jan 2014 17:37:05 +0100 Message-ID: <1388939825.16586.3.camel@odvarok.lan> References: <1388936292-8974-1-git-send-email-fsimonce@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from shell.v3.sk (shell.v3.sk [195.168.3.45]) by alsa0.perex.cz (Postfix) with ESMTP id 851F8260886 for ; Sun, 5 Jan 2014 17:37:13 +0100 (CET) In-Reply-To: <1388936292-8974-1-git-send-email-fsimonce@redhat.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org To: Federico Simoncelli Cc: alsa-devel@alsa-project.org, Federico Simoncelli List-Id: alsa-devel@alsa-project.org 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 > Reviewed-by: Lubomir Rintel > --- > 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 > + > +#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 > -#include > -#include > -#include > -#include > -#include > - > -#include > #include > #include > -#include > - > -/* 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 > +#include > + > +#include > +#include > + > +/* 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);