Skip to content

Commit

Permalink
V4L/DVB (10441): cx18: Fix VBI ioctl() handling and Raw/Sliced VBI st…
Browse files Browse the repository at this point in the history
…ate management

More sliced VBI fixes to bring the cx18 driver closer to full V4L2 spec
compliance for VBI and to get sliced VBI working better.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Andy Walls authored and Mauro Carvalho Chehab committed Mar 30, 2009
1 parent 776fa86 commit c199408
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 29 deletions.
14 changes: 8 additions & 6 deletions drivers/media/video/cx18/cx18-av-vbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
#include "cx18-driver.h"

/*
* For sliced VBI output, we set up to use VIP-1.1, 10-bit mode,
* NN counts 4 bytes Dwords, an IDID of 0x00 0x80 or one with the VBI line #.
* For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
* NN counts 1 byte Dwords, an IDID with the VBI line # in it.
* Thus, according to the VIP-2 Spec, our VBI ancillary data lines
* (should!) look like:
* 4 byte EAV code: 0xff 0x00 0x00 0xRP
Expand All @@ -35,8 +35,8 @@
* 1 byte data identifier: ne010iii (parity bits, 010, DID bits)
* 1 byte secondary data id: nessssss (parity bits, SDID bits)
* 1 byte data word count: necccccc (parity bits, NN Dword count)
* 2 byte Internal DID: 0x00 0x80 (programmed value)
* 4*NN data bytes
* 2 byte Internal DID: VBI-line-# 0x80
* NN data bytes
* 1 byte checksum
* Fill bytes needed to fil out to 4*NN bytes of payload
*
Expand Down Expand Up @@ -65,7 +65,7 @@ struct vbi_anc_data {
u8 sdid;
u8 data_count;
u8 idid[2];
u8 payload[1]; /* 4*data_count of payload */
u8 payload[1]; /* data_count of payload */
/* u8 checksum; */
/* u8 fill[]; Variable number of fill bytes */
};
Expand Down Expand Up @@ -215,6 +215,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
cx18_av_write(cx, 0x406, 0x13);
cx18_av_write(cx, 0x47f, vbi_offset);

/* Force impossible lines to 0 */
if (is_pal) {
for (i = 0; i <= 6; i++)
svbi->service_lines[0][i] =
Expand All @@ -229,6 +230,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
svbi->service_lines[1][i] = 0;
}

/* Build register values for requested service lines */
for (i = 7; i <= 23; i++) {
for (x = 0; x <= 1; x++) {
switch (svbi->service_lines[1-x][i]) {
Expand All @@ -242,7 +244,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
lcr[i] |= 6 << (4 * x);
break;
case V4L2_SLICED_VPS:
lcr[i] |= 9 << (4 * x);
lcr[i] |= 7 << (4 * x); /*'840 differs*/
break;
}
}
Expand Down
109 changes: 86 additions & 23 deletions drivers/media/video/cx18/cx18-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@
#include <media/v4l2-chip-ident.h>
#include <linux/i2c-id.h>

static int cx18_vbi_streaming(struct cx18 *cx)
{
struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
return (s_vbi->handle != CX18_INVALID_TASK_HANDLE) &&
test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
}

u16 cx18_service2vbi(int type)
{
switch (type) {
Expand All @@ -58,12 +65,21 @@ u16 cx18_service2vbi(int type)
}
}

/* Check if VBI services are allowed on the (field, line) for the video std */
static int valid_service_line(int field, int line, int is_pal)
{
return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
return (is_pal && line >= 6 &&
((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
(!is_pal && line >= 10 && line < 22);
}

/*
* For a (field, line, std) and inbound potential set of services for that line,
* return the first valid service of those passed in the incoming set for that
* line in priority order:
* CC, VPS, or WSS over TELETEXT for well known lines
* TELETEXT, before VPS, before CC, before WSS, for other lines
*/
static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
{
u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
Expand All @@ -90,6 +106,10 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
return 0;
}

/*
* Expand the service_set of *fmt into valid service_lines for the std,
* and clear the passed in fmt->service_set
*/
void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
u16 set = fmt->service_set;
Expand All @@ -102,6 +122,10 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
}
}

/*
* Sanitize the service_lines in *fmt per the video std, and return 1
* if any service_line is left as valid after santization
*/
static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
{
int f, l;
Expand All @@ -116,6 +140,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
return set != 0;
}

/* Compute the service_set from the assumed valid service_lines of *fmt */
u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
{
int f, l;
Expand Down Expand Up @@ -162,7 +187,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;

vbifmt->sampling_rate = 27000000;
vbifmt->offset = 248;
vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
vbifmt->samples_per_line = vbi_active_samples - 4;
vbifmt->sample_format = V4L2_PIX_FMT_GREY;
vbifmt->start[0] = cx->vbi.start[0];
Expand All @@ -180,12 +205,25 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;

/* sane, V4L2 spec compliant, defaults */
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
vbifmt->service_set = 0;

/*
* Fetch the configured service_lines and total service_set from the
* digitizer/slicer. Note, cx18_av_vbi() wipes the passed in
* fmt->fmt.sliced under valid calling conditions
*/
if (cx18_av_cmd(cx, VIDIOC_G_FMT, fmt))
return -EINVAL;

cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
/* Ensure V4L2 spec compliant output */
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
}
Expand Down Expand Up @@ -224,10 +262,12 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
vbifmt->reserved[0] = 0;
vbifmt->reserved[1] = 0;

/* If given a service set, expand it validly & clear passed in set */
if (vbifmt->service_set)
cx18_expand_service_set(vbifmt, cx->is_50hz);
check_service_set(vbifmt, cx->is_50hz);
vbifmt->service_set = cx18_get_service_set(vbifmt);
/* Sanitize the service_lines, and compute the new set if any valid */
if (check_service_set(vbifmt, cx->is_50hz))
vbifmt->service_set = cx18_get_service_set(vbifmt);
return 0;
}

Expand Down Expand Up @@ -272,12 +312,22 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
if (ret)
return ret;

if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
if (!cx18_raw_vbi(cx) && cx18_vbi_streaming(cx))
return -EBUSY;

/*
* Set the digitizer registers for raw active VBI.
* Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
* calling conditions
*/
ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
if (ret)
return ret;

/* Store our new v4l2 (non-)sliced VBI state */
cx->vbi.sliced_in->service_set = 0;
cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);

return cx18_g_fmt_vbi_cap(file, fh, fmt);
}

Expand All @@ -293,17 +343,20 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
if (ret)
return ret;

ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
if (ret)
return ret;

if (check_service_set(vbifmt, cx->is_50hz) == 0)
return -EINVAL;
cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);

if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
if (cx18_raw_vbi(cx) && cx18_vbi_streaming(cx))
return -EBUSY;
/*
* Set the service_lines requested in the digitizer/slicer registers.
* Note, cx18_av_vbi() wipes some "impossible" service lines in the
* passed in fmt->fmt.sliced under valid calling conditions
*/
ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
if (ret)
return ret;
/* Store our current v4l2 sliced VBI settings */
cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
return 0;
}
Expand Down Expand Up @@ -657,16 +710,26 @@ static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
int f, l;

if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
for (f = 0; f < 2; f++) {
for (l = 0; l < 24; l++) {
if (valid_service_line(f, l, cx->is_50hz))
cap->service_lines[f][l] = set;
}
if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
return -EINVAL;

cap->service_set = 0;
for (f = 0; f < 2; f++) {
for (l = 0; l < 24; l++) {
if (valid_service_line(f, l, cx->is_50hz)) {
/*
* We can find all v4l2 supported vbi services
* for the standard, on a valid line for the std
*/
cap->service_lines[f][l] = set;
cap->service_set |= set;
} else
cap->service_lines[f][l] = 0;
}
return 0;
}
return -EINVAL;
for (f = 0; f < 3; f++)
cap->reserved[f] = 0;
return 0;
}

static int cx18_g_enc_index(struct file *file, void *fh,
Expand Down

0 comments on commit c199408

Please sign in to comment.