Merge remote-tracking branch 'unicore32/unicore32'
[deliverable/linux.git] / drivers / media / platform / vivid / vivid-vbi-gen.c
CommitLineData
7bb70caa
HV
1/*
2 * vivid-vbi-gen.c - vbi generator support functions.
3 *
4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5 *
6 * This program is free software; you may redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17 * SOFTWARE.
18 */
19
20#include <linux/errno.h>
21#include <linux/kernel.h>
22#include <linux/ktime.h>
5754d0d5 23#include <linux/string.h>
7bb70caa
HV
24#include <linux/videodev2.h>
25
26#include "vivid-vbi-gen.h"
27
28static void wss_insert(u8 *wss, u32 val, unsigned size)
29{
30 while (size--)
31 *wss++ = (val & (1 << size)) ? 0xc0 : 0x10;
32}
33
34static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data,
35 u8 *buf, unsigned sampling_rate)
36{
37 const unsigned rate = 5000000; /* WSS has a 5 MHz transmission rate */
38 u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 };
39 const unsigned zero = 0x07;
40 const unsigned one = 0x38;
41 unsigned bit = 0;
42 u16 wss_data;
43 int i;
44
45 wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29;
46 wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24;
47
48 wss_data = (data->data[1] << 8) | data->data[0];
49 for (i = 0; i <= 13; i++, bit += 6)
50 wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6);
51
52 for (i = 0, bit = 0; bit < sizeof(wss); bit++) {
53 unsigned n = ((bit + 1) * sampling_rate) / rate;
54
55 while (i < n)
56 buf[i++] = wss[bit];
57 }
58}
59
62f28725
HV
60static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data,
61 u8 *buf, unsigned sampling_rate)
62{
63 const unsigned rate = 6937500 / 10; /* Teletext has a 6.9375 MHz transmission rate */
64 u8 teletext[45] = { 0x55, 0x55, 0x27 };
65 unsigned bit = 0;
66 int i;
67
68 memcpy(teletext + 3, data->data, sizeof(teletext) - 3);
69 /* prevents 32 bit overflow */
70 sampling_rate /= 10;
71
72 for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) {
73 unsigned n = ((bit + 1) * sampling_rate) / rate;
74 u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10;
75
76 while (i < n)
77 buf[i++] = val;
78 }
79}
80
7bb70caa
HV
81static void cc_insert(u8 *cc, u8 ch)
82{
83 unsigned tot = 0;
84 unsigned i;
85
86 for (i = 0; i < 7; i++) {
87 cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0;
88 tot += cc[2 * i];
89 }
90 cc[14] = cc[15] = !(tot & 1);
91}
92
93#define CC_PREAMBLE_BITS (14 + 4 + 2)
94
95static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data,
96 u8 *buf, unsigned sampling_rate)
97{
98 const unsigned rate = 1000000; /* CC has a 1 MHz transmission rate */
99
100 u8 cc[CC_PREAMBLE_BITS + 2 * 16] = {
101 /* Clock run-in: 7 cycles */
102 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
103 /* 2 cycles of 0 */
104 0, 0, 0, 0,
105 /* Start bit of 1 (each bit is two cycles) */
106 1, 1
107 };
108 unsigned bit, i;
109
110 cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]);
111 cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]);
112
113 for (i = 0, bit = 0; bit < sizeof(cc); bit++) {
114 unsigned n = ((bit + 1) * sampling_rate) / rate;
115
116 while (i < n)
117 buf[i++] = cc[bit] ? 0xc0 : 0x10;
118 }
119}
120
121void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi,
122 const struct v4l2_vbi_format *vbi_fmt, u8 *buf)
123{
124 unsigned idx;
125
62f28725 126 for (idx = 0; idx < 25; idx++) {
7bb70caa
HV
127 const struct v4l2_sliced_vbi_data *data = vbi->data + idx;
128 unsigned start_2nd_field;
129 unsigned line = data->line;
130 u8 *linebuf = buf;
131
132 start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313;
133 if (data->field)
134 line += start_2nd_field;
135 line -= vbi_fmt->start[data->field];
136
137 if (vbi_fmt->flags & V4L2_VBI_INTERLACED)
138 linebuf += (line * 2 + data->field) *
139 vbi_fmt->samples_per_line;
140 else
141 linebuf += (line + data->field * vbi_fmt->count[0]) *
142 vbi_fmt->samples_per_line;
143 if (data->id == V4L2_SLICED_CAPTION_525)
144 vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate);
145 else if (data->id == V4L2_SLICED_WSS_625)
146 vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate);
62f28725
HV
147 else if (data->id == V4L2_SLICED_TELETEXT_B)
148 vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate);
7bb70caa
HV
149 }
150}
151
152static const u8 vivid_cc_sequence1[30] = {
153 0x14, 0x20, /* Resume Caption Loading */
154 'H', 'e',
155 'l', 'l',
156 'o', ' ',
157 'w', 'o',
158 'r', 'l',
159 'd', '!',
160 0x14, 0x2f, /* End of Caption */
161};
162
163static const u8 vivid_cc_sequence2[30] = {
164 0x14, 0x20, /* Resume Caption Loading */
165 'C', 'l',
166 'o', 's',
167 'e', 'd',
168 ' ', 'c',
169 'a', 'p',
170 't', 'i',
171 'o', 'n',
172 's', ' ',
173 't', 'e',
174 's', 't',
175 0x14, 0x2f, /* End of Caption */
176};
177
178static u8 calc_parity(u8 val)
179{
180 unsigned i;
181 unsigned tot = 0;
182
183 for (i = 0; i < 7; i++)
184 tot += (val & (1 << i)) ? 1 : 0;
185 return val | ((tot & 1) ? 0 : 0x80);
186}
187
188static void vivid_vbi_gen_set_time_of_day(u8 *packet)
189{
190 struct tm tm;
191 u8 checksum, i;
192
193 time_to_tm(get_seconds(), 0, &tm);
194 packet[0] = calc_parity(0x07);
195 packet[1] = calc_parity(0x01);
196 packet[2] = calc_parity(0x40 | tm.tm_min);
197 packet[3] = calc_parity(0x40 | tm.tm_hour);
198 packet[4] = calc_parity(0x40 | tm.tm_mday);
199 if (tm.tm_mday == 1 && tm.tm_mon == 2 &&
200 sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60)
201 packet[4] = calc_parity(0x60 | tm.tm_mday);
202 packet[5] = calc_parity(0x40 | (1 + tm.tm_mon));
203 packet[6] = calc_parity(0x40 | (1 + tm.tm_wday));
204 packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f));
205 packet[8] = calc_parity(0x0f);
206 for (checksum = i = 0; i <= 8; i++)
207 checksum += packet[i] & 0x7f;
208 packet[9] = calc_parity(0x100 - checksum);
209 checksum = 0;
210 packet[10] = calc_parity(0x07);
211 packet[11] = calc_parity(0x04);
212 if (sys_tz.tz_minuteswest >= 0)
213 packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f));
214 else
215 packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f));
216 packet[13] = calc_parity(0);
217 packet[14] = calc_parity(0x0f);
218 for (checksum = 0, i = 10; i <= 14; i++)
219 checksum += packet[i] & 0x7f;
220 packet[15] = calc_parity(0x100 - checksum);
221}
222
62f28725
HV
223static const u8 hamming[16] = {
224 0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f,
225 0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea
226};
227
228static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame)
229{
230 unsigned offset = 2;
231 unsigned i;
232
233 packet[0] = hamming[1 + ((line & 1) << 3)];
234 packet[1] = hamming[line >> 1];
235 memset(packet + 2, 0x20, 40);
236 if (line == 0) {
237 /* subcode */
238 packet[2] = hamming[frame % 10];
239 packet[3] = hamming[frame / 10];
240 packet[4] = hamming[0];
241 packet[5] = hamming[0];
242 packet[6] = hamming[0];
243 packet[7] = hamming[0];
244 packet[8] = hamming[0];
245 packet[9] = hamming[1];
246 offset = 10;
247 }
248 packet += offset;
249 memcpy(packet, "Page: 100 Row: 10", 17);
250 packet[7] = '0' + frame / 10;
251 packet[8] = '0' + frame % 10;
252 packet[15] = '0' + line / 10;
253 packet[16] = '0' + line % 10;
254 for (i = 0; i < 42 - offset; i++)
255 packet[i] = calc_parity(packet[i]);
256}
257
7bb70caa
HV
258void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
259 bool is_60hz, unsigned seqnr)
260{
261 struct v4l2_sliced_vbi_data *data0 = vbi->data;
262 struct v4l2_sliced_vbi_data *data1 = vbi->data + 1;
263 unsigned frame = seqnr % 60;
264
265 memset(vbi->data, 0, sizeof(vbi->data));
266
267 if (!is_60hz) {
62f28725
HV
268 unsigned i;
269
270 for (i = 0; i <= 11; i++) {
271 data0->id = V4L2_SLICED_TELETEXT_B;
272 data0->line = 7 + i;
273 vivid_vbi_gen_teletext(data0->data, i, frame);
274 data0++;
275 }
7bb70caa
HV
276 data0->id = V4L2_SLICED_WSS_625;
277 data0->line = 23;
278 /* 4x3 video aspect ratio */
279 data0->data[0] = 0x08;
62f28725
HV
280 data0++;
281 for (i = 0; i <= 11; i++) {
282 data0->id = V4L2_SLICED_TELETEXT_B;
283 data0->field = 1;
284 data0->line = 7 + i;
285 vivid_vbi_gen_teletext(data0->data, 12 + i, frame);
286 data0++;
287 }
7bb70caa
HV
288 return;
289 }
290
291 data0->id = V4L2_SLICED_CAPTION_525;
292 data0->line = 21;
293 data1->id = V4L2_SLICED_CAPTION_525;
294 data1->field = 1;
295 data1->line = 21;
296
297 if (frame < 15) {
298 data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]);
299 data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]);
300 } else if (frame >= 30 && frame < 45) {
301 frame -= 30;
302 data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]);
303 data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]);
304 } else {
305 data0->data[0] = calc_parity(0);
306 data0->data[1] = calc_parity(0);
307 }
308
309 frame = seqnr % (30 * 60);
310 switch (frame) {
311 case 0:
312 vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet);
313 /* fall through */
314 case 1 ... 7:
315 data1->data[0] = vbi->time_of_day_packet[frame * 2];
316 data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1];
317 break;
318 default:
319 data1->data[0] = calc_parity(0);
320 data1->data[1] = calc_parity(0);
321 break;
322 }
323}
This page took 0.134793 seconds and 5 git commands to generate.