diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-vbi.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-vbi.c | 239 |
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 | ||
26 | static void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3, | 26 | static 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 | ||
44 | static void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4) | 43 | static 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 | ||
95 | static void passthrough_vbi_data(struct ivtv *itv, int cnt) | 94 | void 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 | ||
274 | ssize_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 | ||
490 | void ivtv_disable_vbi(struct ivtv *itv) | 415 | void 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 | ||
504 | void ivtv_vbi_work_handler(struct ivtv *itv) | 425 | void 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 | } |