blob: 91681aa6c6574261102deb36a60fe47fad63e005 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 mxb - v4l2 driver for the Multimedia eXtension Board
3
4 Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
5
6 Visit http://www.mihu.de/linux/saa7146/mxb/
7 for further details about this card.
8
9 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
38#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
39
40/* global variable */
41static int mxb_num = 0;
42
43/* initial frequence the tuner will be tuned to.
44 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] = {
58 { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
59 { 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;
69} input_port_selection[MXB_INPUTS] = {
70 { 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] =
84 {
85 {{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 },
125 { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
126 { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
127 { 0, 0 }
128};
129
130struct mxb
131{
132 struct video_device *video_dev;
133 struct video_device *vbi_dev;
134
135 struct i2c_adapter i2c_adapter;
136
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
152static int mxb_probe(struct saa7146_dev* dev)
153{
154 struct mxb* mxb = NULL;
155 struct i2c_client *client;
156 struct list_head *item;
157 int result;
158
159 if ((result = request_module("saa7111")) < 0) {
160 printk("mxb: saa7111 i2c module not available.\n");
161 return -ENODEV;
162 }
163 if ((result = request_module("tuner")) < 0) {
164 printk("mxb: tuner i2c module not available.\n");
165 return -ENODEV;
166 }
167 if ((result = request_module("tea6420")) < 0) {
168 printk("mxb: tea6420 i2c module not available.\n");
169 return -ENODEV;
170 }
171 if ((result = request_module("tea6415c")) < 0) {
172 printk("mxb: tea6415c i2c module not available.\n");
173 return -ENODEV;
174 }
175 if ((result = request_module("tda9840")) < 0) {
176 printk("mxb: tda9840 i2c module not available.\n");
177 return -ENODEV;
178 }
179
180 mxb = (struct mxb*)kmalloc(sizeof(struct mxb), GFP_KERNEL);
181 if( NULL == mxb ) {
182 DEB_D(("not enough kernel memory.\n"));
183 return -ENOMEM;
184 }
185 memset(mxb, 0x0, sizeof(struct mxb));
186
187 mxb->i2c_adapter = (struct i2c_adapter) {
188 .class = I2C_CLASS_TV_ANALOG,
189 .name = "mxb",
190 };
191
192 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
193 if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
194 DEB_S(("cannot register i2c-device. skipping.\n"));
195 kfree(mxb);
196 return -EFAULT;
197 }
198
199 /* loop through all i2c-devices on the bus and look who is there */
200 list_for_each(item,&mxb->i2c_adapter.clients) {
201 client = list_entry(item, struct i2c_client, list);
202 if( I2C_TEA6420_1 == client->addr )
203 mxb->tea6420_1 = client;
204 if( I2C_TEA6420_2 == client->addr )
205 mxb->tea6420_2 = client;
206 if( I2C_TEA6415C_2 == client->addr )
207 mxb->tea6415c = client;
208 if( I2C_TDA9840 == client->addr )
209 mxb->tda9840 = client;
210 if( I2C_SAA7111 == client->addr )
211 mxb->saa7111a = client;
212 if( 0x60 == client->addr )
213 mxb->tuner = client;
214 }
215
216 /* check if all devices are present */
217 if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c
218 || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) {
219
220 printk("mxb: did not find all i2c devices. aborting\n");
221 i2c_del_adapter(&mxb->i2c_adapter);
222 kfree(mxb);
223 return -ENODEV;
224 }
225
226 /* all devices are present, probe was successful */
227
228 /* we store the pointer in our private data field */
229 dev->ext_priv = mxb;
230
231 return 0;
232}
233
234/* some init data for the saa7740, the so-called 'sound arena module'.
235 there are no specs available, so we simply use some init values */
236static struct {
237 int length;
238 char data[9];
239} mxb_saa7740_init[] = {
240 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
241 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
242 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
243 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
244 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
245 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
246 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
247 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
248 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
249 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
250 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
251 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
252 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
253 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
254 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
255 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
256 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
257 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
258 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
259 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
260 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
261 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
262 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
263 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
264 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
265 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
266 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
267 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
268 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
269 { 3, { 0x48, 0x00, 0x01 } },
270 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
271 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
272 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
273 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
274 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
275 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
276 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
277 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
278 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
279 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
280 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
281 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
282 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
283 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
284 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
285 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
286 { 3, { 0x80, 0xb3, 0x0a } },
287 {-1, { 0} }
288};
289
290static const unsigned char mxb_saa7111_init[] = {
291 0x00, 0x00, /* 00 - ID byte */
292 0x01, 0x00, /* 01 - reserved */
293
294 /*front end */
295 0x02, 0xd8, /* 02 - FUSE=x, GUDL=x, MODE=x */
296 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
297 0x04, 0x00, /* 04 - GAI1=256 */
298 0x05, 0x00, /* 05 - GAI2=256 */
299
300 /* decoder */
301 0x06, 0xf0, /* 06 - HSB at xx(50Hz) / xx(60Hz) pixels after end of last line */
302 0x07, 0x30, /* 07 - HSS at xx(50Hz) / xx(60Hz) pixels after end of last line */
303 0x08, 0xa8, /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
304 0x09, 0x02, /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
305 0x0a, 0x80, /* 0a - BRIG=128 */
306 0x0b, 0x47, /* 0b - CONT=1.109 */
307 0x0c, 0x40, /* 0c - SATN=1.0 */
308 0x0d, 0x00, /* 0d - HUE=0 */
309 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
310 0x0f, 0x00, /* 0f - reserved */
311 0x10, 0xd0, /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
312 0x11, 0x8c, /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
313 0x12, 0x80, /* 12 - xx output control 2 */
314 0x13, 0x30, /* 13 - xx output control 3 */
315 0x14, 0x00, /* 14 - reserved */
316 0x15, 0x15, /* 15 - VBI */
317 0x16, 0x04, /* 16 - VBI */
318 0x17, 0x00, /* 17 - VBI */
319};
320
321/* bring hardware to a sane state. this has to be done, just in case someone
322 wants to capture from this device before it has been properly initialized.
323 the capture engine would badly fail, because no valid signal arrives on the
324 saa7146, thus leading to timeouts and stuff. */
325static int mxb_init_done(struct saa7146_dev* dev)
326{
327 struct mxb* mxb = (struct mxb*)dev->ext_priv;
328 struct video_decoder_init init;
329 struct i2c_msg msg;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700330 struct tuner_setup tun_setup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 int i = 0, err = 0;
333 struct tea6415c_multiplex vm;
334
335 /* select video mode in saa7111a */
336 i = VIDEO_MODE_PAL;
337 /* fixme: currently pointless: gets overwritten by configuration below */
338 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
339
340 /* write configuration to saa7111a */
341 init.data = mxb_saa7111_init;
342 init.len = sizeof(mxb_saa7111_init);
343 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
344
345 /* select tuner-output on saa7111a */
346 i = 0;
347 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
348
349 /* enable vbi bypass */
350 i = 1;
351 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
352
353 /* select a tuner type */
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700354 tun_setup.mode_mask = T_ANALOG_TV;
355 tun_setup.addr = ADDR_UNSET;
Michael Hunold9d2599d2005-07-27 11:46:00 -0700356 tun_setup.type = TUNER_PHILIPS_PAL;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700357 mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
Michael Hunold9d2599d2005-07-27 11:46:00 -0700358 /* tune in some frequency on tuner */
359 mxb->cur_freq.tuner = 0;
360 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
361 mxb->cur_freq.frequency = freq;
362 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
363 &mxb->cur_freq);
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 /* mute audio on tea6420s */
366 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
367 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
368 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
369 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
370
371 /* switch to tuner-channel on tea6415c*/
372 vm.out = 17;
373 vm.in = 3;
374 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
375
376 /* select tuner-output on multicable on tea6415c*/
377 vm.in = 3;
378 vm.out = 13;
379 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 /* the rest for mxb */
382 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 mxb->cur_mute = 1;
384
385 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
386 mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
387
388 /* check if the saa7740 (aka 'sound arena module') is present
389 on the mxb. if so, we must initialize it. due to lack of
390 informations about the saa7740, the values were reverse
391 engineered. */
392 msg.addr = 0x1b;
393 msg.flags = 0;
394 msg.len = mxb_saa7740_init[0].length;
395 msg.buf = &mxb_saa7740_init[0].data[0];
396
397 if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
398 /* the sound arena module is a pos, that's probably the reason
399 philips refuses to hand out a datasheet for the saa7740...
400 it seems to screw up the i2c bus, so we disable fast irq
401 based i2c transactions here and rely on the slow and safe
402 polling method ... */
403 extension.flags &= ~SAA7146_USE_I2C_IRQ;
404 for(i = 1;;i++) {
405 if( -1 == mxb_saa7740_init[i].length ) {
406 break;
407 }
408
409 msg.len = mxb_saa7740_init[i].length;
410 msg.buf = &mxb_saa7740_init[i].data[0];
411 if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
412 DEB_D(("failed to initialize 'sound arena module'.\n"));
413 goto err;
414 }
415 }
416 INFO(("'sound arena module' detected.\n"));
417 }
418err:
419 /* the rest for saa7146: you should definitely set some basic values
420 for the input-port handling of the saa7146. */
421
422 /* ext->saa has been filled by the core driver */
423
424 /* some stuff is done via variables */
425 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
426
427 /* some stuff is done via direct write to the registers */
428
429 /* this is ugly, but because of the fact that this is completely
430 hardware dependend, it should be done directly... */
431 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
432 saa7146_write(dev, DD1_INIT, 0x02000200);
433 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
434
435 return 0;
436}
437
438/* interrupt-handler. this gets called when irq_mask is != 0.
439 it must clear the interrupt-bits in irq_mask it has handled */
440/*
441void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
442{
443 struct mxb* mxb = (struct mxb*)dev->ext_priv;
444}
445*/
446
447static struct saa7146_ext_vv vv_data;
448
449/* this function only gets called when the probing was successful */
450static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
451{
452 struct mxb* mxb = (struct mxb*)dev->ext_priv;
453
454 DEB_EE(("dev:%p\n",dev));
455
456 /* checking for i2c-devices can be omitted here, because we
457 already did this in "mxb_vl42_probe" */
458
459 saa7146_vv_init(dev,&vv_data);
460 if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
461 ERR(("cannot register capture v4l2 device. skipping.\n"));
462 return -1;
463 }
464
465 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
466 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
467 if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
468 ERR(("cannot register vbi v4l2 device. skipping.\n"));
469 }
470 }
471
472 i2c_use_client(mxb->tea6420_1);
473 i2c_use_client(mxb->tea6420_2);
474 i2c_use_client(mxb->tea6415c);
475 i2c_use_client(mxb->tda9840);
476 i2c_use_client(mxb->saa7111a);
477 i2c_use_client(mxb->tuner);
478
479 printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
480
481 mxb_num++;
482 mxb_init_done(dev);
483 return 0;
484}
485
486static int mxb_detach(struct saa7146_dev* dev)
487{
488 struct mxb* mxb = (struct mxb*)dev->ext_priv;
489
490 DEB_EE(("dev:%p\n",dev));
491
492 i2c_release_client(mxb->tea6420_1);
493 i2c_release_client(mxb->tea6420_2);
494 i2c_release_client(mxb->tea6415c);
495 i2c_release_client(mxb->tda9840);
496 i2c_release_client(mxb->saa7111a);
497 i2c_release_client(mxb->tuner);
498
499 saa7146_unregister_device(&mxb->video_dev,dev);
500 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
501 saa7146_unregister_device(&mxb->vbi_dev,dev);
502 }
503 saa7146_vv_release(dev);
504
505 mxb_num--;
506
507 i2c_del_adapter(&mxb->i2c_adapter);
508 kfree(mxb);
509
510 return 0;
511}
512
513static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
514{
515 struct saa7146_dev *dev = fh->dev;
516 struct mxb* mxb = (struct mxb*)dev->ext_priv;
517 struct saa7146_vv *vv = dev->vv_data;
518
519 switch(cmd) {
520 case VIDIOC_ENUMINPUT:
521 {
522 struct v4l2_input *i = arg;
523
524 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
525 if( i->index < 0 || i->index >= MXB_INPUTS) {
526 return -EINVAL;
527 }
528 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
529
530 return 0;
531 }
532 /* the saa7146 provides some controls (brightness, contrast, saturation)
533 which gets registered *after* this function. because of this we have
534 to return with a value != 0 even if the function succeded.. */
535 case VIDIOC_QUERYCTRL:
536 {
537 struct v4l2_queryctrl *qc = arg;
538 int i;
539
540 for (i = MAXCONTROLS - 1; i >= 0; i--) {
541 if (mxb_controls[i].id == qc->id) {
542 *qc = mxb_controls[i];
543 DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
544 return 0;
545 }
546 }
547 return -EAGAIN;
548 }
549 case VIDIOC_G_CTRL:
550 {
551 struct v4l2_control *vc = arg;
552 int i;
553
554 for (i = MAXCONTROLS - 1; i >= 0; i--) {
555 if (mxb_controls[i].id == vc->id) {
556 break;
557 }
558 }
559
560 if( i < 0 ) {
561 return -EAGAIN;
562 }
563
564 switch (vc->id ) {
565 case V4L2_CID_AUDIO_MUTE: {
566 vc->value = mxb->cur_mute;
567 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
568 return 0;
569 }
570 }
571
572 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
573 return 0;
574 }
575
576 case VIDIOC_S_CTRL:
577 {
578 struct v4l2_control *vc = arg;
579 int i = 0;
580
581 for (i = MAXCONTROLS - 1; i >= 0; i--) {
582 if (mxb_controls[i].id == vc->id) {
583 break;
584 }
585 }
586
587 if( i < 0 ) {
588 return -EAGAIN;
589 }
590
591 switch (vc->id ) {
592 case V4L2_CID_AUDIO_MUTE: {
593 mxb->cur_mute = vc->value;
594 if( 0 == vc->value ) {
595 /* switch the audio-source */
596 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
597 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
598 } else {
599 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
600 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
601 }
602 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
603 break;
604 }
605 }
606 return 0;
607 }
608 case VIDIOC_G_INPUT:
609 {
610 int *input = (int *)arg;
611 *input = mxb->cur_input;
612
613 DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
614 return 0;
615 }
616 case VIDIOC_S_INPUT:
617 {
618 int input = *(int *)arg;
619 struct tea6415c_multiplex vm;
620 int i = 0;
621
622 DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
623
624 if (input < 0 || input >= MXB_INPUTS) {
625 return -EINVAL;
626 }
627
628 /* fixme: locke das setzen des inputs mit hilfe des mutexes
629 down(&dev->lock);
630 video_mux(dev,*i);
631 up(&dev->lock);
632 */
633
634 /* fixme: check if streaming capture
635 if ( 0 != dev->streaming ) {
636 DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
637 return -EPERM;
638 }
639 */
640
641 mxb->cur_input = input;
642
643 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
644
645 /* prepare switching of tea6415c and saa7111a;
646 have a look at the 'background'-file for further informations */
647 switch( input ) {
648
649 case TUNER:
650 {
651 i = 0;
652 vm.in = 3;
653 vm.out = 17;
654
655 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
656 printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
657 return -EFAULT;
658 }
659 /* connect tuner-output always to multicable */
660 vm.in = 3;
661 vm.out = 13;
662 break;
663 }
664 case AUX3_YC:
665 {
666 /* nothing to be done here. aux3_yc is
667 directly connected to the saa711a */
668 i = 5;
669 break;
670 }
671 case AUX3:
672 {
673 /* nothing to be done here. aux3 is
674 directly connected to the saa711a */
675 i = 1;
676 break;
677 }
678 case AUX1:
679 {
680 i = 0;
681 vm.in = 1;
682 vm.out = 17;
683 break;
684 }
685 }
686
687 /* switch video in tea6415c only if necessary */
688 switch( input ) {
689 case TUNER:
690 case AUX1:
691 {
692 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
693 printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
694 return -EFAULT;
695 }
696 break;
697 }
698 default:
699 {
700 break;
701 }
702 }
703
704 /* switch video in saa7111a */
705 if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
706 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
707 }
708
709 /* switch the audio-source only if necessary */
710 if( 0 == mxb->cur_mute ) {
711 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
712 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
713 }
714
715 return 0;
716 }
717 case VIDIOC_G_TUNER:
718 {
719 struct v4l2_tuner *t = arg;
720 int byte = 0;
721
722 if( 0 != t->index ) {
723 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
724 return -EINVAL;
725 }
726
727 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
728
729 memset(t,0,sizeof(*t));
730 strcpy(t->name, "Television");
731
732 t->type = V4L2_TUNER_ANALOG_TV;
733 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
734 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
735 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
736 /* FIXME: add the real signal strength here */
737 t->signal = 0xffff;
738 t->afc = 0;
739
740 mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
741 t->audmode = mxb->cur_mode;
742
743 if( byte < 0 ) {
744 t->rxsubchans = V4L2_TUNER_SUB_MONO;
745 } else {
746 switch(byte) {
747 case TDA9840_MONO_DETECT: {
748 t->rxsubchans = V4L2_TUNER_SUB_MONO;
749 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
750 break;
751 }
752 case TDA9840_DUAL_DETECT: {
753 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
754 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
755 break;
756 }
757 case TDA9840_STEREO_DETECT: {
758 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
759 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
760 break;
761 }
762 default: { /* TDA9840_INCORRECT_DETECT */
763 t->rxsubchans = V4L2_TUNER_MODE_MONO;
764 DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
765 break;
766 }
767 }
768 }
769
770 return 0;
771 }
772 case VIDIOC_S_TUNER:
773 {
774 struct v4l2_tuner *t = arg;
775 int result = 0;
776 int byte = 0;
777
778 if( 0 != t->index ) {
779 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
780 return -EINVAL;
781 }
782
783 switch(t->audmode) {
784 case V4L2_TUNER_MODE_STEREO: {
785 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
786 byte = TDA9840_SET_STEREO;
787 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
788 break;
789 }
790 case V4L2_TUNER_MODE_LANG1: {
791 mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
792 byte = TDA9840_SET_LANG1;
793 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
794 break;
795 }
796 case V4L2_TUNER_MODE_LANG2: {
797 mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
798 byte = TDA9840_SET_LANG2;
799 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
800 break;
801 }
802 default: { /* case V4L2_TUNER_MODE_MONO: {*/
803 mxb->cur_mode = V4L2_TUNER_MODE_MONO;
804 byte = TDA9840_SET_MONO;
805 DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
806 break;
807 }
808 }
809
810 if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
811 printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
812 }
813
814 return 0;
815 }
816 case VIDIOC_G_FREQUENCY:
817 {
818 struct v4l2_frequency *f = arg;
819
820 if(0 != mxb->cur_input) {
821 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
822 return -EINVAL;
823 }
824
Michael Hunold9d2599d2005-07-27 11:46:00 -0700825 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Michael Hunold9d2599d2005-07-27 11:46:00 -0700827 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 return 0;
829 }
830 case VIDIOC_S_FREQUENCY:
831 {
832 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 if (0 != f->tuner)
835 return -EINVAL;
836
837 if (V4L2_TUNER_ANALOG_TV != f->type)
838 return -EINVAL;
839
840 if(0 != mxb->cur_input) {
841 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
842 return -EINVAL;
843 }
844
Michael Hunold9d2599d2005-07-27 11:46:00 -0700845 mxb->cur_freq = *f;
846 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700849 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
852 spin_lock(&dev->slock);
853 vv->vbi_fieldcount = 0;
854 spin_unlock(&dev->slock);
855
856 return 0;
857 }
858 case MXB_S_AUDIO_CD:
859 {
860 int i = *(int*)arg;
861
862 if( i < 0 || i >= MXB_AUDIOS ) {
863 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
864 return -EINVAL;
865 }
866
867 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
868
869 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
870 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
871
872 return 0;
873 }
874 case MXB_S_AUDIO_LINE:
875 {
876 int i = *(int*)arg;
877
878 if( i < 0 || i >= MXB_AUDIOS ) {
879 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
880 return -EINVAL;
881 }
882
883 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
884 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
885 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
886
887 return 0;
888 }
889 case VIDIOC_G_AUDIO:
890 {
891 struct v4l2_audio *a = arg;
892
893 if( a->index < 0 || a->index > MXB_INPUTS ) {
894 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
895 return -EINVAL;
896 }
897
898 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
899 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
900
901 return 0;
902 }
903 case VIDIOC_S_AUDIO:
904 {
905 struct v4l2_audio *a = arg;
906 DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
907 return 0;
908 }
909 default:
910/*
911 DEB2(printk("does not handle this ioctl.\n"));
912*/
913 return -ENOIOCTLCMD;
914 }
915 return 0;
916}
917
918static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
919{
920 struct mxb* mxb = (struct mxb*)dev->ext_priv;
921 int zero = 0;
922 int one = 1;
923
924 if(V4L2_STD_PAL_I == std->id ) {
925 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
926 /* set the 7146 gpio register -- I don't know what this does exactly */
927 saa7146_write(dev, GPIO_CTRL, 0x00404050);
928 /* unset the 7111 gpio register -- I don't know what this does exactly */
929 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
930 } else {
931 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
932 /* set the 7146 gpio register -- I don't know what this does exactly */
933 saa7146_write(dev, GPIO_CTRL, 0x00404050);
934 /* set the 7111 gpio register -- I don't know what this does exactly */
935 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
936 }
937 return 0;
938}
939
940static struct saa7146_standard standard[] = {
941 {
942 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
943 .v_offset = 0x17, .v_field = 288,
944 .h_offset = 0x14, .h_pixels = 680,
945 .v_max_out = 576, .h_max_out = 768,
946 }, {
947 .name = "PAL-I", .id = V4L2_STD_PAL_I,
948 .v_offset = 0x17, .v_field = 288,
949 .h_offset = 0x14, .h_pixels = 680,
950 .v_max_out = 576, .h_max_out = 768,
951 }, {
952 .name = "NTSC", .id = V4L2_STD_NTSC,
953 .v_offset = 0x16, .v_field = 240,
954 .h_offset = 0x06, .h_pixels = 708,
955 .v_max_out = 480, .h_max_out = 640,
956 }, {
957 .name = "SECAM", .id = V4L2_STD_SECAM,
958 .v_offset = 0x14, .v_field = 288,
959 .h_offset = 0x14, .h_pixels = 720,
960 .v_max_out = 576, .h_max_out = 768,
961 }
962};
963
964static struct saa7146_pci_extension_data mxb = {
965 .ext_priv = "Multimedia eXtension Board",
966 .ext = &extension,
967};
968
969static struct pci_device_id pci_tbl[] = {
970 {
971 .vendor = PCI_VENDOR_ID_PHILIPS,
972 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
973 .subvendor = 0x0000,
974 .subdevice = 0x0000,
975 .driver_data = (unsigned long)&mxb,
976 }, {
977 .vendor = 0,
978 }
979};
980
981MODULE_DEVICE_TABLE(pci, pci_tbl);
982
983static struct saa7146_ext_vv vv_data = {
984 .inputs = MXB_INPUTS,
985 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
986 .stds = &standard[0],
987 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
988 .std_callback = &std_callback,
989 .ioctls = &ioctls[0],
990 .ioctl = mxb_ioctl,
991};
992
993static struct saa7146_extension extension = {
994 .name = MXB_IDENTIFIER,
995 .flags = SAA7146_USE_I2C_IRQ,
996
997 .pci_tbl = &pci_tbl[0],
998 .module = THIS_MODULE,
999
1000 .probe = mxb_probe,
1001 .attach = mxb_attach,
1002 .detach = mxb_detach,
1003
1004 .irq_mask = 0,
1005 .irq_func = NULL,
1006};
1007
1008static int __init mxb_init_module(void)
1009{
1010 if( 0 != saa7146_register_extension(&extension)) {
1011 DEB_S(("failed to register extension.\n"));
1012 return -ENODEV;
1013 }
1014
1015 return 0;
1016}
1017
1018static void __exit mxb_cleanup_module(void)
1019{
1020 saa7146_unregister_extension(&extension);
1021}
1022
1023module_init(mxb_init_module);
1024module_exit(mxb_cleanup_module);
1025
1026MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
1027MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
1028MODULE_LICENSE("GPL");