blob: 2f23ceab8d446491c73a3d832ec2c824733eb951 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module
3 *
4 * Copyright (C) 1999-2002 Ralph Metzler
5 * & Marcus Metzler for convergence integrated media GmbH
6 *
7 * originally based on code by:
8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
24 *
25 * the project's page is at http://www.linuxtv.org/dvb/
26 */
27
28#include <linux/kernel.h>
29#include <linux/sched.h>
30#include <linux/types.h>
31#include <linux/delay.h>
32#include <linux/fs.h>
33#include <linux/timer.h>
34#include <linux/poll.h>
35#include <linux/byteorder/swabb.h>
36#include <linux/smp_lock.h>
37
38#include "av7110.h"
39#include "av7110_hw.h"
40#include "av7110_av.h"
41
42int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
43{
44 u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
45 struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg };
46
47 if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
48 dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -070049 av7110->dvb_adapter.num, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 return -EIO;
51 }
52 return 0;
53}
54
Johannes Stezenbachd91b7302005-05-16 21:54:38 -070055static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070056{
57 u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
58 u8 msg2[2];
59 struct i2c_msg msgs[2] = {
60 { .flags = 0, .addr = 0x40, .len = 3, .buf = msg1 },
61 { .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 }
62 };
63
64 if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
65 dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -070066 av7110->dvb_adapter.num, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 return -EIO;
68 }
69 *val = (msg2[0] << 8) | msg2[1];
70 return 0;
71}
72
thomas schorppf63f5342005-09-09 13:03:06 -070073static struct v4l2_input inputs[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 {
75 .index = 0,
76 .name = "DVB",
77 .type = V4L2_INPUT_TYPE_CAMERA,
78 .audioset = 1,
79 .tuner = 0, /* ignored */
80 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
81 .status = 0,
82 }, {
83 .index = 1,
84 .name = "Television",
85 .type = V4L2_INPUT_TYPE_TUNER,
86 .audioset = 2,
87 .tuner = 0,
88 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
89 .status = 0,
thomas schorppf63f5342005-09-09 13:03:06 -070090 }, {
91 .index = 2,
92 .name = "Video",
93 .type = V4L2_INPUT_TYPE_CAMERA,
94 .audioset = 0,
95 .tuner = 0,
96 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
97 .status = 0,
98 }, {
99 .index = 3,
100 .name = "Y/C",
101 .type = V4L2_INPUT_TYPE_CAMERA,
102 .audioset = 0,
103 .tuner = 0,
104 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
105 .status = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
107};
108
109static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
110{
111 u8 buf[] = { 0x00, reg, data };
112 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
113
114 dprintk(4, "dev: %p\n", dev);
115
116 if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
117 return -1;
118 return 0;
119}
120
121static int stv0297_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
122{
Mauro Carvalho Chehab9101e622005-12-12 00:37:24 -0800123 u8 buf [] = { reg, data };
124 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 2 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
127 return -1;
128 return 0;
129}
130
131
132static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
133{
134 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
135
136 dprintk(4, "dev: %p\n", dev);
137
138 if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
139 return -1;
140 return 0;
141}
142
143static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
144{
145 u32 div;
146 u8 config;
147 u8 buf[4];
148
149 dprintk(4, "freq: 0x%08x\n", freq);
150
151 /* magic number: 614. tuning with the frequency given by v4l2
152 is always off by 614*62.5 = 38375 kHz...*/
153 div = freq + 614;
154
155 buf[0] = (div >> 8) & 0x7f;
156 buf[1] = div & 0xff;
157 buf[2] = 0x8e;
158
159 if (freq < (u32) (16 * 168.25))
160 config = 0xa0;
161 else if (freq < (u32) (16 * 447.25))
162 config = 0x90;
163 else
164 config = 0x30;
165 config &= ~0x02;
166
167 buf[3] = config;
168
169 return tuner_write(dev, 0x61, buf);
170}
171
172static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
173{
174 u32 div;
175 u8 data[4];
176
177 div = (freq + 38900000 + 31250) / 62500;
178
179 data[0] = (div >> 8) & 0x7f;
180 data[1] = div & 0xff;
181 data[2] = 0xce;
182
183 if (freq < 45000000)
184 return -EINVAL;
185 else if (freq < 137000000)
186 data[3] = 0x01;
187 else if (freq < 403000000)
188 data[3] = 0x02;
189 else if (freq < 860000000)
190 data[3] = 0x04;
191 else
192 return -EINVAL;
193
194 stv0297_writereg(dev, 0x1C, 0x87, 0x78);
195 stv0297_writereg(dev, 0x1C, 0x86, 0xc8);
196 return tuner_write(dev, 0x63, data);
197}
198
199
200
201static struct saa7146_standard analog_standard[];
202static struct saa7146_standard dvb_standard[];
203static struct saa7146_standard standard[];
204
205static struct v4l2_audio msp3400_v4l2_audio = {
206 .index = 0,
207 .name = "Television",
208 .capability = V4L2_AUDCAP_STEREO
209};
210
211static int av7110_dvb_c_switch(struct saa7146_fh *fh)
212{
213 struct saa7146_dev *dev = fh->dev;
214 struct saa7146_vv *vv = dev->vv_data;
215 struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
216 u16 adswitch;
217 int source, sync, err;
218
219 dprintk(4, "%p\n", av7110);
220
221 if ((vv->video_status & STATUS_OVERLAY) != 0) {
222 vv->ov_suspend = vv->video_fh;
223 err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
224 if (err != 0) {
225 dprintk(2, "suspending video failed\n");
226 vv->ov_suspend = NULL;
227 }
228 }
229
230 if (0 != av7110->current_input) {
thomas schorppf63f5342005-09-09 13:03:06 -0700231 dprintk(1, "switching to analog TV:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 adswitch = 1;
233 source = SAA7146_HPS_SOURCE_PORT_B;
234 sync = SAA7146_HPS_SYNC_PORT_B;
235 memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
thomas schorppf63f5342005-09-09 13:03:06 -0700237 switch (av7110->current_input) {
238 case 1:
239 dprintk(1, "switching SAA7113 to Analog Tuner Input.\n");
240 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
241 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
242 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
243 msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
244 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
245 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
246
247 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
248 if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
249 dprintk(1, "setting band in demodulator failed.\n");
250 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
251 saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
252 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF)
253 }
254 if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
255 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
256 break;
257 case 2:
258 dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n");
259 if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
260 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
261 break;
262 case 3:
263 dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n");
264 if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
265 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
266 break;
267 default:
268 dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 }
270 } else {
271 adswitch = 0;
272 source = SAA7146_HPS_SOURCE_PORT_A;
273 sync = SAA7146_HPS_SYNC_PORT_A;
274 memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
275 dprintk(1, "switching DVB mode\n");
276 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
277 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
278 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
279 msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
280 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
281 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
282
283 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
284 if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
285 dprintk(1, "setting band in demodulator failed.\n");
286 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
287 saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
288 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
289 }
290 }
291
292 /* hmm, this does not do anything!? */
293 if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
294 dprintk(1, "ADSwitch error\n");
295
296 saa7146_set_hps_source_and_sync(dev, source, sync);
297
298 if (vv->ov_suspend != NULL) {
299 saa7146_start_preview(vv->ov_suspend);
300 vv->ov_suspend = NULL;
301 }
302
303 return 0;
304}
305
306static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
307{
308 struct saa7146_dev *dev = fh->dev;
309 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
310 dprintk(4, "saa7146_dev: %p\n", dev);
311
312 switch (cmd) {
313 case VIDIOC_G_TUNER:
314 {
315 struct v4l2_tuner *t = arg;
316 u16 stereo_det;
317 s8 stereo;
318
319 dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
320
321 if (!av7110->analog_tuner_flags || t->index != 0)
322 return -EINVAL;
323
324 memset(t, 0, sizeof(*t));
325 strcpy(t->name, "Television");
326
327 t->type = V4L2_TUNER_ANALOG_TV;
328 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
329 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
330 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
331 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
332 /* FIXME: add the real signal strength here */
333 t->signal = 0xffff;
334 t->afc = 0;
335
336 // FIXME: standard / stereo detection is still broken
337 msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
338 dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
340 dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
341 stereo = (s8)(stereo_det >> 8);
342 if (stereo > 0x10) {
343 /* stereo */
344 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
345 t->audmode = V4L2_TUNER_MODE_STEREO;
346 }
347 else if (stereo < -0x10) {
thomas schorppf63f5342005-09-09 13:03:06 -0700348 /* bilingual */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
350 t->audmode = V4L2_TUNER_MODE_LANG1;
351 }
352 else /* mono */
353 t->rxsubchans = V4L2_TUNER_SUB_MONO;
354
355 return 0;
356 }
357 case VIDIOC_S_TUNER:
358 {
359 struct v4l2_tuner *t = arg;
360 u16 fm_matrix, src;
361 dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
362
363 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
364 return -EINVAL;
365
366 switch (t->audmode) {
367 case V4L2_TUNER_MODE_STEREO:
368 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
369 fm_matrix = 0x3001; // stereo
370 src = 0x0020;
371 break;
372 case V4L2_TUNER_MODE_LANG1:
373 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
374 fm_matrix = 0x3000; // mono
375 src = 0x0000;
376 break;
377 case V4L2_TUNER_MODE_LANG2:
378 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
379 fm_matrix = 0x3000; // mono
380 src = 0x0010;
381 break;
thomas schorppf63f5342005-09-09 13:03:06 -0700382 default: /* case V4L2_TUNER_MODE_MONO: */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
384 fm_matrix = 0x3000; // mono
385 src = 0x0030;
386 break;
387 }
388 msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
389 msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
390 msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
391 msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
392 return 0;
393 }
394 case VIDIOC_G_FREQUENCY:
395 {
396 struct v4l2_frequency *f = arg;
397
398 dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
399
400 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
401 return -EINVAL;
402
403 memset(f, 0, sizeof(*f));
404 f->type = V4L2_TUNER_ANALOG_TV;
405 f->frequency = av7110->current_freq;
406 return 0;
407 }
408 case VIDIOC_S_FREQUENCY:
409 {
410 struct v4l2_frequency *f = arg;
411
412 dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
413
414 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
415 return -EINVAL;
416
417 if (V4L2_TUNER_ANALOG_TV != f->type)
418 return -EINVAL;
419
420 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
421 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
422
423 /* tune in desired frequency */
424 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
425 ves1820_set_tv_freq(dev, f->frequency);
426 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
427 stv0297_set_tv_freq(dev, f->frequency);
428 }
429 av7110->current_freq = f->frequency;
430
431 msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
432 msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
433 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
434 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
435 return 0;
436 }
437 case VIDIOC_ENUMINPUT:
438 {
439 struct v4l2_input *i = arg;
440
441 dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
442
443 if (av7110->analog_tuner_flags) {
thomas schorppf63f5342005-09-09 13:03:06 -0700444 if (i->index < 0 || i->index >= 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return -EINVAL;
446 } else {
447 if (i->index != 0)
448 return -EINVAL;
449 }
450
451 memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
452
453 return 0;
454 }
455 case VIDIOC_G_INPUT:
456 {
457 int *input = (int *)arg;
458 *input = av7110->current_input;
459 dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
460 return 0;
461 }
462 case VIDIOC_S_INPUT:
463 {
464 int input = *(int *)arg;
465
466 dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
467
468 if (!av7110->analog_tuner_flags)
469 return 0;
470
thomas schorppf63f5342005-09-09 13:03:06 -0700471 if (input < 0 || input >= 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 return -EINVAL;
473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 av7110->current_input = input;
475 return av7110_dvb_c_switch(fh);
476 }
477 case VIDIOC_G_AUDIO:
478 {
479 struct v4l2_audio *a = arg;
480
481 dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
482 if (a->index != 0)
483 return -EINVAL;
484 memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
485 break;
486 }
487 case VIDIOC_S_AUDIO:
488 {
489 struct v4l2_audio *a = arg;
490 dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
491 break;
492 }
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200493 case VIDIOC_G_SLICED_VBI_CAP:
494 {
495 struct v4l2_sliced_vbi_cap *cap = arg;
496 dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
497 memset(cap, 0, sizeof *cap);
498 if (FW_VERSION(av7110->arm_app) >= 0x2623) {
499 cap->service_set = V4L2_SLICED_WSS_625;
500 cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
501 }
502 break;
503 }
504 case VIDIOC_G_FMT:
505 {
506 struct v4l2_format *f = arg;
507 dprintk(2, "VIDIOC_G_FMT:\n");
508 if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
509 FW_VERSION(av7110->arm_app) < 0x2623)
510 return -EAGAIN; /* handled by core driver */
511 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
512 if (av7110->wssMode) {
513 f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
514 f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
515 f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
516 }
517 break;
518 }
519 case VIDIOC_S_FMT:
520 {
521 struct v4l2_format *f = arg;
522 dprintk(2, "VIDIOC_S_FMT\n");
523 if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
524 FW_VERSION(av7110->arm_app) < 0x2623)
525 return -EAGAIN; /* handled by core driver */
526 if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
527 f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
528 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
529 /* WSS controlled by firmware */
530 av7110->wssMode = 0;
531 av7110->wssData = 0;
532 return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
533 SetWSSConfig, 1, 0);
534 } else {
535 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
536 f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
537 f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
538 f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
539 /* WSS controlled by userspace */
540 av7110->wssMode = 1;
541 av7110->wssData = 0;
542 }
543 break;
544 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 default:
546 printk("no such ioctl\n");
547 return -ENOIOCTLCMD;
548 }
549 return 0;
550}
551
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200552static int av7110_vbi_reset(struct inode *inode, struct file *file)
553{
554 struct saa7146_fh *fh = file->private_data;
555 struct saa7146_dev *dev = fh->dev;
556 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
557
558 dprintk(2, "%s\n", __FUNCTION__);
559 av7110->wssMode = 0;
560 av7110->wssData = 0;
561 if (FW_VERSION(av7110->arm_app) < 0x2623)
562 return 0;
563 else
564 return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
565}
566
567static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
568{
569 struct saa7146_fh *fh = file->private_data;
570 struct saa7146_dev *dev = fh->dev;
571 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
572 struct v4l2_sliced_vbi_data d;
573 int rc;
574
575 dprintk(2, "%s\n", __FUNCTION__);
576 if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
577 return -EINVAL;
578 if (copy_from_user(&d, data, count))
579 return -EFAULT;
580 if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
581 return -EINVAL;
Oliver Endriss4caba422006-03-17 05:29:15 -0300582 if (d.id)
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200583 av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
Oliver Endriss4caba422006-03-17 05:29:15 -0300584 else
585 av7110->wssData = 0x8000;
586 rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200587 return (rc < 0) ? rc : count;
588}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
590/****************************************************************************
591 * INITIALIZATION
592 ****************************************************************************/
593
594static struct saa7146_extension_ioctls ioctls[] = {
595 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
596 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
597 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
598 { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
599 { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
600 { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
601 { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
602 { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
603 { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200604 { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
605 { VIDIOC_G_FMT, SAA7146_BEFORE },
606 { VIDIOC_S_FMT, SAA7146_BEFORE },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 { 0, 0 }
608};
609
610static u8 saa7113_init_regs[] = {
611 0x02, 0xd0,
612 0x03, 0x23,
613 0x04, 0x00,
614 0x05, 0x00,
615 0x06, 0xe9,
616 0x07, 0x0d,
617 0x08, 0x98,
618 0x09, 0x02,
619 0x0a, 0x80,
620 0x0b, 0x40,
621 0x0c, 0x40,
622 0x0d, 0x00,
623 0x0e, 0x01,
624 0x0f, 0x7c,
625 0x10, 0x48,
626 0x11, 0x0c,
627 0x12, 0x8b,
628 0x13, 0x1a,
629 0x14, 0x00,
630 0x15, 0x00,
631 0x16, 0x00,
632 0x17, 0x00,
633 0x18, 0x00,
634 0x19, 0x00,
635 0x1a, 0x00,
636 0x1b, 0x00,
637 0x1c, 0x00,
638 0x1d, 0x00,
639 0x1e, 0x00,
640
641 0x41, 0x77,
642 0x42, 0x77,
643 0x43, 0x77,
644 0x44, 0x77,
645 0x45, 0x77,
646 0x46, 0x77,
647 0x47, 0x77,
648 0x48, 0x77,
649 0x49, 0x77,
650 0x4a, 0x77,
651 0x4b, 0x77,
652 0x4c, 0x77,
653 0x4d, 0x77,
654 0x4e, 0x77,
655 0x4f, 0x77,
656 0x50, 0x77,
657 0x51, 0x77,
658 0x52, 0x77,
659 0x53, 0x77,
660 0x54, 0x77,
661 0x55, 0x77,
662 0x56, 0x77,
663 0x57, 0xff,
664
665 0xff
666};
667
668
669static struct saa7146_ext_vv av7110_vv_data_st;
670static struct saa7146_ext_vv av7110_vv_data_c;
671
672int av7110_init_analog_module(struct av7110 *av7110)
673{
674 u16 version1, version2;
675
676 if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1
677 || i2c_writereg(av7110, 0x80, 0x0, 0) != 1)
678 return -ENODEV;
679
680 printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700681 av7110->dvb_adapter.num);
Marco Schluessler1c13b952006-01-09 15:25:06 -0200682 av7110->adac_type = DVB_ADAC_MSP34x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 msleep(100); // the probing above resets the msp...
684 msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
685 msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
686 dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700687 av7110->dvb_adapter.num, version1, version2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
689 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
690 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
691 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
692 msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
693 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
694 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
695 msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART
696
697 if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
698 INFO(("saa7113 not accessible.\n"));
699 } else {
700 u8 *i = saa7113_init_regs;
701
702 if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
703 /* Fujitsu/Siemens DVB-Cable */
704 av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
705 } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
706 /* Hauppauge/TT DVB-C premium */
707 av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
708 } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
709 /* Hauppauge/TT DVB-C premium */
710 av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
711 }
712
713 /* setup for DVB by default */
714 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
715 if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
716 dprintk(1, "setting band in demodulator failed.\n");
717 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
718 saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
719 saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
720 }
721
722 /* init the saa7113 */
723 while (*i != 0xff) {
724 if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700725 dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 break;
727 }
728 i += 2;
729 }
730 /* setup msp for analog sound: B/G Dual-FM */
731 msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV
732 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1
733 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1
734 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1
735 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1
736 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1
737 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1
738 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2
739 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2
740 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2
741 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2
742 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2
743 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2
744 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2
745 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2
746 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2
747 msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG
748 msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz
749 msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI
750 msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz
751 msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI
752 msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2
753 }
754
755 memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
756 /* set dd1 stream a & b */
757 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
758 saa7146_write(av7110->dev, DD1_INIT, 0x03000700);
759 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
760
761 return 0;
762}
763
764int av7110_init_v4l(struct av7110 *av7110)
765{
766 struct saa7146_dev* dev = av7110->dev;
767 int ret;
768
769 /* special case DVB-C: these cards have an analog tuner
770 plus need some special handling, so we have separate
771 saa7146_ext_vv data for these... */
772 if (av7110->analog_tuner_flags)
773 ret = saa7146_vv_init(dev, &av7110_vv_data_c);
774 else
775 ret = saa7146_vv_init(dev, &av7110_vv_data_st);
776
777 if (ret) {
778 ERR(("cannot init capture device. skipping.\n"));
779 return -ENODEV;
780 }
781
782 if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
783 ERR(("cannot register capture device. skipping.\n"));
784 saa7146_vv_release(dev);
785 return -ENODEV;
786 }
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200787 if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
788 ERR(("cannot register vbi v4l2 device. skipping.\n"));
789 } else {
790 if (av7110->analog_tuner_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 }
793 return 0;
794}
795
796int av7110_exit_v4l(struct av7110 *av7110)
797{
798 saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
799 if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI)
800 saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
801 return 0;
802}
803
804
805
806/* FIXME: these values are experimental values that look better than the
807 values from the latest "official" driver -- at least for me... (MiHu) */
808static struct saa7146_standard standard[] = {
809 {
810 .name = "PAL", .id = V4L2_STD_PAL_BG,
811 .v_offset = 0x15, .v_field = 288,
812 .h_offset = 0x48, .h_pixels = 708,
813 .v_max_out = 576, .h_max_out = 768,
814 }, {
815 .name = "NTSC", .id = V4L2_STD_NTSC,
816 .v_offset = 0x10, .v_field = 244,
817 .h_offset = 0x40, .h_pixels = 708,
818 .v_max_out = 480, .h_max_out = 640,
819 }
820};
821
822static struct saa7146_standard analog_standard[] = {
823 {
824 .name = "PAL", .id = V4L2_STD_PAL_BG,
825 .v_offset = 0x1b, .v_field = 288,
826 .h_offset = 0x08, .h_pixels = 708,
827 .v_max_out = 576, .h_max_out = 768,
828 }, {
829 .name = "NTSC", .id = V4L2_STD_NTSC,
830 .v_offset = 0x10, .v_field = 244,
831 .h_offset = 0x40, .h_pixels = 708,
832 .v_max_out = 480, .h_max_out = 640,
833 }
834};
835
836static struct saa7146_standard dvb_standard[] = {
837 {
838 .name = "PAL", .id = V4L2_STD_PAL_BG,
839 .v_offset = 0x14, .v_field = 288,
840 .h_offset = 0x48, .h_pixels = 708,
841 .v_max_out = 576, .h_max_out = 768,
842 }, {
843 .name = "NTSC", .id = V4L2_STD_NTSC,
844 .v_offset = 0x10, .v_field = 244,
845 .h_offset = 0x40, .h_pixels = 708,
846 .v_max_out = 480, .h_max_out = 640,
847 }
848};
849
850static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
851{
852 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
853
Johannes Stezenbach4ab3f082005-05-16 21:54:27 -0700854 if (std->id & V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 av7110->vidmode = VIDEO_MODE_PAL;
856 av7110_set_vidmode(av7110, av7110->vidmode);
857 }
Johannes Stezenbach4ab3f082005-05-16 21:54:27 -0700858 else if (std->id & V4L2_STD_NTSC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 av7110->vidmode = VIDEO_MODE_NTSC;
860 av7110_set_vidmode(av7110, av7110->vidmode);
861 }
862 else
863 return -1;
864
865 return 0;
866}
867
868
869static struct saa7146_ext_vv av7110_vv_data_st = {
870 .inputs = 1,
871 .audios = 1,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200872 .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .flags = 0,
874
875 .stds = &standard[0],
876 .num_stds = ARRAY_SIZE(standard),
877 .std_callback = &std_callback,
878
879 .ioctls = &ioctls[0],
880 .ioctl = av7110_ioctl,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200881
882 .vbi_fops.open = av7110_vbi_reset,
883 .vbi_fops.release = av7110_vbi_reset,
884 .vbi_fops.write = av7110_vbi_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885};
886
887static struct saa7146_ext_vv av7110_vv_data_c = {
888 .inputs = 1,
889 .audios = 1,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200890 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 .flags = SAA7146_USE_PORT_B_FOR_VBI,
892
893 .stds = &standard[0],
894 .num_stds = ARRAY_SIZE(standard),
895 .std_callback = &std_callback,
896
897 .ioctls = &ioctls[0],
898 .ioctl = av7110_ioctl,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200899
900 .vbi_fops.open = av7110_vbi_reset,
901 .vbi_fops.release = av7110_vbi_reset,
902 .vbi_fops.write = av7110_vbi_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903};
904