blob: 98ad3092a079cb7659c1f8c6c29c1e6bc3b1f557 [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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 int result;
157
158 if ((result = request_module("saa7111")) < 0) {
159 printk("mxb: saa7111 i2c module not available.\n");
160 return -ENODEV;
161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 if ((result = request_module("tea6420")) < 0) {
163 printk("mxb: tea6420 i2c module not available.\n");
164 return -ENODEV;
165 }
166 if ((result = request_module("tea6415c")) < 0) {
167 printk("mxb: tea6415c i2c module not available.\n");
168 return -ENODEV;
169 }
170 if ((result = request_module("tda9840")) < 0) {
171 printk("mxb: tda9840 i2c module not available.\n");
172 return -ENODEV;
173 }
Michael Hunolda08cc442006-11-28 08:13:58 -0300174 if ((result = request_module("tuner")) < 0) {
175 printk("mxb: tuner i2c module not available.\n");
176 return -ENODEV;
177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Panagiotis Issaris74081872006-01-11 19:40:56 -0200179 mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 if( NULL == mxb ) {
181 DEB_D(("not enough kernel memory.\n"));
182 return -ENOMEM;
183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 mxb->i2c_adapter = (struct i2c_adapter) {
186 .class = I2C_CLASS_TV_ANALOG,
187 .name = "mxb",
188 };
189
190 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
191 if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
192 DEB_S(("cannot register i2c-device. skipping.\n"));
193 kfree(mxb);
194 return -EFAULT;
195 }
196
197 /* loop through all i2c-devices on the bus and look who is there */
Trent Piephoa991f442007-10-10 05:37:43 -0300198 list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
Mauro Carvalho Chehab09df1c12006-03-18 08:31:34 -0300199 if( I2C_ADDR_TEA6420_1 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 mxb->tea6420_1 = client;
Mauro Carvalho Chehab09df1c12006-03-18 08:31:34 -0300201 if( I2C_ADDR_TEA6420_2 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 mxb->tea6420_2 = client;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300203 if( I2C_TEA6415C_2 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 mxb->tea6415c = client;
Mauro Carvalho Chehab09df1c12006-03-18 08:31:34 -0300205 if( I2C_ADDR_TDA9840 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 mxb->tda9840 = client;
207 if( I2C_SAA7111 == client->addr )
208 mxb->saa7111a = client;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300209 if( 0x60 == client->addr )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 mxb->tuner = client;
211 }
212
213 /* check if all devices are present */
214 if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c
215 || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) {
216
217 printk("mxb: did not find all i2c devices. aborting\n");
218 i2c_del_adapter(&mxb->i2c_adapter);
219 kfree(mxb);
220 return -ENODEV;
221 }
222
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300223 /* all devices are present, probe was successful */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
225 /* we store the pointer in our private data field */
226 dev->ext_priv = mxb;
227
228 return 0;
229}
230
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300231/* some init data for the saa7740, the so-called 'sound arena module'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 there are no specs available, so we simply use some init values */
233static struct {
234 int length;
235 char data[9];
236} mxb_saa7740_init[] = {
237 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
238 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
239 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
240 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
241 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
242 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
243 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
244 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
245 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
246 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
247 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
248 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
249 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
250 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
251 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
252 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
253 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
254 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
255 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
256 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
257 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
258 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
259 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
260 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
261 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
262 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
263 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
264 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
265 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
266 { 3, { 0x48, 0x00, 0x01 } },
267 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
268 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
269 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
270 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
271 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
272 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
273 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
274 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
275 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
276 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
277 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
278 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
279 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
280 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
281 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
282 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
283 { 3, { 0x80, 0xb3, 0x0a } },
284 {-1, { 0} }
285};
286
287static const unsigned char mxb_saa7111_init[] = {
288 0x00, 0x00, /* 00 - ID byte */
289 0x01, 0x00, /* 01 - reserved */
290
291 /*front end */
292 0x02, 0xd8, /* 02 - FUSE=x, GUDL=x, MODE=x */
293 0x03, 0x23, /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
294 0x04, 0x00, /* 04 - GAI1=256 */
295 0x05, 0x00, /* 05 - GAI2=256 */
296
297 /* decoder */
298 0x06, 0xf0, /* 06 - HSB at xx(50Hz) / xx(60Hz) pixels after end of last line */
299 0x07, 0x30, /* 07 - HSS at xx(50Hz) / xx(60Hz) pixels after end of last line */
300 0x08, 0xa8, /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
301 0x09, 0x02, /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
302 0x0a, 0x80, /* 0a - BRIG=128 */
303 0x0b, 0x47, /* 0b - CONT=1.109 */
304 0x0c, 0x40, /* 0c - SATN=1.0 */
305 0x0d, 0x00, /* 0d - HUE=0 */
306 0x0e, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
307 0x0f, 0x00, /* 0f - reserved */
308 0x10, 0xd0, /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
309 0x11, 0x8c, /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
310 0x12, 0x80, /* 12 - xx output control 2 */
311 0x13, 0x30, /* 13 - xx output control 3 */
312 0x14, 0x00, /* 14 - reserved */
313 0x15, 0x15, /* 15 - VBI */
314 0x16, 0x04, /* 16 - VBI */
315 0x17, 0x00, /* 17 - VBI */
316};
317
318/* bring hardware to a sane state. this has to be done, just in case someone
319 wants to capture from this device before it has been properly initialized.
320 the capture engine would badly fail, because no valid signal arrives on the
321 saa7146, thus leading to timeouts and stuff. */
322static int mxb_init_done(struct saa7146_dev* dev)
323{
324 struct mxb* mxb = (struct mxb*)dev->ext_priv;
325 struct video_decoder_init init;
326 struct i2c_msg msg;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700327 struct tuner_setup tun_setup;
Michael Hunold6acaba82006-03-13 21:20:41 -0800328 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 int i = 0, err = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300331 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
333 /* select video mode in saa7111a */
334 i = VIDEO_MODE_PAL;
335 /* fixme: currently pointless: gets overwritten by configuration below */
336 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
337
338 /* write configuration to saa7111a */
339 init.data = mxb_saa7111_init;
340 init.len = sizeof(mxb_saa7111_init);
341 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
342
343 /* select tuner-output on saa7111a */
344 i = 0;
345 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
346
347 /* enable vbi bypass */
348 i = 1;
349 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
350
351 /* select a tuner type */
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700352 tun_setup.mode_mask = T_ANALOG_TV;
353 tun_setup.addr = ADDR_UNSET;
Michael Hunold9d2599d2005-07-27 11:46:00 -0700354 tun_setup.type = TUNER_PHILIPS_PAL;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700355 mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
Michael Hunold9d2599d2005-07-27 11:46:00 -0700356 /* tune in some frequency on tuner */
357 mxb->cur_freq.tuner = 0;
358 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
359 mxb->cur_freq.frequency = freq;
360 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
361 &mxb->cur_freq);
362
Michael Hunold6acaba82006-03-13 21:20:41 -0800363 /* set a default video standard */
364 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 /* mute audio on tea6420s */
367 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
368 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
369 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
370 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
371
372 /* switch to tuner-channel on tea6415c*/
373 vm.out = 17;
374 vm.in = 3;
375 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
376
377 /* select tuner-output on multicable on tea6415c*/
378 vm.in = 3;
379 vm.out = 13;
380 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 /* the rest for mxb */
383 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 mxb->cur_mute = 1;
385
386 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
387 mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 /* check if the saa7740 (aka 'sound arena module') is present
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300390 on the mxb. if so, we must initialize it. due to lack of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 informations about the saa7740, the values were reverse
392 engineered. */
393 msg.addr = 0x1b;
394 msg.flags = 0;
395 msg.len = mxb_saa7740_init[0].length;
396 msg.buf = &mxb_saa7740_init[0].data[0];
397
398 if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
399 /* the sound arena module is a pos, that's probably the reason
400 philips refuses to hand out a datasheet for the saa7740...
401 it seems to screw up the i2c bus, so we disable fast irq
402 based i2c transactions here and rely on the slow and safe
403 polling method ... */
404 extension.flags &= ~SAA7146_USE_I2C_IRQ;
405 for(i = 1;;i++) {
406 if( -1 == mxb_saa7740_init[i].length ) {
407 break;
408 }
409
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300410 msg.len = mxb_saa7740_init[i].length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 msg.buf = &mxb_saa7740_init[i].data[0];
412 if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
413 DEB_D(("failed to initialize 'sound arena module'.\n"));
414 goto err;
415 }
416 }
417 INFO(("'sound arena module' detected.\n"));
418 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300419err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 /* the rest for saa7146: you should definitely set some basic values
421 for the input-port handling of the saa7146. */
422
423 /* ext->saa has been filled by the core driver */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 /* some stuff is done via variables */
426 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
427
428 /* some stuff is done via direct write to the registers */
429
430 /* this is ugly, but because of the fact that this is completely
431 hardware dependend, it should be done directly... */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300432 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 saa7146_write(dev, DD1_INIT, 0x02000200);
434 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
435
436 return 0;
437}
438
439/* interrupt-handler. this gets called when irq_mask is != 0.
440 it must clear the interrupt-bits in irq_mask it has handled */
441/*
442void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
443{
444 struct mxb* mxb = (struct mxb*)dev->ext_priv;
445}
446*/
447
448static struct saa7146_ext_vv vv_data;
449
450/* this function only gets called when the probing was successful */
451static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
452{
453 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 DEB_EE(("dev:%p\n",dev));
456
457 /* checking for i2c-devices can be omitted here, because we
458 already did this in "mxb_vl42_probe" */
459
460 saa7146_vv_init(dev,&vv_data);
461 if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
462 ERR(("cannot register capture v4l2 device. skipping.\n"));
463 return -1;
464 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300465
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
467 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
468 if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
469 ERR(("cannot register vbi v4l2 device. skipping.\n"));
470 }
471 }
472
473 i2c_use_client(mxb->tea6420_1);
474 i2c_use_client(mxb->tea6420_2);
475 i2c_use_client(mxb->tea6415c);
476 i2c_use_client(mxb->tda9840);
477 i2c_use_client(mxb->saa7111a);
478 i2c_use_client(mxb->tuner);
479
480 printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
481
482 mxb_num++;
483 mxb_init_done(dev);
484 return 0;
485}
486
487static int mxb_detach(struct saa7146_dev* dev)
488{
489 struct mxb* mxb = (struct mxb*)dev->ext_priv;
490
491 DEB_EE(("dev:%p\n",dev));
492
493 i2c_release_client(mxb->tea6420_1);
494 i2c_release_client(mxb->tea6420_2);
495 i2c_release_client(mxb->tea6415c);
496 i2c_release_client(mxb->tda9840);
497 i2c_release_client(mxb->saa7111a);
498 i2c_release_client(mxb->tuner);
499
500 saa7146_unregister_device(&mxb->video_dev,dev);
501 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
502 saa7146_unregister_device(&mxb->vbi_dev,dev);
503 }
504 saa7146_vv_release(dev);
505
506 mxb_num--;
507
508 i2c_del_adapter(&mxb->i2c_adapter);
509 kfree(mxb);
510
511 return 0;
512}
513
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300514static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 struct saa7146_dev *dev = fh->dev;
517 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300518 struct saa7146_vv *vv = dev->vv_data;
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 switch(cmd) {
521 case VIDIOC_ENUMINPUT:
522 {
523 struct v4l2_input *i = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
526 if( i->index < 0 || i->index >= MXB_INPUTS) {
527 return -EINVAL;
528 }
529 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
530
531 return 0;
532 }
533 /* the saa7146 provides some controls (brightness, contrast, saturation)
534 which gets registered *after* this function. because of this we have
535 to return with a value != 0 even if the function succeded.. */
536 case VIDIOC_QUERYCTRL:
537 {
538 struct v4l2_queryctrl *qc = arg;
539 int i;
540
541 for (i = MAXCONTROLS - 1; i >= 0; i--) {
542 if (mxb_controls[i].id == qc->id) {
543 *qc = mxb_controls[i];
544 DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
545 return 0;
546 }
547 }
548 return -EAGAIN;
549 }
550 case VIDIOC_G_CTRL:
551 {
552 struct v4l2_control *vc = arg;
553 int i;
554
555 for (i = MAXCONTROLS - 1; i >= 0; i--) {
556 if (mxb_controls[i].id == vc->id) {
557 break;
558 }
559 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 if( i < 0 ) {
562 return -EAGAIN;
563 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 switch (vc->id ) {
566 case V4L2_CID_AUDIO_MUTE: {
567 vc->value = mxb->cur_mute;
568 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
569 return 0;
570 }
571 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
574 return 0;
575 }
576
577 case VIDIOC_S_CTRL:
578 {
579 struct v4l2_control *vc = arg;
580 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300581
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 for (i = MAXCONTROLS - 1; i >= 0; i--) {
583 if (mxb_controls[i].id == vc->id) {
584 break;
585 }
586 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 if( i < 0 ) {
589 return -EAGAIN;
590 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 switch (vc->id ) {
593 case V4L2_CID_AUDIO_MUTE: {
594 mxb->cur_mute = vc->value;
595 if( 0 == vc->value ) {
596 /* switch the audio-source */
597 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
598 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
599 } else {
600 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
601 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
602 }
603 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
604 break;
605 }
606 }
607 return 0;
608 }
609 case VIDIOC_G_INPUT:
610 {
611 int *input = (int *)arg;
612 *input = mxb->cur_input;
613
614 DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300615 return 0;
616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 case VIDIOC_S_INPUT:
618 {
619 int input = *(int *)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300620 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 int i = 0;
622
623 DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
624
625 if (input < 0 || input >= MXB_INPUTS) {
626 return -EINVAL;
627 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 /* fixme: locke das setzen des inputs mit hilfe des mutexes
Ingo Molnar3593cab2006-02-07 06:49:14 -0200630 mutex_lock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 video_mux(dev,*i);
Ingo Molnar3593cab2006-02-07 06:49:14 -0200632 mutex_unlock(&dev->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 /* fixme: check if streaming capture
636 if ( 0 != dev->streaming ) {
637 DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
638 return -EPERM;
639 }
640 */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300643
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 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 -0300645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 /* prepare switching of tea6415c and saa7111a;
647 have a look at the 'background'-file for further informations */
648 switch( input ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 case TUNER:
651 {
652 i = 0;
653 vm.in = 3;
654 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
657 printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
658 return -EFAULT;
659 }
660 /* connect tuner-output always to multicable */
661 vm.in = 3;
662 vm.out = 13;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300663 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
665 case AUX3_YC:
666 {
667 /* nothing to be done here. aux3_yc is
668 directly connected to the saa711a */
669 i = 5;
670 break;
671 }
672 case AUX3:
673 {
674 /* nothing to be done here. aux3 is
675 directly connected to the saa711a */
676 i = 1;
677 break;
678 }
679 case AUX1:
680 {
681 i = 0;
682 vm.in = 1;
683 vm.out = 17;
684 break;
685 }
686 }
687
688 /* switch video in tea6415c only if necessary */
689 switch( input ) {
690 case TUNER:
691 case AUX1:
692 {
693 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
694 printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
695 return -EFAULT;
696 }
697 break;
698 }
699 default:
700 {
701 break;
702 }
703 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 /* switch video in saa7111a */
706 if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
707 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 /* switch the audio-source only if necessary */
711 if( 0 == mxb->cur_mute ) {
712 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
713 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
714 }
715
716 return 0;
717 }
718 case VIDIOC_G_TUNER:
719 {
720 struct v4l2_tuner *t = arg;
721 int byte = 0;
722
723 if( 0 != t->index ) {
724 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
725 return -EINVAL;
726 }
727
728 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
729
730 memset(t,0,sizeof(*t));
731 strcpy(t->name, "Television");
732
733 t->type = V4L2_TUNER_ANALOG_TV;
734 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
735 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
736 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
737 /* FIXME: add the real signal strength here */
738 t->signal = 0xffff;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300739 t->afc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
742 t->audmode = mxb->cur_mode;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if( byte < 0 ) {
745 t->rxsubchans = V4L2_TUNER_SUB_MONO;
746 } else {
747 switch(byte) {
748 case TDA9840_MONO_DETECT: {
749 t->rxsubchans = V4L2_TUNER_SUB_MONO;
750 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
751 break;
752 }
753 case TDA9840_DUAL_DETECT: {
754 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
755 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
756 break;
757 }
758 case TDA9840_STEREO_DETECT: {
759 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
760 DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
761 break;
762 }
763 default: { /* TDA9840_INCORRECT_DETECT */
764 t->rxsubchans = V4L2_TUNER_MODE_MONO;
765 DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
766 break;
767 }
768 }
769 }
770
771 return 0;
772 }
773 case VIDIOC_S_TUNER:
774 {
775 struct v4l2_tuner *t = arg;
776 int result = 0;
777 int byte = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300778
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 if( 0 != t->index ) {
780 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
781 return -EINVAL;
782 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300783
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 switch(t->audmode) {
785 case V4L2_TUNER_MODE_STEREO: {
786 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
787 byte = TDA9840_SET_STEREO;
788 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
789 break;
790 }
Hans Verkuil301e22d2006-03-18 17:15:00 -0300791 case V4L2_TUNER_MODE_LANG1_LANG2: {
792 mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
793 byte = TDA9840_SET_BOTH;
794 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
795 break;
796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 case V4L2_TUNER_MODE_LANG1: {
798 mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
799 byte = TDA9840_SET_LANG1;
800 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
801 break;
802 }
803 case V4L2_TUNER_MODE_LANG2: {
804 mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
805 byte = TDA9840_SET_LANG2;
806 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
807 break;
808 }
809 default: { /* case V4L2_TUNER_MODE_MONO: {*/
810 mxb->cur_mode = V4L2_TUNER_MODE_MONO;
811 byte = TDA9840_SET_MONO;
812 DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
813 break;
814 }
815 }
816
817 if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
818 printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
819 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300820
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return 0;
822 }
823 case VIDIOC_G_FREQUENCY:
824 {
825 struct v4l2_frequency *f = arg;
826
827 if(0 != mxb->cur_input) {
828 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
829 return -EINVAL;
830 }
831
Michael Hunold9d2599d2005-07-27 11:46:00 -0700832 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Michael Hunold9d2599d2005-07-27 11:46:00 -0700834 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 return 0;
836 }
837 case VIDIOC_S_FREQUENCY:
838 {
839 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 if (0 != f->tuner)
842 return -EINVAL;
843
844 if (V4L2_TUNER_ANALOG_TV != f->type)
845 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300846
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if(0 != mxb->cur_input) {
848 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
849 return -EINVAL;
850 }
851
Michael Hunold9d2599d2005-07-27 11:46:00 -0700852 mxb->cur_freq = *f;
853 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300855 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700856 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
858 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
859 spin_lock(&dev->slock);
860 vv->vbi_fieldcount = 0;
861 spin_unlock(&dev->slock);
862
863 return 0;
864 }
865 case MXB_S_AUDIO_CD:
866 {
867 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300868
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if( i < 0 || i >= MXB_AUDIOS ) {
870 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
871 return -EINVAL;
872 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
875
876 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
877 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
878
879 return 0;
880 }
881 case MXB_S_AUDIO_LINE:
882 {
883 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300884
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 if( i < 0 || i >= MXB_AUDIOS ) {
886 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
887 return -EINVAL;
888 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
891 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
892 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
893
894 return 0;
895 }
896 case VIDIOC_G_AUDIO:
897 {
898 struct v4l2_audio *a = arg;
899
900 if( a->index < 0 || a->index > MXB_INPUTS ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300901 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return -EINVAL;
903 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300904
905 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 return 0;
909 }
910 case VIDIOC_S_AUDIO:
911 {
912 struct v4l2_audio *a = arg;
913 DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
914 return 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300915 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 default:
917/*
918 DEB2(printk("does not handle this ioctl.\n"));
919*/
920 return -ENOIOCTLCMD;
921 }
922 return 0;
923}
924
925static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
926{
927 struct mxb* mxb = (struct mxb*)dev->ext_priv;
928 int zero = 0;
929 int one = 1;
930
931 if(V4L2_STD_PAL_I == std->id ) {
Michael Hunold6acaba82006-03-13 21:20:41 -0800932 v4l2_std_id std = V4L2_STD_PAL_I;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
934 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300935 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 /* unset the 7111 gpio register -- I don't know what this does exactly */
937 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
Michael Hunold6acaba82006-03-13 21:20:41 -0800938 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800940 v4l2_std_id std = V4L2_STD_PAL_BG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
942 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300943 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 /* set the 7111 gpio register -- I don't know what this does exactly */
945 mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
Michael Hunold6acaba82006-03-13 21:20:41 -0800946 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 }
948 return 0;
949}
950
951static struct saa7146_standard standard[] = {
952 {
953 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
954 .v_offset = 0x17, .v_field = 288,
955 .h_offset = 0x14, .h_pixels = 680,
956 .v_max_out = 576, .h_max_out = 768,
957 }, {
958 .name = "PAL-I", .id = V4L2_STD_PAL_I,
959 .v_offset = 0x17, .v_field = 288,
960 .h_offset = 0x14, .h_pixels = 680,
961 .v_max_out = 576, .h_max_out = 768,
962 }, {
963 .name = "NTSC", .id = V4L2_STD_NTSC,
964 .v_offset = 0x16, .v_field = 240,
965 .h_offset = 0x06, .h_pixels = 708,
966 .v_max_out = 480, .h_max_out = 640,
967 }, {
968 .name = "SECAM", .id = V4L2_STD_SECAM,
969 .v_offset = 0x14, .v_field = 288,
970 .h_offset = 0x14, .h_pixels = 720,
971 .v_max_out = 576, .h_max_out = 768,
972 }
973};
974
975static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300976 .ext_priv = "Multimedia eXtension Board",
977 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978};
979
980static struct pci_device_id pci_tbl[] = {
981 {
982 .vendor = PCI_VENDOR_ID_PHILIPS,
983 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
984 .subvendor = 0x0000,
985 .subdevice = 0x0000,
986 .driver_data = (unsigned long)&mxb,
987 }, {
988 .vendor = 0,
989 }
990};
991
992MODULE_DEVICE_TABLE(pci, pci_tbl);
993
994static struct saa7146_ext_vv vv_data = {
995 .inputs = MXB_INPUTS,
996 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
997 .stds = &standard[0],
998 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300999 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 .ioctls = &ioctls[0],
1001 .ioctl = mxb_ioctl,
1002};
1003
1004static struct saa7146_extension extension = {
1005 .name = MXB_IDENTIFIER,
1006 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001007
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .pci_tbl = &pci_tbl[0],
1009 .module = THIS_MODULE,
1010
1011 .probe = mxb_probe,
1012 .attach = mxb_attach,
1013 .detach = mxb_detach,
1014
1015 .irq_mask = 0,
1016 .irq_func = NULL,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001017};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019static int __init mxb_init_module(void)
1020{
1021 if( 0 != saa7146_register_extension(&extension)) {
1022 DEB_S(("failed to register extension.\n"));
1023 return -ENODEV;
1024 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -03001025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return 0;
1027}
1028
1029static void __exit mxb_cleanup_module(void)
1030{
1031 saa7146_unregister_extension(&extension);
1032}
1033
1034module_init(mxb_init_module);
1035module_exit(mxb_cleanup_module);
1036
1037MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
1038MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
1039MODULE_LICENSE("GPL");