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.c283
1 files changed, 127 insertions, 156 deletions
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index a7282a91bd97..c151bcf5519a 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -18,10 +18,69 @@
18 */ 18 */
19 19
20#include "ivtv-driver.h" 20#include "ivtv-driver.h"
21#include "ivtv-video.h" 21#include "ivtv-i2c.h"
22#include "ivtv-vbi.h"
23#include "ivtv-ioctl.h" 22#include "ivtv-ioctl.h"
24#include "ivtv-queue.h" 23#include "ivtv-queue.h"
24#include "ivtv-vbi.h"
25
26static void ivtv_set_vps(struct ivtv *itv, int enabled)
27{
28 struct v4l2_sliced_vbi_data data;
29
30 if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
31 return;
32 data.id = V4L2_SLICED_VPS;
33 data.field = 0;
34 data.line = enabled ? 16 : 0;
35 data.data[2] = itv->vbi.vps_payload.data[0];
36 data.data[8] = itv->vbi.vps_payload.data[1];
37 data.data[9] = itv->vbi.vps_payload.data[2];
38 data.data[10] = itv->vbi.vps_payload.data[3];
39 data.data[11] = itv->vbi.vps_payload.data[4];
40 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
41}
42
43static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
44{
45 struct v4l2_sliced_vbi_data data;
46
47 if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
48 return;
49 data.id = V4L2_SLICED_CAPTION_525;
50 data.field = 0;
51 data.line = (mode & 1) ? 21 : 0;
52 data.data[0] = cc->odd[0];
53 data.data[1] = cc->odd[1];
54 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
55 data.field = 1;
56 data.line = (mode & 2) ? 21 : 0;
57 data.data[0] = cc->even[0];
58 data.data[1] = cc->even[1];
59 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
60}
61
62static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
63{
64 struct v4l2_sliced_vbi_data data;
65
66 if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
67 return;
68 /* When using a 50 Hz system, always turn on the
69 wide screen signal with 4x3 ratio as the default.
70 Turning this signal on and off can confuse certain
71 TVs. As far as I can tell there is no reason not to
72 transmit this signal. */
73 if ((itv->std & V4L2_STD_625_50) && !enabled) {
74 enabled = 1;
75 mode = 0x08; /* 4x3 full format */
76 }
77 data.id = V4L2_SLICED_WSS_625;
78 data.field = 0;
79 data.line = enabled ? 23 : 0;
80 data.data[0] = mode & 0xff;
81 data.data[1] = (mode >> 8) & 0xff;
82 ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
83}
25 84
26static int odd_parity(u8 c) 85static int odd_parity(u8 c)
27{ 86{
@@ -32,62 +91,50 @@ static int odd_parity(u8 c)
32 return c & 1; 91 return c & 1;
33} 92}
34 93
35static 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)
36{ 95{
37 int wss = 0; 96 struct vbi_info *vi = &itv->vbi;
38 u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; 97 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
39 u8 vps[13];
40 int found_cc = 0; 98 int found_cc = 0;
41 int found_wss = 0; 99 size_t i;
42 int found_vps = 0;
43 int cc_pos = itv->vbi.cc_pos;
44 int i;
45 100
46 for (i = 0; i < cnt; i++) { 101 for (i = 0; i < cnt; i++) {
47 struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; 102 const struct v4l2_sliced_vbi_data *d = sliced + i;
48 103
49 if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { 104 if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
50 found_cc = 1;
51 if (d->field) { 105 if (d->field) {
52 cc[2] = d->data[0]; 106 cc.even[0] = d->data[0];
53 cc[3] = d->data[1]; 107 cc.even[1] = d->data[1];
54 } else { 108 } else {
55 cc[0] = d->data[0]; 109 cc.odd[0] = d->data[0];
56 cc[1] = d->data[1]; 110 cc.odd[1] = d->data[1];
57 } 111 }
112 found_cc = 1;
58 } 113 }
59 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) {
60 memcpy(vps, d->data, sizeof(vps)); 115 struct vbi_vps vps;
61 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 }
62 } 126 }
63 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) {
64 wss = d->data[0] | d->data[1] << 8; 128 int wss = d->data[0] | d->data[1] << 8;
65 found_wss = 1;
66 }
67 }
68
69 if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
70 itv->vbi.wss = wss;
71 itv->vbi.wss_found = found_wss;
72 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
73 }
74 129
75 if (found_vps || itv->vbi.vps_found) { 130 if (vi->wss_payload != wss) {
76 itv->vbi.vps[0] = vps[2]; 131 vi->wss_payload = wss;
77 itv->vbi.vps[1] = vps[8]; 132 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
78 itv->vbi.vps[2] = vps[9]; 133 }
79 itv->vbi.vps[3] = vps[10]; 134 }
80 itv->vbi.vps[4] = vps[11];
81 itv->vbi.vps_found = found_vps;
82 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
83 } 135 }
84 136 if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
85 if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { 137 vi->cc_payload[vi->cc_payload_idx++] = cc;
86 itv->vbi.cc_data_odd[cc_pos] = cc[0];
87 itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
88 itv->vbi.cc_data_even[cc_pos] = cc[2];
89 itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
90 itv->vbi.cc_pos = cc_pos + 2;
91 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); 138 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
92 } 139 }
93} 140}
@@ -163,8 +210,8 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
163 linemask[1] = 0xf; 210 linemask[1] = 0xf;
164 p += 4; 211 p += 4;
165 } else { 212 } else {
166 /* unknown VBI data stream */ 213 /* unknown VBI data, convert to empty VBI frame */
167 return 0; 214 linemask[0] = linemask[1] = 0;
168 } 215 }
169 for (i = 0; i < 36; i++) { 216 for (i = 0; i < 36; i++) {
170 int err = 0; 217 int err = 0;
@@ -211,69 +258,6 @@ static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
211 return line * sizeof(itv->vbi.sliced_dec_data[0]); 258 return line * sizeof(itv->vbi.sliced_dec_data[0]);
212} 259}
213 260
214ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
215{
216 /* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
217 const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
218 u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
219 int found_cc = 0;
220 int cc_pos = itv->vbi.cc_pos;
221
222 while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
223 switch (p->id) {
224 case V4L2_SLICED_CAPTION_525:
225 if (p->line == 21) {
226 found_cc = 1;
227 if (p->field) {
228 cc[2] = p->data[0];
229 cc[3] = p->data[1];
230 } else {
231 cc[0] = p->data[0];
232 cc[1] = p->data[1];
233 }
234 }
235 break;
236
237 case V4L2_SLICED_VPS:
238 if (p->line == 16 && p->field == 0) {
239 itv->vbi.vps[0] = p->data[2];
240 itv->vbi.vps[1] = p->data[8];
241 itv->vbi.vps[2] = p->data[9];
242 itv->vbi.vps[3] = p->data[10];
243 itv->vbi.vps[4] = p->data[11];
244 itv->vbi.vps_found = 1;
245 set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
246 }
247 break;
248
249 case V4L2_SLICED_WSS_625:
250 if (p->line == 23 && p->field == 0) {
251 /* No lock needed for WSS */
252 itv->vbi.wss = p->data[0] | (p->data[1] << 8);
253 itv->vbi.wss_found = 1;
254 set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
255 }
256 break;
257
258 default:
259 break;
260 }
261 count -= sizeof(*p);
262 p++;
263 }
264
265 if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
266 itv->vbi.cc_data_odd[cc_pos] = cc[0];
267 itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
268 itv->vbi.cc_data_even[cc_pos] = cc[2];
269 itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
270 itv->vbi.cc_pos = cc_pos + 2;
271 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
272 }
273
274 return (const char __user *)p - ubuf;
275}
276
277/* 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
278 field. 262 field.
279 Returns new compressed size. */ 263 Returns new compressed size. */
@@ -422,108 +406,95 @@ void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
422 memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); 406 memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
423 buf->bytesused = cnt; 407 buf->bytesused = cnt;
424 408
425 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]));
426 return; 411 return;
427 } 412 }
428} 413}
429 414
430void ivtv_disable_vbi(struct ivtv *itv) 415void ivtv_disable_cc(struct ivtv *itv)
431{ 416{
432 clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); 417 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
433 clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); 418
434 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); 419 clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
435 ivtv_set_wss(itv, 0, 0); 420 ivtv_set_cc(itv, 0, &cc);
436 ivtv_set_cc(itv, 0, 0, 0, 0, 0); 421 itv->vbi.cc_payload_idx = 0;
437 ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
438 itv->vbi.vps_found = itv->vbi.wss_found = 0;
439 itv->vbi.wss = 0;
440 itv->vbi.cc_pos = 0;
441} 422}
442 423
443 424
444void ivtv_vbi_work_handler(struct ivtv *itv) 425void ivtv_vbi_work_handler(struct ivtv *itv)
445{ 426{
427 struct vbi_info *vi = &itv->vbi;
446 struct v4l2_sliced_vbi_data data; 428 struct v4l2_sliced_vbi_data data;
429 struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
447 430
448 /* Lock */ 431 /* Lock */
449 if (itv->output_mode == OUT_PASSTHROUGH) { 432 if (itv->output_mode == OUT_PASSTHROUGH) {
450 /* Note: currently only the saa7115 is used in a PVR350,
451 so these commands are for now saa7115 specific. */
452 if (itv->is_50hz) { 433 if (itv->is_50hz) {
453 data.id = V4L2_SLICED_WSS_625; 434 data.id = V4L2_SLICED_WSS_625;
454 data.field = 0; 435 data.field = 0;
455 436
456 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) {
457 ivtv_set_wss(itv, 1, data.data[0] & 0xf); 438 ivtv_set_wss(itv, 1, data.data[0] & 0xf);
458 itv->vbi.wss_no_update = 0; 439 vi->wss_missing_cnt = 0;
459 } else if (itv->vbi.wss_no_update == 4) { 440 } else if (vi->wss_missing_cnt == 4) {
460 ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ 441 ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
461 } else { 442 } else {
462 itv->vbi.wss_no_update++; 443 vi->wss_missing_cnt++;
463 } 444 }
464 } 445 }
465 else { 446 else {
466 u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
467 int mode = 0; 447 int mode = 0;
468 448
469 data.id = V4L2_SLICED_CAPTION_525; 449 data.id = V4L2_SLICED_CAPTION_525;
470 data.field = 0; 450 data.field = 0;
471 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) {
472 mode |= 1; 452 mode |= 1;
473 c1 = data.data[0]; 453 cc.odd[0] = data.data[0];
474 c2 = data.data[1]; 454 cc.odd[1] = data.data[1];
475 } 455 }
476 data.field = 1; 456 data.field = 1;
477 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) {
478 mode |= 2; 458 mode |= 2;
479 c3 = data.data[0]; 459 cc.even[0] = data.data[0];
480 c4 = data.data[1]; 460 cc.even[1] = data.data[1];
481 } 461 }
482 if (mode) { 462 if (mode) {
483 itv->vbi.cc_no_update = 0; 463 vi->cc_missing_cnt = 0;
484 ivtv_set_cc(itv, mode, c1, c2, c3, c4); 464 ivtv_set_cc(itv, mode, &cc);
485 } else if (itv->vbi.cc_no_update == 4) { 465 } else if (vi->cc_missing_cnt == 4) {
486 ivtv_set_cc(itv, 0, 0, 0, 0, 0); 466 ivtv_set_cc(itv, 0, &cc);
487 } else { 467 } else {
488 itv->vbi.cc_no_update++; 468 vi->cc_missing_cnt++;
489 } 469 }
490 } 470 }
491 return; 471 return;
492 } 472 }
493 473
494 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)) {
495 /* Lock */ 475 ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
496 ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
497 } 476 }
498 477
499 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)) {
500 if (itv->vbi.cc_pos == 0) { 479 if (vi->cc_payload_idx == 0) {
501 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);
502 } 482 }
503 while (itv->vbi.cc_pos) { 483 while (vi->cc_payload_idx) {
504 u8 cc_odd0 = itv->vbi.cc_data_odd[0]; 484 cc = vi->cc_payload[0];
505 u8 cc_odd1 = itv->vbi.cc_data_odd[1]; 485
506 u8 cc_even0 = itv->vbi.cc_data_even[0]; 486 memcpy(vi->cc_payload, vi->cc_payload + 1,
507 u8 cc_even1 = itv->vbi.cc_data_even[1]; 487 sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
508 488 vi->cc_payload_idx--;
509 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)
510 memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
511 itv->vbi.cc_pos -= 2;
512 if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
513 continue; 490 continue;
514 491
515 /* Send to Saa7127 */ 492 ivtv_set_cc(itv, 3, &cc);
516 ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
517 if (itv->vbi.cc_pos == 0)
518 set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
519 break; 493 break;
520 } 494 }
521 } 495 }
522 496
523 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)) {
524 /* Lock */ 498 ivtv_set_vps(itv, 1);
525 ivtv_set_vps(itv, itv->vbi.vps_found,
526 itv->vbi.vps[0], itv->vbi.vps[1],
527 itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
528 } 499 }
529} 500}