blob: 8ef578caba3b982c8d63f1047b4c300ac11b45ee [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 */
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030041static int mxb_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
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
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030050static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051module_param(debug, int, 0644);
52MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
53
54#define MXB_INPUTS 4
55enum { TUNER, AUX1, AUX3, AUX3_YC };
56
57static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030058 { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
60 { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
61 { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
62};
63
64/* this array holds the information, which port of the saa7146 each
65 input actually uses. the mxb uses port 0 for every input */
66static struct {
67 int hps_source;
68 int hps_sync;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030069} input_port_selection[MXB_INPUTS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
71 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
72 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
73 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
74};
75
76/* this array holds the information of the audio source (mxb_audios),
77 which has to be switched corresponding to the video source (mxb_channels) */
78static int video_audio_connect[MXB_INPUTS] =
79 { 0, 1, 3, 3 };
80
81/* these are the necessary input-output-pins for bringing one audio source
82(see above) to the CD-output */
83static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030084 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 {{1,1,0},{1,1,0}}, /* Tuner */
86 {{5,1,0},{6,1,0}}, /* AUX 1 */
87 {{4,1,0},{6,1,0}}, /* AUX 2 */
88 {{3,1,0},{6,1,0}}, /* AUX 3 */
89 {{1,1,0},{3,1,0}}, /* Radio */
90 {{1,1,0},{2,1,0}}, /* CD-Rom */
91 {{6,1,0},{6,1,0}} /* Mute */
92 };
93
94/* these are the necessary input-output-pins for bringing one audio source
95(see above) to the line-output */
96static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
97 {
98 {{2,3,0},{1,2,0}},
99 {{5,3,0},{6,2,0}},
100 {{4,3,0},{6,2,0}},
101 {{3,3,0},{6,2,0}},
102 {{2,3,0},{3,2,0}},
103 {{2,3,0},{2,2,0}},
104 {{6,3,0},{6,2,0}} /* Mute */
105 };
106
107#define MAXCONTROLS 1
108static struct v4l2_queryctrl mxb_controls[] = {
109 { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
110};
111
112static struct saa7146_extension_ioctls ioctls[] = {
113 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
114 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
115 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
116 { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
117 { VIDIOC_G_CTRL, SAA7146_BEFORE },
118 { VIDIOC_S_CTRL, SAA7146_BEFORE },
119 { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
120 { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
121 { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
122 { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
123 { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
124 { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300125 { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
126 { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 { 0, 0 }
128};
129
130struct mxb
131{
132 struct video_device *video_dev;
133 struct video_device *vbi_dev;
134
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300135 struct i2c_adapter i2c_adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 struct i2c_client* saa7111a;
138 struct i2c_client* tda9840;
139 struct i2c_client* tea6415c;
140 struct i2c_client* tuner;
141 struct i2c_client* tea6420_1;
142 struct i2c_client* tea6420_2;
143
144 int cur_mode; /* current audio mode (mono, stereo, ...) */
145 int cur_input; /* current input */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int cur_mute; /* current mute status */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700147 struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148};
149
150static struct saa7146_extension extension;
151
Jean Delvare961f80f2008-01-27 18:14:51 +0100152static int mxb_check_clients(struct device *dev, void *data)
153{
154 struct mxb* mxb = data;
155 struct i2c_client *client = i2c_verify_client(dev);
156
157 if( !client )
158 return 0;
159
160 if( I2C_ADDR_TEA6420_1 == client->addr )
161 mxb->tea6420_1 = client;
162 if( I2C_ADDR_TEA6420_2 == client->addr )
163 mxb->tea6420_2 = client;
164 if( I2C_TEA6415C_2 == client->addr )
165 mxb->tea6415c = client;
166 if( I2C_ADDR_TDA9840 == client->addr )
167 mxb->tda9840 = client;
168 if( I2C_SAA7111 == client->addr )
169 mxb->saa7111a = client;
170 if( 0x60 == client->addr )
171 mxb->tuner = client;
172
173 return 0;
174}
175
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176static int mxb_probe(struct saa7146_dev* dev)
177{
178 struct mxb* mxb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 int result;
180
181 if ((result = request_module("saa7111")) < 0) {
182 printk("mxb: saa7111 i2c module not available.\n");
183 return -ENODEV;
184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 if ((result = request_module("tea6420")) < 0) {
186 printk("mxb: tea6420 i2c module not available.\n");
187 return -ENODEV;
188 }
189 if ((result = request_module("tea6415c")) < 0) {
190 printk("mxb: tea6415c i2c module not available.\n");
191 return -ENODEV;
192 }
193 if ((result = request_module("tda9840")) < 0) {
194 printk("mxb: tda9840 i2c module not available.\n");
195 return -ENODEV;
196 }
Michael Hunolda08cc442006-11-28 08:13:58 -0300197 if ((result = request_module("tuner")) < 0) {
198 printk("mxb: tuner i2c module not available.\n");
199 return -ENODEV;
200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Panagiotis Issaris74081872006-01-11 19:40:56 -0200202 mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 if( NULL == mxb ) {
204 DEB_D(("not enough kernel memory.\n"));
205 return -ENOMEM;
206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 mxb->i2c_adapter = (struct i2c_adapter) {
209 .class = I2C_CLASS_TV_ANALOG,
210 .name = "mxb",
211 };
212
213 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
214 if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
215 DEB_S(("cannot register i2c-device. skipping.\n"));
216 kfree(mxb);
217 return -EFAULT;
218 }
219
220 /* loop through all i2c-devices on the bus and look who is there */
Jean Delvare961f80f2008-01-27 18:14:51 +0100221 device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
223 /* check if all devices are present */
Al Viro5fa12472008-03-29 03:07:38 +0000224 if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
225 !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 printk("mxb: did not find all i2c devices. aborting\n");
227 i2c_del_adapter(&mxb->i2c_adapter);
228 kfree(mxb);
229 return -ENODEV;
230 }
231
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300232 /* all devices are present, probe was successful */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 /* we store the pointer in our private data field */
235 dev->ext_priv = mxb;
236
237 return 0;
238}
239
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300240/* some init data for the saa7740, the so-called 'sound arena module'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 there are no specs available, so we simply use some init values */
242static struct {
243 int length;
244 char data[9];
245} mxb_saa7740_init[] = {
246 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
247 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
248 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
249 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
250 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
251 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
252 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
253 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
254 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
255 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
256 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
257 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
258 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
259 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
260 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
261 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
262 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
263 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
264 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
265 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
266 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
267 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
268 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
269 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
270 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
271 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
272 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
273 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
274 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
275 { 3, { 0x48, 0x00, 0x01 } },
276 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
277 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
278 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
279 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
280 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
281 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
282 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
283 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
284 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
285 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
286 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
287 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
288 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
289 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
290 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
291 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
292 { 3, { 0x80, 0xb3, 0x0a } },
293 {-1, { 0} }
294};
295
296static const unsigned char mxb_saa7111_init[] = {
297 0x00, 0x00, /* 00 - ID byte */
298 0x01, 0x00, /* 01 - reserved */
299
300 /*front end */
301 0x02, 0xd8, /* 02 - FUSE=x, GUDL=x, MODE=x */
302 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
303 0x04, 0x00, /* 04 - GAI1=256 */
304 0x05, 0x00, /* 05 - GAI2=256 */
305
306 /* decoder */
307 0x06, 0xf0, /* 06 - HSB at xx(50Hz) / xx(60Hz) pixels after end of last line */
308 0x07, 0x30, /* 07 - HSS at xx(50Hz) / xx(60Hz) pixels after end of last line */
309 0x08, 0xa8, /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
310 0x09, 0x02, /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
311 0x0a, 0x80, /* 0a - BRIG=128 */
312 0x0b, 0x47, /* 0b - CONT=1.109 */
313 0x0c, 0x40, /* 0c - SATN=1.0 */
314 0x0d, 0x00, /* 0d - HUE=0 */
315 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
316 0x0f, 0x00, /* 0f - reserved */
317 0x10, 0xd0, /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
318 0x11, 0x8c, /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
319 0x12, 0x80, /* 12 - xx output control 2 */
320 0x13, 0x30, /* 13 - xx output control 3 */
321 0x14, 0x00, /* 14 - reserved */
322 0x15, 0x15, /* 15 - VBI */
323 0x16, 0x04, /* 16 - VBI */
324 0x17, 0x00, /* 17 - VBI */
325};
326
327/* bring hardware to a sane state. this has to be done, just in case someone
328 wants to capture from this device before it has been properly initialized.
329 the capture engine would badly fail, because no valid signal arrives on the
330 saa7146, thus leading to timeouts and stuff. */
331static int mxb_init_done(struct saa7146_dev* dev)
332{
333 struct mxb* mxb = (struct mxb*)dev->ext_priv;
334 struct video_decoder_init init;
335 struct i2c_msg msg;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700336 struct tuner_setup tun_setup;
Michael Hunold6acaba82006-03-13 21:20:41 -0800337 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
339 int i = 0, err = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300340 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 /* select video mode in saa7111a */
343 i = VIDEO_MODE_PAL;
344 /* fixme: currently pointless: gets overwritten by configuration below */
345 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
346
347 /* write configuration to saa7111a */
348 init.data = mxb_saa7111_init;
349 init.len = sizeof(mxb_saa7111_init);
350 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
351
352 /* select tuner-output on saa7111a */
353 i = 0;
354 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
355
356 /* enable vbi bypass */
357 i = 1;
358 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
359
360 /* select a tuner type */
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700361 tun_setup.mode_mask = T_ANALOG_TV;
362 tun_setup.addr = ADDR_UNSET;
Michael Hunold9d2599d2005-07-27 11:46:00 -0700363 tun_setup.type = TUNER_PHILIPS_PAL;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700364 mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
Michael Hunold9d2599d2005-07-27 11:46:00 -0700365 /* tune in some frequency on tuner */
366 mxb->cur_freq.tuner = 0;
367 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
368 mxb->cur_freq.frequency = freq;
369 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
370 &mxb->cur_freq);
371
Michael Hunold6acaba82006-03-13 21:20:41 -0800372 /* set a default video standard */
373 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 /* mute audio on tea6420s */
376 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
377 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
378 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
379 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
380
381 /* switch to tuner-channel on tea6415c*/
382 vm.out = 17;
383 vm.in = 3;
384 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
385
386 /* select tuner-output on multicable on tea6415c*/
387 vm.in = 3;
388 vm.out = 13;
389 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* the rest for mxb */
392 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 mxb->cur_mute = 1;
394
395 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
396 mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300397
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 /* check if the saa7740 (aka 'sound arena module') is present
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300399 on the mxb. if so, we must initialize it. due to lack of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 informations about the saa7740, the values were reverse
401 engineered. */
402 msg.addr = 0x1b;
403 msg.flags = 0;
404 msg.len = mxb_saa7740_init[0].length;
405 msg.buf = &mxb_saa7740_init[0].data[0];
406
407 if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
408 /* the sound arena module is a pos, that's probably the reason
409 philips refuses to hand out a datasheet for the saa7740...
410 it seems to screw up the i2c bus, so we disable fast irq
411 based i2c transactions here and rely on the slow and safe
412 polling method ... */
413 extension.flags &= ~SAA7146_USE_I2C_IRQ;
414 for(i = 1;;i++) {
415 if( -1 == mxb_saa7740_init[i].length ) {
416 break;
417 }
418
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300419 msg.len = mxb_saa7740_init[i].length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 msg.buf = &mxb_saa7740_init[i].data[0];
421 if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
422 DEB_D(("failed to initialize 'sound arena module'.\n"));
423 goto err;
424 }
425 }
426 INFO(("'sound arena module' detected.\n"));
427 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300428err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 /* the rest for saa7146: you should definitely set some basic values
430 for the input-port handling of the saa7146. */
431
432 /* ext->saa has been filled by the core driver */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300433
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 /* some stuff is done via variables */
435 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
436
437 /* some stuff is done via direct write to the registers */
438
439 /* this is ugly, but because of the fact that this is completely
440 hardware dependend, it should be done directly... */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300441 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 saa7146_write(dev, DD1_INIT, 0x02000200);
443 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
444
445 return 0;
446}
447
448/* interrupt-handler. this gets called when irq_mask is != 0.
449 it must clear the interrupt-bits in irq_mask it has handled */
450/*
451void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
452{
453 struct mxb* mxb = (struct mxb*)dev->ext_priv;
454}
455*/
456
457static struct saa7146_ext_vv vv_data;
458
459/* this function only gets called when the probing was successful */
460static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
461{
462 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 DEB_EE(("dev:%p\n",dev));
465
466 /* checking for i2c-devices can be omitted here, because we
467 already did this in "mxb_vl42_probe" */
468
469 saa7146_vv_init(dev,&vv_data);
470 if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
471 ERR(("cannot register capture v4l2 device. skipping.\n"));
472 return -1;
473 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
476 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
477 if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
478 ERR(("cannot register vbi v4l2 device. skipping.\n"));
479 }
480 }
481
482 i2c_use_client(mxb->tea6420_1);
483 i2c_use_client(mxb->tea6420_2);
484 i2c_use_client(mxb->tea6415c);
485 i2c_use_client(mxb->tda9840);
486 i2c_use_client(mxb->saa7111a);
487 i2c_use_client(mxb->tuner);
488
489 printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
490
491 mxb_num++;
492 mxb_init_done(dev);
493 return 0;
494}
495
496static int mxb_detach(struct saa7146_dev* dev)
497{
498 struct mxb* mxb = (struct mxb*)dev->ext_priv;
499
500 DEB_EE(("dev:%p\n",dev));
501
502 i2c_release_client(mxb->tea6420_1);
503 i2c_release_client(mxb->tea6420_2);
504 i2c_release_client(mxb->tea6415c);
505 i2c_release_client(mxb->tda9840);
506 i2c_release_client(mxb->saa7111a);
507 i2c_release_client(mxb->tuner);
508
509 saa7146_unregister_device(&mxb->video_dev,dev);
510 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
511 saa7146_unregister_device(&mxb->vbi_dev,dev);
512 }
513 saa7146_vv_release(dev);
514
515 mxb_num--;
516
517 i2c_del_adapter(&mxb->i2c_adapter);
518 kfree(mxb);
519
520 return 0;
521}
522
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300523static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 struct saa7146_dev *dev = fh->dev;
526 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300527 struct saa7146_vv *vv = dev->vv_data;
528
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 switch(cmd) {
530 case VIDIOC_ENUMINPUT:
531 {
532 struct v4l2_input *i = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300533
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
535 if( i->index < 0 || i->index >= MXB_INPUTS) {
536 return -EINVAL;
537 }
538 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
539
540 return 0;
541 }
542 /* the saa7146 provides some controls (brightness, contrast, saturation)
543 which gets registered *after* this function. because of this we have
544 to return with a value != 0 even if the function succeded.. */
545 case VIDIOC_QUERYCTRL:
546 {
547 struct v4l2_queryctrl *qc = arg;
548 int i;
549
550 for (i = MAXCONTROLS - 1; i >= 0; i--) {
551 if (mxb_controls[i].id == qc->id) {
552 *qc = mxb_controls[i];
553 DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
554 return 0;
555 }
556 }
557 return -EAGAIN;
558 }
559 case VIDIOC_G_CTRL:
560 {
561 struct v4l2_control *vc = arg;
562 int i;
563
564 for (i = MAXCONTROLS - 1; i >= 0; i--) {
565 if (mxb_controls[i].id == vc->id) {
566 break;
567 }
568 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if( i < 0 ) {
571 return -EAGAIN;
572 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 switch (vc->id ) {
575 case V4L2_CID_AUDIO_MUTE: {
576 vc->value = mxb->cur_mute;
577 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
578 return 0;
579 }
580 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
583 return 0;
584 }
585
586 case VIDIOC_S_CTRL:
587 {
588 struct v4l2_control *vc = arg;
589 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300590
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 for (i = MAXCONTROLS - 1; i >= 0; i--) {
592 if (mxb_controls[i].id == vc->id) {
593 break;
594 }
595 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if( i < 0 ) {
598 return -EAGAIN;
599 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300600
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 switch (vc->id ) {
602 case V4L2_CID_AUDIO_MUTE: {
603 mxb->cur_mute = vc->value;
604 if( 0 == vc->value ) {
605 /* switch the audio-source */
606 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
607 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
608 } else {
609 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
610 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
611 }
612 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
613 break;
614 }
615 }
616 return 0;
617 }
618 case VIDIOC_G_INPUT:
619 {
620 int *input = (int *)arg;
621 *input = mxb->cur_input;
622
623 DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300624 return 0;
625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 case VIDIOC_S_INPUT:
627 {
628 int input = *(int *)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300629 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 int i = 0;
631
632 DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
633
634 if (input < 0 || input >= MXB_INPUTS) {
635 return -EINVAL;
636 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300637
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 /* fixme: locke das setzen des inputs mit hilfe des mutexes
Ingo Molnar3593cab2006-02-07 06:49:14 -0200639 mutex_lock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 video_mux(dev,*i);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200641 mutex_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 /* fixme: check if streaming capture
645 if ( 0 != dev->streaming ) {
646 DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
647 return -EPERM;
648 }
649 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300652
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 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 -0300654
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 /* prepare switching of tea6415c and saa7111a;
656 have a look at the 'background'-file for further informations */
657 switch( input ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 case TUNER:
660 {
661 i = 0;
662 vm.in = 3;
663 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300664
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
666 printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
667 return -EFAULT;
668 }
669 /* connect tuner-output always to multicable */
670 vm.in = 3;
671 vm.out = 13;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300672 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 }
674 case AUX3_YC:
675 {
676 /* nothing to be done here. aux3_yc is
677 directly connected to the saa711a */
678 i = 5;
679 break;
680 }
681 case AUX3:
682 {
683 /* nothing to be done here. aux3 is
684 directly connected to the saa711a */
685 i = 1;
686 break;
687 }
688 case AUX1:
689 {
690 i = 0;
691 vm.in = 1;
692 vm.out = 17;
693 break;
694 }
695 }
696
697 /* switch video in tea6415c only if necessary */
698 switch( input ) {
699 case TUNER:
700 case AUX1:
701 {
702 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
703 printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
704 return -EFAULT;
705 }
706 break;
707 }
708 default:
709 {
710 break;
711 }
712 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 /* switch video in saa7111a */
715 if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
716 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 /* switch the audio-source only if necessary */
720 if( 0 == mxb->cur_mute ) {
721 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
722 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
723 }
724
725 return 0;
726 }
727 case VIDIOC_G_TUNER:
728 {
729 struct v4l2_tuner *t = arg;
730 int byte = 0;
731
732 if( 0 != t->index ) {
733 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
734 return -EINVAL;
735 }
736
737 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
738
739 memset(t,0,sizeof(*t));
740 strcpy(t->name, "Television");
741
742 t->type = V4L2_TUNER_ANALOG_TV;
743 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
744 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
745 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
746 /* FIXME: add the real signal strength here */
747 t->signal = 0xffff;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300748 t->afc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
751 t->audmode = mxb->cur_mode;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300752
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if( byte < 0 ) {
754 t->rxsubchans = V4L2_TUNER_SUB_MONO;
755 } else {
756 switch(byte) {
757 case TDA9840_MONO_DETECT: {
758 t->rxsubchans = V4L2_TUNER_SUB_MONO;
759 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
760 break;
761 }
762 case TDA9840_DUAL_DETECT: {
763 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
764 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
765 break;
766 }
767 case TDA9840_STEREO_DETECT: {
768 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
769 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
770 break;
771 }
772 default: { /* TDA9840_INCORRECT_DETECT */
773 t->rxsubchans = V4L2_TUNER_MODE_MONO;
774 DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
775 break;
776 }
777 }
778 }
779
780 return 0;
781 }
782 case VIDIOC_S_TUNER:
783 {
784 struct v4l2_tuner *t = arg;
785 int result = 0;
786 int byte = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 if( 0 != t->index ) {
789 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
790 return -EINVAL;
791 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 switch(t->audmode) {
794 case V4L2_TUNER_MODE_STEREO: {
795 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
796 byte = TDA9840_SET_STEREO;
797 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
798 break;
799 }
Hans Verkuil301e22d2006-03-18 17:15:00 -0300800 case V4L2_TUNER_MODE_LANG1_LANG2: {
801 mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
802 byte = TDA9840_SET_BOTH;
803 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
804 break;
805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 case V4L2_TUNER_MODE_LANG1: {
807 mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
808 byte = TDA9840_SET_LANG1;
809 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
810 break;
811 }
812 case V4L2_TUNER_MODE_LANG2: {
813 mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
814 byte = TDA9840_SET_LANG2;
815 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
816 break;
817 }
818 default: { /* case V4L2_TUNER_MODE_MONO: {*/
819 mxb->cur_mode = V4L2_TUNER_MODE_MONO;
820 byte = TDA9840_SET_MONO;
821 DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
822 break;
823 }
824 }
825
826 if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
827 printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
828 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300829
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 return 0;
831 }
832 case VIDIOC_G_FREQUENCY:
833 {
834 struct v4l2_frequency *f = arg;
835
836 if(0 != mxb->cur_input) {
837 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
838 return -EINVAL;
839 }
840
Michael Hunold9d2599d2005-07-27 11:46:00 -0700841 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Michael Hunold9d2599d2005-07-27 11:46:00 -0700843 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 return 0;
845 }
846 case VIDIOC_S_FREQUENCY:
847 {
848 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849
850 if (0 != f->tuner)
851 return -EINVAL;
852
853 if (V4L2_TUNER_ANALOG_TV != f->type)
854 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 if(0 != mxb->cur_input) {
857 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
858 return -EINVAL;
859 }
860
Michael Hunold9d2599d2005-07-27 11:46:00 -0700861 mxb->cur_freq = *f;
862 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300864 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700865 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
868 spin_lock(&dev->slock);
869 vv->vbi_fieldcount = 0;
870 spin_unlock(&dev->slock);
871
872 return 0;
873 }
874 case MXB_S_AUDIO_CD:
875 {
876 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if( i < 0 || i >= MXB_AUDIOS ) {
879 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
880 return -EINVAL;
881 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300882
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
884
885 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
886 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
887
888 return 0;
889 }
890 case MXB_S_AUDIO_LINE:
891 {
892 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300893
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if( i < 0 || i >= MXB_AUDIOS ) {
895 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
896 return -EINVAL;
897 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300898
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
900 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
901 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
902
903 return 0;
904 }
905 case VIDIOC_G_AUDIO:
906 {
907 struct v4l2_audio *a = arg;
908
909 if( a->index < 0 || a->index > MXB_INPUTS ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300910 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 return -EINVAL;
912 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300913
914 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return 0;
918 }
919 case VIDIOC_S_AUDIO:
920 {
921 struct v4l2_audio *a = arg;
922 DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
923 return 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 default:
926/*
927 DEB2(printk("does not handle this ioctl.\n"));
928*/
929 return -ENOIOCTLCMD;
930 }
931 return 0;
932}
933
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300934static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300936 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 int zero = 0;
938 int one = 1;
939
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300940 if (V4L2_STD_PAL_I == standard->id) {
Michael Hunold6acaba82006-03-13 21:20:41 -0800941 v4l2_std_id std = V4L2_STD_PAL_I;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
944 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300945 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 /* unset the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300947 mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
Michael Hunold6acaba82006-03-13 21:20:41 -0800948 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800950 v4l2_std_id std = V4L2_STD_PAL_BG;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300951
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
953 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300954 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 /* set the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300956 mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
Michael Hunold6acaba82006-03-13 21:20:41 -0800957 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 }
959 return 0;
960}
961
962static struct saa7146_standard standard[] = {
963 {
964 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
965 .v_offset = 0x17, .v_field = 288,
966 .h_offset = 0x14, .h_pixels = 680,
967 .v_max_out = 576, .h_max_out = 768,
968 }, {
969 .name = "PAL-I", .id = V4L2_STD_PAL_I,
970 .v_offset = 0x17, .v_field = 288,
971 .h_offset = 0x14, .h_pixels = 680,
972 .v_max_out = 576, .h_max_out = 768,
973 }, {
974 .name = "NTSC", .id = V4L2_STD_NTSC,
975 .v_offset = 0x16, .v_field = 240,
976 .h_offset = 0x06, .h_pixels = 708,
977 .v_max_out = 480, .h_max_out = 640,
978 }, {
979 .name = "SECAM", .id = V4L2_STD_SECAM,
980 .v_offset = 0x14, .v_field = 288,
981 .h_offset = 0x14, .h_pixels = 720,
982 .v_max_out = 576, .h_max_out = 768,
983 }
984};
985
986static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300987 .ext_priv = "Multimedia eXtension Board",
988 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989};
990
991static struct pci_device_id pci_tbl[] = {
992 {
993 .vendor = PCI_VENDOR_ID_PHILIPS,
994 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
995 .subvendor = 0x0000,
996 .subdevice = 0x0000,
997 .driver_data = (unsigned long)&mxb,
998 }, {
999 .vendor = 0,
1000 }
1001};
1002
1003MODULE_DEVICE_TABLE(pci, pci_tbl);
1004
1005static struct saa7146_ext_vv vv_data = {
1006 .inputs = MXB_INPUTS,
1007 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
1008 .stds = &standard[0],
1009 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001010 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 .ioctls = &ioctls[0],
1012 .ioctl = mxb_ioctl,
1013};
1014
1015static struct saa7146_extension extension = {
1016 .name = MXB_IDENTIFIER,
1017 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 .pci_tbl = &pci_tbl[0],
1020 .module = THIS_MODULE,
1021
1022 .probe = mxb_probe,
1023 .attach = mxb_attach,
1024 .detach = mxb_detach,
1025
1026 .irq_mask = 0,
1027 .irq_func = NULL,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001028};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
1030static int __init mxb_init_module(void)
1031{
1032 if( 0 != saa7146_register_extension(&extension)) {
1033 DEB_S(("failed to register extension.\n"));
1034 return -ENODEV;
1035 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return 0;
1038}
1039
1040static void __exit mxb_cleanup_module(void)
1041{
1042 saa7146_unregister_extension(&extension);
1043}
1044
1045module_init(mxb_init_module);
1046module_exit(mxb_cleanup_module);
1047
1048MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
1049MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
1050MODULE_LICENSE("GPL");