mxb.c 26.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
    mxb - v4l2 driver for the Multimedia eXtension Board
3

4
    Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
L
Linus Torvalds 已提交
5 6 7

    Visit http://www.mihu.de/linux/saa7146/mxb/
    for further details about this card.
8

L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define DEBUG_VARIABLE debug

#include <media/saa7146_vv.h>
#include <media/tuner.h>
#include <linux/video_decoder.h>
29
#include <media/v4l2-common.h>
30
#include <media/saa7115.h>
L
Linus Torvalds 已提交
31 32 33 34 35 36 37 38

#include "mxb.h"
#include "tea6415c.h"
#include "tea6420.h"
#include "tda9840.h"

#define I2C_SAA7111 0x24

39
#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
L
Linus Torvalds 已提交
40 41

/* global variable */
42
static int mxb_num;
L
Linus Torvalds 已提交
43

44
/* initial frequence the tuner will be tuned to.
L
Linus Torvalds 已提交
45 46 47 48 49 50
   in verden (lower saxony, germany) 4148 is a
   channel called "phoenix" */
static int freq = 4148;
module_param(freq, int, 0644);
MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");

51
static int debug;
L
Linus Torvalds 已提交
52 53 54 55 56 57 58
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");

#define MXB_INPUTS 4
enum { TUNER, AUX1, AUX3, AUX3_YC };

static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
59
	{ TUNER,	"Tuner",		V4L2_INPUT_TYPE_TUNER,	1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
L
Linus Torvalds 已提交
60 61 62 63 64 65 66 67 68 69
	{ AUX1,		"AUX1",			V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
	{ AUX3,		"AUX3 Composite",	V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
	{ AUX3_YC,	"AUX3 S-Video",		V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
};

/* this array holds the information, which port of the saa7146 each
   input actually uses. the mxb uses port 0 for every input */
static struct {
	int hps_source;
	int hps_sync;
70
} input_port_selection[MXB_INPUTS] = {
L
Linus Torvalds 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84
	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
	{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
};

/* this array holds the information of the audio source (mxb_audios),
   which has to be switched corresponding to the video source (mxb_channels) */
static int video_audio_connect[MXB_INPUTS] =
	{ 0, 1, 3, 3 };

/* these are the necessary input-output-pins for bringing one audio source
(see above) to the CD-output */
static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
85
		{
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
		{{1,1,0},{1,1,0}},	/* Tuner */
		{{5,1,0},{6,1,0}},	/* AUX 1 */
		{{4,1,0},{6,1,0}},	/* AUX 2 */
		{{3,1,0},{6,1,0}},	/* AUX 3 */
		{{1,1,0},{3,1,0}},	/* Radio */
		{{1,1,0},{2,1,0}},	/* CD-Rom */
		{{6,1,0},{6,1,0}}	/* Mute */
		};

/* these are the necessary input-output-pins for bringing one audio source
(see above) to the line-output */
static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
		{
		{{2,3,0},{1,2,0}},
		{{5,3,0},{6,2,0}},
		{{4,3,0},{6,2,0}},
		{{3,3,0},{6,2,0}},
		{{2,3,0},{3,2,0}},
		{{2,3,0},{2,2,0}},
		{{6,3,0},{6,2,0}}	/* Mute */
		};

#define MAXCONTROLS	1
static struct v4l2_queryctrl mxb_controls[] = {
	{ V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
};

static struct saa7146_extension_ioctls ioctls[] = {
	{ VIDIOC_ENUMINPUT, 	SAA7146_EXCLUSIVE },
	{ VIDIOC_G_INPUT,	SAA7146_EXCLUSIVE },
	{ VIDIOC_S_INPUT,	SAA7146_EXCLUSIVE },
	{ VIDIOC_QUERYCTRL, 	SAA7146_BEFORE },
	{ VIDIOC_G_CTRL,	SAA7146_BEFORE },
	{ VIDIOC_S_CTRL,	SAA7146_BEFORE },
	{ VIDIOC_G_TUNER, 	SAA7146_EXCLUSIVE },
	{ VIDIOC_S_TUNER, 	SAA7146_EXCLUSIVE },
	{ VIDIOC_G_FREQUENCY,	SAA7146_EXCLUSIVE },
	{ VIDIOC_S_FREQUENCY, 	SAA7146_EXCLUSIVE },
	{ VIDIOC_G_AUDIO, 	SAA7146_EXCLUSIVE },
	{ VIDIOC_S_AUDIO, 	SAA7146_EXCLUSIVE },
126 127
	{ VIDIOC_DBG_G_REGISTER, 	SAA7146_EXCLUSIVE },
	{ VIDIOC_DBG_S_REGISTER, 	SAA7146_EXCLUSIVE },
128 129
	{ MXB_S_AUDIO_CD, 	SAA7146_EXCLUSIVE },	/* custom control */
	{ MXB_S_AUDIO_LINE, 	SAA7146_EXCLUSIVE },	/* custom control */
L
Linus Torvalds 已提交
130 131 132 133 134 135 136 137
	{ 0,			0 }
};

struct mxb
{
	struct video_device	*video_dev;
	struct video_device	*vbi_dev;

138
	struct i2c_adapter	i2c_adapter;
L
Linus Torvalds 已提交
139

140 141 142 143 144 145
	struct i2c_client	*saa7111a;
	struct i2c_client	*tda9840;
	struct i2c_client	*tea6415c;
	struct i2c_client	*tuner;
	struct i2c_client	*tea6420_1;
	struct i2c_client	*tea6420_2;
L
Linus Torvalds 已提交
146 147 148 149

	int	cur_mode;	/* current audio mode (mono, stereo, ...) */
	int	cur_input;	/* current input */
	int	cur_mute;	/* current mute status */
150
	struct v4l2_frequency	cur_freq;	/* current frequency the tuner is tuned to */
L
Linus Torvalds 已提交
151 152 153 154
};

static struct saa7146_extension extension;

155 156
static int mxb_check_clients(struct device *dev, void *data)
{
157
	struct mxb *mxb = data;
158 159
	struct i2c_client *client = i2c_verify_client(dev);

160
	if (!client)
161 162
		return 0;

163
	if (I2C_ADDR_TEA6420_1 == client->addr)
164
		mxb->tea6420_1 = client;
165
	if (I2C_ADDR_TEA6420_2 == client->addr)
166
		mxb->tea6420_2 = client;
167
	if (I2C_TEA6415C_2 == client->addr)
168
		mxb->tea6415c = client;
169
	if (I2C_ADDR_TDA9840 == client->addr)
170
		mxb->tda9840 = client;
171
	if (I2C_SAA7111 == client->addr)
172
		mxb->saa7111a = client;
173
	if (0x60 == client->addr)
174 175 176 177 178
		mxb->tuner = client;

	return 0;
}

L
Linus Torvalds 已提交
179 180 181 182 183
static int mxb_probe(struct saa7146_dev* dev)
{
	struct mxb* mxb = NULL;
	int result;

184 185
	result = request_module("saa7115");
	if (result < 0) {
L
Linus Torvalds 已提交
186 187 188
		printk("mxb: saa7111 i2c module not available.\n");
		return -ENODEV;
	}
189 190
	result = request_module("tea6420");
	if (result < 0) {
L
Linus Torvalds 已提交
191 192 193
		printk("mxb: tea6420 i2c module not available.\n");
		return -ENODEV;
	}
194 195
	result = request_module("tea6415c");
	if (result < 0) {
L
Linus Torvalds 已提交
196 197 198
		printk("mxb: tea6415c i2c module not available.\n");
		return -ENODEV;
	}
199 200
	result = request_module("tda9840");
	if (result < 0) {
L
Linus Torvalds 已提交
201 202 203
		printk("mxb: tda9840 i2c module not available.\n");
		return -ENODEV;
	}
204 205
	result = request_module("tuner");
	if (result < 0) {
206 207 208
		printk("mxb: tuner i2c module not available.\n");
		return -ENODEV;
	}
L
Linus Torvalds 已提交
209

P
 
Panagiotis Issaris 已提交
210
	mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
L
Linus Torvalds 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
	if( NULL == mxb ) {
		DEB_D(("not enough kernel memory.\n"));
		return -ENOMEM;
	}

	mxb->i2c_adapter = (struct i2c_adapter) {
		.class = I2C_CLASS_TV_ANALOG,
		.name = "mxb",
	};

	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
	if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
		DEB_S(("cannot register i2c-device. skipping.\n"));
		kfree(mxb);
		return -EFAULT;
	}

	/* loop through all i2c-devices on the bus and look who is there */
229
	device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
L
Linus Torvalds 已提交
230 231

	/* check if all devices are present */
A
Al Viro 已提交
232 233
	if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
	    !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
L
Linus Torvalds 已提交
234 235 236 237 238 239
		printk("mxb: did not find all i2c devices. aborting\n");
		i2c_del_adapter(&mxb->i2c_adapter);
		kfree(mxb);
		return -ENODEV;
	}

240
	/* all devices are present, probe was successful */
L
Linus Torvalds 已提交
241 242 243 244 245 246 247

	/* we store the pointer in our private data field */
	dev->ext_priv = mxb;

	return 0;
}

248
/* some init data for the saa7740, the so-called 'sound arena module'.
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
   there are no specs available, so we simply use some init values */
static struct {
	int	length;
	char	data[9];
} mxb_saa7740_init[] = {
	{ 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
	{ 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
	{ 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
	{ 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
	{ 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
	{ 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
	{ 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
	{ 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
	{ 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
	{ 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
	{ 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
	{ 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
	{ 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
	{ 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
	{ 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
	{ 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
	{ 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
	{ 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
	{ 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
	{ 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
	{ 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
	{ 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
	{ 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
	{ 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
	{ 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
	{ 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
	{ 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
	{ 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
	{ 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
	{ 3, { 0x48, 0x00, 0x01 } },
	{ 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
	{ 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
	{ 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
	{ 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
	{ 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
	{ 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
	{ 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
	{ 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
	{ 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
	{ 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
	{ 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
	{ 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
	{ 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
	{ 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
	{ 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
	{ 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
	{ 3, { 0x80, 0xb3, 0x0a } },
301
	{-1, { 0 } }
L
Linus Torvalds 已提交
302 303 304 305 306 307 308 309 310 311
};

/* bring hardware to a sane state. this has to be done, just in case someone
   wants to capture from this device before it has been properly initialized.
   the capture engine would badly fail, because no valid signal arrives on the
   saa7146, thus leading to timeouts and stuff. */
static int mxb_init_done(struct saa7146_dev* dev)
{
	struct mxb* mxb = (struct mxb*)dev->ext_priv;
	struct i2c_msg msg;
312
	struct tuner_setup tun_setup;
313
	v4l2_std_id std = V4L2_STD_PAL_BG;
314
	struct v4l2_routing route;
L
Linus Torvalds 已提交
315 316

	int i = 0, err = 0;
317
	struct tea6415c_multiplex vm;
L
Linus Torvalds 已提交
318 319

	/* select video mode in saa7111a */
320
	mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
L
Linus Torvalds 已提交
321 322 323

	/* select tuner-output on saa7111a */
	i = 0;
324 325 326
	route.input = SAA7115_COMPOSITE0;
	route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
	mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
L
Linus Torvalds 已提交
327 328

	/* select a tuner type */
329 330
	tun_setup.mode_mask = T_ANALOG_TV;
	tun_setup.addr = ADDR_UNSET;
331
	tun_setup.type = TUNER_PHILIPS_PAL;
332
	mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
333 334 335 336 337 338 339
	/* tune in some frequency on tuner */
	mxb->cur_freq.tuner = 0;
	mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
	mxb->cur_freq.frequency = freq;
	mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
					&mxb->cur_freq);

340 341 342
	/* set a default video standard */
	mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);

L
Linus Torvalds 已提交
343
	/* mute audio on tea6420s */
344 345 346 347
	mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
	mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
	mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
	mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
L
Linus Torvalds 已提交
348 349 350 351

	/* switch to tuner-channel on tea6415c*/
	vm.out = 17;
	vm.in  = 3;
352
	mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
L
Linus Torvalds 已提交
353 354 355 356

	/* select tuner-output on multicable on tea6415c*/
	vm.in  = 3;
	vm.out = 13;
357
	mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
358

L
Linus Torvalds 已提交
359 360 361 362 363
	/* the rest for mxb */
	mxb->cur_input = 0;
	mxb->cur_mute = 1;

	mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
364

L
Linus Torvalds 已提交
365
	/* check if the saa7740 (aka 'sound arena module') is present
366
	   on the mxb. if so, we must initialize it. due to lack of
L
Linus Torvalds 已提交
367 368 369 370 371 372 373
	   informations about the saa7740, the values were reverse
	   engineered. */
	msg.addr = 0x1b;
	msg.flags = 0;
	msg.len = mxb_saa7740_init[0].length;
	msg.buf = &mxb_saa7740_init[0].data[0];

374 375
	err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
	if (err == 1) {
L
Linus Torvalds 已提交
376 377 378 379 380 381
		/* the sound arena module is a pos, that's probably the reason
		   philips refuses to hand out a datasheet for the saa7740...
		   it seems to screw up the i2c bus, so we disable fast irq
		   based i2c transactions here and rely on the slow and safe
		   polling method ... */
		extension.flags &= ~SAA7146_USE_I2C_IRQ;
382 383
		for (i = 1; ; i++) {
			if (-1 == mxb_saa7740_init[i].length)
L
Linus Torvalds 已提交
384 385
				break;

386
			msg.len = mxb_saa7740_init[i].length;
L
Linus Torvalds 已提交
387
			msg.buf = &mxb_saa7740_init[i].data[0];
388 389
			err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
			if (err != 1) {
L
Linus Torvalds 已提交
390 391 392 393 394 395
				DEB_D(("failed to initialize 'sound arena module'.\n"));
				goto err;
			}
		}
		INFO(("'sound arena module' detected.\n"));
	}
396
err:
L
Linus Torvalds 已提交
397 398 399 400
	/* the rest for saa7146: you should definitely set some basic values
	   for the input-port handling of the saa7146. */

	/* ext->saa has been filled by the core driver */
401

L
Linus Torvalds 已提交
402
	/* some stuff is done via variables */
403 404
	saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
			input_port_selection[mxb->cur_input].hps_sync);
L
Linus Torvalds 已提交
405 406 407 408 409

	/* some stuff is done via direct write to the registers */

	/* this is ugly, but because of the fact that this is completely
	   hardware dependend, it should be done directly... */
410
	saa7146_write(dev, DD1_STREAM_B,	0x00000000);
L
Linus Torvalds 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
	saa7146_write(dev, DD1_INIT,		0x02000200);
	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));

	return 0;
}

/* interrupt-handler. this gets called when irq_mask is != 0.
   it must clear the interrupt-bits in irq_mask it has handled */
/*
void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
{
	struct mxb* mxb = (struct mxb*)dev->ext_priv;
}
*/

static struct saa7146_ext_vv vv_data;

/* this function only gets called when the probing was successful */
429
static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
L
Linus Torvalds 已提交
430
{
431
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
432

433
	DEB_EE(("dev:%p\n", dev));
L
Linus Torvalds 已提交
434 435 436 437

	/* checking for i2c-devices can be omitted here, because we
	   already did this in "mxb_vl42_probe" */

438 439
	saa7146_vv_init(dev, &vv_data);
	if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
L
Linus Torvalds 已提交
440 441 442
		ERR(("cannot register capture v4l2 device. skipping.\n"));
		return -1;
	}
443

L
Linus Torvalds 已提交
444
	/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
445 446
	if (MXB_BOARD_CAN_DO_VBI(dev)) {
		if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
L
Linus Torvalds 已提交
447 448 449 450 451 452 453 454 455 456 457
			ERR(("cannot register vbi v4l2 device. skipping.\n"));
		}
	}

	i2c_use_client(mxb->tea6420_1);
	i2c_use_client(mxb->tea6420_2);
	i2c_use_client(mxb->tea6415c);
	i2c_use_client(mxb->tda9840);
	i2c_use_client(mxb->saa7111a);
	i2c_use_client(mxb->tuner);

458
	printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
L
Linus Torvalds 已提交
459 460 461 462 463 464

	mxb_num++;
	mxb_init_done(dev);
	return 0;
}

465
static int mxb_detach(struct saa7146_dev *dev)
L
Linus Torvalds 已提交
466
{
467
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
L
Linus Torvalds 已提交
468

469
	DEB_EE(("dev:%p\n", dev));
L
Linus Torvalds 已提交
470 471 472 473 474 475 476 477 478

	i2c_release_client(mxb->tea6420_1);
	i2c_release_client(mxb->tea6420_2);
	i2c_release_client(mxb->tea6415c);
	i2c_release_client(mxb->tda9840);
	i2c_release_client(mxb->saa7111a);
	i2c_release_client(mxb->tuner);

	saa7146_unregister_device(&mxb->video_dev,dev);
479 480
	if (MXB_BOARD_CAN_DO_VBI(dev))
		saa7146_unregister_device(&mxb->vbi_dev, dev);
L
Linus Torvalds 已提交
481 482 483 484 485 486 487 488 489 490
	saa7146_vv_release(dev);

	mxb_num--;

	i2c_del_adapter(&mxb->i2c_adapter);
	kfree(mxb);

	return 0;
}

491
static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
L
Linus Torvalds 已提交
492 493
{
	struct saa7146_dev *dev = fh->dev;
494
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
495 496
	struct saa7146_vv *vv = dev->vv_data;

L
Linus Torvalds 已提交
497 498 499 500
	switch(cmd) {
	case VIDIOC_ENUMINPUT:
	{
		struct v4l2_input *i = arg;
501

L
Linus Torvalds 已提交
502
		DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
503
		if (i->index < 0 || i->index >= MXB_INPUTS)
L
Linus Torvalds 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
			return -EINVAL;
		memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
		return 0;
	}
	/* the saa7146 provides some controls (brightness, contrast, saturation)
	   which gets registered *after* this function. because of this we have
	   to return with a value != 0 even if the function succeded.. */
	case VIDIOC_QUERYCTRL:
	{
		struct v4l2_queryctrl *qc = arg;
		int i;

		for (i = MAXCONTROLS - 1; i >= 0; i--) {
			if (mxb_controls[i].id == qc->id) {
				*qc = mxb_controls[i];
519
				DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
L
Linus Torvalds 已提交
520 521 522 523 524 525 526 527 528 529 530
				return 0;
			}
		}
		return -EAGAIN;
	}
	case VIDIOC_G_CTRL:
	{
		struct v4l2_control *vc = arg;
		int i;

		for (i = MAXCONTROLS - 1; i >= 0; i--) {
531
			if (mxb_controls[i].id == vc->id)
L
Linus Torvalds 已提交
532 533
				break;
		}
534

535
		if (i < 0)
L
Linus Torvalds 已提交
536
			return -EAGAIN;
537

538 539 540 541
		if (vc->id == V4L2_CID_AUDIO_MUTE) {
			vc->value = mxb->cur_mute;
			DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
			return 0;
L
Linus Torvalds 已提交
542
		}
543

544
		DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
L
Linus Torvalds 已提交
545 546 547 548 549
		return 0;
	}

	case VIDIOC_S_CTRL:
	{
550
		struct v4l2_control *vc = arg;
L
Linus Torvalds 已提交
551
		int i = 0;
552

L
Linus Torvalds 已提交
553
		for (i = MAXCONTROLS - 1; i >= 0; i--) {
554
			if (mxb_controls[i].id == vc->id)
L
Linus Torvalds 已提交
555 556
				break;
		}
557

558
		if (i < 0)
L
Linus Torvalds 已提交
559
			return -EAGAIN;
560

561 562 563 564 565 566 567 568 569 570 571 572 573
		if (vc->id == V4L2_CID_AUDIO_MUTE) {
			mxb->cur_mute = vc->value;
			if (!vc->value) {
				/* switch the audio-source */
				mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
						&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
				mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
						&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
			} else {
				mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
						&TEA6420_line[6][0]);
				mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
						&TEA6420_line[6][1]);
L
Linus Torvalds 已提交
574
			}
575
			DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
L
Linus Torvalds 已提交
576 577 578 579 580 581 582 583
		}
		return 0;
	}
	case VIDIOC_G_INPUT:
	{
		int *input = (int *)arg;
		*input = mxb->cur_input;

584
		DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
585 586
		return 0;
	}
L
Linus Torvalds 已提交
587 588 589
	case VIDIOC_S_INPUT:
	{
		int input = *(int *)arg;
590 591
		struct tea6415c_multiplex vm;
		struct v4l2_routing route;
L
Linus Torvalds 已提交
592 593
		int i = 0;

594
		DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
L
Linus Torvalds 已提交
595

596
		if (input < 0 || input >= MXB_INPUTS)
L
Linus Torvalds 已提交
597
			return -EINVAL;
598

L
Linus Torvalds 已提交
599
		mxb->cur_input = input;
600

601 602
		saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
				input_port_selection[input].hps_sync);
603

L
Linus Torvalds 已提交
604 605
		/* prepare switching of tea6415c and saa7111a;
		   have a look at the 'background'-file for further informations  */
606 607 608 609 610 611 612 613 614
		switch (input) {
		case TUNER:
			i = SAA7115_COMPOSITE0;
			vm.in  = 3;
			vm.out = 17;

			if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
				printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
				return -EFAULT;
L
Linus Torvalds 已提交
615
			}
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
			/* connect tuner-output always to multicable */
			vm.in  = 3;
			vm.out = 13;
			break;
		case AUX3_YC:
			/* nothing to be done here. aux3_yc is
			   directly connected to the saa711a */
			i = SAA7115_SVIDEO1;
			break;
		case AUX3:
			/* nothing to be done here. aux3 is
			   directly connected to the saa711a */
			i = SAA7115_COMPOSITE1;
			break;
		case AUX1:
			i = SAA7115_COMPOSITE0;
			vm.in  = 1;
			vm.out = 17;
			break;
L
Linus Torvalds 已提交
635 636 637
		}

		/* switch video in tea6415c only if necessary */
638 639 640 641 642 643
		switch (input) {
		case TUNER:
		case AUX1:
			if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
				printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
				return -EFAULT;
L
Linus Torvalds 已提交
644
			}
645 646 647
			break;
		default:
			break;
L
Linus Torvalds 已提交
648
		}
649

L
Linus Torvalds 已提交
650
		/* switch video in saa7111a */
651 652 653
		route.input = i;
		route.output = 0;
		if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
L
Linus Torvalds 已提交
654 655 656 657
			printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");

		/* switch the audio-source only if necessary */
		if( 0 == mxb->cur_mute ) {
658 659 660 661
			mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
					&TEA6420_line[video_audio_connect[input]][0]);
			mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
				       &TEA6420_line[video_audio_connect[input]][1]);
L
Linus Torvalds 已提交
662 663 664 665 666 667 668 669
		}

		return 0;
	}
	case VIDIOC_G_TUNER:
	{
		struct v4l2_tuner *t = arg;

670
		if (t->index) {
L
Linus Torvalds 已提交
671 672 673 674 675 676
			DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
			return -EINVAL;
		}

		DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));

677 678
		memset(t, 0, sizeof(*t));
		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
L
Linus Torvalds 已提交
679

680
		strlcpy(t->name, "TV Tuner", sizeof(t->name));
L
Linus Torvalds 已提交
681
		t->type = V4L2_TUNER_ANALOG_TV;
682 683
		t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
L
Linus Torvalds 已提交
684 685 686 687 688 689
		t->audmode = mxb->cur_mode;
		return 0;
	}
	case VIDIOC_S_TUNER:
	{
		struct v4l2_tuner *t = arg;
690

691
		if (t->index) {
L
Linus Torvalds 已提交
692 693 694
			DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
			return -EINVAL;
		}
695

696 697
		mxb->cur_mode = t->audmode;
		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
L
Linus Torvalds 已提交
698 699 700 701 702 703
		return 0;
	}
	case VIDIOC_G_FREQUENCY:
	{
		struct v4l2_frequency *f = arg;

704 705 706
		if (mxb->cur_input) {
			DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
						mxb->cur_input));
L
Linus Torvalds 已提交
707 708 709
			return -EINVAL;
		}

710
		*f = mxb->cur_freq;
L
Linus Torvalds 已提交
711

712
		DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
L
Linus Torvalds 已提交
713 714 715 716 717 718
		return 0;
	}
	case VIDIOC_S_FREQUENCY:
	{
		struct v4l2_frequency *f = arg;

719
		if (f->tuner)
L
Linus Torvalds 已提交
720 721 722 723
			return -EINVAL;

		if (V4L2_TUNER_ANALOG_TV != f->type)
			return -EINVAL;
724

725 726
		if (mxb->cur_input) {
			DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
L
Linus Torvalds 已提交
727 728 729
			return -EINVAL;
		}

730 731
		mxb->cur_freq = *f;
		DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
L
Linus Torvalds 已提交
732

733
		/* tune in desired frequency */
734
		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
L
Linus Torvalds 已提交
735 736 737 738 739 740 741 742 743 744 745

		/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
		spin_lock(&dev->slock);
		vv->vbi_fieldcount = 0;
		spin_unlock(&dev->slock);

		return 0;
	}
	case MXB_S_AUDIO_CD:
	{
		int i = *(int*)arg;
746

747
		if (i < 0 || i >= MXB_AUDIOS) {
L
Linus Torvalds 已提交
748 749 750
			DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
			return -EINVAL;
		}
751

L
Linus Torvalds 已提交
752 753 754 755 756 757 758 759 760 761
		DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));

		mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
		mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);

		return 0;
	}
	case MXB_S_AUDIO_LINE:
	{
		int i = *(int*)arg;
762

763
		if (i < 0 || i >= MXB_AUDIOS) {
L
Linus Torvalds 已提交
764 765 766
			DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
			return -EINVAL;
		}
767

L
Linus Torvalds 已提交
768 769 770 771 772 773 774 775 776 777
		DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
		mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
		mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);

		return 0;
	}
	case VIDIOC_G_AUDIO:
	{
		struct v4l2_audio *a = arg;

778 779
		if (a->index < 0 || a->index > MXB_INPUTS) {
			DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
L
Linus Torvalds 已提交
780 781
			return -EINVAL;
		}
782

783
		DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
L
Linus Torvalds 已提交
784
		memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
785

L
Linus Torvalds 已提交
786 787 788 789 790
		return 0;
	}
	case VIDIOC_S_AUDIO:
	{
		struct v4l2_audio *a = arg;
791 792

		DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
L
Linus Torvalds 已提交
793
		return 0;
794
	}
795
#ifdef CONFIG_VIDEO_ADV_DEBUG
796 797 798
	case VIDIOC_DBG_S_REGISTER:
	case VIDIOC_DBG_G_REGISTER:
		i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
799 800
		return 0;
#endif
L
Linus Torvalds 已提交
801 802 803 804 805 806 807 808 809
	default:
/*
		DEB2(printk("does not handle this ioctl.\n"));
*/
		return -ENOIOCTLCMD;
	}
	return 0;
}

810
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
L
Linus Torvalds 已提交
811
{
812
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
L
Linus Torvalds 已提交
813 814 815
	int zero = 0;
	int one = 1;

816
	if (V4L2_STD_PAL_I == standard->id) {
817
		v4l2_std_id std = V4L2_STD_PAL_I;
818

L
Linus Torvalds 已提交
819 820
		DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
		/* set the 7146 gpio register -- I don't know what this does exactly */
821
		saa7146_write(dev, GPIO_CTRL, 0x00404050);
L
Linus Torvalds 已提交
822
		/* unset the 7111 gpio register -- I don't know what this does exactly */
823
		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
824
		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
L
Linus Torvalds 已提交
825
	} else {
826
		v4l2_std_id std = V4L2_STD_PAL_BG;
827

L
Linus Torvalds 已提交
828 829
		DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
		/* set the 7146 gpio register -- I don't know what this does exactly */
830
		saa7146_write(dev, GPIO_CTRL, 0x00404050);
L
Linus Torvalds 已提交
831
		/* set the 7111 gpio register -- I don't know what this does exactly */
832
		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
833
		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
L
Linus Torvalds 已提交
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
	}
	return 0;
}

static struct saa7146_standard standard[] = {
	{
		.name	= "PAL-BG", 	.id	= V4L2_STD_PAL_BG,
		.v_offset	= 0x17,	.v_field 	= 288,
		.h_offset	= 0x14,	.h_pixels 	= 680,
		.v_max_out	= 576,	.h_max_out	= 768,
	}, {
		.name	= "PAL-I", 	.id	= V4L2_STD_PAL_I,
		.v_offset	= 0x17,	.v_field 	= 288,
		.h_offset	= 0x14,	.h_pixels 	= 680,
		.v_max_out	= 576,	.h_max_out	= 768,
	}, {
		.name	= "NTSC", 	.id	= V4L2_STD_NTSC,
		.v_offset	= 0x16,	.v_field 	= 240,
		.h_offset	= 0x06,	.h_pixels 	= 708,
		.v_max_out	= 480,	.h_max_out	= 640,
	}, {
		.name	= "SECAM", 	.id	= V4L2_STD_SECAM,
		.v_offset	= 0x14,	.v_field 	= 288,
		.h_offset	= 0x14,	.h_pixels 	= 720,
		.v_max_out	= 576,	.h_max_out	= 768,
	}
};

static struct saa7146_pci_extension_data mxb = {
863 864
	.ext_priv = "Multimedia eXtension Board",
	.ext = &extension,
L
Linus Torvalds 已提交
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
};

static struct pci_device_id pci_tbl[] = {
	{
		.vendor    = PCI_VENDOR_ID_PHILIPS,
		.device	   = PCI_DEVICE_ID_PHILIPS_SAA7146,
		.subvendor = 0x0000,
		.subdevice = 0x0000,
		.driver_data = (unsigned long)&mxb,
	}, {
		.vendor	= 0,
	}
};

MODULE_DEVICE_TABLE(pci, pci_tbl);

static struct saa7146_ext_vv vv_data = {
	.inputs		= MXB_INPUTS,
	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
	.stds		= &standard[0],
	.num_stds	= sizeof(standard)/sizeof(struct saa7146_standard),
886
	.std_callback	= &std_callback,
L
Linus Torvalds 已提交
887 888 889 890 891 892 893
	.ioctls		= &ioctls[0],
	.ioctl		= mxb_ioctl,
};

static struct saa7146_extension extension = {
	.name		= MXB_IDENTIFIER,
	.flags		= SAA7146_USE_I2C_IRQ,
894

L
Linus Torvalds 已提交
895 896 897 898 899 900 901 902 903
	.pci_tbl	= &pci_tbl[0],
	.module		= THIS_MODULE,

	.probe		= mxb_probe,
	.attach		= mxb_attach,
	.detach		= mxb_detach,

	.irq_mask	= 0,
	.irq_func	= NULL,
904
};
L
Linus Torvalds 已提交
905 906 907

static int __init mxb_init_module(void)
{
908
	if (saa7146_register_extension(&extension)) {
L
Linus Torvalds 已提交
909 910 911
		DEB_S(("failed to register extension.\n"));
		return -ENODEV;
	}
912

L
Linus Torvalds 已提交
913 914 915 916 917 918 919 920 921 922 923 924 925 926
	return 0;
}

static void __exit mxb_cleanup_module(void)
{
	saa7146_unregister_extension(&extension);
}

module_init(mxb_init_module);
module_exit(mxb_cleanup_module);

MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
MODULE_LICENSE("GPL");