blob: b0aea4002d1124235922f2396553e43f0079092b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 mxb - v4l2 driver for the Multimedia eXtension Board
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03003
Michael Hunold6acaba82006-03-13 21:20:41 -08004 Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005
6 Visit http://www.mihu.de/linux/saa7146/mxb/
7 for further details about this card.
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03008
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24#define DEBUG_VARIABLE debug
25
26#include <media/saa7146_vv.h>
27#include <media/tuner.h>
28#include <linux/video_decoder.h>
Michael Krufky5e453dc2006-01-09 15:32:31 -020029#include <media/v4l2-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include "mxb.h"
32#include "tea6415c.h"
33#include "tea6420.h"
34#include "tda9840.h"
35
36#define I2C_SAA7111 0x24
37
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030038#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* global variable */
41static int mxb_num = 0;
42
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030043/* initial frequence the tuner will be tuned to.
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 in verden (lower saxony, germany) 4148 is a
45 channel called "phoenix" */
46static int freq = 4148;
47module_param(freq, int, 0644);
48MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
49
50static int debug = 0;
51module_param(debug, int, 0644);
52MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
53
54#define MXB_INPUTS 4
55enum { TUNER, AUX1, AUX3, AUX3_YC };
56
57static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030058 { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
60 { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
61 { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
62};
63
64/* this array holds the information, which port of the saa7146 each
65 input actually uses. the mxb uses port 0 for every input */
66static struct {
67 int hps_source;
68 int hps_sync;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030069} input_port_selection[MXB_INPUTS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
71 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
72 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
73 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
74};
75
76/* this array holds the information of the audio source (mxb_audios),
77 which has to be switched corresponding to the video source (mxb_channels) */
78static int video_audio_connect[MXB_INPUTS] =
79 { 0, 1, 3, 3 };
80
81/* these are the necessary input-output-pins for bringing one audio source
82(see above) to the CD-output */
83static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030084 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 {{1,1,0},{1,1,0}}, /* Tuner */
86 {{5,1,0},{6,1,0}}, /* AUX 1 */
87 {{4,1,0},{6,1,0}}, /* AUX 2 */
88 {{3,1,0},{6,1,0}}, /* AUX 3 */
89 {{1,1,0},{3,1,0}}, /* Radio */
90 {{1,1,0},{2,1,0}}, /* CD-Rom */
91 {{6,1,0},{6,1,0}} /* Mute */
92 };
93
94/* these are the necessary input-output-pins for bringing one audio source
95(see above) to the line-output */
96static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
97 {
98 {{2,3,0},{1,2,0}},
99 {{5,3,0},{6,2,0}},
100 {{4,3,0},{6,2,0}},
101 {{3,3,0},{6,2,0}},
102 {{2,3,0},{3,2,0}},
103 {{2,3,0},{2,2,0}},
104 {{6,3,0},{6,2,0}} /* Mute */
105 };
106
107#define MAXCONTROLS 1
108static struct v4l2_queryctrl mxb_controls[] = {
109 { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
110};
111
112static struct saa7146_extension_ioctls ioctls[] = {
113 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
114 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
115 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
116 { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
117 { VIDIOC_G_CTRL, SAA7146_BEFORE },
118 { VIDIOC_S_CTRL, SAA7146_BEFORE },
119 { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
120 { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
121 { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
122 { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
123 { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
124 { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300125 { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
126 { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 { 0, 0 }
128};
129
130struct mxb
131{
132 struct video_device *video_dev;
133 struct video_device *vbi_dev;
134
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300135 struct i2c_adapter i2c_adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 struct i2c_client* saa7111a;
138 struct i2c_client* tda9840;
139 struct i2c_client* tea6415c;
140 struct i2c_client* tuner;
141 struct i2c_client* tea6420_1;
142 struct i2c_client* tea6420_2;
143
144 int cur_mode; /* current audio mode (mono, stereo, ...) */
145 int cur_input; /* current input */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int cur_mute; /* current mute status */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700147 struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148};
149
150static struct saa7146_extension extension;
151
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
Panagiotis Issaris74081872006-01-11 19:40:56 -0200180 mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 if( NULL == mxb ) {
182 DEB_D(("not enough kernel memory.\n"));
183 return -ENOMEM;
184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
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 Chehab09df1c12006-03-18 08:31:34 -0300201 if( I2C_ADDR_TEA6420_1 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 mxb->tea6420_1 = client;
Mauro Carvalho Chehab09df1c12006-03-18 08:31:34 -0300203 if( I2C_ADDR_TEA6420_2 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 mxb->tea6420_2 = client;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300205 if( I2C_TEA6415C_2 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 mxb->tea6415c = client;
Mauro Carvalho Chehab09df1c12006-03-18 08:31:34 -0300207 if( I2C_ADDR_TDA9840 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 mxb->tda9840 = client;
209 if( I2C_SAA7111 == client->addr )
210 mxb->saa7111a = client;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300211 if( 0x60 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 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 Chehaba8733ca2006-03-17 10:37:02 -0300225 /* all devices are present, probe was successful */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226
227 /* we store the pointer in our private data field */
228 dev->ext_priv = mxb;
229
230 return 0;
231}
232
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300233/* some init data for the saa7740, the so-called 'sound arena module'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 there are no specs available, so we simply use some init values */
235static 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
289static 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. */
324static 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 Chehab85369df2005-07-12 13:58:59 -0700329 struct tuner_setup tun_setup;
Michael Hunold6acaba82006-03-13 21:20:41 -0800330 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 int i = 0, err = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300333 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
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
Michael Hunold6acaba82006-03-13 21:20:41 -0800365 /* set a default video standard */
366 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
367
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 /* 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 Chehaba8733ca2006-03-17 10:37:02 -0300383
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 /* the rest for mxb */
385 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 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 Chehaba8733ca2006-03-17 10:37:02 -0300390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* check if the saa7740 (aka 'sound arena module') is present
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300392 on the mxb. if so, we must initialize it. due to lack of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 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 Chehaba8733ca2006-03-17 10:37:02 -0300412 msg.len = mxb_saa7740_init[i].length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 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 Chehaba8733ca2006-03-17 10:37:02 -0300421err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 /* 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 Chehaba8733ca2006-03-17 10:37:02 -0300426
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 /* 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 Chehaba8733ca2006-03-17 10:37:02 -0300434 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 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/*
444void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
445{
446 struct mxb* mxb = (struct mxb*)dev->ext_priv;
447}
448*/
449
450static struct saa7146_ext_vv vv_data;
451
452/* this function only gets called when the probing was successful */
453static 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 Chehaba8733ca2006-03-17 10:37:02 -0300456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 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 Chehaba8733ca2006-03-17 10:37:02 -0300467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 /* 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
489static 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 Chehaba8733ca2006-03-17 10:37:02 -0300516static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 struct saa7146_dev *dev = fh->dev;
519 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300520 struct saa7146_vv *vv = dev->vv_data;
521
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 switch(cmd) {
523 case VIDIOC_ENUMINPUT:
524 {
525 struct v4l2_input *i = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 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 Chehaba8733ca2006-03-17 10:37:02 -0300562
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if( i < 0 ) {
564 return -EAGAIN;
565 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300566
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 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 Chehaba8733ca2006-03-17 10:37:02 -0300574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 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 Chehaba8733ca2006-03-17 10:37:02 -0300583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 for (i = MAXCONTROLS - 1; i >= 0; i--) {
585 if (mxb_controls[i].id == vc->id) {
586 break;
587 }
588 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300589
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if( i < 0 ) {
591 return -EAGAIN;
592 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 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 Chehaba8733ca2006-03-17 10:37:02 -0300617 return 0;
618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 case VIDIOC_S_INPUT:
620 {
621 int input = *(int *)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300622 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 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 Chehaba8733ca2006-03-17 10:37:02 -0300630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 /* fixme: locke das setzen des inputs mit hilfe des mutexes
Ingo Molnar3593cab2006-02-07 06:49:14 -0200632 mutex_lock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 video_mux(dev,*i);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200634 mutex_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300636
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 /* 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 Chehaba8733ca2006-03-17 10:37:02 -0300643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 /* prepare switching of tea6415c and saa7111a;
649 have a look at the 'background'-file for further informations */
650 switch( input ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 case TUNER:
653 {
654 i = 0;
655 vm.in = 3;
656 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 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 Chehaba8733ca2006-03-17 10:37:02 -0300665 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 }
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 Chehaba8733ca2006-03-17 10:37:02 -0300706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 /* 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 Chehaba8733ca2006-03-17 10:37:02 -0300710 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
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 Chehaba8733ca2006-03-17 10:37:02 -0300741 t->afc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
744 t->audmode = mxb->cur_mode;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 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 Chehaba8733ca2006-03-17 10:37:02 -0300780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 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 Chehaba8733ca2006-03-17 10:37:02 -0300785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 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 Verkuil301e22d2006-03-18 17:15:00 -0300793 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 Torvalds1da177e2005-04-16 15:20:36 -0700799 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 Chehaba8733ca2006-03-17 10:37:02 -0300822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 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 Hunold9d2599d2005-07-27 11:46:00 -0700834 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Michael Hunold9d2599d2005-07-27 11:46:00 -0700836 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 return 0;
838 }
839 case VIDIOC_S_FREQUENCY:
840 {
841 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 if (0 != f->tuner)
844 return -EINVAL;
845
846 if (V4L2_TUNER_ANALOG_TV != f->type)
847 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 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 Hunold9d2599d2005-07-27 11:46:00 -0700854 mxb->cur_freq = *f;
855 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300857 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700858 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
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 Chehaba8733ca2006-03-17 10:37:02 -0300870
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 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 Chehaba8733ca2006-03-17 10:37:02 -0300875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 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 Chehaba8733ca2006-03-17 10:37:02 -0300886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 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 Chehaba8733ca2006-03-17 10:37:02 -0300891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 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 Chehaba8733ca2006-03-17 10:37:02 -0300903 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 return -EINVAL;
905 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300906
907 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 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 Chehaba8733ca2006-03-17 10:37:02 -0300917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 default:
919/*
920 DEB2(printk("does not handle this ioctl.\n"));
921*/
922 return -ENOIOCTLCMD;
923 }
924 return 0;
925}
926
927static 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 Hunold6acaba82006-03-13 21:20:41 -0800934 v4l2_std_id std = V4L2_STD_PAL_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 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 Chehaba8733ca2006-03-17 10:37:02 -0300937 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /* 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 Hunold6acaba82006-03-13 21:20:41 -0800940 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800942 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 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 Chehaba8733ca2006-03-17 10:37:02 -0300945 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 /* 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 Hunold6acaba82006-03-13 21:20:41 -0800948 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 }
950 return 0;
951}
952
953static 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
977static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300978 .ext_priv = "Multimedia eXtension Board",
979 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980};
981
982static 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
994MODULE_DEVICE_TABLE(pci, pci_tbl);
995
996static 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 Chehaba8733ca2006-03-17 10:37:02 -03001001 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 .ioctls = &ioctls[0],
1003 .ioctl = mxb_ioctl,
1004};
1005
1006static struct saa7146_extension extension = {
1007 .name = MXB_IDENTIFIER,
1008 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 .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 Chehaba8733ca2006-03-17 10:37:02 -03001019};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021static 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 Chehaba8733ca2006-03-17 10:37:02 -03001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return 0;
1029}
1030
1031static void __exit mxb_cleanup_module(void)
1032{
1033 saa7146_unregister_extension(&extension);
1034}
1035
1036module_init(mxb_init_module);
1037module_exit(mxb_cleanup_module);
1038
1039MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
1040MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
1041MODULE_LICENSE("GPL");