aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ivtv/ivtv-vbi.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2007-08-25 13:11:23 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-10-09 21:07:14 -0400
commit2f3a98931f51be6093df7c6cc2633bf238778b7d (patch)
treef25f00c9f0a46c9c4885a24445dc795a2151fc97 /drivers/media/video/ivtv/ivtv-vbi.c
parent26e9d599561e9a964bd4d7c2be0029db8aaff852 (diff)
V4L/DVB (6116): ivtv: VBI cleanups and fixes
Besides some VBI cleanups this patch also fixes a subtle problem with the VBI re-insertion stream where the PIO work handler wasn't called quickly enough, resulting in occasional corrupt data. Furthermore the CC output didn't disable CC correctly and at the right time, causing duplicates to be sent. An saa7127 fix for VPS output was also added: the wrong data was sent. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-vbi.c')
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c239
1 files changed, 75 insertions, 164 deletions
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 5d8a40f3d2b6..c151bcf5519a 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -23,8 +23,7 @@
23#include "ivtv-queue.h" 23#include "ivtv-queue.h"
24#include "ivtv-vbi.h" 24#include "ivtv-vbi.h"
25 25
26static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, 26static void ivtv_set_vps(struct ivtv *itv, int enabled)
27 u8 vps4, u8 vps5)
28{ 27{
29 struct v4l2_sliced_vbi_data data; 28 struct v4l2_sliced_vbi_data data;
30 29
@@ -33,15 +32,15 @@ static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps
33 data.id = V4L2_SLICED_VPS; 32 data.id = V4L2_SLICED_VPS;
34 data.field = 0; 33 data.field = 0;
35 data.line = enabled ? 16 : 0; 34 data.line = enabled ? 16 : 0;
36 data.data[4] = vps1; 35 data.data[2] = itv->vbi.vps_payload.data[0];
37 data.data[10] = vps2; 36 data.data[8] = itv->vbi.vps_payload.data[1];
38 data.data[11] = vps3; 37 data.data[9] = itv->vbi.vps_payload.data[2];
39 data.data[12] = vps4; 38 data.data[10] = itv->vbi.vps_payload.data[3];
40 data.data[13] = vps5; 39 data.data[11] = itv->vbi.vps_payload.data[4];
41 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); 40 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
42} 41}
43 42
44static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) 43static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
45{ 44{
46 struct v4l2_sliced_vbi_data data; 45 struct v4l2_sliced_vbi_data data;
47 46
@@ -50,13 +49,13 @@ static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 c
50 data.id = V4L2_SLICED_CAPTION_525; 49 data.id = V4L2_SLICED_CAPTION_525;
51 data.field = 0; 50 data.field = 0;
52 data.line = (mode & 1) ? 21 : 0; 51 data.line = (mode & 1) ? 21 : 0;
53 data.data[0] = cc1; 52 data.data[0] = cc->odd[0];
54 data.data[1] = cc2; 53 data.data[1] = cc->odd[1];
55 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); 54 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
56 data.field = 1; 55 data.field = 1;
57 data.line = (mode & 2) ? 21 : 0; 56 data.line = (mode & 2) ? 21 : 0;
58 data.data[0] = cc3; 57 data.data[0] = cc->even[0];
59 data.data[1] = cc4; 58 data.data[1] = cc->even[1];
60 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data); 59 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
61} 60}
62 61
@@ -92,62 +91,50 @@ static int odd_parity(u8 c)
92 return c & 1; 91 return c & 1;
93} 92}
94 93
95static void passthrough_vbi_data(struct ivtv *itv, int cnt) 94void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
96{ 95{
97 int wss = 0; 96 struct vbi_info *vi = &itv->vbi;
98 u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; 97 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
99 u8 vps[13];
100 int found_cc = 0; 98 int found_cc = 0;
101 int found_wss = 0; 99 size_t i;
102 int found_vps = 0;
103 int cc_pos = itv->vbi.cc_pos;
104 int i;
105 100
106 for (i = 0; i < cnt; i++) { 101 for (i = 0; i < cnt; i++) {
107 struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; 102 const struct v4l2_sliced_vbi_data *d = sliced + i;
108 103
109 if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { 104 if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
110 found_cc = 1;
111 if (d->field) { 105 if (d->field) {
112 cc[2] = d->data[0]; 106 cc.even[0] = d->data[0];
113 cc[3] = d->data[1]; 107 cc.even[1] = d->data[1];
114 } else { 108 } else {
115 cc[0] = d->data[0]; 109 cc.odd[0] = d->data[0];
116 cc[1] = d->data[1]; 110 cc.odd[1] = d->data[1];
117 } 111 }
112 found_cc = 1;
118 } 113 }
119 else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { 114 else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
120 memcpy(vps, d->data, sizeof(vps)); 115 struct vbi_vps vps;
121 found_vps = 1; 116
117 vps.data[0] = d->data[2];
118 vps.data[1] = d->data[8];
119 vps.data[2] = d->data[9];
120 vps.data[3] = d->data[10];
121 vps.data[4] = d->data[11];
122 if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
123 vi->vps_payload = vps;
124 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
125 }
122 } 126 }
123 else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { 127 else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
124 wss = d->data[0] | d->data[1] << 8; 128 int wss = d->data[0] | d->data[1] << 8;
125 found_wss = 1;
126 }
127 }
128 129
129 if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) { 130 if (vi->wss_payload != wss) {
130 itv->vbi.wss = wss; 131 vi->wss_payload = wss;
131 itv->vbi.wss_found = found_wss; 132 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
132 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); 133 }
133 } 134 }
134
135 if (found_vps || itv->vbi.vps_found) {
136 itv->vbi.vps[0] = vps[2];
137 itv->vbi.vps[1] = vps[8];
138 itv->vbi.vps[2] = vps[9];
139 itv->vbi.vps[3] = vps[10];
140 itv->vbi.vps[4] = vps[11];
141 itv->vbi.vps_found = found_vps;
142 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
143 } 135 }
144 136 if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
145 if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { 137 vi->cc_payload[vi->cc_payload_idx++] = cc;
146 itv->vbi.cc_data_odd[cc_pos] = cc[0];
147 itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
148 itv->vbi.cc_data_even[cc_pos] = cc[2];
149 itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
150 itv->vbi.cc_pos = cc_pos + 2;
151 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); 138 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
152 } 139 }
153} 140}
@@ -271,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
271 return line * sizeof(itv->vbi.sliced_dec_data[0]); 258 return line * sizeof(itv->vbi.sliced_dec_data[0]);
272} 259}
273 260
274ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
275{
276 /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
277 const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
278 u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
279 int found_cc = 0;
280 int cc_pos = itv->vbi.cc_pos;
281
282 while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
283 switch (p->id) {
284 case V4L2_SLICED_CAPTION_525:
285 if (p->line == 21) {
286 found_cc = 1;
287 if (p->field) {
288 cc[2] = p->data[0];
289 cc[3] = p->data[1];
290 } else {
291 cc[0] = p->data[0];
292 cc[1] = p->data[1];
293 }
294 }
295 break;
296
297 case V4L2_SLICED_VPS:
298 if (p->line == 16 && p->field == 0) {
299 itv->vbi.vps[0] = p->data[2];
300 itv->vbi.vps[1] = p->data[8];
301 itv->vbi.vps[2] = p->data[9];
302 itv->vbi.vps[3] = p->data[10];
303 itv->vbi.vps[4] = p->data[11];
304 itv->vbi.vps_found = 1;
305 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
306 }
307 break;
308
309 case V4L2_SLICED_WSS_625:
310 if (p->line == 23 && p->field == 0) {
311 /* No lock needed for WSS */
312 itv->vbi.wss = p->data[0] | (p->data[1] << 8);
313 itv->vbi.wss_found = 1;
314 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
315 }
316 break;
317
318 default:
319 break;
320 }
321 count -= sizeof(*p);
322 p++;
323 }
324
325 if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
326 itv->vbi.cc_data_odd[cc_pos] = cc[0];
327 itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
328 itv->vbi.cc_data_even[cc_pos] = cc[2];
329 itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
330 itv->vbi.cc_pos = cc_pos + 2;
331 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
332 }
333
334 return (const char __user *)p - ubuf;
335}
336
337/* Compress raw VBI format, removes leading SAV codes and surplus space after the 261/* Compress raw VBI format, removes leading SAV codes and surplus space after the
338 field. 262 field.
339 Returns new compressed size. */ 263 Returns new compressed size. */
@@ -482,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
482 memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); 406 memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
483 buf->bytesused = cnt; 407 buf->bytesused = cnt;
484 408
485 passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); 409 ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
410 cnt / sizeof(itv->vbi.sliced_dec_data[0]));
486 return; 411 return;
487 } 412 }
488} 413}
489 414
490void ivtv_disable_vbi(struct ivtv *itv) 415void ivtv_disable_cc(struct ivtv *itv)
491{ 416{
492 clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); 417 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
493 clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); 418
494 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); 419 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
495 ivtv_set_wss(itv, 0, 0); 420 ivtv_set_cc(itv, 0, &cc);
496 ivtv_set_cc(itv, 0, 0, 0, 0, 0); 421 itv->vbi.cc_payload_idx = 0;
497 ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
498 itv->vbi.vps_found = itv->vbi.wss_found = 0;
499 itv->vbi.wss = 0;
500 itv->vbi.cc_pos = 0;
501} 422}
502 423
503 424
504void ivtv_vbi_work_handler(struct ivtv *itv) 425void ivtv_vbi_work_handler(struct ivtv *itv)
505{ 426{
427 struct vbi_info *vi = &itv->vbi;
506 struct v4l2_sliced_vbi_data data; 428 struct v4l2_sliced_vbi_data data;
429 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
507 430
508 /* Lock */ 431 /* Lock */
509 if (itv->output_mode == OUT_PASSTHROUGH) { 432 if (itv->output_mode == OUT_PASSTHROUGH) {
510 /* Note: currently only the saa7115 is used in a PVR350,
511 so these commands are for now saa7115 specific. */
512 if (itv->is_50hz) { 433 if (itv->is_50hz) {
513 data.id = V4L2_SLICED_WSS_625; 434 data.id = V4L2_SLICED_WSS_625;
514 data.field = 0; 435 data.field = 0;
515 436
516 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { 437 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
517 ivtv_set_wss(itv, 1, data.data[0] & 0xf); 438 ivtv_set_wss(itv, 1, data.data[0] & 0xf);
518 itv->vbi.wss_no_update = 0; 439 vi->wss_missing_cnt = 0;
519 } else if (itv->vbi.wss_no_update == 4) { 440 } else if (vi->wss_missing_cnt == 4) {
520 ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ 441 ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
521 } else { 442 } else {
522 itv->vbi.wss_no_update++; 443 vi->wss_missing_cnt++;
523 } 444 }
524 } 445 }
525 else { 446 else {
526 u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
527 int mode = 0; 447 int mode = 0;
528 448
529 data.id = V4L2_SLICED_CAPTION_525; 449 data.id = V4L2_SLICED_CAPTION_525;
530 data.field = 0; 450 data.field = 0;
531 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { 451 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
532 mode |= 1; 452 mode |= 1;
533 c1 = data.data[0]; 453 cc.odd[0] = data.data[0];
534 c2 = data.data[1]; 454 cc.odd[1] = data.data[1];
535 } 455 }
536 data.field = 1; 456 data.field = 1;
537 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { 457 if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
538 mode |= 2; 458 mode |= 2;
539 c3 = data.data[0]; 459 cc.even[0] = data.data[0];
540 c4 = data.data[1]; 460 cc.even[1] = data.data[1];
541 } 461 }
542 if (mode) { 462 if (mode) {
543 itv->vbi.cc_no_update = 0; 463 vi->cc_missing_cnt = 0;
544 ivtv_set_cc(itv, mode, c1, c2, c3, c4); 464 ivtv_set_cc(itv, mode, &cc);
545 } else if (itv->vbi.cc_no_update == 4) { 465 } else if (vi->cc_missing_cnt == 4) {
546 ivtv_set_cc(itv, 0, 0, 0, 0, 0); 466 ivtv_set_cc(itv, 0, &cc);
547 } else { 467 } else {
548 itv->vbi.cc_no_update++; 468 vi->cc_missing_cnt++;
549 } 469 }
550 } 470 }
551 return; 471 return;
552 } 472 }
553 473
554 if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { 474 if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
555 /* Lock */ 475 ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
556 ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
557 } 476 }
558 477
559 if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { 478 if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
560 if (itv->vbi.cc_pos == 0) { 479 if (vi->cc_payload_idx == 0) {
561 ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); 480 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
481 ivtv_set_cc(itv, 3, &cc);
562 } 482 }
563 while (itv->vbi.cc_pos) { 483 while (vi->cc_payload_idx) {
564 u8 cc_odd0 = itv->vbi.cc_data_odd[0]; 484 cc = vi->cc_payload[0];
565 u8 cc_odd1 = itv->vbi.cc_data_odd[1]; 485
566 u8 cc_even0 = itv->vbi.cc_data_even[0]; 486 memcpy(vi->cc_payload, vi->cc_payload + 1,
567 u8 cc_even1 = itv->vbi.cc_data_even[1]; 487 sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
568 488 vi->cc_payload_idx--;
569 memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); 489 if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
570 memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
571 itv->vbi.cc_pos -= 2;
572 if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
573 continue; 490 continue;
574 491
575 /* Send to Saa7127 */ 492 ivtv_set_cc(itv, 3, &cc);
576 ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
577 if (itv->vbi.cc_pos == 0)
578 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
579 break; 493 break;
580 } 494 }
581 } 495 }
582 496
583 if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { 497 if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
584 /* Lock */ 498 ivtv_set_vps(itv, 1);
585 ivtv_set_vps(itv, itv->vbi.vps_found,
586 itv->vbi.vps[0], itv->vbi.vps[1],
587 itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
588 } 499 }
589} 500}