diff options
author | Andy Walls <awalls@radix.net> | 2009-02-05 20:37:49 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:42:38 -0400 |
commit | c1994084d6ad7d1a411219727fc135a18c40f9c8 (patch) | |
tree | 742eb86f0a99d458119525fa3566c53436567292 /drivers/media/video | |
parent | 776fa869883e60a065df13e73252344477c8e1aa (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.c | 14 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 109 |
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 | ||
45 | static 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 | |||
45 | u16 cx18_service2vbi(int type) | 52 | u16 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 */ | ||
61 | static int valid_service_line(int field, int line, int is_pal) | 69 | static 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 | */ | ||
67 | static u16 select_service_from_set(int field, int line, u16 set, int is_pal) | 83 | static 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 | */ | ||
93 | void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | 113 | void 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 | */ | ||
105 | static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | 129 | static 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 */ | ||
119 | u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) | 144 | u16 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 | ||
672 | static int cx18_g_enc_index(struct file *file, void *fh, | 735 | static int cx18_g_enc_index(struct file *file, void *fh, |