aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-02-05 20:37:49 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-03-30 11:42:38 -0400
commitc1994084d6ad7d1a411219727fc135a18c40f9c8 (patch)
tree742eb86f0a99d458119525fa3566c53436567292 /drivers/media/video
parent776fa869883e60a065df13e73252344477c8e1aa (diff)
V4L/DVB (10441): cx18: Fix VBI ioctl() handling and Raw/Sliced VBI state 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>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/cx18/cx18-av-vbi.c14
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c109
2 files changed, 94 insertions, 29 deletions
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
index 72325d774a60..b5763372a316 100644
--- a/drivers/media/video/cx18/cx18-av-vbi.c
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -25,8 +25,8 @@
25#include "cx18-driver.h" 25#include "cx18-driver.h"
26 26
27/* 27/*
28 * For sliced VBI output, we set up to use VIP-1.1, 10-bit mode, 28 * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
29 * NN counts 4 bytes Dwords, an IDID of 0x00 0x80 or one with the VBI line #. 29 * NN counts 1 byte Dwords, an IDID with the VBI line # in it.
30 * Thus, according to the VIP-2 Spec, our VBI ancillary data lines 30 * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
31 * (should!) look like: 31 * (should!) look like:
32 * 4 byte EAV code: 0xff 0x00 0x00 0xRP 32 * 4 byte EAV code: 0xff 0x00 0x00 0xRP
@@ -35,8 +35,8 @@
35 * 1 byte data identifier: ne010iii (parity bits, 010, DID bits) 35 * 1 byte data identifier: ne010iii (parity bits, 010, DID bits)
36 * 1 byte secondary data id: nessssss (parity bits, SDID bits) 36 * 1 byte secondary data id: nessssss (parity bits, SDID bits)
37 * 1 byte data word count: necccccc (parity bits, NN Dword count) 37 * 1 byte data word count: necccccc (parity bits, NN Dword count)
38 * 2 byte Internal DID: 0x00 0x80 (programmed value) 38 * 2 byte Internal DID: VBI-line-# 0x80
39 * 4*NN data bytes 39 * NN data bytes
40 * 1 byte checksum 40 * 1 byte checksum
41 * Fill bytes needed to fil out to 4*NN bytes of payload 41 * Fill bytes needed to fil out to 4*NN bytes of payload
42 * 42 *
@@ -65,7 +65,7 @@ struct vbi_anc_data {
65 u8 sdid; 65 u8 sdid;
66 u8 data_count; 66 u8 data_count;
67 u8 idid[2]; 67 u8 idid[2];
68 u8 payload[1]; /* 4*data_count of payload */ 68 u8 payload[1]; /* data_count of payload */
69 /* u8 checksum; */ 69 /* u8 checksum; */
70 /* u8 fill[]; Variable number of fill bytes */ 70 /* u8 fill[]; Variable number of fill bytes */
71}; 71};
@@ -215,6 +215,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
215 cx18_av_write(cx, 0x406, 0x13); 215 cx18_av_write(cx, 0x406, 0x13);
216 cx18_av_write(cx, 0x47f, vbi_offset); 216 cx18_av_write(cx, 0x47f, vbi_offset);
217 217
218 /* Force impossible lines to 0 */
218 if (is_pal) { 219 if (is_pal) {
219 for (i = 0; i <= 6; i++) 220 for (i = 0; i <= 6; i++)
220 svbi->service_lines[0][i] = 221 svbi->service_lines[0][i] =
@@ -229,6 +230,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
229 svbi->service_lines[1][i] = 0; 230 svbi->service_lines[1][i] = 0;
230 } 231 }
231 232
233 /* Build register values for requested service lines */
232 for (i = 7; i <= 23; i++) { 234 for (i = 7; i <= 23; i++) {
233 for (x = 0; x <= 1; x++) { 235 for (x = 0; x <= 1; x++) {
234 switch (svbi->service_lines[1-x][i]) { 236 switch (svbi->service_lines[1-x][i]) {
@@ -242,7 +244,7 @@ int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
242 lcr[i] |= 6 << (4 * x); 244 lcr[i] |= 6 << (4 * x);
243 break; 245 break;
244 case V4L2_SLICED_VPS: 246 case V4L2_SLICED_VPS:
245 lcr[i] |= 9 << (4 * x); 247 lcr[i] |= 7 << (4 * x); /*'840 differs*/
246 break; 248 break;
247 } 249 }
248 } 250 }
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 1adb97220920..a454ede568a5 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -42,6 +42,13 @@
42#include <media/v4l2-chip-ident.h> 42#include <media/v4l2-chip-ident.h>
43#include <linux/i2c-id.h> 43#include <linux/i2c-id.h>
44 44
45static int cx18_vbi_streaming(struct cx18 *cx)
46{
47 struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
48 return (s_vbi->handle != CX18_INVALID_TASK_HANDLE) &&
49 test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
50}
51
45u16 cx18_service2vbi(int type) 52u16 cx18_service2vbi(int type)
46{ 53{
47 switch (type) { 54 switch (type) {
@@ -58,12 +65,21 @@ u16 cx18_service2vbi(int type)
58 } 65 }
59} 66}
60 67
68/* Check if VBI services are allowed on the (field, line) for the video std */
61static int valid_service_line(int field, int line, int is_pal) 69static int valid_service_line(int field, int line, int is_pal)
62{ 70{
63 return (is_pal && line >= 6 && (line != 23 || field == 0)) || 71 return (is_pal && line >= 6 &&
72 ((field == 0 && line <= 23) || (field == 1 && line <= 22))) ||
64 (!is_pal && line >= 10 && line < 22); 73 (!is_pal && line >= 10 && line < 22);
65} 74}
66 75
76/*
77 * For a (field, line, std) and inbound potential set of services for that line,
78 * return the first valid service of those passed in the incoming set for that
79 * line in priority order:
80 * CC, VPS, or WSS over TELETEXT for well known lines
81 * TELETEXT, before VPS, before CC, before WSS, for other lines
82 */
67static u16 select_service_from_set(int field, int line, u16 set, int is_pal) 83static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
68{ 84{
69 u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); 85 u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
@@ -90,6 +106,10 @@ static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
90 return 0; 106 return 0;
91} 107}
92 108
109/*
110 * Expand the service_set of *fmt into valid service_lines for the std,
111 * and clear the passed in fmt->service_set
112 */
93void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) 113void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
94{ 114{
95 u16 set = fmt->service_set; 115 u16 set = fmt->service_set;
@@ -102,6 +122,10 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
102 } 122 }
103} 123}
104 124
125/*
126 * Sanitize the service_lines in *fmt per the video std, and return 1
127 * if any service_line is left as valid after santization
128 */
105static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) 129static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
106{ 130{
107 int f, l; 131 int f, l;
@@ -116,6 +140,7 @@ static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
116 return set != 0; 140 return set != 0;
117} 141}
118 142
143/* Compute the service_set from the assumed valid service_lines of *fmt */
119u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) 144u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
120{ 145{
121 int f, l; 146 int f, l;
@@ -162,7 +187,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh,
162 struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; 187 struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi;
163 188
164 vbifmt->sampling_rate = 27000000; 189 vbifmt->sampling_rate = 27000000;
165 vbifmt->offset = 248; 190 vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */
166 vbifmt->samples_per_line = vbi_active_samples - 4; 191 vbifmt->samples_per_line = vbi_active_samples - 4;
167 vbifmt->sample_format = V4L2_PIX_FMT_GREY; 192 vbifmt->sample_format = V4L2_PIX_FMT_GREY;
168 vbifmt->start[0] = cx->vbi.start[0]; 193 vbifmt->start[0] = cx->vbi.start[0];
@@ -180,12 +205,25 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh,
180 struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; 205 struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
181 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; 206 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
182 207
208 /* sane, V4L2 spec compliant, defaults */
183 vbifmt->reserved[0] = 0; 209 vbifmt->reserved[0] = 0;
184 vbifmt->reserved[1] = 0; 210 vbifmt->reserved[1] = 0;
185 vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; 211 vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
186 memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); 212 memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
213 vbifmt->service_set = 0;
214
215 /*
216 * Fetch the configured service_lines and total service_set from the
217 * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in
218 * fmt->fmt.sliced under valid calling conditions
219 */
220 if (cx18_av_cmd(cx, VIDIOC_G_FMT, fmt))
221 return -EINVAL;
187 222
188 cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); 223 /* Ensure V4L2 spec compliant output */
224 vbifmt->reserved[0] = 0;
225 vbifmt->reserved[1] = 0;
226 vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
189 vbifmt->service_set = cx18_get_service_set(vbifmt); 227 vbifmt->service_set = cx18_get_service_set(vbifmt);
190 return 0; 228 return 0;
191} 229}
@@ -224,10 +262,12 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
224 vbifmt->reserved[0] = 0; 262 vbifmt->reserved[0] = 0;
225 vbifmt->reserved[1] = 0; 263 vbifmt->reserved[1] = 0;
226 264
265 /* If given a service set, expand it validly & clear passed in set */
227 if (vbifmt->service_set) 266 if (vbifmt->service_set)
228 cx18_expand_service_set(vbifmt, cx->is_50hz); 267 cx18_expand_service_set(vbifmt, cx->is_50hz);
229 check_service_set(vbifmt, cx->is_50hz); 268 /* Sanitize the service_lines, and compute the new set if any valid */
230 vbifmt->service_set = cx18_get_service_set(vbifmt); 269 if (check_service_set(vbifmt, cx->is_50hz))
270 vbifmt->service_set = cx18_get_service_set(vbifmt);
231 return 0; 271 return 0;
232} 272}
233 273
@@ -272,12 +312,22 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh,
272 if (ret) 312 if (ret)
273 return ret; 313 return ret;
274 314
275 if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) 315 if (!cx18_raw_vbi(cx) && cx18_vbi_streaming(cx))
276 return -EBUSY; 316 return -EBUSY;
277 317
318 /*
319 * Set the digitizer registers for raw active VBI.
320 * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid
321 * calling conditions
322 */
323 ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
324 if (ret)
325 return ret;
326
327 /* Store our new v4l2 (non-)sliced VBI state */
278 cx->vbi.sliced_in->service_set = 0; 328 cx->vbi.sliced_in->service_set = 0;
279 cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; 329 cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE;
280 cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); 330
281 return cx18_g_fmt_vbi_cap(file, fh, fmt); 331 return cx18_g_fmt_vbi_cap(file, fh, fmt);
282} 332}
283 333
@@ -293,17 +343,20 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
293 if (ret) 343 if (ret)
294 return ret; 344 return ret;
295 345
296 ret = cx18_try_fmt_sliced_vbi_cap(file, fh, fmt); 346 cx18_try_fmt_sliced_vbi_cap(file, fh, fmt);
297 if (ret)
298 return ret;
299
300 if (check_service_set(vbifmt, cx->is_50hz) == 0)
301 return -EINVAL;
302 347
303 if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) 348 if (cx18_raw_vbi(cx) && cx18_vbi_streaming(cx))
304 return -EBUSY; 349 return -EBUSY;
350 /*
351 * Set the service_lines requested in the digitizer/slicer registers.
352 * Note, cx18_av_vbi() wipes some "impossible" service lines in the
353 * passed in fmt->fmt.sliced under valid calling conditions
354 */
355 ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
356 if (ret)
357 return ret;
358 /* Store our current v4l2 sliced VBI settings */
305 cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; 359 cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
306 cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
307 memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); 360 memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
308 return 0; 361 return 0;
309} 362}
@@ -657,16 +710,26 @@ static int cx18_g_sliced_vbi_cap(struct file *file, void *fh,
657 int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; 710 int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
658 int f, l; 711 int f, l;
659 712
660 if (cap->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { 713 if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
661 for (f = 0; f < 2; f++) { 714 return -EINVAL;
662 for (l = 0; l < 24; l++) { 715
663 if (valid_service_line(f, l, cx->is_50hz)) 716 cap->service_set = 0;
664 cap->service_lines[f][l] = set; 717 for (f = 0; f < 2; f++) {
665 } 718 for (l = 0; l < 24; l++) {
719 if (valid_service_line(f, l, cx->is_50hz)) {
720 /*
721 * We can find all v4l2 supported vbi services
722 * for the standard, on a valid line for the std
723 */
724 cap->service_lines[f][l] = set;
725 cap->service_set |= set;
726 } else
727 cap->service_lines[f][l] = 0;
666 } 728 }
667 return 0;
668 } 729 }
669 return -EINVAL; 730 for (f = 0; f < 3; f++)
731 cap->reserved[f] = 0;
732 return 0;
670} 733}
671 734
672static int cx18_g_enc_index(struct file *file, void *fh, 735static int cx18_g_enc_index(struct file *file, void *fh,