Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/ivtv/ivtv-vbi.c
17887 views
1
/*
2
Vertical Blank Interval support functions
3
Copyright (C) 2004-2007 Hans Verkuil <[email protected]>
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-i2c.h"
22
#include "ivtv-ioctl.h"
23
#include "ivtv-queue.h"
24
#include "ivtv-cards.h"
25
#include "ivtv-vbi.h"
26
27
static void ivtv_set_vps(struct ivtv *itv, int enabled)
28
{
29
struct v4l2_sliced_vbi_data data;
30
31
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
32
return;
33
data.id = V4L2_SLICED_VPS;
34
data.field = 0;
35
data.line = enabled ? 16 : 0;
36
data.data[2] = itv->vbi.vps_payload.data[0];
37
data.data[8] = itv->vbi.vps_payload.data[1];
38
data.data[9] = itv->vbi.vps_payload.data[2];
39
data.data[10] = itv->vbi.vps_payload.data[3];
40
data.data[11] = itv->vbi.vps_payload.data[4];
41
ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
42
}
43
44
static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
45
{
46
struct v4l2_sliced_vbi_data data;
47
48
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
49
return;
50
data.id = V4L2_SLICED_CAPTION_525;
51
data.field = 0;
52
data.line = (mode & 1) ? 21 : 0;
53
data.data[0] = cc->odd[0];
54
data.data[1] = cc->odd[1];
55
ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
56
data.field = 1;
57
data.line = (mode & 2) ? 21 : 0;
58
data.data[0] = cc->even[0];
59
data.data[1] = cc->even[1];
60
ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
61
}
62
63
static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
64
{
65
struct v4l2_sliced_vbi_data data;
66
67
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
68
return;
69
/* When using a 50 Hz system, always turn on the
70
wide screen signal with 4x3 ratio as the default.
71
Turning this signal on and off can confuse certain
72
TVs. As far as I can tell there is no reason not to
73
transmit this signal. */
74
if ((itv->std_out & V4L2_STD_625_50) && !enabled) {
75
enabled = 1;
76
mode = 0x08; /* 4x3 full format */
77
}
78
data.id = V4L2_SLICED_WSS_625;
79
data.field = 0;
80
data.line = enabled ? 23 : 0;
81
data.data[0] = mode & 0xff;
82
data.data[1] = (mode >> 8) & 0xff;
83
ivtv_call_hw(itv, IVTV_HW_SAA7127, vbi, s_vbi_data, &data);
84
}
85
86
static int odd_parity(u8 c)
87
{
88
c ^= (c >> 4);
89
c ^= (c >> 2);
90
c ^= (c >> 1);
91
92
return c & 1;
93
}
94
95
static void ivtv_write_vbi_line(struct ivtv *itv,
96
const struct v4l2_sliced_vbi_data *d,
97
struct vbi_cc *cc, int *found_cc)
98
{
99
struct vbi_info *vi = &itv->vbi;
100
101
if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
102
if (d->field) {
103
cc->even[0] = d->data[0];
104
cc->even[1] = d->data[1];
105
} else {
106
cc->odd[0] = d->data[0];
107
cc->odd[1] = d->data[1];
108
}
109
*found_cc = 1;
110
} else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
111
struct vbi_vps vps;
112
113
vps.data[0] = d->data[2];
114
vps.data[1] = d->data[8];
115
vps.data[2] = d->data[9];
116
vps.data[3] = d->data[10];
117
vps.data[4] = d->data[11];
118
if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
119
vi->vps_payload = vps;
120
set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
121
}
122
} else if (d->id == V4L2_SLICED_WSS_625 &&
123
d->line == 23 && d->field == 0) {
124
int wss = d->data[0] | d->data[1] << 8;
125
126
if (vi->wss_payload != wss) {
127
vi->wss_payload = wss;
128
set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
129
}
130
}
131
}
132
133
static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc)
134
{
135
struct vbi_info *vi = &itv->vbi;
136
137
if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
138
memcpy(&vi->cc_payload[vi->cc_payload_idx], cc,
139
sizeof(struct vbi_cc));
140
vi->cc_payload_idx++;
141
set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
142
}
143
}
144
145
static void ivtv_write_vbi(struct ivtv *itv,
146
const struct v4l2_sliced_vbi_data *sliced,
147
size_t cnt)
148
{
149
struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
150
int found_cc = 0;
151
size_t i;
152
153
for (i = 0; i < cnt; i++)
154
ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
155
156
if (found_cc)
157
ivtv_write_vbi_cc_lines(itv, &cc);
158
}
159
160
ssize_t
161
ivtv_write_vbi_from_user(struct ivtv *itv,
162
const struct v4l2_sliced_vbi_data __user *sliced,
163
size_t cnt)
164
{
165
struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
166
int found_cc = 0;
167
size_t i;
168
struct v4l2_sliced_vbi_data d;
169
ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data);
170
171
for (i = 0; i < cnt; i++) {
172
if (copy_from_user(&d, sliced + i,
173
sizeof(struct v4l2_sliced_vbi_data))) {
174
ret = -EFAULT;
175
break;
176
}
177
ivtv_write_vbi_line(itv, &d, &cc, &found_cc);
178
}
179
180
if (found_cc)
181
ivtv_write_vbi_cc_lines(itv, &cc);
182
183
return ret;
184
}
185
186
static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
187
{
188
int line = 0;
189
int i;
190
u32 linemask[2] = { 0, 0 };
191
unsigned short size;
192
static const u8 mpeg_hdr_data[] = {
193
0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
194
0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
195
0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
196
0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
197
};
198
const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
199
int idx = itv->vbi.frame % IVTV_VBI_FRAMES;
200
u8 *dst = &itv->vbi.sliced_mpeg_data[idx][0];
201
202
for (i = 0; i < lines; i++) {
203
int f, l;
204
205
if (itv->vbi.sliced_data[i].id == 0)
206
continue;
207
208
l = itv->vbi.sliced_data[i].line - 6;
209
f = itv->vbi.sliced_data[i].field;
210
if (f)
211
l += 18;
212
if (l < 32)
213
linemask[0] |= (1 << l);
214
else
215
linemask[1] |= (1 << (l - 32));
216
dst[sd + 12 + line * 43] =
217
ivtv_service2vbi(itv->vbi.sliced_data[i].id);
218
memcpy(dst + sd + 12 + line * 43 + 1, itv->vbi.sliced_data[i].data, 42);
219
line++;
220
}
221
memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
222
if (line == 36) {
223
/* All lines are used, so there is no space for the linemask
224
(the max size of the VBI data is 36 * 43 + 4 bytes).
225
So in this case we use the magic number 'ITV0'. */
226
memcpy(dst + sd, "ITV0", 4);
227
memcpy(dst + sd + 4, dst + sd + 12, line * 43);
228
size = 4 + ((43 * line + 3) & ~3);
229
} else {
230
memcpy(dst + sd, "itv0", 4);
231
cpu_to_le32s(&linemask[0]);
232
cpu_to_le32s(&linemask[1]);
233
memcpy(dst + sd + 4, &linemask[0], 8);
234
size = 12 + ((43 * line + 3) & ~3);
235
}
236
dst[4+16] = (size + 10) >> 8;
237
dst[5+16] = (size + 10) & 0xff;
238
dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
239
dst[10+16] = (pts_stamp >> 22) & 0xff;
240
dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
241
dst[12+16] = (pts_stamp >> 7) & 0xff;
242
dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
243
itv->vbi.sliced_mpeg_size[idx] = sd + size;
244
}
245
246
static int ivtv_convert_ivtv_vbi(struct ivtv *itv, u8 *p)
247
{
248
u32 linemask[2];
249
int i, l, id2;
250
int line = 0;
251
252
if (!memcmp(p, "itv0", 4)) {
253
memcpy(linemask, p + 4, 8);
254
p += 12;
255
} else if (!memcmp(p, "ITV0", 4)) {
256
linemask[0] = 0xffffffff;
257
linemask[1] = 0xf;
258
p += 4;
259
} else {
260
/* unknown VBI data, convert to empty VBI frame */
261
linemask[0] = linemask[1] = 0;
262
}
263
for (i = 0; i < 36; i++) {
264
int err = 0;
265
266
if (i < 32 && !(linemask[0] & (1 << i)))
267
continue;
268
if (i >= 32 && !(linemask[1] & (1 << (i - 32))))
269
continue;
270
id2 = *p & 0xf;
271
switch (id2) {
272
case IVTV_SLICED_TYPE_TELETEXT_B:
273
id2 = V4L2_SLICED_TELETEXT_B;
274
break;
275
case IVTV_SLICED_TYPE_CAPTION_525:
276
id2 = V4L2_SLICED_CAPTION_525;
277
err = !odd_parity(p[1]) || !odd_parity(p[2]);
278
break;
279
case IVTV_SLICED_TYPE_VPS:
280
id2 = V4L2_SLICED_VPS;
281
break;
282
case IVTV_SLICED_TYPE_WSS_625:
283
id2 = V4L2_SLICED_WSS_625;
284
break;
285
default:
286
id2 = 0;
287
break;
288
}
289
if (err == 0) {
290
l = (i < 18) ? i + 6 : i - 18 + 6;
291
itv->vbi.sliced_dec_data[line].line = l;
292
itv->vbi.sliced_dec_data[line].field = i >= 18;
293
itv->vbi.sliced_dec_data[line].id = id2;
294
memcpy(itv->vbi.sliced_dec_data[line].data, p + 1, 42);
295
line++;
296
}
297
p += 43;
298
}
299
while (line < 36) {
300
itv->vbi.sliced_dec_data[line].id = 0;
301
itv->vbi.sliced_dec_data[line].line = 0;
302
itv->vbi.sliced_dec_data[line].field = 0;
303
line++;
304
}
305
return line * sizeof(itv->vbi.sliced_dec_data[0]);
306
}
307
308
/* Compress raw VBI format, removes leading SAV codes and surplus space after the
309
field.
310
Returns new compressed size. */
311
static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size)
312
{
313
u32 line_size = itv->vbi.raw_decoder_line_size;
314
u32 lines = itv->vbi.count;
315
u8 sav1 = itv->vbi.raw_decoder_sav_odd_field;
316
u8 sav2 = itv->vbi.raw_decoder_sav_even_field;
317
u8 *q = buf;
318
u8 *p;
319
int i;
320
321
for (i = 0; i < lines; i++) {
322
p = buf + i * line_size;
323
324
/* Look for SAV code */
325
if (p[0] != 0xff || p[1] || p[2] || (p[3] != sav1 && p[3] != sav2)) {
326
break;
327
}
328
memcpy(q, p + 4, line_size - 4);
329
q += line_size - 4;
330
}
331
return lines * (line_size - 4);
332
}
333
334
335
/* Compressed VBI format, all found sliced blocks put next to one another
336
Returns new compressed size */
337
static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav)
338
{
339
u32 line_size = itv->vbi.sliced_decoder_line_size;
340
struct v4l2_decode_vbi_line vbi;
341
int i;
342
unsigned lines = 0;
343
344
/* find the first valid line */
345
for (i = 0; i < size; i++, buf++) {
346
if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
347
break;
348
}
349
350
size -= i;
351
if (size < line_size) {
352
return line;
353
}
354
for (i = 0; i < size / line_size; i++) {
355
u8 *p = buf + i * line_size;
356
357
/* Look for SAV code */
358
if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) {
359
continue;
360
}
361
vbi.p = p + 4;
362
v4l2_subdev_call(itv->sd_video, vbi, decode_vbi_line, &vbi);
363
if (vbi.type && !(lines & (1 << vbi.line))) {
364
lines |= 1 << vbi.line;
365
itv->vbi.sliced_data[line].id = vbi.type;
366
itv->vbi.sliced_data[line].field = vbi.is_second_field;
367
itv->vbi.sliced_data[line].line = vbi.line;
368
memcpy(itv->vbi.sliced_data[line].data, vbi.p, 42);
369
line++;
370
}
371
}
372
return line;
373
}
374
375
void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
376
u64 pts_stamp, int streamtype)
377
{
378
u8 *p = (u8 *) buf->buf;
379
u32 size = buf->bytesused;
380
int y;
381
382
/* Raw VBI data */
383
if (streamtype == IVTV_ENC_STREAM_TYPE_VBI && ivtv_raw_vbi(itv)) {
384
u8 type;
385
386
ivtv_buf_swap(buf);
387
388
type = p[3];
389
390
size = buf->bytesused = compress_raw_buf(itv, p, size);
391
392
/* second field of the frame? */
393
if (type == itv->vbi.raw_decoder_sav_even_field) {
394
/* Dirty hack needed for backwards
395
compatibility of old VBI software. */
396
p += size - 4;
397
memcpy(p, &itv->vbi.frame, 4);
398
itv->vbi.frame++;
399
}
400
return;
401
}
402
403
/* Sliced VBI data with data insertion */
404
if (streamtype == IVTV_ENC_STREAM_TYPE_VBI) {
405
int lines;
406
407
ivtv_buf_swap(buf);
408
409
/* first field */
410
lines = compress_sliced_buf(itv, 0, p, size / 2,
411
itv->vbi.sliced_decoder_sav_odd_field);
412
/* second field */
413
/* experimentation shows that the second half does not always begin
414
at the exact address. So start a bit earlier (hence 32). */
415
lines = compress_sliced_buf(itv, lines, p + size / 2 - 32, size / 2 + 32,
416
itv->vbi.sliced_decoder_sav_even_field);
417
/* always return at least one empty line */
418
if (lines == 0) {
419
itv->vbi.sliced_data[0].id = 0;
420
itv->vbi.sliced_data[0].line = 0;
421
itv->vbi.sliced_data[0].field = 0;
422
lines = 1;
423
}
424
buf->bytesused = size = lines * sizeof(itv->vbi.sliced_data[0]);
425
memcpy(p, &itv->vbi.sliced_data[0], size);
426
427
if (itv->vbi.insert_mpeg) {
428
copy_vbi_data(itv, lines, pts_stamp);
429
}
430
itv->vbi.frame++;
431
return;
432
}
433
434
/* Sliced VBI re-inserted from an MPEG stream */
435
if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
436
/* If the size is not 4-byte aligned, then the starting address
437
for the swapping is also shifted. After swapping the data the
438
real start address of the VBI data is exactly 4 bytes after the
439
original start. It's a bit fiddly but it works like a charm.
440
Non-4-byte alignment happens when an lseek is done on the input
441
mpeg file to a non-4-byte aligned position. So on arrival here
442
the VBI data is also non-4-byte aligned. */
443
int offset = size & 3;
444
int cnt;
445
446
if (offset) {
447
p += 4 - offset;
448
}
449
/* Swap Buffer */
450
for (y = 0; y < size; y += 4) {
451
swab32s((u32 *)(p + y));
452
}
453
454
cnt = ivtv_convert_ivtv_vbi(itv, p + offset);
455
memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
456
buf->bytesused = cnt;
457
458
ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
459
cnt / sizeof(itv->vbi.sliced_dec_data[0]));
460
return;
461
}
462
}
463
464
void ivtv_disable_cc(struct ivtv *itv)
465
{
466
struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
467
468
clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
469
ivtv_set_cc(itv, 0, &cc);
470
itv->vbi.cc_payload_idx = 0;
471
}
472
473
474
void ivtv_vbi_work_handler(struct ivtv *itv)
475
{
476
struct vbi_info *vi = &itv->vbi;
477
struct v4l2_sliced_vbi_data data;
478
struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
479
480
/* Lock */
481
if (itv->output_mode == OUT_PASSTHROUGH) {
482
if (itv->is_50hz) {
483
data.id = V4L2_SLICED_WSS_625;
484
data.field = 0;
485
486
if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
487
ivtv_set_wss(itv, 1, data.data[0] & 0xf);
488
vi->wss_missing_cnt = 0;
489
} else if (vi->wss_missing_cnt == 4) {
490
ivtv_set_wss(itv, 1, 0x8); /* 4x3 full format */
491
} else {
492
vi->wss_missing_cnt++;
493
}
494
}
495
else {
496
int mode = 0;
497
498
data.id = V4L2_SLICED_CAPTION_525;
499
data.field = 0;
500
if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
501
mode |= 1;
502
cc.odd[0] = data.data[0];
503
cc.odd[1] = data.data[1];
504
}
505
data.field = 1;
506
if (v4l2_subdev_call(itv->sd_video, vbi, g_vbi_data, &data) == 0) {
507
mode |= 2;
508
cc.even[0] = data.data[0];
509
cc.even[1] = data.data[1];
510
}
511
if (mode) {
512
vi->cc_missing_cnt = 0;
513
ivtv_set_cc(itv, mode, &cc);
514
} else if (vi->cc_missing_cnt == 4) {
515
ivtv_set_cc(itv, 0, &cc);
516
} else {
517
vi->cc_missing_cnt++;
518
}
519
}
520
return;
521
}
522
523
if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
524
ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
525
}
526
527
if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
528
if (vi->cc_payload_idx == 0) {
529
clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
530
ivtv_set_cc(itv, 3, &cc);
531
}
532
while (vi->cc_payload_idx) {
533
cc = vi->cc_payload[0];
534
535
memcpy(vi->cc_payload, vi->cc_payload + 1,
536
sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
537
vi->cc_payload_idx--;
538
if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
539
continue;
540
541
ivtv_set_cc(itv, 3, &cc);
542
break;
543
}
544
}
545
546
if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
547
ivtv_set_vps(itv, 1);
548
}
549
}
550
551