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

V4L/DVB: Add closed captioning support for the HVR-950q

Add NTSC closed captioning support for au0828 based products.  Note that this
also required reworking the locking to support streaming on both the video and
VBI devices (the logic for which I copied from my changes made to the em28xx
several months ago).

This work was sponsored by GetWellNetwork Inc.
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent fab9bfbe
au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
obj-$(CONFIG_VIDEO_AU0828) += au0828.o obj-$(CONFIG_VIDEO_AU0828) += au0828.o
......
/*
au0828-vbi.c - VBI driver for au0828
Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
This work was sponsored by GetWellNetwork Inc.
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 "au0828.h"
static unsigned int vbibufs = 5;
module_param(vbibufs, int, 0644);
MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
/* ------------------------------------------------------------------ */
static void
free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
{
struct au0828_fh *fh = vq->priv_data;
struct au0828_dev *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)
{
struct au0828_fh *fh = q->priv_data;
struct au0828_dev *dev = fh->dev;
*size = dev->vbi_width * dev->vbi_height * 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 au0828_fh *fh = q->priv_data;
struct au0828_dev *dev = fh->dev;
struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
int rc = 0;
buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
buf->vb.width = dev->vbi_width;
buf->vb.height = dev->vbi_height;
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 au0828_buffer *buf = container_of(vb,
struct au0828_buffer,
vb);
struct au0828_fh *fh = vq->priv_data;
struct au0828_dev *dev = fh->dev;
struct au0828_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 au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
free_buffer(q, buf);
}
struct videobuf_queue_ops au0828_vbi_qops = {
.buf_setup = vbi_setup,
.buf_prepare = vbi_prepare,
.buf_queue = vbi_queue,
.buf_release = vbi_release,
};
This diff is collapsed.
...@@ -60,6 +60,10 @@ ...@@ -60,6 +60,10 @@
#define AU0828_MAX_INPUT 4 #define AU0828_MAX_INPUT 4
/* au0828 resource types (used for res_get/res_lock etc */
#define AU0828_RESOURCE_VIDEO 0x01
#define AU0828_RESOURCE_VBI 0x02
enum au0828_itype { enum au0828_itype {
AU0828_VMUX_UNDEFINED = 0, AU0828_VMUX_UNDEFINED = 0,
AU0828_VMUX_COMPOSITE, AU0828_VMUX_COMPOSITE,
...@@ -115,8 +119,10 @@ enum au0828_dev_state { ...@@ -115,8 +119,10 @@ enum au0828_dev_state {
struct au0828_fh { struct au0828_fh {
struct au0828_dev *dev; struct au0828_dev *dev;
unsigned int stream_on:1; /* Locks streams */ unsigned int resources;
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;
}; };
...@@ -145,7 +151,8 @@ struct au0828_usb_isoc_ctl { ...@@ -145,7 +151,8 @@ struct au0828_usb_isoc_ctl {
int tmp_buf_len; int tmp_buf_len;
/* Stores already requested buffers */ /* Stores already requested buffers */
struct au0828_buffer *buf; struct au0828_buffer *buf;
struct au0828_buffer *vbi_buf;
/* Stores the number of received fields */ /* Stores the number of received fields */
int nfields; int nfields;
...@@ -194,11 +201,14 @@ struct au0828_dev { ...@@ -194,11 +201,14 @@ struct au0828_dev {
/* Analog */ /* Analog */
struct v4l2_device v4l2_dev; struct v4l2_device v4l2_dev;
int users; int users;
unsigned int stream_on:1; /* Locks streams */ unsigned int resources; /* resources in use */
struct video_device *vdev; struct video_device *vdev;
struct video_device *vbi_dev; struct video_device *vbi_dev;
int width; int width;
int height; int height;
int vbi_width;
int vbi_height;
u32 vbi_read;
u32 field_size; u32 field_size;
u32 frame_size; u32 frame_size;
u32 bytesperline; u32 bytesperline;
...@@ -219,6 +229,7 @@ struct au0828_dev { ...@@ -219,6 +229,7 @@ struct au0828_dev {
/* Isoc control struct */ /* Isoc control struct */
struct au0828_dmaqueue vidq; struct au0828_dmaqueue vidq;
struct au0828_dmaqueue vbiq;
struct au0828_usb_isoc_ctl isoc_ctl; struct au0828_usb_isoc_ctl isoc_ctl;
spinlock_t slock; spinlock_t slock;
...@@ -278,6 +289,9 @@ void au0828_analog_unregister(struct au0828_dev *dev); ...@@ -278,6 +289,9 @@ void au0828_analog_unregister(struct au0828_dev *dev);
extern int au0828_dvb_register(struct au0828_dev *dev); extern int au0828_dvb_register(struct au0828_dev *dev);
extern void au0828_dvb_unregister(struct au0828_dev *dev); extern void au0828_dvb_unregister(struct au0828_dev *dev);
/* au0828-vbi.c */
extern struct videobuf_queue_ops au0828_vbi_qops;
#define dprintk(level, fmt, arg...)\ #define dprintk(level, fmt, arg...)\
do { if (au0828_debug & level)\ do { if (au0828_debug & level)\
printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\ printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
......
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