blob: cde5d3ae7ec783b32f73e9ee517013daa1be59c7 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/delay.h>
31#include <linux/fs.h>
32#include <linux/timer.h>
33#include <linux/poll.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/smp_lock.h>
35
36#include "av7110.h"
37#include "av7110_hw.h"
38#include "av7110_av.h"
39
40int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
41{
42 u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
Tim Kaiser61391e02006-06-25 09:14:07 -030043 struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
44
45 switch (av7110->adac_type) {
46 case DVB_ADAC_MSP34x0:
47 msgs.addr = 0x40;
48 break;
49 case DVB_ADAC_MSP34x5:
50 msgs.addr = 0x42;
51 break;
52 default:
53 return 0;
54 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56 if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
57 dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -070058 av7110->dvb_adapter.num, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 return -EIO;
60 }
61 return 0;
62}
63
Johannes Stezenbachd91b7302005-05-16 21:54:38 -070064static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
66 u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
67 u8 msg2[2];
68 struct i2c_msg msgs[2] = {
Tim Kaiser61391e02006-06-25 09:14:07 -030069 { .flags = 0 , .len = 3, .buf = msg1 },
70 { .flags = I2C_M_RD, .len = 2, .buf = msg2 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 };
72
Tim Kaiser61391e02006-06-25 09:14:07 -030073 switch (av7110->adac_type) {
74 case DVB_ADAC_MSP34x0:
75 msgs[0].addr = 0x40;
76 msgs[1].addr = 0x40;
77 break;
78 case DVB_ADAC_MSP34x5:
79 msgs[0].addr = 0x42;
80 msgs[1].addr = 0x42;
81 break;
82 default:
83 return 0;
84 }
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
87 dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -070088 av7110->dvb_adapter.num, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 return -EIO;
90 }
91 *val = (msg2[0] << 8) | msg2[1];
92 return 0;
93}
94
thomas schorppf63f5342005-09-09 13:03:06 -070095static struct v4l2_input inputs[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 {
97 .index = 0,
98 .name = "DVB",
99 .type = V4L2_INPUT_TYPE_CAMERA,
100 .audioset = 1,
101 .tuner = 0, /* ignored */
102 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
103 .status = 0,
104 }, {
105 .index = 1,
106 .name = "Television",
107 .type = V4L2_INPUT_TYPE_TUNER,
108 .audioset = 2,
109 .tuner = 0,
110 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
111 .status = 0,
thomas schorppf63f5342005-09-09 13:03:06 -0700112 }, {
113 .index = 2,
114 .name = "Video",
115 .type = V4L2_INPUT_TYPE_CAMERA,
116 .audioset = 0,
117 .tuner = 0,
118 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
119 .status = 0,
120 }, {
121 .index = 3,
122 .name = "Y/C",
123 .type = V4L2_INPUT_TYPE_CAMERA,
124 .audioset = 0,
125 .tuner = 0,
126 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
127 .status = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 }
129};
130
131static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
132{
133 u8 buf[] = { 0x00, reg, data };
134 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
144{
145 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
146
147 dprintk(4, "dev: %p\n", dev);
148
149 if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
150 return -1;
151 return 0;
152}
153
154static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
155{
156 u32 div;
157 u8 config;
158 u8 buf[4];
159
160 dprintk(4, "freq: 0x%08x\n", freq);
161
162 /* magic number: 614. tuning with the frequency given by v4l2
163 is always off by 614*62.5 = 38375 kHz...*/
164 div = freq + 614;
165
166 buf[0] = (div >> 8) & 0x7f;
167 buf[1] = div & 0xff;
168 buf[2] = 0x8e;
169
170 if (freq < (u32) (16 * 168.25))
171 config = 0xa0;
172 else if (freq < (u32) (16 * 447.25))
173 config = 0x90;
174 else
175 config = 0x30;
176 config &= ~0x02;
177
178 buf[3] = config;
179
180 return tuner_write(dev, 0x61, buf);
181}
182
183static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
184{
Marco Schluessler89e4d592007-02-13 09:31:07 -0300185 struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 u32 div;
187 u8 data[4];
188
189 div = (freq + 38900000 + 31250) / 62500;
190
191 data[0] = (div >> 8) & 0x7f;
192 data[1] = div & 0xff;
193 data[2] = 0xce;
194
195 if (freq < 45000000)
196 return -EINVAL;
197 else if (freq < 137000000)
198 data[3] = 0x01;
199 else if (freq < 403000000)
200 data[3] = 0x02;
201 else if (freq < 860000000)
202 data[3] = 0x04;
203 else
204 return -EINVAL;
205
Marco Schluessler89e4d592007-02-13 09:31:07 -0300206 if (av7110->fe->ops.i2c_gate_ctrl)
207 av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 return tuner_write(dev, 0x63, data);
209}
210
211
212
213static struct saa7146_standard analog_standard[];
214static struct saa7146_standard dvb_standard[];
215static struct saa7146_standard standard[];
216
217static struct v4l2_audio msp3400_v4l2_audio = {
218 .index = 0,
219 .name = "Television",
220 .capability = V4L2_AUDCAP_STEREO
221};
222
223static int av7110_dvb_c_switch(struct saa7146_fh *fh)
224{
225 struct saa7146_dev *dev = fh->dev;
226 struct saa7146_vv *vv = dev->vv_data;
227 struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
228 u16 adswitch;
229 int source, sync, err;
230
231 dprintk(4, "%p\n", av7110);
232
233 if ((vv->video_status & STATUS_OVERLAY) != 0) {
234 vv->ov_suspend = vv->video_fh;
235 err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
236 if (err != 0) {
237 dprintk(2, "suspending video failed\n");
238 vv->ov_suspend = NULL;
239 }
240 }
241
242 if (0 != av7110->current_input) {
thomas schorppf63f5342005-09-09 13:03:06 -0700243 dprintk(1, "switching to analog TV:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 adswitch = 1;
245 source = SAA7146_HPS_SOURCE_PORT_B;
246 sync = SAA7146_HPS_SYNC_PORT_B;
247 memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
thomas schorppf63f5342005-09-09 13:03:06 -0700249 switch (av7110->current_input) {
250 case 1:
251 dprintk(1, "switching SAA7113 to Analog Tuner Input.\n");
252 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
253 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
254 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
255 msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
256 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
257 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
258
259 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
260 if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
261 dprintk(1, "setting band in demodulator failed.\n");
262 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
Marco Schluessler6a857742006-07-10 03:34:16 -0300263 saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
264 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
thomas schorppf63f5342005-09-09 13:03:06 -0700265 }
266 if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
267 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
268 break;
269 case 2:
270 dprintk(1, "switching SAA7113 to Video AV CVBS Input.\n");
271 if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
272 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
273 break;
274 case 3:
275 dprintk(1, "switching SAA7113 to Video AV Y/C Input.\n");
276 if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
277 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
278 break;
279 default:
280 dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282 } else {
283 adswitch = 0;
284 source = SAA7146_HPS_SOURCE_PORT_A;
285 sync = SAA7146_HPS_SYNC_PORT_A;
286 memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
287 dprintk(1, "switching DVB mode\n");
288 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
289 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
290 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
291 msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
292 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
293 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
294
295 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
296 if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
297 dprintk(1, "setting band in demodulator failed.\n");
298 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
Marco Schluessler6a857742006-07-10 03:34:16 -0300299 saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
300 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302 }
303
304 /* hmm, this does not do anything!? */
305 if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
306 dprintk(1, "ADSwitch error\n");
307
308 saa7146_set_hps_source_and_sync(dev, source, sync);
309
310 if (vv->ov_suspend != NULL) {
311 saa7146_start_preview(vv->ov_suspend);
312 vv->ov_suspend = NULL;
313 }
314
315 return 0;
316}
317
318static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
319{
320 struct saa7146_dev *dev = fh->dev;
321 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
322 dprintk(4, "saa7146_dev: %p\n", dev);
323
324 switch (cmd) {
325 case VIDIOC_G_TUNER:
326 {
327 struct v4l2_tuner *t = arg;
328 u16 stereo_det;
329 s8 stereo;
330
331 dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
332
333 if (!av7110->analog_tuner_flags || t->index != 0)
334 return -EINVAL;
335
336 memset(t, 0, sizeof(*t));
337 strcpy(t->name, "Television");
338
339 t->type = V4L2_TUNER_ANALOG_TV;
340 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
341 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
342 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
343 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
344 /* FIXME: add the real signal strength here */
345 t->signal = 0xffff;
346 t->afc = 0;
347
348 // FIXME: standard / stereo detection is still broken
349 msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
350 dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
352 dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
353 stereo = (s8)(stereo_det >> 8);
354 if (stereo > 0x10) {
355 /* stereo */
356 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
357 t->audmode = V4L2_TUNER_MODE_STEREO;
358 }
359 else if (stereo < -0x10) {
thomas schorppf63f5342005-09-09 13:03:06 -0700360 /* bilingual */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
362 t->audmode = V4L2_TUNER_MODE_LANG1;
363 }
364 else /* mono */
365 t->rxsubchans = V4L2_TUNER_SUB_MONO;
366
367 return 0;
368 }
369 case VIDIOC_S_TUNER:
370 {
371 struct v4l2_tuner *t = arg;
372 u16 fm_matrix, src;
373 dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
374
375 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
376 return -EINVAL;
377
378 switch (t->audmode) {
379 case V4L2_TUNER_MODE_STEREO:
380 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
381 fm_matrix = 0x3001; // stereo
382 src = 0x0020;
383 break;
Hans Verkuil301e22d2006-03-18 17:15:00 -0300384 case V4L2_TUNER_MODE_LANG1_LANG2:
385 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
386 fm_matrix = 0x3000; // bilingual
387 src = 0x0020;
388 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 case V4L2_TUNER_MODE_LANG1:
390 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
391 fm_matrix = 0x3000; // mono
392 src = 0x0000;
393 break;
394 case V4L2_TUNER_MODE_LANG2:
395 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
396 fm_matrix = 0x3000; // mono
397 src = 0x0010;
398 break;
thomas schorppf63f5342005-09-09 13:03:06 -0700399 default: /* case V4L2_TUNER_MODE_MONO: */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
401 fm_matrix = 0x3000; // mono
402 src = 0x0030;
403 break;
404 }
405 msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
406 msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
407 msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
408 msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
409 return 0;
410 }
411 case VIDIOC_G_FREQUENCY:
412 {
413 struct v4l2_frequency *f = arg;
414
415 dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
416
417 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
418 return -EINVAL;
419
420 memset(f, 0, sizeof(*f));
421 f->type = V4L2_TUNER_ANALOG_TV;
422 f->frequency = av7110->current_freq;
423 return 0;
424 }
425 case VIDIOC_S_FREQUENCY:
426 {
427 struct v4l2_frequency *f = arg;
428
429 dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
430
431 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
432 return -EINVAL;
433
434 if (V4L2_TUNER_ANALOG_TV != f->type)
435 return -EINVAL;
436
437 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
438 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
439
440 /* tune in desired frequency */
441 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
442 ves1820_set_tv_freq(dev, f->frequency);
443 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
444 stv0297_set_tv_freq(dev, f->frequency);
445 }
446 av7110->current_freq = f->frequency;
447
448 msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
449 msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
450 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
451 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
452 return 0;
453 }
454 case VIDIOC_ENUMINPUT:
455 {
456 struct v4l2_input *i = arg;
457
458 dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
459
460 if (av7110->analog_tuner_flags) {
thomas schorppf63f5342005-09-09 13:03:06 -0700461 if (i->index < 0 || i->index >= 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 return -EINVAL;
463 } else {
464 if (i->index != 0)
465 return -EINVAL;
466 }
467
468 memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
469
470 return 0;
471 }
472 case VIDIOC_G_INPUT:
473 {
474 int *input = (int *)arg;
475 *input = av7110->current_input;
476 dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
477 return 0;
478 }
479 case VIDIOC_S_INPUT:
480 {
481 int input = *(int *)arg;
482
483 dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
484
485 if (!av7110->analog_tuner_flags)
486 return 0;
487
thomas schorppf63f5342005-09-09 13:03:06 -0700488 if (input < 0 || input >= 4)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 return -EINVAL;
490
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 av7110->current_input = input;
492 return av7110_dvb_c_switch(fh);
493 }
494 case VIDIOC_G_AUDIO:
495 {
496 struct v4l2_audio *a = arg;
497
498 dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
499 if (a->index != 0)
500 return -EINVAL;
501 memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
502 break;
503 }
504 case VIDIOC_S_AUDIO:
505 {
506 struct v4l2_audio *a = arg;
507 dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
508 break;
509 }
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200510 case VIDIOC_G_SLICED_VBI_CAP:
511 {
512 struct v4l2_sliced_vbi_cap *cap = arg;
513 dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
514 memset(cap, 0, sizeof *cap);
515 if (FW_VERSION(av7110->arm_app) >= 0x2623) {
516 cap->service_set = V4L2_SLICED_WSS_625;
517 cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
518 }
519 break;
520 }
521 case VIDIOC_G_FMT:
522 {
523 struct v4l2_format *f = arg;
524 dprintk(2, "VIDIOC_G_FMT:\n");
525 if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
526 FW_VERSION(av7110->arm_app) < 0x2623)
527 return -EAGAIN; /* handled by core driver */
528 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
529 if (av7110->wssMode) {
530 f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
531 f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
532 f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
533 }
534 break;
535 }
536 case VIDIOC_S_FMT:
537 {
538 struct v4l2_format *f = arg;
539 dprintk(2, "VIDIOC_S_FMT\n");
540 if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
541 FW_VERSION(av7110->arm_app) < 0x2623)
542 return -EAGAIN; /* handled by core driver */
543 if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
544 f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
545 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
546 /* WSS controlled by firmware */
547 av7110->wssMode = 0;
548 av7110->wssData = 0;
549 return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
550 SetWSSConfig, 1, 0);
551 } else {
552 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
553 f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
554 f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
555 f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
556 /* WSS controlled by userspace */
557 av7110->wssMode = 1;
558 av7110->wssData = 0;
559 }
560 break;
561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 default:
563 printk("no such ioctl\n");
564 return -ENOIOCTLCMD;
565 }
566 return 0;
567}
568
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200569static int av7110_vbi_reset(struct inode *inode, struct file *file)
570{
571 struct saa7146_fh *fh = file->private_data;
572 struct saa7146_dev *dev = fh->dev;
573 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
574
575 dprintk(2, "%s\n", __FUNCTION__);
576 av7110->wssMode = 0;
577 av7110->wssData = 0;
578 if (FW_VERSION(av7110->arm_app) < 0x2623)
579 return 0;
580 else
581 return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
582}
583
584static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
585{
586 struct saa7146_fh *fh = file->private_data;
587 struct saa7146_dev *dev = fh->dev;
588 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
589 struct v4l2_sliced_vbi_data d;
590 int rc;
591
592 dprintk(2, "%s\n", __FUNCTION__);
593 if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
594 return -EINVAL;
595 if (copy_from_user(&d, data, count))
596 return -EFAULT;
597 if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
598 return -EINVAL;
Oliver Endriss4caba422006-03-17 05:29:15 -0300599 if (d.id)
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200600 av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
Oliver Endriss4caba422006-03-17 05:29:15 -0300601 else
602 av7110->wssData = 0x8000;
603 rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200604 return (rc < 0) ? rc : count;
605}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607/****************************************************************************
608 * INITIALIZATION
609 ****************************************************************************/
610
611static struct saa7146_extension_ioctls ioctls[] = {
612 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
613 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
614 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
615 { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
616 { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
617 { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
618 { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
619 { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
620 { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200621 { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
622 { VIDIOC_G_FMT, SAA7146_BEFORE },
623 { VIDIOC_S_FMT, SAA7146_BEFORE },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 { 0, 0 }
625};
626
627static u8 saa7113_init_regs[] = {
628 0x02, 0xd0,
629 0x03, 0x23,
630 0x04, 0x00,
631 0x05, 0x00,
632 0x06, 0xe9,
633 0x07, 0x0d,
634 0x08, 0x98,
635 0x09, 0x02,
636 0x0a, 0x80,
637 0x0b, 0x40,
638 0x0c, 0x40,
639 0x0d, 0x00,
640 0x0e, 0x01,
641 0x0f, 0x7c,
642 0x10, 0x48,
643 0x11, 0x0c,
644 0x12, 0x8b,
645 0x13, 0x1a,
646 0x14, 0x00,
647 0x15, 0x00,
648 0x16, 0x00,
649 0x17, 0x00,
650 0x18, 0x00,
651 0x19, 0x00,
652 0x1a, 0x00,
653 0x1b, 0x00,
654 0x1c, 0x00,
655 0x1d, 0x00,
656 0x1e, 0x00,
657
658 0x41, 0x77,
659 0x42, 0x77,
660 0x43, 0x77,
661 0x44, 0x77,
662 0x45, 0x77,
663 0x46, 0x77,
664 0x47, 0x77,
665 0x48, 0x77,
666 0x49, 0x77,
667 0x4a, 0x77,
668 0x4b, 0x77,
669 0x4c, 0x77,
670 0x4d, 0x77,
671 0x4e, 0x77,
672 0x4f, 0x77,
673 0x50, 0x77,
674 0x51, 0x77,
675 0x52, 0x77,
676 0x53, 0x77,
677 0x54, 0x77,
678 0x55, 0x77,
679 0x56, 0x77,
680 0x57, 0xff,
681
682 0xff
683};
684
685
686static struct saa7146_ext_vv av7110_vv_data_st;
687static struct saa7146_ext_vv av7110_vv_data_c;
688
689int av7110_init_analog_module(struct av7110 *av7110)
690{
691 u16 version1, version2;
692
Tim Kaiser61391e02006-06-25 09:14:07 -0300693 if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
694 i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
695 printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
696 av7110->dvb_adapter.num);
697 av7110->adac_type = DVB_ADAC_MSP34x0;
698 } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
699 i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
700 printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n",
701 av7110->dvb_adapter.num);
702 av7110->adac_type = DVB_ADAC_MSP34x5;
703 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -ENODEV;
705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 msleep(100); // the probing above resets the msp...
707 msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
708 msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
Tim Kaiser61391e02006-06-25 09:14:07 -0300709 dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700710 av7110->dvb_adapter.num, version1, version2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
712 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
713 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
714 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
715 msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
716 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
717 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
Tim Kaiser61391e02006-06-25 09:14:07 -0300718 msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
721 INFO(("saa7113 not accessible.\n"));
722 } else {
723 u8 *i = saa7113_init_regs;
724
725 if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
726 /* Fujitsu/Siemens DVB-Cable */
727 av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
728 } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
729 /* Hauppauge/TT DVB-C premium */
730 av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
731 } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
732 /* Hauppauge/TT DVB-C premium */
733 av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
734 }
735
736 /* setup for DVB by default */
737 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
738 if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
739 dprintk(1, "setting band in demodulator failed.\n");
740 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
Marco Schluessler6a857742006-07-10 03:34:16 -0300741 saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
742 saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 }
744
745 /* init the saa7113 */
746 while (*i != 0xff) {
747 if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700748 dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 break;
750 }
751 i += 2;
752 }
753 /* setup msp for analog sound: B/G Dual-FM */
754 msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV
755 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1
756 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1
757 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1
758 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1
759 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1
760 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1
761 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2
762 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2
763 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2
764 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2
765 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2
766 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2
767 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2
768 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2
769 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2
770 msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG
771 msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz
772 msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI
773 msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz
774 msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI
775 msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2
776 }
777
778 memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
779 /* set dd1 stream a & b */
780 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
781 saa7146_write(av7110->dev, DD1_INIT, 0x03000700);
782 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
783
784 return 0;
785}
786
787int av7110_init_v4l(struct av7110 *av7110)
788{
789 struct saa7146_dev* dev = av7110->dev;
790 int ret;
791
792 /* special case DVB-C: these cards have an analog tuner
793 plus need some special handling, so we have separate
794 saa7146_ext_vv data for these... */
795 if (av7110->analog_tuner_flags)
796 ret = saa7146_vv_init(dev, &av7110_vv_data_c);
797 else
798 ret = saa7146_vv_init(dev, &av7110_vv_data_st);
799
800 if (ret) {
801 ERR(("cannot init capture device. skipping.\n"));
802 return -ENODEV;
803 }
804
805 if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
806 ERR(("cannot register capture device. skipping.\n"));
807 saa7146_vv_release(dev);
808 return -ENODEV;
809 }
Oliver Endriss78577352007-01-27 21:13:06 -0300810 if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200811 ERR(("cannot register vbi v4l2 device. skipping.\n"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 return 0;
813}
814
815int av7110_exit_v4l(struct av7110 *av7110)
816{
Marco Schluesslere19c55f2007-01-31 14:32:29 -0300817 struct saa7146_dev* dev = av7110->dev;
818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
Oliver Endriss78577352007-01-27 21:13:06 -0300820 saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
Marco Schluesslere19c55f2007-01-31 14:32:29 -0300821
822 saa7146_vv_release(dev);
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 return 0;
825}
826
827
828
829/* FIXME: these values are experimental values that look better than the
830 values from the latest "official" driver -- at least for me... (MiHu) */
831static struct saa7146_standard standard[] = {
832 {
833 .name = "PAL", .id = V4L2_STD_PAL_BG,
834 .v_offset = 0x15, .v_field = 288,
835 .h_offset = 0x48, .h_pixels = 708,
836 .v_max_out = 576, .h_max_out = 768,
837 }, {
838 .name = "NTSC", .id = V4L2_STD_NTSC,
839 .v_offset = 0x10, .v_field = 244,
840 .h_offset = 0x40, .h_pixels = 708,
841 .v_max_out = 480, .h_max_out = 640,
842 }
843};
844
845static struct saa7146_standard analog_standard[] = {
846 {
847 .name = "PAL", .id = V4L2_STD_PAL_BG,
848 .v_offset = 0x1b, .v_field = 288,
849 .h_offset = 0x08, .h_pixels = 708,
850 .v_max_out = 576, .h_max_out = 768,
851 }, {
852 .name = "NTSC", .id = V4L2_STD_NTSC,
853 .v_offset = 0x10, .v_field = 244,
854 .h_offset = 0x40, .h_pixels = 708,
855 .v_max_out = 480, .h_max_out = 640,
856 }
857};
858
859static struct saa7146_standard dvb_standard[] = {
860 {
861 .name = "PAL", .id = V4L2_STD_PAL_BG,
862 .v_offset = 0x14, .v_field = 288,
863 .h_offset = 0x48, .h_pixels = 708,
864 .v_max_out = 576, .h_max_out = 768,
865 }, {
866 .name = "NTSC", .id = V4L2_STD_NTSC,
867 .v_offset = 0x10, .v_field = 244,
868 .h_offset = 0x40, .h_pixels = 708,
869 .v_max_out = 480, .h_max_out = 640,
870 }
871};
872
873static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
874{
875 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
876
Johannes Stezenbach4ab3f082005-05-16 21:54:27 -0700877 if (std->id & V4L2_STD_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 av7110->vidmode = VIDEO_MODE_PAL;
879 av7110_set_vidmode(av7110, av7110->vidmode);
880 }
Johannes Stezenbach4ab3f082005-05-16 21:54:27 -0700881 else if (std->id & V4L2_STD_NTSC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 av7110->vidmode = VIDEO_MODE_NTSC;
883 av7110_set_vidmode(av7110, av7110->vidmode);
884 }
885 else
886 return -1;
887
888 return 0;
889}
890
891
892static struct saa7146_ext_vv av7110_vv_data_st = {
893 .inputs = 1,
894 .audios = 1,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200895 .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 .flags = 0,
897
898 .stds = &standard[0],
899 .num_stds = ARRAY_SIZE(standard),
900 .std_callback = &std_callback,
901
902 .ioctls = &ioctls[0],
903 .ioctl = av7110_ioctl,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200904
905 .vbi_fops.open = av7110_vbi_reset,
906 .vbi_fops.release = av7110_vbi_reset,
907 .vbi_fops.write = av7110_vbi_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908};
909
910static struct saa7146_ext_vv av7110_vv_data_c = {
911 .inputs = 1,
912 .audios = 1,
Oliver Endrissd7e7a152006-09-14 00:43:22 -0300913 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 .flags = SAA7146_USE_PORT_B_FOR_VBI,
915
916 .stds = &standard[0],
917 .num_stds = ARRAY_SIZE(standard),
918 .std_callback = &std_callback,
919
920 .ioctls = &ioctls[0],
921 .ioctl = av7110_ioctl,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200922
923 .vbi_fops.open = av7110_vbi_reset,
924 .vbi_fops.release = av7110_vbi_reset,
925 .vbi_fops.write = av7110_vbi_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926};
927