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

V4L/DVB (13932): em28xx: add PAL support for VBI

Make the VBI support work for PAL standards in addition to NTSC.

This work was sponsored by EyeMagnet Limited.

Thanks go out to Andy Walls for providing a CD containing test PAL/VBI captures
and to Steven Toth for providing a PVR-350 to do signal generation with.
Signed-off-by: default avatarDevin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6a207100
...@@ -691,9 +691,15 @@ int em28xx_set_outfmt(struct em28xx *dev) ...@@ -691,9 +691,15 @@ int em28xx_set_outfmt(struct em28xx *dev)
if (em28xx_vbi_supported(dev) == 1) { if (em28xx_vbi_supported(dev) == 1) {
vinctrl |= EM28XX_VINCTRL_VBI_RAW; vinctrl |= EM28XX_VINCTRL_VBI_RAW;
em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00); em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
if (dev->norm & V4L2_STD_525_60) {
/* NTSC */
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09); em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, 0xb4); } else if (dev->norm & V4L2_STD_625_50) {
em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, 0x0c); /* PAL */
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
}
} }
return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl); return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
...@@ -760,6 +766,13 @@ int em28xx_resolution_set(struct em28xx *dev) ...@@ -760,6 +766,13 @@ int em28xx_resolution_set(struct em28xx *dev)
width = norm_maxw(dev); width = norm_maxw(dev);
height = norm_maxh(dev); height = norm_maxh(dev);
/* Properly setup VBI */
dev->vbi_width = 720;
if (dev->norm & V4L2_STD_525_60)
dev->vbi_height = 12;
else
dev->vbi_height = 18;
if (!dev->progressive) if (!dev->progressive)
height >>= norm_maxh(dev); height >>= norm_maxh(dev);
......
...@@ -71,7 +71,11 @@ free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) ...@@ -71,7 +71,11 @@ free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
static int static int
vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
{ {
*size = 720 * 12 * 2; struct em28xx_fh *fh = q->priv_data;
struct em28xx *dev = fh->dev;
*size = dev->vbi_width * dev->vbi_height * 2;
if (0 == *count) if (0 == *count)
*count = vbibufs; *count = vbibufs;
if (*count < 2) if (*count < 2)
...@@ -85,19 +89,18 @@ static int ...@@ -85,19 +89,18 @@ static int
vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
enum v4l2_field field) enum v4l2_field field)
{ {
struct em28xx_fh *fh = q->priv_data;
struct em28xx *dev = fh->dev;
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
int rc = 0; int rc = 0;
unsigned int size;
size = 720 * 12 * 2;
buf->vb.size = size; buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL; return -EINVAL;
buf->vb.width = 720; buf->vb.width = dev->vbi_width;
buf->vb.height = 12; buf->vb.height = dev->vbi_height;
buf->vb.field = field; buf->vb.field = field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
......
...@@ -282,7 +282,7 @@ static void em28xx_copy_vbi(struct em28xx *dev, ...@@ -282,7 +282,7 @@ static void em28xx_copy_vbi(struct em28xx *dev,
{ {
void *startwrite, *startread; void *startwrite, *startread;
int offset; int offset;
int bytesperline = 720; int bytesperline = dev->vbi_width;
if (dev == NULL) { if (dev == NULL) {
em28xx_isocdbg("dev is null\n"); em28xx_isocdbg("dev is null\n");
...@@ -323,8 +323,8 @@ static void em28xx_copy_vbi(struct em28xx *dev, ...@@ -323,8 +323,8 @@ static void em28xx_copy_vbi(struct em28xx *dev,
/* Make sure the bottom field populates the second half of the frame */ /* Make sure the bottom field populates the second half of the frame */
if (buf->top_field == 0) { if (buf->top_field == 0) {
startwrite += bytesperline * 0x0c; startwrite += bytesperline * dev->vbi_height;
offset += bytesperline * 0x0c; offset += bytesperline * dev->vbi_height;
} }
memcpy(startwrite, startread, len); memcpy(startwrite, startread, len);
...@@ -578,8 +578,7 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb) ...@@ -578,8 +578,7 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
dev->cur_field = p[2]; dev->cur_field = p[2];
} }
/* FIXME: get rid of hard-coded value */ vbi_size = dev->vbi_width * dev->vbi_height;
vbi_size = 720 * 0x0c;
if (dev->capture_type == 0) { if (dev->capture_type == 0) {
if (dev->vbi_read >= vbi_size) { if (dev->vbi_read >= vbi_size) {
...@@ -1850,18 +1849,27 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, ...@@ -1850,18 +1849,27 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format) struct v4l2_format *format)
{ {
format->fmt.vbi.samples_per_line = 720; struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0; format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0; format->fmt.vbi.flags = 0;
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
format->fmt.vbi.count[0] = dev->vbi_height;
format->fmt.vbi.count[1] = dev->vbi_height;
/* Varies by video standard (NTSC, PAL, etc.) */ /* Varies by video standard (NTSC, PAL, etc.) */
/* FIXME: hard-coded for NTSC support */ if (dev->norm & V4L2_STD_525_60) {
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */ /* NTSC */
format->fmt.vbi.count[0] = 12;
format->fmt.vbi.count[1] = 12;
format->fmt.vbi.start[0] = 10; format->fmt.vbi.start[0] = 10;
format->fmt.vbi.start[1] = 273; format->fmt.vbi.start[1] = 273;
} else if (dev->norm & V4L2_STD_625_50) {
/* PAL */
format->fmt.vbi.start[0] = 6;
format->fmt.vbi.start[1] = 318;
}
return 0; return 0;
} }
...@@ -1869,18 +1877,27 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, ...@@ -1869,18 +1877,27 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format) struct v4l2_format *format)
{ {
format->fmt.vbi.samples_per_line = 720; struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0; format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0; format->fmt.vbi.flags = 0;
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
format->fmt.vbi.count[0] = dev->vbi_height;
format->fmt.vbi.count[1] = dev->vbi_height;
/* Varies by video standard (NTSC, PAL, etc.) */ /* Varies by video standard (NTSC, PAL, etc.) */
/* FIXME: hard-coded for NTSC support */ if (dev->norm & V4L2_STD_525_60) {
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */ /* NTSC */
format->fmt.vbi.count[0] = 12;
format->fmt.vbi.count[1] = 12;
format->fmt.vbi.start[0] = 10; format->fmt.vbi.start[0] = 10;
format->fmt.vbi.start[1] = 273; format->fmt.vbi.start[1] = 273;
} else if (dev->norm & V4L2_STD_625_50) {
/* PAL */
format->fmt.vbi.start[0] = 6;
format->fmt.vbi.start[1] = 318;
}
return 0; return 0;
} }
...@@ -1922,7 +1939,8 @@ static int vidioc_querybuf(struct file *file, void *priv, ...@@ -1922,7 +1939,8 @@ static int vidioc_querybuf(struct file *file, void *priv,
At a minimum, it causes a crash in zvbi since it does At a minimum, it causes a crash in zvbi since it does
a memcpy based on the source buffer length */ a memcpy based on the source buffer length */
int result = videobuf_querybuf(&fh->vb_vbiq, b); int result = videobuf_querybuf(&fh->vb_vbiq, b);
b->length = 17280; b->length = dev->vbi_width * dev->vbi_height * 2;
return result; return result;
} }
} }
......
...@@ -552,7 +552,8 @@ struct em28xx { ...@@ -552,7 +552,8 @@ struct em28xx {
int capture_type; int capture_type;
int vbi_read; int vbi_read;
unsigned char cur_field; unsigned char cur_field;
unsigned int vbi_width;
unsigned int vbi_height; /* lines per field */
struct work_struct request_module_wk; struct work_struct request_module_wk;
......
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