blob: 621d1740829761874c87b646be32577f9d9f0d76 [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>
Hans Verkuil707ecf42008-09-06 15:40:25 -030030#include <media/saa7115.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32#include "mxb.h"
33#include "tea6415c.h"
34#include "tea6420.h"
35#include "tda9840.h"
36
37#define I2C_SAA7111 0x24
38
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030039#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* global variable */
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030042static int mxb_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030044/* initial frequence the tuner will be tuned to.
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 in verden (lower saxony, germany) 4148 is a
46 channel called "phoenix" */
47static int freq = 4148;
48module_param(freq, int, 0644);
49MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
50
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030051static int debug;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052module_param(debug, int, 0644);
53MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
54
55#define MXB_INPUTS 4
56enum { TUNER, AUX1, AUX3, AUX3_YC };
57
58static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030059 { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
61 { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
62 { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
63};
64
65/* this array holds the information, which port of the saa7146 each
66 input actually uses. the mxb uses port 0 for every input */
67static struct {
68 int hps_source;
69 int hps_sync;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030070} input_port_selection[MXB_INPUTS] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 { 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 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
75};
76
77/* this array holds the information of the audio source (mxb_audios),
78 which has to be switched corresponding to the video source (mxb_channels) */
79static int video_audio_connect[MXB_INPUTS] =
80 { 0, 1, 3, 3 };
81
82/* these are the necessary input-output-pins for bringing one audio source
83(see above) to the CD-output */
84static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -030085 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 {{1,1,0},{1,1,0}}, /* Tuner */
87 {{5,1,0},{6,1,0}}, /* AUX 1 */
88 {{4,1,0},{6,1,0}}, /* AUX 2 */
89 {{3,1,0},{6,1,0}}, /* AUX 3 */
90 {{1,1,0},{3,1,0}}, /* Radio */
91 {{1,1,0},{2,1,0}}, /* CD-Rom */
92 {{6,1,0},{6,1,0}} /* Mute */
93 };
94
95/* these are the necessary input-output-pins for bringing one audio source
96(see above) to the line-output */
97static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
98 {
99 {{2,3,0},{1,2,0}},
100 {{5,3,0},{6,2,0}},
101 {{4,3,0},{6,2,0}},
102 {{3,3,0},{6,2,0}},
103 {{2,3,0},{3,2,0}},
104 {{2,3,0},{2,2,0}},
105 {{6,3,0},{6,2,0}} /* Mute */
106 };
107
108#define MAXCONTROLS 1
109static struct v4l2_queryctrl mxb_controls[] = {
110 { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
111};
112
113static struct saa7146_extension_ioctls ioctls[] = {
114 { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
115 { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
116 { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
117 { VIDIOC_QUERYCTRL, SAA7146_BEFORE },
118 { VIDIOC_G_CTRL, SAA7146_BEFORE },
119 { VIDIOC_S_CTRL, SAA7146_BEFORE },
120 { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
121 { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
122 { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
123 { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
124 { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
125 { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
Hans Verkuil707ecf42008-09-06 15:40:25 -0300126 { VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE },
127 { VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE },
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300128 { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
129 { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 { 0, 0 }
131};
132
133struct mxb
134{
135 struct video_device *video_dev;
136 struct video_device *vbi_dev;
137
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300138 struct i2c_adapter i2c_adapter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 struct i2c_client* saa7111a;
141 struct i2c_client* tda9840;
142 struct i2c_client* tea6415c;
143 struct i2c_client* tuner;
144 struct i2c_client* tea6420_1;
145 struct i2c_client* tea6420_2;
146
147 int cur_mode; /* current audio mode (mono, stereo, ...) */
148 int cur_input; /* current input */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 int cur_mute; /* current mute status */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700150 struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151};
152
153static struct saa7146_extension extension;
154
Jean Delvare961f80f2008-01-27 18:14:51 +0100155static int mxb_check_clients(struct device *dev, void *data)
156{
157 struct mxb* mxb = data;
158 struct i2c_client *client = i2c_verify_client(dev);
159
Hans Verkuil707ecf42008-09-06 15:40:25 -0300160 if (!client)
Jean Delvare961f80f2008-01-27 18:14:51 +0100161 return 0;
162
Hans Verkuil707ecf42008-09-06 15:40:25 -0300163 if (I2C_ADDR_TEA6420_1 == client->addr)
Jean Delvare961f80f2008-01-27 18:14:51 +0100164 mxb->tea6420_1 = client;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300165 if (I2C_ADDR_TEA6420_2 == client->addr)
Jean Delvare961f80f2008-01-27 18:14:51 +0100166 mxb->tea6420_2 = client;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300167 if (I2C_TEA6415C_2 == client->addr)
Jean Delvare961f80f2008-01-27 18:14:51 +0100168 mxb->tea6415c = client;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300169 if (I2C_ADDR_TDA9840 == client->addr)
Jean Delvare961f80f2008-01-27 18:14:51 +0100170 mxb->tda9840 = client;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300171 if (I2C_SAA7111 == client->addr)
Jean Delvare961f80f2008-01-27 18:14:51 +0100172 mxb->saa7111a = client;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300173 if (0x60 == client->addr)
Jean Delvare961f80f2008-01-27 18:14:51 +0100174 mxb->tuner = client;
175
176 return 0;
177}
178
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179static int mxb_probe(struct saa7146_dev* dev)
180{
181 struct mxb* mxb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 int result;
183
Hans Verkuil707ecf42008-09-06 15:40:25 -0300184 result = request_module("saa7115");
185 if (result < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 printk("mxb: saa7111 i2c module not available.\n");
187 return -ENODEV;
188 }
Hans Verkuil707ecf42008-09-06 15:40:25 -0300189 result = request_module("tea6420");
190 if (result < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 printk("mxb: tea6420 i2c module not available.\n");
192 return -ENODEV;
193 }
Hans Verkuil707ecf42008-09-06 15:40:25 -0300194 result = request_module("tea6415c");
195 if (result < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 printk("mxb: tea6415c i2c module not available.\n");
197 return -ENODEV;
198 }
Hans Verkuil707ecf42008-09-06 15:40:25 -0300199 result = request_module("tda9840");
200 if (result < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 printk("mxb: tda9840 i2c module not available.\n");
202 return -ENODEV;
203 }
Hans Verkuil707ecf42008-09-06 15:40:25 -0300204 result = request_module("tuner");
205 if (result < 0) {
Michael Hunolda08cc442006-11-28 08:13:58 -0300206 printk("mxb: tuner i2c module not available.\n");
207 return -ENODEV;
208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Panagiotis Issaris74081872006-01-11 19:40:56 -0200210 mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 if( NULL == mxb ) {
212 DEB_D(("not enough kernel memory.\n"));
213 return -ENOMEM;
214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 mxb->i2c_adapter = (struct i2c_adapter) {
217 .class = I2C_CLASS_TV_ANALOG,
218 .name = "mxb",
219 };
220
221 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
222 if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
223 DEB_S(("cannot register i2c-device. skipping.\n"));
224 kfree(mxb);
225 return -EFAULT;
226 }
227
228 /* loop through all i2c-devices on the bus and look who is there */
Jean Delvare961f80f2008-01-27 18:14:51 +0100229 device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 /* check if all devices are present */
Al Viro5fa12472008-03-29 03:07:38 +0000232 if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
233 !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 printk("mxb: did not find all i2c devices. aborting\n");
235 i2c_del_adapter(&mxb->i2c_adapter);
236 kfree(mxb);
237 return -ENODEV;
238 }
239
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300240 /* all devices are present, probe was successful */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 /* we store the pointer in our private data field */
243 dev->ext_priv = mxb;
244
245 return 0;
246}
247
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300248/* some init data for the saa7740, the so-called 'sound arena module'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 there are no specs available, so we simply use some init values */
250static struct {
251 int length;
252 char data[9];
253} mxb_saa7740_init[] = {
254 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
255 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
256 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
257 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
258 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
259 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
260 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
261 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
262 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
263 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
264 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
265 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
266 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
267 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
268 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
269 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
270 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
271 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
272 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
273 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
274 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
275 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
276 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
277 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
278 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
279 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
280 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
281 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
282 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
283 { 3, { 0x48, 0x00, 0x01 } },
284 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
285 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
286 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
287 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
288 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
289 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
290 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
291 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
292 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
293 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
294 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
295 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
296 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
297 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
298 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
299 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
300 { 3, { 0x80, 0xb3, 0x0a } },
301 {-1, { 0} }
302};
303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304/* bring hardware to a sane state. this has to be done, just in case someone
305 wants to capture from this device before it has been properly initialized.
306 the capture engine would badly fail, because no valid signal arrives on the
307 saa7146, thus leading to timeouts and stuff. */
308static int mxb_init_done(struct saa7146_dev* dev)
309{
310 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 struct i2c_msg msg;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700312 struct tuner_setup tun_setup;
Michael Hunold6acaba82006-03-13 21:20:41 -0800313 v4l2_std_id std = V4L2_STD_PAL_BG;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300314 struct v4l2_routing route;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 int i = 0, err = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300317 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 /* select video mode in saa7111a */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 /* fixme: currently pointless: gets overwritten by configuration below */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300321 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 /* select tuner-output on saa7111a */
324 i = 0;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300325 route.input = SAA7115_COMPOSITE0;
326 route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
327 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
329 /* select a tuner type */
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700330 tun_setup.mode_mask = T_ANALOG_TV;
331 tun_setup.addr = ADDR_UNSET;
Michael Hunold9d2599d2005-07-27 11:46:00 -0700332 tun_setup.type = TUNER_PHILIPS_PAL;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300333 mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
Michael Hunold9d2599d2005-07-27 11:46:00 -0700334 /* tune in some frequency on tuner */
335 mxb->cur_freq.tuner = 0;
336 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
337 mxb->cur_freq.frequency = freq;
338 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
339 &mxb->cur_freq);
340
Michael Hunold6acaba82006-03-13 21:20:41 -0800341 /* set a default video standard */
342 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
343
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 /* mute audio on tea6420s */
345 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
346 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
347 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
348 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
349
350 /* switch to tuner-channel on tea6415c*/
351 vm.out = 17;
352 vm.in = 3;
353 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
354
355 /* select tuner-output on multicable on tea6415c*/
356 vm.in = 3;
357 vm.out = 13;
358 mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 /* the rest for mxb */
361 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 mxb->cur_mute = 1;
363
364 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 /* check if the saa7740 (aka 'sound arena module') is present
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300367 on the mxb. if so, we must initialize it. due to lack of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 informations about the saa7740, the values were reverse
369 engineered. */
370 msg.addr = 0x1b;
371 msg.flags = 0;
372 msg.len = mxb_saa7740_init[0].length;
373 msg.buf = &mxb_saa7740_init[0].data[0];
374
375 if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
376 /* the sound arena module is a pos, that's probably the reason
377 philips refuses to hand out a datasheet for the saa7740...
378 it seems to screw up the i2c bus, so we disable fast irq
379 based i2c transactions here and rely on the slow and safe
380 polling method ... */
381 extension.flags &= ~SAA7146_USE_I2C_IRQ;
382 for(i = 1;;i++) {
383 if( -1 == mxb_saa7740_init[i].length ) {
384 break;
385 }
386
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300387 msg.len = mxb_saa7740_init[i].length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 msg.buf = &mxb_saa7740_init[i].data[0];
389 if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
390 DEB_D(("failed to initialize 'sound arena module'.\n"));
391 goto err;
392 }
393 }
394 INFO(("'sound arena module' detected.\n"));
395 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300396err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 /* the rest for saa7146: you should definitely set some basic values
398 for the input-port handling of the saa7146. */
399
400 /* ext->saa has been filled by the core driver */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 /* some stuff is done via variables */
403 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
404
405 /* some stuff is done via direct write to the registers */
406
407 /* this is ugly, but because of the fact that this is completely
408 hardware dependend, it should be done directly... */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300409 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 saa7146_write(dev, DD1_INIT, 0x02000200);
411 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
412
413 return 0;
414}
415
416/* interrupt-handler. this gets called when irq_mask is != 0.
417 it must clear the interrupt-bits in irq_mask it has handled */
418/*
419void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
420{
421 struct mxb* mxb = (struct mxb*)dev->ext_priv;
422}
423*/
424
425static struct saa7146_ext_vv vv_data;
426
427/* this function only gets called when the probing was successful */
428static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
429{
430 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 DEB_EE(("dev:%p\n",dev));
433
434 /* checking for i2c-devices can be omitted here, because we
435 already did this in "mxb_vl42_probe" */
436
Hans Verkuila8327812008-07-25 10:31:23 -0300437 saa7146_vv_init(dev, &vv_data);
438 if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 ERR(("cannot register capture v4l2 device. skipping.\n"));
440 return -1;
441 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
Hans Verkuila8327812008-07-25 10:31:23 -0300444 if (MXB_BOARD_CAN_DO_VBI(dev)) {
445 if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 ERR(("cannot register vbi v4l2 device. skipping.\n"));
447 }
448 }
449
450 i2c_use_client(mxb->tea6420_1);
451 i2c_use_client(mxb->tea6420_2);
452 i2c_use_client(mxb->tea6415c);
453 i2c_use_client(mxb->tda9840);
454 i2c_use_client(mxb->saa7111a);
455 i2c_use_client(mxb->tuner);
456
Hans Verkuila8327812008-07-25 10:31:23 -0300457 printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 mxb_num++;
460 mxb_init_done(dev);
461 return 0;
462}
463
464static int mxb_detach(struct saa7146_dev* dev)
465{
466 struct mxb* mxb = (struct mxb*)dev->ext_priv;
467
468 DEB_EE(("dev:%p\n",dev));
469
470 i2c_release_client(mxb->tea6420_1);
471 i2c_release_client(mxb->tea6420_2);
472 i2c_release_client(mxb->tea6415c);
473 i2c_release_client(mxb->tda9840);
474 i2c_release_client(mxb->saa7111a);
475 i2c_release_client(mxb->tuner);
476
477 saa7146_unregister_device(&mxb->video_dev,dev);
478 if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
479 saa7146_unregister_device(&mxb->vbi_dev,dev);
480 }
481 saa7146_vv_release(dev);
482
483 mxb_num--;
484
485 i2c_del_adapter(&mxb->i2c_adapter);
486 kfree(mxb);
487
488 return 0;
489}
490
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300491static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
493 struct saa7146_dev *dev = fh->dev;
494 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300495 struct saa7146_vv *vv = dev->vv_data;
496
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 switch(cmd) {
498 case VIDIOC_ENUMINPUT:
499 {
500 struct v4l2_input *i = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300501
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
503 if( i->index < 0 || i->index >= MXB_INPUTS) {
504 return -EINVAL;
505 }
506 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
507
508 return 0;
509 }
510 /* the saa7146 provides some controls (brightness, contrast, saturation)
511 which gets registered *after* this function. because of this we have
512 to return with a value != 0 even if the function succeded.. */
513 case VIDIOC_QUERYCTRL:
514 {
515 struct v4l2_queryctrl *qc = arg;
516 int i;
517
518 for (i = MAXCONTROLS - 1; i >= 0; i--) {
519 if (mxb_controls[i].id == qc->id) {
520 *qc = mxb_controls[i];
521 DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
522 return 0;
523 }
524 }
525 return -EAGAIN;
526 }
527 case VIDIOC_G_CTRL:
528 {
529 struct v4l2_control *vc = arg;
530 int i;
531
532 for (i = MAXCONTROLS - 1; i >= 0; i--) {
533 if (mxb_controls[i].id == vc->id) {
534 break;
535 }
536 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if( i < 0 ) {
539 return -EAGAIN;
540 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 switch (vc->id ) {
543 case V4L2_CID_AUDIO_MUTE: {
544 vc->value = mxb->cur_mute;
545 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
546 return 0;
547 }
548 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
551 return 0;
552 }
553
554 case VIDIOC_S_CTRL:
555 {
556 struct v4l2_control *vc = arg;
557 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 for (i = MAXCONTROLS - 1; i >= 0; i--) {
560 if (mxb_controls[i].id == vc->id) {
561 break;
562 }
563 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if( i < 0 ) {
566 return -EAGAIN;
567 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 switch (vc->id ) {
570 case V4L2_CID_AUDIO_MUTE: {
571 mxb->cur_mute = vc->value;
572 if( 0 == vc->value ) {
573 /* switch the audio-source */
574 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
575 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
576 } else {
577 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
578 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
579 }
580 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
581 break;
582 }
583 }
584 return 0;
585 }
586 case VIDIOC_G_INPUT:
587 {
588 int *input = (int *)arg;
589 *input = mxb->cur_input;
590
591 DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300592 return 0;
593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 case VIDIOC_S_INPUT:
595 {
596 int input = *(int *)arg;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300597 struct tea6415c_multiplex vm;
598 struct v4l2_routing route;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 int i = 0;
600
601 DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
602
603 if (input < 0 || input >= MXB_INPUTS) {
604 return -EINVAL;
605 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300608
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 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 -0300610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 /* prepare switching of tea6415c and saa7111a;
612 have a look at the 'background'-file for further informations */
613 switch( input ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 case TUNER:
616 {
Hans Verkuil707ecf42008-09-06 15:40:25 -0300617 i = SAA7115_COMPOSITE0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 vm.in = 3;
619 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
622 printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
623 return -EFAULT;
624 }
625 /* connect tuner-output always to multicable */
626 vm.in = 3;
627 vm.out = 13;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300628 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
630 case AUX3_YC:
631 {
632 /* nothing to be done here. aux3_yc is
633 directly connected to the saa711a */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300634 i = SAA7115_SVIDEO1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 break;
636 }
637 case AUX3:
638 {
639 /* nothing to be done here. aux3 is
640 directly connected to the saa711a */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300641 i = SAA7115_COMPOSITE1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 break;
643 }
644 case AUX1:
645 {
Hans Verkuil707ecf42008-09-06 15:40:25 -0300646 i = SAA7115_COMPOSITE0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 vm.in = 1;
648 vm.out = 17;
649 break;
650 }
651 }
652
653 /* switch video in tea6415c only if necessary */
654 switch( input ) {
655 case TUNER:
656 case AUX1:
657 {
658 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
659 printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
660 return -EFAULT;
661 }
662 break;
663 }
664 default:
665 {
666 break;
667 }
668 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /* switch video in saa7111a */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300671 route.input = i;
672 route.output = 0;
673 if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 /* switch the audio-source only if necessary */
677 if( 0 == mxb->cur_mute ) {
678 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
679 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
680 }
681
682 return 0;
683 }
684 case VIDIOC_G_TUNER:
685 {
686 struct v4l2_tuner *t = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Hans Verkuil707ecf42008-09-06 15:40:25 -0300688 if (t->index) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
690 return -EINVAL;
691 }
692
693 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
694
Hans Verkuil707ecf42008-09-06 15:40:25 -0300695 memset(t, 0, sizeof(*t));
696 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Hans Verkuil707ecf42008-09-06 15:40:25 -0300698 strlcpy(t->name, "TV Tuner", sizeof(t->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 t->type = V4L2_TUNER_ANALOG_TV;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300700 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
701 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 t->audmode = mxb->cur_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return 0;
704 }
705 case VIDIOC_S_TUNER:
706 {
707 struct v4l2_tuner *t = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300708
Hans Verkuil707ecf42008-09-06 15:40:25 -0300709 if (t->index) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
711 return -EINVAL;
712 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300713
Hans Verkuil707ecf42008-09-06 15:40:25 -0300714 mxb->cur_mode = t->audmode;
715 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 return 0;
717 }
718 case VIDIOC_G_FREQUENCY:
719 {
720 struct v4l2_frequency *f = arg;
721
722 if(0 != mxb->cur_input) {
723 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
724 return -EINVAL;
725 }
726
Michael Hunold9d2599d2005-07-27 11:46:00 -0700727 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Michael Hunold9d2599d2005-07-27 11:46:00 -0700729 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return 0;
731 }
732 case VIDIOC_S_FREQUENCY:
733 {
734 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 if (0 != f->tuner)
737 return -EINVAL;
738
739 if (V4L2_TUNER_ANALOG_TV != f->type)
740 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300741
Hans Verkuil707ecf42008-09-06 15:40:25 -0300742 if (mxb->cur_input) {
743 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 return -EINVAL;
745 }
746
Michael Hunold9d2599d2005-07-27 11:46:00 -0700747 mxb->cur_freq = *f;
748 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300750 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700751 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
753 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
754 spin_lock(&dev->slock);
755 vv->vbi_fieldcount = 0;
756 spin_unlock(&dev->slock);
757
758 return 0;
759 }
760 case MXB_S_AUDIO_CD:
761 {
762 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300763
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 if( i < 0 || i >= MXB_AUDIOS ) {
765 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
766 return -EINVAL;
767 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
770
771 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
772 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
773
774 return 0;
775 }
776 case MXB_S_AUDIO_LINE:
777 {
778 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 if( i < 0 || i >= MXB_AUDIOS ) {
781 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
782 return -EINVAL;
783 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
786 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
787 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
788
789 return 0;
790 }
791 case VIDIOC_G_AUDIO:
792 {
793 struct v4l2_audio *a = arg;
794
795 if( a->index < 0 || a->index > MXB_INPUTS ) {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300796 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 return -EINVAL;
798 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300799
800 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return 0;
804 }
805 case VIDIOC_S_AUDIO:
806 {
807 struct v4l2_audio *a = arg;
808 DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
809 return 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300810 }
Hans Verkuil707ecf42008-09-06 15:40:25 -0300811 case VIDIOC_DBG_S_REGISTER:
812 case VIDIOC_DBG_G_REGISTER:
813 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
814 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 default:
816/*
817 DEB2(printk("does not handle this ioctl.\n"));
818*/
819 return -ENOIOCTLCMD;
820 }
821 return 0;
822}
823
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300824static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825{
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300826 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 int zero = 0;
828 int one = 1;
829
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300830 if (V4L2_STD_PAL_I == standard->id) {
Michael Hunold6acaba82006-03-13 21:20:41 -0800831 v4l2_std_id std = V4L2_STD_PAL_I;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
834 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300835 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 /* unset the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300837 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
Michael Hunold6acaba82006-03-13 21:20:41 -0800838 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800840 v4l2_std_id std = V4L2_STD_PAL_BG;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
843 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300844 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 /* set the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300846 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
Michael Hunold6acaba82006-03-13 21:20:41 -0800847 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 return 0;
850}
851
852static struct saa7146_standard standard[] = {
853 {
854 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
855 .v_offset = 0x17, .v_field = 288,
856 .h_offset = 0x14, .h_pixels = 680,
857 .v_max_out = 576, .h_max_out = 768,
858 }, {
859 .name = "PAL-I", .id = V4L2_STD_PAL_I,
860 .v_offset = 0x17, .v_field = 288,
861 .h_offset = 0x14, .h_pixels = 680,
862 .v_max_out = 576, .h_max_out = 768,
863 }, {
864 .name = "NTSC", .id = V4L2_STD_NTSC,
865 .v_offset = 0x16, .v_field = 240,
866 .h_offset = 0x06, .h_pixels = 708,
867 .v_max_out = 480, .h_max_out = 640,
868 }, {
869 .name = "SECAM", .id = V4L2_STD_SECAM,
870 .v_offset = 0x14, .v_field = 288,
871 .h_offset = 0x14, .h_pixels = 720,
872 .v_max_out = 576, .h_max_out = 768,
873 }
874};
875
876static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300877 .ext_priv = "Multimedia eXtension Board",
878 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879};
880
881static struct pci_device_id pci_tbl[] = {
882 {
883 .vendor = PCI_VENDOR_ID_PHILIPS,
884 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
885 .subvendor = 0x0000,
886 .subdevice = 0x0000,
887 .driver_data = (unsigned long)&mxb,
888 }, {
889 .vendor = 0,
890 }
891};
892
893MODULE_DEVICE_TABLE(pci, pci_tbl);
894
895static struct saa7146_ext_vv vv_data = {
896 .inputs = MXB_INPUTS,
897 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
898 .stds = &standard[0],
899 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300900 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 .ioctls = &ioctls[0],
902 .ioctl = mxb_ioctl,
903};
904
905static struct saa7146_extension extension = {
906 .name = MXB_IDENTIFIER,
907 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 .pci_tbl = &pci_tbl[0],
910 .module = THIS_MODULE,
911
912 .probe = mxb_probe,
913 .attach = mxb_attach,
914 .detach = mxb_detach,
915
916 .irq_mask = 0,
917 .irq_func = NULL,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300918};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920static int __init mxb_init_module(void)
921{
922 if( 0 != saa7146_register_extension(&extension)) {
923 DEB_S(("failed to register extension.\n"));
924 return -ENODEV;
925 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return 0;
928}
929
930static void __exit mxb_cleanup_module(void)
931{
932 saa7146_unregister_extension(&extension);
933}
934
935module_init(mxb_init_module);
936module_exit(mxb_cleanup_module);
937
938MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
939MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
940MODULE_LICENSE("GPL");