Commit | Line | Data |
---|---|---|
1a0adaf3 HV |
1 | /* |
2 | Vertical Blank Interval support functions | |
3 | Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | ||
20 | #include "ivtv-driver.h" | |
21 | #include "ivtv-video.h" | |
22 | #include "ivtv-vbi.h" | |
23 | #include "ivtv-ioctl.h" | |
24 | #include "ivtv-queue.h" | |
25 | ||
26 | static int odd_parity(u8 c) | |
27 | { | |
28 | c ^= (c >> 4); | |
29 | c ^= (c >> 2); | |
30 | c ^= (c >> 1); | |
31 | ||
32 | return c & 1; | |
33 | } | |
34 | ||
1a0adaf3 HV |
35 | static void passthrough_vbi_data(struct ivtv *itv, int cnt) |
36 | { | |
37 | int wss = 0; | |
38 | u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 }; | |
39 | u8 vps[13]; | |
40 | int found_cc = 0; | |
41 | int found_wss = 0; | |
42 | int found_vps = 0; | |
43 | int cc_pos = itv->vbi.cc_pos; | |
44 | int i; | |
45 | ||
46 | for (i = 0; i < cnt; i++) { | |
47 | struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i; | |
48 | ||
49 | if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) { | |
50 | found_cc = 1; | |
51 | if (d->field) { | |
52 | cc[2] = d->data[0]; | |
53 | cc[3] = d->data[1]; | |
54 | } else { | |
55 | cc[0] = d->data[0]; | |
56 | cc[1] = d->data[1]; | |
57 | } | |
58 | } | |
59 | else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) { | |
60 | memcpy(vps, d->data, sizeof(vps)); | |
61 | found_vps = 1; | |
62 | } | |
63 | else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) { | |
64 | 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 | ||
75 | if (found_vps || itv->vbi.vps_found) { | |
76 | itv->vbi.vps[0] = vps[2]; | |
77 | itv->vbi.vps[1] = vps[8]; | |
78 | itv->vbi.vps[2] = vps[9]; | |
79 | itv->vbi.vps[3] = vps[10]; | |
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 | } | |
84 | ||
85 | if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) { | |
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); | |
92 | } | |
93 | } | |
94 | ||
95 | static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp) | |
96 | { | |
97 | int line = 0; | |
98 | int i; | |
99 | u32 linemask[2] = { 0, 0 }; | |
100 | unsigned short size; | |
101 | static const u8 mpeg_hdr_data[] = { | |
102 | 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, | |
103 | 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, | |
104 | 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, | |
105 | 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff | |
106 | }; | |
107 | const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ | |
108 | int idx = itv->vbi.frame % IVTV_VBI_FRAMES; | |
109 | u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0]; | |
110 | ||
111 | for (i = 0; i < lines; i++) { | |
112 | int f, l; | |
113 | ||
114 | if (itv->vbi.sliced_data[i].id == 0) | |
115 | continue; | |
116 | ||
117 | l = itv->vbi.sliced_data[i].line - 6; | |
118 | f = itv->vbi.sliced_data[i].field; | |
119 | if (f) | |
120 | l += 18; | |
121 | if (l < 32) | |
122 | linemask[0] |= (1 << l); | |
123 | else | |
124 | linemask[1] |= (1 << (l - 32)); | |
125 | dst[sd + 12 + line * 43] = service2vbi(itv->vbi.sliced_data[i].id); | |
126 | memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42); | |
127 | line++; | |
128 | } | |
129 | memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); | |
130 | if (line == 36) { | |
131 | /* All lines are used, so there is no space for the linemask | |
132 | (the max size of the VBI data is 36 * 43 + 4 bytes). | |
133 | So in this case we use the magic number 'ITV0'. */ | |
134 | memcpy(dst + sd, "ITV0", 4); | |
135 | memcpy(dst + sd + 4, dst + sd + 12, line * 43); | |
136 | size = 4 + ((43 * line + 3) & ~3); | |
137 | } else { | |
138 | memcpy(dst + sd, "itv0", 4); | |
139 | memcpy(dst + sd + 4, &linemask[0], 8); | |
140 | size = 12 + ((43 * line + 3) & ~3); | |
141 | } | |
142 | dst[4+16] = (size + 10) >> 8; | |
143 | dst[5+16] = (size + 10) & 0xff; | |
144 | dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); | |
145 | dst[10+16] = (pts_stamp >> 22) & 0xff; | |
146 | dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); | |
147 | dst[12+16] = (pts_stamp >> 7) & 0xff; | |
148 | dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); | |
149 | itv->vbi.sliced_mpeg_size[idx] = sd + size; | |
150 | } | |
151 | ||
152 | static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p) | |
153 | { | |
154 | u32 linemask[2]; | |
155 | int i, l, id2; | |
156 | int line = 0; | |
157 | ||
158 | if (!memcmp(p, "itv0", 4)) { | |
159 | memcpy(linemask, p + 4, 8); | |
160 | p += 12; | |
161 | } else if (!memcmp(p, "ITV0", 4)) { | |
162 | linemask[0] = 0xffffffff; | |
163 | linemask[1] = 0xf; | |
164 | p += 4; | |
165 | } else { | |
166 | /* unknown VBI data stream */ | |
167 | return 0; | |
168 | } | |
169 | for (i = 0; i < 36; i++) { | |
170 | int err = 0; | |
171 | ||
172 | if (i < 32 && !(linemask[0] & (1 << i))) | |
173 | continue; | |
174 | if (i >= 32 && !(linemask[1] & (1 << (i - 32)))) | |
175 | continue; | |
176 | id2 = *p & 0xf; | |
177 | switch (id2) { | |
178 | case IVTV_SLICED_TYPE_TELETEXT_B: | |
179 | id2 = V4L2_SLICED_TELETEXT_B; | |
180 | break; | |
181 | case IVTV_SLICED_TYPE_CAPTION_525: | |
182 | id2 = V4L2_SLICED_CAPTION_525; | |
183 | err = !odd_parity(p[1]) || !odd_parity(p[2]); | |
184 | break; | |
185 | case IVTV_SLICED_TYPE_VPS: | |
186 | id2 = V4L2_SLICED_VPS; | |
187 | break; | |
188 | case IVTV_SLICED_TYPE_WSS_625: | |
189 | id2 = V4L2_SLICED_WSS_625; | |
190 | break; | |
191 | default: | |
192 | id2 = 0; | |
193 | break; | |
194 | } | |
195 | if (err == 0) { | |
196 | l = (i < 18) ? i + 6 : i - 18 + 6; | |
197 | itv->vbi.sliced_dec_data[line].line = l; | |
198 | itv->vbi.sliced_dec_data[line].field = i >= 18; | |
199 | itv->vbi.sliced_dec_data[line].id = id2; | |
200 | memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42); | |
201 | line++; | |
202 | } | |
203 | p += 43; | |
204 | } | |
205 | while (line < 36) { | |
206 | itv->vbi.sliced_dec_data[line].id = 0; | |
207 | itv->vbi.sliced_dec_data[line].line = 0; | |
208 | itv->vbi.sliced_dec_data[line].field = 0; | |
209 | line++; | |
210 | } | |
211 | return line * sizeof(itv->vbi.sliced_dec_data[0]); | |
212 | } | |
213 | ||
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 | ||
1a0adaf3 HV |
222 | while (count >= sizeof(struct v4l2_sliced_vbi_data)) { |
223 | switch (p->id) { | |
224 | case V4L2_SLICED_CAPTION_525: | |
47fd3ba9 HV |
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 | } | |
1a0adaf3 HV |
234 | } |
235 | break; | |
236 | ||
237 | case V4L2_SLICED_VPS: | |
47fd3ba9 | 238 | if (p->line == 16 && p->field == 0) { |
1a0adaf3 HV |
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: | |
47fd3ba9 | 250 | if (p->line == 23 && p->field == 0) { |
1a0adaf3 HV |
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 | |
278 | field. | |
279 | Returns new compressed size. */ | |
280 | static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) | |
281 | { | |
282 | u32 line_size = itv->vbi.raw_decoder_line_size; | |
283 | u32 lines = itv->vbi.count; | |
284 | u8 sav1 = itv->vbi.raw_decoder_sav_odd_field; | |
285 | u8 sav2 = itv->vbi.raw_decoder_sav_even_field; | |
286 | u8 *q = buf; | |
287 | u8 *p; | |
288 | int i; | |
289 | ||
290 | for (i = 0; i < lines; i++) { | |
291 | p = buf + i * line_size; | |
292 | ||
293 | /* Look for SAV code */ | |
294 | if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) { | |
295 | break; | |
296 | } | |
297 | memcpy(q, p + 4, line_size - 4); | |
298 | q += line_size - 4; | |
299 | } | |
300 | return lines * (line_size - 4); | |
301 | } | |
302 | ||
303 | ||
304 | /* Compressed VBI format, all found sliced blocks put next to one another | |
305 | Returns new compressed size */ | |
306 | static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) | |
307 | { | |
308 | u32 line_size = itv->vbi.sliced_decoder_line_size; | |
309 | struct v4l2_decode_vbi_line vbi; | |
310 | int i; | |
311 | ||
312 | /* find the first valid line */ | |
313 | for (i = 0; i < size; i++, buf++) { | |
314 | if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) | |
315 | break; | |
316 | } | |
317 | ||
318 | size -= i; | |
319 | if (size < line_size) { | |
320 | return line; | |
321 | } | |
322 | for (i = 0; i < size / line_size; i++) { | |
323 | u8 *p = buf + i * line_size; | |
324 | ||
325 | /* Look for SAV code */ | |
326 | if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) { | |
327 | continue; | |
328 | } | |
329 | vbi.p = p + 4; | |
330 | itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); | |
331 | if (vbi.type) { | |
332 | itv->vbi.sliced_data[line].id = vbi.type; | |
333 | itv->vbi.sliced_data[line].field = vbi.is_second_field; | |
334 | itv->vbi.sliced_data[line].line = vbi.line; | |
335 | memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42); | |
336 | line++; | |
337 | } | |
338 | } | |
339 | return line; | |
340 | } | |
341 | ||
342 | void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf, | |
343 | u64 pts_stamp, int streamtype) | |
344 | { | |
345 | u8 *p = (u8 *) buf->buf; | |
346 | u32 size = buf->bytesused; | |
347 | int y; | |
348 | ||
349 | /* Raw VBI data */ | |
350 | if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set == 0) { | |
351 | u8 type; | |
352 | ||
353 | ivtv_buf_swap(buf); | |
354 | ||
355 | type = p[3]; | |
356 | ||
357 | size = buf->bytesused = compress_raw_buf(itv, p, size); | |
358 | ||
359 | /* second field of the frame? */ | |
360 | if (type == itv->vbi.raw_decoder_sav_even_field) { | |
361 | /* Dirty hack needed for backwards | |
362 | compatibility of old VBI software. */ | |
363 | p += size - 4; | |
364 | memcpy(p, &itv->vbi.frame, 4); | |
365 | itv->vbi.frame++; | |
366 | } | |
367 | return; | |
368 | } | |
369 | ||
370 | /* Sliced VBI data with data insertion */ | |
371 | if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) { | |
372 | int lines; | |
373 | ||
374 | ivtv_buf_swap(buf); | |
375 | ||
376 | /* first field */ | |
377 | lines = compress_sliced_buf(itv, 0, p, size / 2, | |
378 | itv->vbi.sliced_decoder_sav_odd_field); | |
379 | /* second field */ | |
380 | /* experimentation shows that the second half does not always begin | |
381 | at the exact address. So start a bit earlier (hence 32). */ | |
382 | lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32, | |
383 | itv->vbi.sliced_decoder_sav_even_field); | |
384 | /* always return at least one empty line */ | |
385 | if (lines == 0) { | |
386 | itv->vbi.sliced_data[0].id = 0; | |
387 | itv->vbi.sliced_data[0].line = 0; | |
388 | itv->vbi.sliced_data[0].field = 0; | |
389 | lines = 1; | |
390 | } | |
391 | buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]); | |
392 | memcpy(p, &itv->vbi.sliced_data[0], size); | |
393 | ||
394 | if (itv->vbi.insert_mpeg) { | |
395 | copy_vbi_data(itv, lines, pts_stamp); | |
396 | } | |
397 | itv->vbi.frame++; | |
398 | return; | |
399 | } | |
400 | ||
401 | /* Sliced VBI re-inserted from an MPEG stream */ | |
402 | if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) { | |
403 | /* If the size is not 4-byte aligned, then the starting address | |
404 | for the swapping is also shifted. After swapping the data the | |
405 | real start address of the VBI data is exactly 4 bytes after the | |
406 | original start. It's a bit fiddly but it works like a charm. | |
407 | Non-4-byte alignment happens when an lseek is done on the input | |
408 | mpeg file to a non-4-byte aligned position. So on arrival here | |
409 | the VBI data is also non-4-byte aligned. */ | |
410 | int offset = size & 3; | |
411 | int cnt; | |
412 | ||
413 | if (offset) { | |
414 | p += 4 - offset; | |
415 | } | |
416 | /* Swap Buffer */ | |
417 | for (y = 0; y < size; y += 4) { | |
418 | swab32s((u32 *)(p + y)); | |
419 | } | |
420 | ||
421 | cnt = ivtv_convert_ivtv_vbi(itv, p + offset); | |
422 | memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt); | |
423 | buf->bytesused = cnt; | |
424 | ||
425 | passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0])); | |
426 | return; | |
427 | } | |
428 | } | |
429 | ||
430 | void ivtv_disable_vbi(struct ivtv *itv) | |
431 | { | |
432 | clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags); | |
433 | clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags); | |
434 | clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags); | |
435 | ivtv_set_wss(itv, 0, 0); | |
436 | ivtv_set_cc(itv, 0, 0, 0, 0, 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 | } | |
442 | ||
1e13f9e3 | 443 | |
dc02d50a | 444 | void ivtv_vbi_work_handler(struct ivtv *itv) |
1a0adaf3 | 445 | { |
1a0adaf3 | 446 | struct v4l2_sliced_vbi_data data; |
1a0adaf3 HV |
447 | |
448 | /* Lock */ | |
449 | 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) { | |
453 | data.id = V4L2_SLICED_WSS_625; | |
454 | data.field = 0; | |
455 | ||
456 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | |
457 | ivtv_set_wss(itv, 1, data.data[0] & 0xf); | |
458 | itv->vbi.wss_no_update = 0; | |
459 | } else if (itv->vbi.wss_no_update == 4) { | |
460 | ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */ | |
461 | } else { | |
462 | itv->vbi.wss_no_update++; | |
463 | } | |
464 | } | |
465 | else { | |
466 | u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0; | |
467 | int mode = 0; | |
468 | ||
469 | data.id = V4L2_SLICED_CAPTION_525; | |
470 | data.field = 0; | |
471 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | |
472 | mode |= 1; | |
473 | c1 = data.data[0]; | |
474 | c2 = data.data[1]; | |
475 | } | |
476 | data.field = 1; | |
477 | if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) { | |
478 | mode |= 2; | |
479 | c3 = data.data[0]; | |
480 | c4 = data.data[1]; | |
481 | } | |
482 | if (mode) { | |
483 | itv->vbi.cc_no_update = 0; | |
484 | ivtv_set_cc(itv, mode, c1, c2, c3, c4); | |
485 | } else if (itv->vbi.cc_no_update == 4) { | |
486 | ivtv_set_cc(itv, 0, 0, 0, 0, 0); | |
487 | } else { | |
488 | itv->vbi.cc_no_update++; | |
489 | } | |
490 | } | |
491 | return; | |
492 | } | |
493 | ||
494 | if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) { | |
495 | /* Lock */ | |
496 | ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf); | |
497 | } | |
498 | ||
499 | if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) { | |
500 | if (itv->vbi.cc_pos == 0) { | |
501 | ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80); | |
502 | } | |
503 | while (itv->vbi.cc_pos) { | |
504 | u8 cc_odd0 = itv->vbi.cc_data_odd[0]; | |
505 | u8 cc_odd1 = itv->vbi.cc_data_odd[1]; | |
506 | u8 cc_even0 = itv->vbi.cc_data_even[0]; | |
507 | u8 cc_even1 = itv->vbi.cc_data_even[1]; | |
508 | ||
509 | memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2); | |
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; | |
514 | ||
515 | /* Send to Saa7127 */ | |
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; | |
520 | } | |
521 | } | |
522 | ||
523 | if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) { | |
524 | /* Lock */ | |
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 | } | |
529 | } |