V4L/DVB (9162): ivtv: fix raw/sliced VBI mixup

The service_set field was used in saa7115 and cx25840 to determine
whether raw or sliced VBI was desired. This is incorrect since it is
perfectly valid to select sliced VBI with a service_set of 0.

Instead these drivers should checked on VIDIOC_S_FMT whether the type
field matches the raw or sliced VBI type.

Updated ivtv accordingly.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 69f2bbd..58e6ef1 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -141,10 +141,11 @@
 		u8 lcr[24];
 
 		fmt = arg;
-		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+		if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE &&
+		    fmt->type != V4L2_BUF_TYPE_VBI_CAPTURE)
 			return -EINVAL;
 		svbi = &fmt->fmt.sliced;
-		if (svbi->service_set == 0) {
+		if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
 			/* raw VBI */
 			memset(svbi, 0, sizeof(*svbi));
 
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 7aa61b6..aeaa13f 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -720,7 +720,7 @@
 	itv->speed = 1000;
 
 	/* VBI */
-	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
 	itv->vbi.sliced_in = &itv->vbi.in.fmt.sliced;
 
 	/* Init the sg table for osd/yuv output */
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index b76a122..be2d779 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -750,6 +750,12 @@
 /* First-open initialization: load firmware, init cx25840, etc. */
 int ivtv_init_on_first_open(struct ivtv *itv);
 
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int ivtv_raw_vbi(const struct ivtv *itv)
+{
+	return itv->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
 /* This is a PCI post thing, where if the pci register is not read, then
    the write doesn't always take effect right away. By reading back the
    register any pending PCI writes will be performed (in order), and so
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 304261e..b7457fc 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -78,7 +78,7 @@
 	if (type == IVTV_DEC_STREAM_TYPE_MPG) {
 		vbi_type = IVTV_DEC_STREAM_TYPE_VBI;
 	} else if (type == IVTV_ENC_STREAM_TYPE_MPG &&
-		   itv->vbi.insert_mpeg && itv->vbi.sliced_in->service_set) {
+		   itv->vbi.insert_mpeg && !ivtv_raw_vbi(itv)) {
 		vbi_type = IVTV_ENC_STREAM_TYPE_VBI;
 	} else {
 		return 0;
@@ -305,7 +305,7 @@
 
 	if (len > ucount) len = ucount;
 	if (itv->vbi.insert_mpeg && s->type == IVTV_ENC_STREAM_TYPE_MPG &&
-	    itv->vbi.sliced_in->service_set && buf != &itv->vbi.sliced_mpeg_buf) {
+	    !ivtv_raw_vbi(itv) && buf != &itv->vbi.sliced_mpeg_buf) {
 		const char *start = buf->buf + buf->readpos;
 		const char *p = start + 1;
 		const u8 *q;
@@ -372,7 +372,7 @@
 	/* Each VBI buffer is one frame, the v4l2 API says that for VBI the frames should
 	   arrive one-by-one, so make sure we never output more than one VBI frame at a time */
 	if (s->type == IVTV_DEC_STREAM_TYPE_VBI ||
-			(s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set))
+	    (s->type == IVTV_ENC_STREAM_TYPE_VBI && !ivtv_raw_vbi(itv)))
 		single_frame = 1;
 
 	for (;;) {
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index f5b289e..3d0013b 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -575,8 +575,11 @@
 {
 	struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
 
+	if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
+		return -EBUSY;
 	itv->vbi.sliced_in->service_set = 0;
-	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
+	itv->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
+	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
 	return ivtv_g_fmt_vbi_cap(file, fh, fmt);
 }
 
@@ -591,8 +594,9 @@
 		return ret;
 
 	check_service_set(vbifmt, itv->is_50hz);
-	if (atomic_read(&itv->capturing) > 0)
+	if (ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0)
 		return -EBUSY;
+	itv->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
 	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
 	memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
 	return 0;
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 24273fb..5bbf31e 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -334,7 +334,7 @@
 
 static void ivtv_vbi_setup(struct ivtv *itv)
 {
-	int raw = itv->vbi.sliced_in->service_set == 0;
+	int raw = ivtv_raw_vbi(itv);
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	int lines;
 	int i;
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 1ce9deb..4a37a7d 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -334,7 +334,7 @@
 	int y;
 
 	/* Raw VBI data */
-	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) {
+	if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) {
 		u8 type;
 
 		ivtv_buf_swap(buf);
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 4ed7d65..c8e9cb3 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1057,7 +1057,7 @@
 	for (i = 0; i <= 23; i++)
 		lcr[i] = 0xff;
 
-	if (fmt->service_set == 0) {
+	if (fmt == NULL) {
 		/* raw VBI */
 		if (is_50hz)
 			for (i = 6; i <= 23; i++)
@@ -1113,7 +1113,7 @@
 	}
 
 	/* enable/disable raw VBI capturing */
-	saa711x_writeregs(client, fmt->service_set == 0 ?
+	saa711x_writeregs(client, fmt == NULL ?
 				saa7115_cfg_vbi_on :
 				saa7115_cfg_vbi_off);
 }
@@ -1153,6 +1153,10 @@
 		saa711x_set_lcr(client, &fmt->fmt.sliced);
 		return 0;
 	}
+	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+		saa711x_set_lcr(client, NULL);
+		return 0;
+	}
 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;