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/cx18/cx18-ioctl.c | |
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/cx18/cx18-ioctl.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 109 |
1 files changed, 86 insertions, 23 deletions
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, |