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