aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtv-vbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-vbi.c')
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
new file mode 100644
index 000000000000..b53ca508dacc
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -0,0 +1,545 @@
1/*
2 Vertical Blank Interval support functions
3 Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include "ivtv-driver.h"
21#include "ivtv-video.h"
22#include "ivtv-vbi.h"
23#include "ivtv-ioctl.h"
24#include "ivtv-queue.h"
25
26static int odd_parity(u8 c)
27{
28 c ^= (c >> 4);
29 c ^= (c >> 2);
30 c ^= (c >> 1);
31
32 return c & 1;
33}
34
35void vbi_schedule_work(struct ivtv *itv)
36{
37 queue_work(itv->vbi.work_queues, &itv->vbi.work_queue);
38}
39
40static void passthrough_vbi_data(struct ivtv *itv, int cnt)
41{
42 int wss = 0;
43 u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
44 u8 vps[13];
45 int found_cc = 0;
46 int found_wss = 0;
47 int found_vps = 0;
48 int cc_pos = itv->vbi.cc_pos;
49 int i;
50
51 for (i = 0; i < cnt; i++) {
52 struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i;
53
54 if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
55 found_cc = 1;
56 if (d->field) {
57 cc[2] = d->data[0];
58 cc[3] = d->data[1];
59 } else {
60 cc[0] = d->data[0];
61 cc[1] = d->data[1];
62 }
63 }
64 else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
65 memcpy(vps, d->data, sizeof(vps));
66 found_vps = 1;
67 }
68 else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
69 wss = d->data[0] | d->data[1] << 8;
70 found_wss = 1;
71 }
72 }
73
74 if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
75 itv->vbi.wss = wss;
76 itv->vbi.wss_found = found_wss;
77 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
78 }
79
80 if (found_vps || itv->vbi.vps_found) {
81 itv->vbi.vps[0] = vps[2];
82 itv->vbi.vps[1] = vps[8];
83 itv->vbi.vps[2] = vps[9];
84 itv->vbi.vps[3] = vps[10];
85 itv->vbi.vps[4] = vps[11];
86 itv->vbi.vps_found = found_vps;
87 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
88 }
89
90 if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
91 itv->vbi.cc_data_odd[cc_pos] = cc[0];
92 itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
93 itv->vbi.cc_data_even[cc_pos] = cc[2];
94 itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
95 itv->vbi.cc_pos = cc_pos + 2;
96 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
97 }
98}
99
100static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
101{
102 int line = 0;
103 int i;
104 u32 linemask[2] = { 0, 0 };
105 unsigned short size;
106 static const u8 mpeg_hdr_data[] = {
107 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
108 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
109 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
110 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
111 };
112 const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
113 int idx = itv->vbi.frame % IVTV_VBI_FRAMES;
114 u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0];
115
116 for (i = 0; i < lines; i++) {
117 int f, l;
118
119 if (itv->vbi.sliced_data[i].id == 0)
120 continue;
121
122 l = itv->vbi.sliced_data[i].line - 6;
123 f = itv->vbi.sliced_data[i].field;
124 if (f)
125 l += 18;
126 if (l < 32)
127 linemask[0] |= (1 << l);
128 else
129 linemask[1] |= (1 << (l - 32));
130 dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id);
131 memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
132 line++;
133 }
134 memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
135 if (line == 36) {
136 /* All lines are used, so there is no space for the linemask
137 (the max size of the VBI data is 36 * 43 + 4 bytes).
138 So in this case we use the magic number 'ITV0'. */
139 memcpy(dst + sd, "ITV0", 4);
140 memcpy(dst + sd + 4, dst + sd + 12, line * 43);
141 size = 4 + ((43 * line + 3) & ~3);
142 } else {
143 memcpy(dst + sd, "itv0", 4);
144 memcpy(dst + sd + 4, &linemask[0], 8);
145 size = 12 + ((43 * line + 3) & ~3);
146 }
147 dst[4+16] = (size + 10) >> 8;
148 dst[5+16] = (size + 10) & 0xff;
149 dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
150 dst[10+16] = (pts_stamp >> 22) & 0xff;
151 dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
152 dst[12+16] = (pts_stamp >> 7) & 0xff;
153 dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
154 itv->vbi.sliced_mpeg_size[idx] = sd + size;
155}
156
157static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
158{
159 u32 linemask[2];
160 int i, l, id2;
161 int line = 0;
162
163 if (!memcmp(p, "itv0", 4)) {
164 memcpy(linemask, p + 4, 8);
165 p += 12;
166 } else if (!memcmp(p, "ITV0", 4)) {
167 linemask[0] = 0xffffffff;
168 linemask[1] = 0xf;
169 p += 4;
170 } else {
171 /* unknown VBI data stream */
172 return 0;
173 }
174 for (i = 0; i < 36; i++) {
175 int err = 0;
176
177 if (i < 32 && !(linemask[0] & (1 << i)))
178 continue;
179 if (i >= 32 && !(linemask[1] & (1 << (i - 32))))
180 continue;
181 id2 = *p & 0xf;
182 switch (id2) {
183 case IVTV_SLICED_TYPE_TELETEXT_B:
184 id2 = V4L2_SLICED_TELETEXT_B;
185 break;
186 case IVTV_SLICED_TYPE_CAPTION_525:
187 id2 = V4L2_SLICED_CAPTION_525;
188 err = !odd_parity(p[1]) || !odd_parity(p[2]);
189 break;
190 case IVTV_SLICED_TYPE_VPS:
191 id2 = V4L2_SLICED_VPS;
192 break;
193 case IVTV_SLICED_TYPE_WSS_625:
194 id2 = V4L2_SLICED_WSS_625;
195 break;
196 default:
197 id2 = 0;
198 break;
199 }
200 if (err == 0) {
201 l = (i < 18) ? i + 6 : i - 18 + 6;
202 itv->vbi.sliced_dec_data[line].line = l;
203 itv->vbi.sliced_dec_data[line].field = i >= 18;
204 itv->vbi.sliced_dec_data[line].id = id2;
205 memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42);
206 line++;
207 }
208 p += 43;
209 }
210 while (line < 36) {
211 itv->vbi.sliced_dec_data[line].id = 0;
212 itv->vbi.sliced_dec_data[line].line = 0;
213 itv->vbi.sliced_dec_data[line].field = 0;
214 line++;
215 }
216 return line * sizeof(itv->vbi.sliced_dec_data[0]);
217}
218
219ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
220{
221 /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
222 const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
223 u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
224 int found_cc = 0;
225 int cc_pos = itv->vbi.cc_pos;
226
227 if (itv->vbi.service_set_out == 0)
228 return -EPERM;
229
230 while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
231 switch (p->id) {
232 case V4L2_SLICED_CAPTION_525:
233 if (p->id == V4L2_SLICED_CAPTION_525 &&
234 p->line == 21 &&
235 (itv->vbi.service_set_out &
236 V4L2_SLICED_CAPTION_525) == 0) {
237 break;
238 }
239 found_cc = 1;
240 if (p->field) {
241 cc[2] = p->data[0];
242 cc[3] = p->data[1];
243 } else {
244 cc[0] = p->data[0];
245 cc[1] = p->data[1];
246 }
247 break;
248
249 case V4L2_SLICED_VPS:
250 if (p->line == 16 && p->field == 0 &&
251 (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
252 itv->vbi.vps[0] = p->data[2];
253 itv->vbi.vps[1] = p->data[8];
254 itv->vbi.vps[2] = p->data[9];
255 itv->vbi.vps[3] = p->data[10];
256 itv->vbi.vps[4] = p->data[11];
257 itv->vbi.vps_found = 1;
258 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
259 }
260 break;
261
262 case V4L2_SLICED_WSS_625:
263 if (p->line == 23 && p->field == 0 &&
264 (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
265 /* No lock needed for WSS */
266 itv->vbi.wss = p->data[0] | (p->data[1] << 8);
267 itv->vbi.wss_found = 1;
268 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
269 }
270 break;
271
272 default:
273 break;
274 }
275 count -= sizeof(*p);
276 p++;
277 }
278
279 if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
280 itv->vbi.cc_data_odd[cc_pos] = cc[0];
281 itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
282 itv->vbi.cc_data_even[cc_pos] = cc[2];
283 itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
284 itv->vbi.cc_pos = cc_pos + 2;
285 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
286 }
287
288 return (const char __user *)p - ubuf;
289}
290
291/* Compress raw VBI format, removes leading SAV codes and surplus space after the
292 field.
293 Returns new compressed size. */
294static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size)
295{
296 u32 line_size = itv->vbi.raw_decoder_line_size;
297 u32 lines = itv->vbi.count;
298 u8 sav1 = itv->vbi.raw_decoder_sav_odd_field;
299 u8 sav2 = itv->vbi.raw_decoder_sav_even_field;
300 u8 *q = buf;
301 u8 *p;
302 int i;
303
304 for (i = 0; i < lines; i++) {
305 p = buf + i * line_size;
306
307 /* Look for SAV code */
308 if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) {
309 break;
310 }
311 memcpy(q, p + 4, line_size - 4);
312 q += line_size - 4;
313 }
314 return lines * (line_size - 4);
315}
316
317
318/* Compressed VBI format, all found sliced blocks put next to one another
319 Returns new compressed size */
320static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav)
321{
322 u32 line_size = itv->vbi.sliced_decoder_line_size;
323 struct v4l2_decode_vbi_line vbi;
324 int i;
325
326 /* find the first valid line */
327 for (i = 0; i < size; i++, buf++) {
328 if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
329 break;
330 }
331
332 size -= i;
333 if (size < line_size) {
334 return line;
335 }
336 for (i = 0; i < size / line_size; i++) {
337 u8 *p = buf + i * line_size;
338
339 /* Look for SAV code */
340 if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) {
341 continue;
342 }
343 vbi.p = p + 4;
344 itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
345 if (vbi.type) {
346 itv->vbi.sliced_data[line].id = vbi.type;
347 itv->vbi.sliced_data[line].field = vbi.is_second_field;
348 itv->vbi.sliced_data[line].line = vbi.line;
349 memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42);
350 line++;
351 }
352 }
353 return line;
354}
355
356void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
357 u64 pts_stamp, int streamtype)
358{
359 u8 *p = (u8 *) buf->buf;
360 u32 size = buf->bytesused;
361 int y;
362
363 /* Raw VBI data */
364 if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) {
365 u8 type;
366
367 ivtv_buf_swap(buf);
368
369 type = p[3];
370
371 size = buf->bytesused = compress_raw_buf(itv, p, size);
372
373 /* second field of the frame? */
374 if (type == itv->vbi.raw_decoder_sav_even_field) {
375 /* Dirty hack needed for backwards
376 compatibility of old VBI software. */
377 p += size - 4;
378 memcpy(p, &itv->vbi.frame, 4);
379 itv->vbi.frame++;
380 }
381 return;
382 }
383
384 /* Sliced VBI data with data insertion */
385 if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) {
386 int lines;
387
388 ivtv_buf_swap(buf);
389
390 /* first field */
391 lines = compress_sliced_buf(itv, 0, p, size / 2,
392 itv->vbi.sliced_decoder_sav_odd_field);
393 /* second field */
394 /* experimentation shows that the second half does not always begin
395 at the exact address. So start a bit earlier (hence 32). */
396 lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32,
397 itv->vbi.sliced_decoder_sav_even_field);
398 /* always return at least one empty line */
399 if (lines == 0) {
400 itv->vbi.sliced_data[0].id = 0;
401 itv->vbi.sliced_data[0].line = 0;
402 itv->vbi.sliced_data[0].field = 0;
403 lines = 1;
404 }
405 buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]);
406 memcpy(p, &itv->vbi.sliced_data[0], size);
407
408 if (itv->vbi.insert_mpeg) {
409 copy_vbi_data(itv, lines, pts_stamp);
410 }
411 itv->vbi.frame++;
412 return;
413 }
414
415 /* Sliced VBI re-inserted from an MPEG stream */
416 if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
417 /* If the size is not 4-byte aligned, then the starting address
418 for the swapping is also shifted. After swapping the data the
419 real start address of the VBI data is exactly 4 bytes after the
420 original start. It's a bit fiddly but it works like a charm.
421 Non-4-byte alignment happens when an lseek is done on the input
422 mpeg file to a non-4-byte aligned position. So on arrival here
423 the VBI data is also non-4-byte aligned. */
424 int offset = size & 3;
425 int cnt;
426
427 if (offset) {
428 p += 4 - offset;
429 }
430 /* Swap Buffer */
431 for (y = 0; y < size; y += 4) {
432 swab32s((u32 *)(p + y));
433 }
434
435 cnt = ivtv_convert_ivtv_vbi(itv, p + offset);
436 memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
437 buf->bytesused = cnt;
438
439 passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0]));
440 return;
441 }
442}
443
444void ivtv_disable_vbi(struct ivtv *itv)
445{
446 clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
447 clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
448 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
449 ivtv_set_wss(itv, 0, 0);
450 ivtv_set_cc(itv, 0, 0, 0, 0, 0);
451 ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
452 itv->vbi.vps_found = itv->vbi.wss_found = 0;
453 itv->vbi.wss = 0;
454 itv->vbi.cc_pos = 0;
455}
456
457void vbi_work_handler(struct work_struct *work)
458{
459 struct vbi_info *info = container_of(work, struct vbi_info, work_queue);
460 struct ivtv *itv = container_of(info, struct ivtv, vbi);
461 struct v4l2_sliced_vbi_data data;
462 DEFINE_WAIT(wait);
463
464 /* Lock */
465 if (itv->output_mode == OUT_PASSTHROUGH) {
466 /* Note: currently only the saa7115 is used in a PVR350,
467 so these commands are for now saa7115 specific. */
468 if (itv->is_50hz) {
469 data.id = V4L2_SLICED_WSS_625;
470 data.field = 0;
471
472 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
473 ivtv_set_wss(itv, 1, data.data[0] & 0xf);
474 itv->vbi.wss_no_update = 0;
475 } else if (itv->vbi.wss_no_update == 4) {
476 ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
477 } else {
478 itv->vbi.wss_no_update++;
479 }
480 }
481 else {
482 u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
483 int mode = 0;
484
485 data.id = V4L2_SLICED_CAPTION_525;
486 data.field = 0;
487 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
488 mode |= 1;
489 c1 = data.data[0];
490 c2 = data.data[1];
491 }
492 data.field = 1;
493 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
494 mode |= 2;
495 c3 = data.data[0];
496 c4 = data.data[1];
497 }
498 if (mode) {
499 itv->vbi.cc_no_update = 0;
500 ivtv_set_cc(itv, mode, c1, c2, c3, c4);
501 } else if (itv->vbi.cc_no_update == 4) {
502 ivtv_set_cc(itv, 0, 0, 0, 0, 0);
503 } else {
504 itv->vbi.cc_no_update++;
505 }
506 }
507 return;
508 }
509
510 if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
511 /* Lock */
512 ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
513 }
514
515 if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
516 if (itv->vbi.cc_pos == 0) {
517 ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80);
518 }
519 while (itv->vbi.cc_pos) {
520 u8 cc_odd0 = itv->vbi.cc_data_odd[0];
521 u8 cc_odd1 = itv->vbi.cc_data_odd[1];
522 u8 cc_even0 = itv->vbi.cc_data_even[0];
523 u8 cc_even1 = itv->vbi.cc_data_even[1];
524
525 memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2);
526 memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
527 itv->vbi.cc_pos -= 2;
528 if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
529 continue;
530
531 /* Send to Saa7127 */
532 ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
533 if (itv->vbi.cc_pos == 0)
534 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
535 break;
536 }
537 }
538
539 if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
540 /* Lock */
541 ivtv_set_vps(itv, itv->vbi.vps_found,
542 itv->vbi.vps[0], itv->vbi.vps[1],
543 itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
544 }
545}