diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-vbi.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-vbi.c | 283 |
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 | |||
26 | static 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 | |||
43 | static 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 | |||
62 | static 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 | ||
26 | static int odd_parity(u8 c) | 85 | static 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 | ||
35 | 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) |
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 | ||
214 | ssize_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 | ||
430 | void ivtv_disable_vbi(struct ivtv *itv) | 415 | void 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 | ||
444 | void ivtv_vbi_work_handler(struct ivtv *itv) | 425 | void 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 | } |