WIP FPC-III support
[linux/fpc-iii.git] / drivers / media / pci / cx18 / cx18-av-vbi.c
bloba0d465924e75e30753f367c0b79ee1086c480e3a
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * cx18 ADEC VBI functions
5 * Derived from cx25840-vbi.c
7 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
8 */
11 #include "cx18-driver.h"
14 * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode,
15 * NN counts 1 byte Dwords, an IDID with the VBI line # in it.
16 * Thus, according to the VIP-2 Spec, our VBI ancillary data lines
17 * (should!) look like:
18 * 4 byte EAV code: 0xff 0x00 0x00 0xRP
19 * unknown number of possible idle bytes
20 * 3 byte Anc data preamble: 0x00 0xff 0xff
21 * 1 byte data identifier: ne010iii (parity bits, 010, DID bits)
22 * 1 byte secondary data id: nessssss (parity bits, SDID bits)
23 * 1 byte data word count: necccccc (parity bits, NN Dword count)
24 * 2 byte Internal DID: VBI-line-# 0x80
25 * NN data bytes
26 * 1 byte checksum
27 * Fill bytes needed to fil out to 4*NN bytes of payload
29 * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, &
30 * in the vertical blanking interval are:
31 * 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0)
32 * 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0)
34 * Since the V bit is only allowed to toggle in the EAV RP code, just
35 * before the first active region line and for active lines, they are:
36 * 0x90 (Task 0 0 HorizontalBlank 0 0 0 0)
37 * 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0)
39 * The user application DID bytes we care about are:
40 * 0x91 (1 0 010 0 !ActiveLine AncDataPresent)
41 * 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent)
44 static const u8 sliced_vbi_did[2] = { 0x91, 0x55 };
46 struct vbi_anc_data {
47 /* u8 eav[4]; */
48 /* u8 idle[]; Variable number of idle bytes */
49 u8 preamble[3];
50 u8 did;
51 u8 sdid;
52 u8 data_count;
53 u8 idid[2];
54 u8 payload[1]; /* data_count of payload */
55 /* u8 checksum; */
56 /* u8 fill[]; Variable number of fill bytes */
59 static int odd_parity(u8 c)
61 c ^= (c >> 4);
62 c ^= (c >> 2);
63 c ^= (c >> 1);
65 return c & 1;
68 static int decode_vps(u8 *dst, u8 *p)
70 static const u8 biphase_tbl[] = {
71 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
72 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
73 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
74 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
75 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
76 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
77 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
78 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
79 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
80 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
81 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
82 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
83 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
84 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
85 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
86 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
87 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
88 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
89 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
90 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
91 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
92 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
93 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
94 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
95 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
96 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
97 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
98 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
99 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
100 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
101 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
102 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
105 u8 c, err = 0;
106 int i;
108 for (i = 0; i < 2 * 13; i += 2) {
109 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
110 c = (biphase_tbl[p[i + 1]] & 0xf) |
111 ((biphase_tbl[p[i]] & 0xf) << 4);
112 dst[i / 2] = c;
115 return err & 0xf0;
118 int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
120 struct cx18 *cx = v4l2_get_subdevdata(sd);
121 struct cx18_av_state *state = &cx->av_state;
122 static const u16 lcr2vbi[] = {
123 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
124 0, V4L2_SLICED_WSS_625, 0, /* 4 */
125 V4L2_SLICED_CAPTION_525, /* 6 */
126 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
127 0, 0, 0, 0
129 int is_pal = !(state->std & V4L2_STD_525_60);
130 int i;
132 memset(svbi->service_lines, 0, sizeof(svbi->service_lines));
133 svbi->service_set = 0;
135 /* we're done if raw VBI is active */
136 if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
137 return 0;
139 if (is_pal) {
140 for (i = 7; i <= 23; i++) {
141 u8 v = cx18_av_read(cx, 0x424 + i - 7);
143 svbi->service_lines[0][i] = lcr2vbi[v >> 4];
144 svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
145 svbi->service_set |= svbi->service_lines[0][i] |
146 svbi->service_lines[1][i];
148 } else {
149 for (i = 10; i <= 21; i++) {
150 u8 v = cx18_av_read(cx, 0x424 + i - 10);
152 svbi->service_lines[0][i] = lcr2vbi[v >> 4];
153 svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
154 svbi->service_set |= svbi->service_lines[0][i] |
155 svbi->service_lines[1][i];
158 return 0;
161 int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
163 struct cx18 *cx = v4l2_get_subdevdata(sd);
164 struct cx18_av_state *state = &cx->av_state;
166 /* Setup standard */
167 cx18_av_std_setup(cx);
169 /* VBI Offset */
170 cx18_av_write(cx, 0x47f, state->slicer_line_delay);
171 cx18_av_write(cx, 0x404, 0x2e);
172 return 0;
175 int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
177 struct cx18 *cx = v4l2_get_subdevdata(sd);
178 struct cx18_av_state *state = &cx->av_state;
179 int is_pal = !(state->std & V4L2_STD_525_60);
180 int i, x;
181 u8 lcr[24];
183 for (x = 0; x <= 23; x++)
184 lcr[x] = 0x00;
186 /* Setup standard */
187 cx18_av_std_setup(cx);
189 /* Sliced VBI */
190 cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
191 cx18_av_write(cx, 0x406, 0x13);
192 cx18_av_write(cx, 0x47f, state->slicer_line_delay);
194 /* Force impossible lines to 0 */
195 if (is_pal) {
196 for (i = 0; i <= 6; i++)
197 svbi->service_lines[0][i] =
198 svbi->service_lines[1][i] = 0;
199 } else {
200 for (i = 0; i <= 9; i++)
201 svbi->service_lines[0][i] =
202 svbi->service_lines[1][i] = 0;
204 for (i = 22; i <= 23; i++)
205 svbi->service_lines[0][i] =
206 svbi->service_lines[1][i] = 0;
209 /* Build register values for requested service lines */
210 for (i = 7; i <= 23; i++) {
211 for (x = 0; x <= 1; x++) {
212 switch (svbi->service_lines[1-x][i]) {
213 case V4L2_SLICED_TELETEXT_B:
214 lcr[i] |= 1 << (4 * x);
215 break;
216 case V4L2_SLICED_WSS_625:
217 lcr[i] |= 4 << (4 * x);
218 break;
219 case V4L2_SLICED_CAPTION_525:
220 lcr[i] |= 6 << (4 * x);
221 break;
222 case V4L2_SLICED_VPS:
223 lcr[i] |= 9 << (4 * x);
224 break;
229 if (is_pal) {
230 for (x = 1, i = 0x424; i <= 0x434; i++, x++)
231 cx18_av_write(cx, i, lcr[6 + x]);
232 } else {
233 for (x = 1, i = 0x424; i <= 0x430; i++, x++)
234 cx18_av_write(cx, i, lcr[9 + x]);
235 for (i = 0x431; i <= 0x434; i++)
236 cx18_av_write(cx, i, 0);
239 cx18_av_write(cx, 0x43c, 0x16);
240 /* Should match vblank set in cx18_av_std_setup() */
241 cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
242 return 0;
245 int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
246 struct v4l2_decode_vbi_line *vbi)
248 struct cx18 *cx = v4l2_get_subdevdata(sd);
249 struct cx18_av_state *state = &cx->av_state;
250 struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p;
251 u8 *p;
252 int did, sdid, l, err = 0;
255 * Check for the ancillary data header for sliced VBI
257 if (anc->preamble[0] ||
258 anc->preamble[1] != 0xff || anc->preamble[2] != 0xff ||
259 (anc->did != sliced_vbi_did[0] &&
260 anc->did != sliced_vbi_did[1])) {
261 vbi->line = vbi->type = 0;
262 return 0;
265 did = anc->did;
266 sdid = anc->sdid & 0xf;
267 l = anc->idid[0] & 0x3f;
268 l += state->slicer_line_offset;
269 p = anc->payload;
271 /* Decode the SDID set by the slicer */
272 switch (sdid) {
273 case 1:
274 sdid = V4L2_SLICED_TELETEXT_B;
275 break;
276 case 4:
277 sdid = V4L2_SLICED_WSS_625;
278 break;
279 case 6:
280 sdid = V4L2_SLICED_CAPTION_525;
281 err = !odd_parity(p[0]) || !odd_parity(p[1]);
282 break;
283 case 9:
284 sdid = V4L2_SLICED_VPS;
285 if (decode_vps(p, p) != 0)
286 err = 1;
287 break;
288 default:
289 sdid = 0;
290 err = 1;
291 break;
294 vbi->type = err ? 0 : sdid;
295 vbi->line = err ? 0 : l;
296 vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]);
297 vbi->p = p;
298 return 0;