blob: add6d0d680bed7fc8e43ac6d687232cd12627ab9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 mxb - v4l2 driver for the Multimedia eXtension Board
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03003
Michael Hunold6acaba82006-03-13 21:20:41 -08004 Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005
6 Visit http://www.mihu.de/linux/saa7146/mxb/
7 for further details about this card.
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#define DEBUG_VARIABLE debug
25
26#include <media/saa7146_vv.h>
27#include <media/tuner.h>
28#include <linux/video_decoder.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -020029#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include "mxb.h"
32#include "tea6415c.h"
33#include "tea6420.h"
34#include "tda9840.h"
35
36#define I2C_SAA7111 0x24
37
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030038#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* global variable */
41static int mxb_num = 0;
42
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030043/* initial frequence the tuner will be tuned to.
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 in verden (lower saxony, germany) 4148 is a
45 channel called "phoenix" */
46static int freq = 4148;
47module_param(freq, int, 0644);
48MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
49
50static int debug = 0;
51module_param(debug, int, 0644);
52MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
53
54#define MXB_INPUTS 4
55enum { TUNER, AUX1, AUX3, AUX3_YC };
56
57static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030058 { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
60 { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
61 { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
62};
63
64/* this array holds the information, which port of the saa7146 each
65 input actually uses. the mxb uses port 0 for every input */
66static struct {
67 int hps_source;
68 int hps_sync;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030069} input_port_selection[MXB_INPUTS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
71 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
72 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
73 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
74};
75
76/* this array holds the information of the audio source (mxb_audios),
77 which has to be switched corresponding to the video source (mxb_channels) */
78static int video_audio_connect[MXB_INPUTS] =
79 { 0, 1, 3, 3 };
80
81/* these are the necessary input-output-pins for bringing one audio source
82(see above) to the CD-output */
83static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030084 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 {{1,1,0},{1,1,0}}, /* Tuner */
86 {{5,1,0},{6,1,0}}, /* AUX 1 */
87 {{4,1,0},{6,1,0}}, /* AUX 2 */
88 {{3,1,0},{6,1,0}}, /* AUX 3 */
89 {{1,1,0},{3,1,0}}, /* Radio */
90 {{1,1,0},{2,1,0}}, /* CD-Rom */
91 {{6,1,0},{6,1,0}} /* Mute */
92 };
93
94/* these are the necessary input-output-pins for bringing one audio source
95(see above) to the line-output */
96static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
97 {
98 {{2,3,0},{1,2,0}},
99 {{5,3,0},{6,2,0}},
100 {{4,3,0},{6,2,0}},
101 {{3,3,0},{6,2,0}},
102 {{2,3,0},{3,2,0}},
103 {{2,3,0},{2,2,0}},
104 {{6,3,0},{6,2,0}} /* Mute */
105 };
106
107#define MAXCONTROLS 1
108static struct v4l2_queryctrl mxb_controls[] = {
109 { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
110};
111
112static struct saa7146_extension_ioctls ioctls[] = {
113 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
114 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
115 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
116 { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
117 { VIDIOC_G_CTRL, SAA7146_BEFORE },
118 { VIDIOC_S_CTRL, SAA7146_BEFORE },
119 { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
120 { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
121 { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
122 { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
123 { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
124 { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300125 { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
126 { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 { 0, 0 }
128};
129
130struct mxb
131{
132 struct video_device *video_dev;
133 struct video_device *vbi_dev;
134
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300135 struct i2c_adapter i2c_adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 struct i2c_client* saa7111a;
138 struct i2c_client* tda9840;
139 struct i2c_client* tea6415c;
140 struct i2c_client* tuner;
141 struct i2c_client* tea6420_1;
142 struct i2c_client* tea6420_2;
143
144 int cur_mode; /* current audio mode (mono, stereo, ...) */
145 int cur_input; /* current input */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int cur_mute; /* current mute status */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700147 struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148};
149
150static struct saa7146_extension extension;
151
Jean Delvare961f80f2008-01-27 18:14:51 +0100152static int mxb_check_clients(struct device *dev, void *data)
153{
154 struct mxb* mxb = data;
155 struct i2c_client *client = i2c_verify_client(dev);
156
157 if( !client )
158 return 0;
159
160 if( I2C_ADDR_TEA6420_1 == client->addr )
161 mxb->tea6420_1 = client;
162 if( I2C_ADDR_TEA6420_2 == client->addr )
163 mxb->tea6420_2 = client;
164 if( I2C_TEA6415C_2 == client->addr )
165 mxb->tea6415c = client;
166 if( I2C_ADDR_TDA9840 == client->addr )
167 mxb->tda9840 = client;
168 if( I2C_SAA7111 == client->addr )
169 mxb->saa7111a = client;
170 if( 0x60 == client->addr )
171 mxb->tuner = client;
172
173 return 0;
174}
175
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176static int mxb_probe(struct saa7146_dev* dev)
177{
178 struct mxb* mxb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 int result;
180
181 if ((result = request_module("saa7111")) < 0) {
182 printk("mxb: saa7111 i2c module not available.\n");
183 return -ENODEV;
184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 if ((result = request_module("tea6420")) < 0) {
186 printk("mxb: tea6420 i2c module not available.\n");
187 return -ENODEV;
188 }
189 if ((result = request_module("tea6415c")) < 0) {
190 printk("mxb: tea6415c i2c module not available.\n");
191 return -ENODEV;
192 }
193 if ((result = request_module("tda9840")) < 0) {
194 printk("mxb: tda9840 i2c module not available.\n");
195 return -ENODEV;
196 }
Michael Hunolda08cc442006-11-28 08:13:58 -0300197 if ((result = request_module("tuner")) < 0) {
198 printk("mxb: tuner i2c module not available.\n");
199 return -ENODEV;
200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Panagiotis Issaris74081872006-01-11 19:40:56 -0200202 mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 if( NULL == mxb ) {
204 DEB_D(("not enough kernel memory.\n"));
205 return -ENOMEM;
206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 mxb->i2c_adapter = (struct i2c_adapter) {
209 .class = I2C_CLASS_TV_ANALOG,
210 .name = "mxb",
211 };
212
213 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
214 if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
215 DEB_S(("cannot register i2c-device. skipping.\n"));
216 kfree(mxb);
217 return -EFAULT;
218 }
219
220 /* loop through all i2c-devices on the bus and look who is there */
Jean Delvare961f80f2008-01-27 18:14:51 +0100221 device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 /* check if all devices are present */
224 if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c
225 || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) {
226
227 printk("mxb: did not find all i2c devices. aborting\n");
228 i2c_del_adapter(&mxb->i2c_adapter);
229 kfree(mxb);
230 return -ENODEV;
231 }
232
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300233 /* all devices are present, probe was successful */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 /* we store the pointer in our private data field */
236 dev->ext_priv = mxb;
237
238 return 0;
239}
240
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300241/* some init data for the saa7740, the so-called 'sound arena module'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 there are no specs available, so we simply use some init values */
243static struct {
244 int length;
245 char data[9];
246} mxb_saa7740_init[] = {
247 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
248 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
249 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
250 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
251 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
252 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
253 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
254 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
255 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
256 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
257 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
258 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
259 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
260 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
261 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
262 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
263 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
264 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
265 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
266 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
267 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
268 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
269 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
270 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
271 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
272 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
273 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
274 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
275 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
276 { 3, { 0x48, 0x00, 0x01 } },
277 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
278 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
279 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
280 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
281 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
282 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
283 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
284 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
285 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
286 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
287 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
288 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
289 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
290 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
291 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
292 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
293 { 3, { 0x80, 0xb3, 0x0a } },
294 {-1, { 0} }
295};
296
297static const unsigned char mxb_saa7111_init[] = {
298 0x00, 0x00, /* 00 - ID byte */
299 0x01, 0x00, /* 01 - reserved */
300
301 /*front end */
302 0x02, 0xd8, /* 02 - FUSE=x, GUDL=x, MODE=x */
303 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
304 0x04, 0x00, /* 04 - GAI1=256 */
305 0x05, 0x00, /* 05 - GAI2=256 */
306
307 /* decoder */
308 0x06, 0xf0, /* 06 - HSB at xx(50Hz) / xx(60Hz) pixels after end of last line */
309 0x07, 0x30, /* 07 - HSS at xx(50Hz) / xx(60Hz) pixels after end of last line */
310 0x08, 0xa8, /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
311 0x09, 0x02, /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
312 0x0a, 0x80, /* 0a - BRIG=128 */
313 0x0b, 0x47, /* 0b - CONT=1.109 */
314 0x0c, 0x40, /* 0c - SATN=1.0 */
315 0x0d, 0x00, /* 0d - HUE=0 */
316 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
317 0x0f, 0x00, /* 0f - reserved */
318 0x10, 0xd0, /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
319 0x11, 0x8c, /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
320 0x12, 0x80, /* 12 - xx output control 2 */
321 0x13, 0x30, /* 13 - xx output control 3 */
322 0x14, 0x00, /* 14 - reserved */
323 0x15, 0x15, /* 15 - VBI */
324 0x16, 0x04, /* 16 - VBI */
325 0x17, 0x00, /* 17 - VBI */
326};
327
328/* bring hardware to a sane state. this has to be done, just in case someone
329 wants to capture from this device before it has been properly initialized.
330 the capture engine would badly fail, because no valid signal arrives on the
331 saa7146, thus leading to timeouts and stuff. */
332static int mxb_init_done(struct saa7146_dev* dev)
333{
334 struct mxb* mxb = (struct mxb*)dev->ext_priv;
335 struct video_decoder_init init;
336 struct i2c_msg msg;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700337 struct tuner_setup tun_setup;
Michael Hunold6acaba82006-03-13 21:20:41 -0800338 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 int i = 0, err = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300341 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 /* select video mode in saa7111a */
344 i = VIDEO_MODE_PAL;
345 /* fixme: currently pointless: gets overwritten by configuration below */
346 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
347
348 /* write configuration to saa7111a */
349 init.data = mxb_saa7111_init;
350 init.len = sizeof(mxb_saa7111_init);
351 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
352
353 /* select tuner-output on saa7111a */
354 i = 0;
355 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
356
357 /* enable vbi bypass */
358 i = 1;
359 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
360
361 /* select a tuner type */
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700362 tun_setup.mode_mask = T_ANALOG_TV;
363 tun_setup.addr = ADDR_UNSET;
Michael Hunold9d2599d2005-07-27 11:46:00 -0700364 tun_setup.type = TUNER_PHILIPS_PAL;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700365 mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
Michael Hunold9d2599d2005-07-27 11:46:00 -0700366 /* tune in some frequency on tuner */
367 mxb->cur_freq.tuner = 0;
368 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
369 mxb->cur_freq.frequency = freq;
370 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
371 &mxb->cur_freq);
372
Michael Hunold6acaba82006-03-13 21:20:41 -0800373 /* set a default video standard */
374 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
375
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 /* mute audio on tea6420s */
377 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
378 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
379 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
380 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
381
382 /* switch to tuner-channel on tea6415c*/
383 vm.out = 17;
384 vm.in = 3;
385 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
386
387 /* select tuner-output on multicable on tea6415c*/
388 vm.in = 3;
389 vm.out = 13;
390 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300391
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 /* the rest for mxb */
393 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 mxb->cur_mute = 1;
395
396 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
397 mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 /* check if the saa7740 (aka 'sound arena module') is present
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300400 on the mxb. if so, we must initialize it. due to lack of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 informations about the saa7740, the values were reverse
402 engineered. */
403 msg.addr = 0x1b;
404 msg.flags = 0;
405 msg.len = mxb_saa7740_init[0].length;
406 msg.buf = &mxb_saa7740_init[0].data[0];
407
408 if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
409 /* the sound arena module is a pos, that's probably the reason
410 philips refuses to hand out a datasheet for the saa7740...
411 it seems to screw up the i2c bus, so we disable fast irq
412 based i2c transactions here and rely on the slow and safe
413 polling method ... */
414 extension.flags &= ~SAA7146_USE_I2C_IRQ;
415 for(i = 1;;i++) {
416 if( -1 == mxb_saa7740_init[i].length ) {
417 break;
418 }
419
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300420 msg.len = mxb_saa7740_init[i].length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 msg.buf = &mxb_saa7740_init[i].data[0];
422 if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
423 DEB_D(("failed to initialize 'sound arena module'.\n"));
424 goto err;
425 }
426 }
427 INFO(("'sound arena module' detected.\n"));
428 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300429err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* the rest for saa7146: you should definitely set some basic values
431 for the input-port handling of the saa7146. */
432
433 /* ext->saa has been filled by the core driver */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300434
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 /* some stuff is done via variables */
436 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
437
438 /* some stuff is done via direct write to the registers */
439
440 /* this is ugly, but because of the fact that this is completely
441 hardware dependend, it should be done directly... */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300442 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 saa7146_write(dev, DD1_INIT, 0x02000200);
444 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
445
446 return 0;
447}
448
449/* interrupt-handler. this gets called when irq_mask is != 0.
450 it must clear the interrupt-bits in irq_mask it has handled */
451/*
452void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
453{
454 struct mxb* mxb = (struct mxb*)dev->ext_priv;
455}
456*/
457
458static struct saa7146_ext_vv vv_data;
459
460/* this function only gets called when the probing was successful */
461static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
462{
463 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 DEB_EE(("dev:%p\n",dev));
466
467 /* checking for i2c-devices can be omitted here, because we
468 already did this in "mxb_vl42_probe" */
469
470 saa7146_vv_init(dev,&vv_data);
471 if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
472 ERR(("cannot register capture v4l2 device. skipping.\n"));
473 return -1;
474 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300475
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
477 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
478 if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
479 ERR(("cannot register vbi v4l2 device. skipping.\n"));
480 }
481 }
482
483 i2c_use_client(mxb->tea6420_1);
484 i2c_use_client(mxb->tea6420_2);
485 i2c_use_client(mxb->tea6415c);
486 i2c_use_client(mxb->tda9840);
487 i2c_use_client(mxb->saa7111a);
488 i2c_use_client(mxb->tuner);
489
490 printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
491
492 mxb_num++;
493 mxb_init_done(dev);
494 return 0;
495}
496
497static int mxb_detach(struct saa7146_dev* dev)
498{
499 struct mxb* mxb = (struct mxb*)dev->ext_priv;
500
501 DEB_EE(("dev:%p\n",dev));
502
503 i2c_release_client(mxb->tea6420_1);
504 i2c_release_client(mxb->tea6420_2);
505 i2c_release_client(mxb->tea6415c);
506 i2c_release_client(mxb->tda9840);
507 i2c_release_client(mxb->saa7111a);
508 i2c_release_client(mxb->tuner);
509
510 saa7146_unregister_device(&mxb->video_dev,dev);
511 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
512 saa7146_unregister_device(&mxb->vbi_dev,dev);
513 }
514 saa7146_vv_release(dev);
515
516 mxb_num--;
517
518 i2c_del_adapter(&mxb->i2c_adapter);
519 kfree(mxb);
520
521 return 0;
522}
523
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300524static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525{
526 struct saa7146_dev *dev = fh->dev;
527 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300528 struct saa7146_vv *vv = dev->vv_data;
529
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 switch(cmd) {
531 case VIDIOC_ENUMINPUT:
532 {
533 struct v4l2_input *i = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
536 if( i->index < 0 || i->index >= MXB_INPUTS) {
537 return -EINVAL;
538 }
539 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
540
541 return 0;
542 }
543 /* the saa7146 provides some controls (brightness, contrast, saturation)
544 which gets registered *after* this function. because of this we have
545 to return with a value != 0 even if the function succeded.. */
546 case VIDIOC_QUERYCTRL:
547 {
548 struct v4l2_queryctrl *qc = arg;
549 int i;
550
551 for (i = MAXCONTROLS - 1; i >= 0; i--) {
552 if (mxb_controls[i].id == qc->id) {
553 *qc = mxb_controls[i];
554 DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
555 return 0;
556 }
557 }
558 return -EAGAIN;
559 }
560 case VIDIOC_G_CTRL:
561 {
562 struct v4l2_control *vc = arg;
563 int i;
564
565 for (i = MAXCONTROLS - 1; i >= 0; i--) {
566 if (mxb_controls[i].id == vc->id) {
567 break;
568 }
569 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 if( i < 0 ) {
572 return -EAGAIN;
573 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 switch (vc->id ) {
576 case V4L2_CID_AUDIO_MUTE: {
577 vc->value = mxb->cur_mute;
578 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
579 return 0;
580 }
581 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
584 return 0;
585 }
586
587 case VIDIOC_S_CTRL:
588 {
589 struct v4l2_control *vc = arg;
590 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 for (i = MAXCONTROLS - 1; i >= 0; i--) {
593 if (mxb_controls[i].id == vc->id) {
594 break;
595 }
596 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 if( i < 0 ) {
599 return -EAGAIN;
600 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300601
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 switch (vc->id ) {
603 case V4L2_CID_AUDIO_MUTE: {
604 mxb->cur_mute = vc->value;
605 if( 0 == vc->value ) {
606 /* switch the audio-source */
607 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
608 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
609 } else {
610 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
611 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
612 }
613 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
614 break;
615 }
616 }
617 return 0;
618 }
619 case VIDIOC_G_INPUT:
620 {
621 int *input = (int *)arg;
622 *input = mxb->cur_input;
623
624 DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300625 return 0;
626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 case VIDIOC_S_INPUT:
628 {
629 int input = *(int *)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300630 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 int i = 0;
632
633 DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
634
635 if (input < 0 || input >= MXB_INPUTS) {
636 return -EINVAL;
637 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 /* fixme: locke das setzen des inputs mit hilfe des mutexes
Ingo Molnar3593cab2006-02-07 06:49:14 -0200640 mutex_lock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 video_mux(dev,*i);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200642 mutex_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 /* fixme: check if streaming capture
646 if ( 0 != dev->streaming ) {
647 DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
648 return -EPERM;
649 }
650 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /* prepare switching of tea6415c and saa7111a;
657 have a look at the 'background'-file for further informations */
658 switch( input ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 case TUNER:
661 {
662 i = 0;
663 vm.in = 3;
664 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300665
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
667 printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
668 return -EFAULT;
669 }
670 /* connect tuner-output always to multicable */
671 vm.in = 3;
672 vm.out = 13;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300673 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 }
675 case AUX3_YC:
676 {
677 /* nothing to be done here. aux3_yc is
678 directly connected to the saa711a */
679 i = 5;
680 break;
681 }
682 case AUX3:
683 {
684 /* nothing to be done here. aux3 is
685 directly connected to the saa711a */
686 i = 1;
687 break;
688 }
689 case AUX1:
690 {
691 i = 0;
692 vm.in = 1;
693 vm.out = 17;
694 break;
695 }
696 }
697
698 /* switch video in tea6415c only if necessary */
699 switch( input ) {
700 case TUNER:
701 case AUX1:
702 {
703 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
704 printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
705 return -EFAULT;
706 }
707 break;
708 }
709 default:
710 {
711 break;
712 }
713 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 /* switch video in saa7111a */
716 if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
717 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 /* switch the audio-source only if necessary */
721 if( 0 == mxb->cur_mute ) {
722 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
723 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
724 }
725
726 return 0;
727 }
728 case VIDIOC_G_TUNER:
729 {
730 struct v4l2_tuner *t = arg;
731 int byte = 0;
732
733 if( 0 != t->index ) {
734 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
735 return -EINVAL;
736 }
737
738 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
739
740 memset(t,0,sizeof(*t));
741 strcpy(t->name, "Television");
742
743 t->type = V4L2_TUNER_ANALOG_TV;
744 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
745 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
746 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
747 /* FIXME: add the real signal strength here */
748 t->signal = 0xffff;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300749 t->afc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
751 mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
752 t->audmode = mxb->cur_mode;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300753
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 if( byte < 0 ) {
755 t->rxsubchans = V4L2_TUNER_SUB_MONO;
756 } else {
757 switch(byte) {
758 case TDA9840_MONO_DETECT: {
759 t->rxsubchans = V4L2_TUNER_SUB_MONO;
760 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
761 break;
762 }
763 case TDA9840_DUAL_DETECT: {
764 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
765 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
766 break;
767 }
768 case TDA9840_STEREO_DETECT: {
769 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
770 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
771 break;
772 }
773 default: { /* TDA9840_INCORRECT_DETECT */
774 t->rxsubchans = V4L2_TUNER_MODE_MONO;
775 DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
776 break;
777 }
778 }
779 }
780
781 return 0;
782 }
783 case VIDIOC_S_TUNER:
784 {
785 struct v4l2_tuner *t = arg;
786 int result = 0;
787 int byte = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if( 0 != t->index ) {
790 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
791 return -EINVAL;
792 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300793
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 switch(t->audmode) {
795 case V4L2_TUNER_MODE_STEREO: {
796 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
797 byte = TDA9840_SET_STEREO;
798 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
799 break;
800 }
Hans Verkuil301e22d2006-03-18 17:15:00 -0300801 case V4L2_TUNER_MODE_LANG1_LANG2: {
802 mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
803 byte = TDA9840_SET_BOTH;
804 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
805 break;
806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 case V4L2_TUNER_MODE_LANG1: {
808 mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
809 byte = TDA9840_SET_LANG1;
810 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
811 break;
812 }
813 case V4L2_TUNER_MODE_LANG2: {
814 mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
815 byte = TDA9840_SET_LANG2;
816 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
817 break;
818 }
819 default: { /* case V4L2_TUNER_MODE_MONO: {*/
820 mxb->cur_mode = V4L2_TUNER_MODE_MONO;
821 byte = TDA9840_SET_MONO;
822 DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
823 break;
824 }
825 }
826
827 if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
828 printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
829 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return 0;
832 }
833 case VIDIOC_G_FREQUENCY:
834 {
835 struct v4l2_frequency *f = arg;
836
837 if(0 != mxb->cur_input) {
838 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
839 return -EINVAL;
840 }
841
Michael Hunold9d2599d2005-07-27 11:46:00 -0700842 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
Michael Hunold9d2599d2005-07-27 11:46:00 -0700844 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 return 0;
846 }
847 case VIDIOC_S_FREQUENCY:
848 {
849 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851 if (0 != f->tuner)
852 return -EINVAL;
853
854 if (V4L2_TUNER_ANALOG_TV != f->type)
855 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if(0 != mxb->cur_input) {
858 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
859 return -EINVAL;
860 }
861
Michael Hunold9d2599d2005-07-27 11:46:00 -0700862 mxb->cur_freq = *f;
863 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300865 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700866 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
869 spin_lock(&dev->slock);
870 vv->vbi_fieldcount = 0;
871 spin_unlock(&dev->slock);
872
873 return 0;
874 }
875 case MXB_S_AUDIO_CD:
876 {
877 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if( i < 0 || i >= MXB_AUDIOS ) {
880 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
881 return -EINVAL;
882 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300883
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
885
886 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
887 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
888
889 return 0;
890 }
891 case MXB_S_AUDIO_LINE:
892 {
893 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300894
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if( i < 0 || i >= MXB_AUDIOS ) {
896 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
897 return -EINVAL;
898 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
901 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
902 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
903
904 return 0;
905 }
906 case VIDIOC_G_AUDIO:
907 {
908 struct v4l2_audio *a = arg;
909
910 if( a->index < 0 || a->index > MXB_INPUTS ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300911 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 return -EINVAL;
913 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300914
915 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 return 0;
919 }
920 case VIDIOC_S_AUDIO:
921 {
922 struct v4l2_audio *a = arg;
923 DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
924 return 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 default:
927/*
928 DEB2(printk("does not handle this ioctl.\n"));
929*/
930 return -ENOIOCTLCMD;
931 }
932 return 0;
933}
934
935static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
936{
937 struct mxb* mxb = (struct mxb*)dev->ext_priv;
938 int zero = 0;
939 int one = 1;
940
941 if(V4L2_STD_PAL_I == std->id ) {
Michael Hunold6acaba82006-03-13 21:20:41 -0800942 v4l2_std_id std = V4L2_STD_PAL_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
944 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300945 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 /* unset the 7111 gpio register -- I don't know what this does exactly */
947 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
Michael Hunold6acaba82006-03-13 21:20:41 -0800948 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800950 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
952 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300953 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 /* set the 7111 gpio register -- I don't know what this does exactly */
955 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
Michael Hunold6acaba82006-03-13 21:20:41 -0800956 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 }
958 return 0;
959}
960
961static struct saa7146_standard standard[] = {
962 {
963 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
964 .v_offset = 0x17, .v_field = 288,
965 .h_offset = 0x14, .h_pixels = 680,
966 .v_max_out = 576, .h_max_out = 768,
967 }, {
968 .name = "PAL-I", .id = V4L2_STD_PAL_I,
969 .v_offset = 0x17, .v_field = 288,
970 .h_offset = 0x14, .h_pixels = 680,
971 .v_max_out = 576, .h_max_out = 768,
972 }, {
973 .name = "NTSC", .id = V4L2_STD_NTSC,
974 .v_offset = 0x16, .v_field = 240,
975 .h_offset = 0x06, .h_pixels = 708,
976 .v_max_out = 480, .h_max_out = 640,
977 }, {
978 .name = "SECAM", .id = V4L2_STD_SECAM,
979 .v_offset = 0x14, .v_field = 288,
980 .h_offset = 0x14, .h_pixels = 720,
981 .v_max_out = 576, .h_max_out = 768,
982 }
983};
984
985static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300986 .ext_priv = "Multimedia eXtension Board",
987 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988};
989
990static struct pci_device_id pci_tbl[] = {
991 {
992 .vendor = PCI_VENDOR_ID_PHILIPS,
993 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
994 .subvendor = 0x0000,
995 .subdevice = 0x0000,
996 .driver_data = (unsigned long)&mxb,
997 }, {
998 .vendor = 0,
999 }
1000};
1001
1002MODULE_DEVICE_TABLE(pci, pci_tbl);
1003
1004static struct saa7146_ext_vv vv_data = {
1005 .inputs = MXB_INPUTS,
1006 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
1007 .stds = &standard[0],
1008 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001009 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 .ioctls = &ioctls[0],
1011 .ioctl = mxb_ioctl,
1012};
1013
1014static struct saa7146_extension extension = {
1015 .name = MXB_IDENTIFIER,
1016 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 .pci_tbl = &pci_tbl[0],
1019 .module = THIS_MODULE,
1020
1021 .probe = mxb_probe,
1022 .attach = mxb_attach,
1023 .detach = mxb_detach,
1024
1025 .irq_mask = 0,
1026 .irq_func = NULL,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001027};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
1029static int __init mxb_init_module(void)
1030{
1031 if( 0 != saa7146_register_extension(&extension)) {
1032 DEB_S(("failed to register extension.\n"));
1033 return -ENODEV;
1034 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return 0;
1037}
1038
1039static void __exit mxb_cleanup_module(void)
1040{
1041 saa7146_unregister_extension(&extension);
1042}
1043
1044module_init(mxb_init_module);
1045module_exit(mxb_cleanup_module);
1046
1047MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
1048MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
1049MODULE_LICENSE("GPL");