V4L/DVB (9805): cx18: Port fix for raw/sliced VBI mixup from ivtv and cx25840

This is a port of the fixes Hans Verkuil made for ivtv/cx25840:
The service_set field was used 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 the driver should check on VIDIOC_S_FMT whether the type
field matches the raw or sliced VBI type.

Updated the cx18 driver accordingly, including an additional check in
cx18_start_v4l2_encode_stream() that didn't exist in ivtv.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
index 02fdf57..1527ea4 100644
--- a/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/drivers/media/video/cx18/cx18-av-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/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 255d547..e845cd6 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -594,7 +594,7 @@
 	init_waitqueue_head(&cx->dma_waitq);
 
 	/* VBI */
-	cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+	cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
 	cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
 	cx->vbi.raw_size = 1456;
 	cx->vbi.raw_decoder_line_size = 1456;
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 29c296f..018d98f 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -504,4 +504,10 @@
 /* First-open initialization: load firmware, etc. */
 int cx18_init_on_first_open(struct cx18 *cx);
 
+/* Test if the current VBI mode is raw (1) or sliced (0) */
+static inline int cx18_raw_vbi(const struct cx18 *cx)
+{
+	return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE;
+}
+
 #endif /* CX18_DRIVER_H */
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index 61192e6..1856d59 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -67,12 +67,11 @@
 	}
 	s->id = id->open_id;
 
-	/* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
-	   CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+	/* CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
 	   (provided VBI insertion is on and sliced VBI is selected), for all
 	   other streams we're done */
 	if (type == CX18_ENC_STREAM_TYPE_MPG &&
-		   cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+	    cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) {
 		vbi_type = CX18_ENC_STREAM_TYPE_VBI;
 	} else {
 		return 0;
@@ -258,7 +257,7 @@
 	if (len > ucount)
 		len = ucount;
 	if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
-	    cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+	    !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) {
 		const char *start = buf->buf + buf->readpos;
 		const char *p = start + 1;
 		const u8 *q;
@@ -333,8 +332,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 == CX18_ENC_STREAM_TYPE_VBI &&
-	    cx->vbi.sliced_in->service_set)
+	if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx))
 		single_frame = 1;
 
 	for (;;) {
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index ece799e..e608748 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -238,13 +238,12 @@
 	if (ret)
 		return ret;
 
-	if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
-			cx->vbi.sliced_in->service_set &&
-			atomic_read(&cx->ana_capturing) > 0)
+	if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0)
 		return -EBUSY;
 
 	cx->vbi.sliced_in->service_set = 0;
-	cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+	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);
 }
 
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 9ead459..c87cd53 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -340,7 +340,7 @@
 static void cx18_vbi_setup(struct cx18_stream *s)
 {
 	struct cx18 *cx = s->cx;
-	int raw = cx->vbi.sliced_in->service_set == 0;
+	int raw = cx18_raw_vbi(cx);
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	int lines;
 
@@ -471,8 +471,8 @@
 		captype = CAPTURE_CHANNEL_TYPE_PCM;
 		break;
 	case CX18_ENC_STREAM_TYPE_VBI:
-		captype = cx->vbi.sliced_in->service_set ?
-		    CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+		captype = cx18_raw_vbi(cx) ?
+		     CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI;
 		cx->vbi.frame = 0;
 		cx->vbi.inserted_frame = 0;
 		memset(cx->vbi.sliced_mpeg_size,
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
index 22e76ee..03f0e81 100644
--- a/drivers/media/video/cx18/cx18-vbi.c
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -160,7 +160,7 @@
 		return;
 
 	/* Raw VBI data */
-	if (cx->vbi.sliced_in->service_set == 0) {
+	if (cx18_raw_vbi(cx)) {
 		u8 type;
 
 		cx18_buf_swap(buf);