Commit acfdaf05 authored by Devin Heitmueller's avatar Devin Heitmueller Committed by Mauro Carvalho Chehab

V4L/DVB (12742): em28xx: add raw VBI support for NTSC

Add support for raw VBI capture for the em28xx bridge, currently only for
NTSC.  Support for PAL capture to follow shortly (including the removal of
numerous hard-coded NTSC-specific sizes for capture buffers, etc).

Note that the code currently changes the default current norm from PAL to
NTSC (so that zvbi-ntsc-cc works properly).  The default norm really should
be moved into a board-level parameter.

This work was sponsored by EyeMagnet Limited.
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 06a5eeef
em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \
em28xx-input.o em28xx-input.o em28xx-vbi.o
em28xx-alsa-objs := em28xx-audio.o em28xx-alsa-objs := em28xx-audio.o
......
...@@ -2590,6 +2590,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, ...@@ -2590,6 +2590,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
/* init video dma queues */ /* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued); INIT_LIST_HEAD(&dev->vidq.queued);
INIT_LIST_HEAD(&dev->vbiq.active);
INIT_LIST_HEAD(&dev->vbiq.queued);
if (dev->board.has_msp34xx) { if (dev->board.has_msp34xx) {
......
...@@ -964,6 +964,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, ...@@ -964,6 +964,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
{ {
struct em28xx_dmaqueue *dma_q = &dev->vidq; struct em28xx_dmaqueue *dma_q = &dev->vidq;
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
int i; int i;
int sb_size, pipe; int sb_size, pipe;
struct urb *urb; struct urb *urb;
...@@ -993,7 +994,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, ...@@ -993,7 +994,8 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
} }
dev->isoc_ctl.max_pkt_size = max_pkt_size; dev->isoc_ctl.max_pkt_size = max_pkt_size;
dev->isoc_ctl.buf = NULL; dev->isoc_ctl.vid_buf = NULL;
dev->isoc_ctl.vbi_buf = NULL;
sb_size = max_packets * dev->isoc_ctl.max_pkt_size; sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
...@@ -1043,6 +1045,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets, ...@@ -1043,6 +1045,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
} }
init_waitqueue_head(&dma_q->wq); init_waitqueue_head(&dma_q->wq);
init_waitqueue_head(&vbi_dma_q->wq);
em28xx_capture_start(dev, 1); em28xx_capture_start(dev, 1);
......
/*
em28xx-vbi.c - VBI driver for em28xx
Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
This work was sponsored by EyeMagnet Limited.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include "em28xx.h"
static unsigned int vbibufs = 5;
module_param(vbibufs,int,0644);
MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
static unsigned int vbi_debug;
module_param(vbi_debug,int,0644);
MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \
printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg)
/* ------------------------------------------------------------------ */
static void
free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
{
struct em28xx_fh *fh = vq->priv_data;
struct em28xx *dev = fh->dev;
unsigned long flags = 0;
if (in_interrupt())
BUG();
/* We used to wait for the buffer to finish here, but this didn't work
because, as we were keeping the state as VIDEOBUF_QUEUED,
videobuf_queue_cancel marked it as finished for us.
(Also, it could wedge forever if the hardware was misconfigured.)
This should be safe; by the time we get here, the buffer isn't
queued anymore. If we ever start marking the buffers as
VIDEOBUF_ACTIVE, it won't be, though.
*/
spin_lock_irqsave(&dev->slock, flags);
if (dev->isoc_ctl.vbi_buf == buf)
dev->isoc_ctl.vbi_buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
videobuf_vmalloc_free(&buf->vb);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
static int
vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{
*size = 720 * 12 * 2;
if (0 == *count)
*count = vbibufs;
if (*count < 2)
*count = 2;
if (*count > 32)
*count = 32;
return 0;
}
static int
vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct em28xx_fh *fh = q->priv_data;
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
int rc = 0;
unsigned int size;
size = 720 * 12 * 2;
buf->vb.size = size;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
buf->vb.width = 720;
buf->vb.height = 12;
buf->vb.field = field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
rc = videobuf_iolock(q, &buf->vb, NULL);
if (rc < 0)
goto fail;
}
buf->vb.state = VIDEOBUF_PREPARED;
return 0;
fail:
free_buffer(q, buf);
return rc;
}
static void
vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
struct em28xx_buffer *buf = container_of(vb,
struct em28xx_buffer,
vb);
struct em28xx_fh *fh = vq->priv_data;
struct em28xx *dev = fh->dev;
struct em28xx_dmaqueue *vbiq = &dev->vbiq;
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &vbiq->active);
}
static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
free_buffer(q, buf);
}
struct videobuf_queue_ops em28xx_vbi_qops = {
.buf_setup = vbi_setup,
.buf_prepare = vbi_prepare,
.buf_queue = vbi_queue,
.buf_release = vbi_release,
};
/* ------------------------------------------------------------------ */
/*
* Local variables:
* c-basic-offset: 8
* End:
*/
This diff is collapsed.
...@@ -214,7 +214,8 @@ struct em28xx_usb_isoc_ctl { ...@@ -214,7 +214,8 @@ struct em28xx_usb_isoc_ctl {
int tmp_buf_len; int tmp_buf_len;
/* Stores already requested buffers */ /* Stores already requested buffers */
struct em28xx_buffer *buf; struct em28xx_buffer *vid_buf;
struct em28xx_buffer *vbi_buf;
/* Stores the number of received fields */ /* Stores the number of received fields */
int nfields; int nfields;
...@@ -467,6 +468,7 @@ struct em28xx_fh { ...@@ -467,6 +468,7 @@ struct em28xx_fh {
int radio; int radio;
struct videobuf_queue vb_vidq; struct videobuf_queue vb_vidq;
struct videobuf_queue vb_vbiq;
enum v4l2_buf_type type; enum v4l2_buf_type type;
}; };
...@@ -565,6 +567,7 @@ struct em28xx { ...@@ -565,6 +567,7 @@ struct em28xx {
/* Isoc control struct */ /* Isoc control struct */
struct em28xx_dmaqueue vidq; struct em28xx_dmaqueue vidq;
struct em28xx_dmaqueue vbiq;
struct em28xx_usb_isoc_ctl isoc_ctl; struct em28xx_usb_isoc_ctl isoc_ctl;
spinlock_t slock; spinlock_t slock;
...@@ -693,6 +696,9 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev); ...@@ -693,6 +696,9 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev);
int em28xx_ir_init(struct em28xx *dev); int em28xx_ir_init(struct em28xx *dev);
int em28xx_ir_fini(struct em28xx *dev); int em28xx_ir_fini(struct em28xx *dev);
/* Provided by em28xx-vbi.c */
extern struct videobuf_queue_ops em28xx_vbi_qops;
/* printk macros */ /* printk macros */
#define em28xx_err(fmt, arg...) do {\ #define em28xx_err(fmt, arg...) do {\
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment