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.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}