blob: b2dae5062e65cf1ff1974a99b459406ddbc34efa [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
Hans Verkuil26338122008-09-06 17:24:30 -0300140 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
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{
Hans Verkuil26338122008-09-06 17:24:30 -0300157 struct mxb *mxb = data;
Jean Delvare961f80f2008-01-27 18:14:51 +0100158 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 } },
Hans Verkuil26338122008-09-06 17:24:30 -0300301 {-1, { 0 } }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302};
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;
Hans Verkuil26338122008-09-06 17:24:30 -0300317 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 /* select video mode in saa7111a */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300320 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 /* select tuner-output on saa7111a */
323 i = 0;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300324 route.input = SAA7115_COMPOSITE0;
325 route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
326 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
328 /* select a tuner type */
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700329 tun_setup.mode_mask = T_ANALOG_TV;
330 tun_setup.addr = ADDR_UNSET;
Michael Hunold9d2599d2005-07-27 11:46:00 -0700331 tun_setup.type = TUNER_PHILIPS_PAL;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300332 mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
Michael Hunold9d2599d2005-07-27 11:46:00 -0700333 /* tune in some frequency on tuner */
334 mxb->cur_freq.tuner = 0;
335 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
336 mxb->cur_freq.frequency = freq;
337 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
338 &mxb->cur_freq);
339
Michael Hunold6acaba82006-03-13 21:20:41 -0800340 /* set a default video standard */
341 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
342
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 /* mute audio on tea6420s */
Hans Verkuil26338122008-09-06 17:24:30 -0300344 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
345 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
346 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
347 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 /* switch to tuner-channel on tea6415c*/
350 vm.out = 17;
351 vm.in = 3;
Hans Verkuil26338122008-09-06 17:24:30 -0300352 mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
354 /* select tuner-output on multicable on tea6415c*/
355 vm.in = 3;
356 vm.out = 13;
Hans Verkuil26338122008-09-06 17:24:30 -0300357 mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 /* the rest for mxb */
360 mxb->cur_input = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 mxb->cur_mute = 1;
362
363 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 /* check if the saa7740 (aka 'sound arena module') is present
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300366 on the mxb. if so, we must initialize it. due to lack of
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 informations about the saa7740, the values were reverse
368 engineered. */
369 msg.addr = 0x1b;
370 msg.flags = 0;
371 msg.len = mxb_saa7740_init[0].length;
372 msg.buf = &mxb_saa7740_init[0].data[0];
373
Hans Verkuil26338122008-09-06 17:24:30 -0300374 err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
375 if (err == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 /* 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;
Hans Verkuil26338122008-09-06 17:24:30 -0300382 for (i = 1; ; i++) {
383 if (-1 == mxb_saa7740_init[i].length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300386 msg.len = mxb_saa7740_init[i].length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 msg.buf = &mxb_saa7740_init[i].data[0];
Hans Verkuil26338122008-09-06 17:24:30 -0300388 err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
389 if (err != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 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 */
Hans Verkuil26338122008-09-06 17:24:30 -0300403 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
404 input_port_selection[mxb->cur_input].hps_sync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405
406 /* some stuff is done via direct write to the registers */
407
408 /* this is ugly, but because of the fact that this is completely
409 hardware dependend, it should be done directly... */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300410 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 saa7146_write(dev, DD1_INIT, 0x02000200);
412 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
413
414 return 0;
415}
416
417/* interrupt-handler. this gets called when irq_mask is != 0.
418 it must clear the interrupt-bits in irq_mask it has handled */
419/*
420void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
421{
422 struct mxb* mxb = (struct mxb*)dev->ext_priv;
423}
424*/
425
426static struct saa7146_ext_vv vv_data;
427
428/* this function only gets called when the probing was successful */
Hans Verkuil26338122008-09-06 17:24:30 -0300429static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
Hans Verkuil26338122008-09-06 17:24:30 -0300431 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300432
Hans Verkuil26338122008-09-06 17:24:30 -0300433 DEB_EE(("dev:%p\n", dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
435 /* checking for i2c-devices can be omitted here, because we
436 already did this in "mxb_vl42_probe" */
437
Hans Verkuila8327812008-07-25 10:31:23 -0300438 saa7146_vv_init(dev, &vv_data);
439 if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 ERR(("cannot register capture v4l2 device. skipping.\n"));
441 return -1;
442 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
Hans Verkuila8327812008-07-25 10:31:23 -0300445 if (MXB_BOARD_CAN_DO_VBI(dev)) {
446 if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 ERR(("cannot register vbi v4l2 device. skipping.\n"));
448 }
449 }
450
451 i2c_use_client(mxb->tea6420_1);
452 i2c_use_client(mxb->tea6420_2);
453 i2c_use_client(mxb->tea6415c);
454 i2c_use_client(mxb->tda9840);
455 i2c_use_client(mxb->saa7111a);
456 i2c_use_client(mxb->tuner);
457
Hans Verkuila8327812008-07-25 10:31:23 -0300458 printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 mxb_num++;
461 mxb_init_done(dev);
462 return 0;
463}
464
Hans Verkuil26338122008-09-06 17:24:30 -0300465static int mxb_detach(struct saa7146_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Hans Verkuil26338122008-09-06 17:24:30 -0300467 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
Hans Verkuil26338122008-09-06 17:24:30 -0300469 DEB_EE(("dev:%p\n", dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470
471 i2c_release_client(mxb->tea6420_1);
472 i2c_release_client(mxb->tea6420_2);
473 i2c_release_client(mxb->tea6415c);
474 i2c_release_client(mxb->tda9840);
475 i2c_release_client(mxb->saa7111a);
476 i2c_release_client(mxb->tuner);
477
478 saa7146_unregister_device(&mxb->video_dev,dev);
Hans Verkuil26338122008-09-06 17:24:30 -0300479 if (MXB_BOARD_CAN_DO_VBI(dev))
480 saa7146_unregister_device(&mxb->vbi_dev, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 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;
Hans Verkuil26338122008-09-06 17:24:30 -0300494 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));
Hans Verkuil26338122008-09-06 17:24:30 -0300503 if (i->index < 0 || i->index >= MXB_INPUTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 return 0;
507 }
508 /* the saa7146 provides some controls (brightness, contrast, saturation)
509 which gets registered *after* this function. because of this we have
510 to return with a value != 0 even if the function succeded.. */
511 case VIDIOC_QUERYCTRL:
512 {
513 struct v4l2_queryctrl *qc = arg;
514 int i;
515
516 for (i = MAXCONTROLS - 1; i >= 0; i--) {
517 if (mxb_controls[i].id == qc->id) {
518 *qc = mxb_controls[i];
Hans Verkuil26338122008-09-06 17:24:30 -0300519 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 return 0;
521 }
522 }
523 return -EAGAIN;
524 }
525 case VIDIOC_G_CTRL:
526 {
527 struct v4l2_control *vc = arg;
528 int i;
529
530 for (i = MAXCONTROLS - 1; i >= 0; i--) {
Hans Verkuil26338122008-09-06 17:24:30 -0300531 if (mxb_controls[i].id == vc->id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300534
Hans Verkuil26338122008-09-06 17:24:30 -0300535 if (i < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 return -EAGAIN;
Hans Verkuil26338122008-09-06 17:24:30 -0300537
538 if (vc->id == V4L2_CID_AUDIO_MUTE) {
539 vc->value = mxb->cur_mute;
540 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
541 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300543
Hans Verkuil26338122008-09-06 17:24:30 -0300544 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return 0;
546 }
547
548 case VIDIOC_S_CTRL:
549 {
Hans Verkuil26338122008-09-06 17:24:30 -0300550 struct v4l2_control *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 for (i = MAXCONTROLS - 1; i >= 0; i--) {
Hans Verkuil26338122008-09-06 17:24:30 -0300554 if (mxb_controls[i].id == vc->id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300557
Hans Verkuil26338122008-09-06 17:24:30 -0300558 if (i < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return -EAGAIN;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300560
Hans Verkuil26338122008-09-06 17:24:30 -0300561 if (vc->id == V4L2_CID_AUDIO_MUTE) {
562 mxb->cur_mute = vc->value;
563 if (!vc->value) {
564 /* switch the audio-source */
565 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
566 &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
567 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
568 &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
569 } else {
570 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
571 &TEA6420_line[6][0]);
572 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
573 &TEA6420_line[6][1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 }
Hans Verkuil26338122008-09-06 17:24:30 -0300575 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 }
577 return 0;
578 }
579 case VIDIOC_G_INPUT:
580 {
581 int *input = (int *)arg;
582 *input = mxb->cur_input;
583
Hans Verkuil26338122008-09-06 17:24:30 -0300584 DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300585 return 0;
586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 case VIDIOC_S_INPUT:
588 {
589 int input = *(int *)arg;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300590 struct tea6415c_multiplex vm;
591 struct v4l2_routing route;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 int i = 0;
593
Hans Verkuil26338122008-09-06 17:24:30 -0300594 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Hans Verkuil26338122008-09-06 17:24:30 -0300596 if (input < 0 || input >= MXB_INPUTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300600
Hans Verkuil26338122008-09-06 17:24:30 -0300601 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
602 input_port_selection[input].hps_sync);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300603
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 /* prepare switching of tea6415c and saa7111a;
605 have a look at the 'background'-file for further informations */
Hans Verkuil26338122008-09-06 17:24:30 -0300606 switch (input) {
607 case TUNER:
608 i = SAA7115_COMPOSITE0;
609 vm.in = 3;
610 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300611
Hans Verkuil26338122008-09-06 17:24:30 -0300612 if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
613 printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
614 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
Hans Verkuil26338122008-09-06 17:24:30 -0300616 /* connect tuner-output always to multicable */
617 vm.in = 3;
618 vm.out = 13;
619 break;
620 case AUX3_YC:
621 /* nothing to be done here. aux3_yc is
622 directly connected to the saa711a */
623 i = SAA7115_SVIDEO1;
624 break;
625 case AUX3:
626 /* nothing to be done here. aux3 is
627 directly connected to the saa711a */
628 i = SAA7115_COMPOSITE1;
629 break;
630 case AUX1:
631 i = SAA7115_COMPOSITE0;
632 vm.in = 1;
633 vm.out = 17;
634 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 }
636
637 /* switch video in tea6415c only if necessary */
Hans Verkuil26338122008-09-06 17:24:30 -0300638 switch (input) {
639 case TUNER:
640 case AUX1:
641 if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
642 printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
643 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
Hans Verkuil26338122008-09-06 17:24:30 -0300645 break;
646 default:
647 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300649
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 /* switch video in saa7111a */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300651 route.input = i;
652 route.output = 0;
653 if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 /* switch the audio-source only if necessary */
657 if( 0 == mxb->cur_mute ) {
Hans Verkuil26338122008-09-06 17:24:30 -0300658 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
659 &TEA6420_line[video_audio_connect[input]][0]);
660 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
661 &TEA6420_line[video_audio_connect[input]][1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 }
663
664 return 0;
665 }
666 case VIDIOC_G_TUNER:
667 {
668 struct v4l2_tuner *t = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Hans Verkuil707ecf42008-09-06 15:40:25 -0300670 if (t->index) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
672 return -EINVAL;
673 }
674
675 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
676
Hans Verkuil707ecf42008-09-06 15:40:25 -0300677 memset(t, 0, sizeof(*t));
678 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Hans Verkuil707ecf42008-09-06 15:40:25 -0300680 strlcpy(t->name, "TV Tuner", sizeof(t->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 t->type = V4L2_TUNER_ANALOG_TV;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300682 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
683 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 t->audmode = mxb->cur_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return 0;
686 }
687 case VIDIOC_S_TUNER:
688 {
689 struct v4l2_tuner *t = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300690
Hans Verkuil707ecf42008-09-06 15:40:25 -0300691 if (t->index) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
693 return -EINVAL;
694 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300695
Hans Verkuil707ecf42008-09-06 15:40:25 -0300696 mxb->cur_mode = t->audmode;
697 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 return 0;
699 }
700 case VIDIOC_G_FREQUENCY:
701 {
702 struct v4l2_frequency *f = arg;
703
Hans Verkuil26338122008-09-06 17:24:30 -0300704 if (mxb->cur_input) {
705 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
706 mxb->cur_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 return -EINVAL;
708 }
709
Michael Hunold9d2599d2005-07-27 11:46:00 -0700710 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Michael Hunold9d2599d2005-07-27 11:46:00 -0700712 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 return 0;
714 }
715 case VIDIOC_S_FREQUENCY:
716 {
717 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Hans Verkuil26338122008-09-06 17:24:30 -0300719 if (f->tuner)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return -EINVAL;
721
722 if (V4L2_TUNER_ANALOG_TV != f->type)
723 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300724
Hans Verkuil707ecf42008-09-06 15:40:25 -0300725 if (mxb->cur_input) {
726 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return -EINVAL;
728 }
729
Michael Hunold9d2599d2005-07-27 11:46:00 -0700730 mxb->cur_freq = *f;
731 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300733 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700734 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
737 spin_lock(&dev->slock);
738 vv->vbi_fieldcount = 0;
739 spin_unlock(&dev->slock);
740
741 return 0;
742 }
743 case MXB_S_AUDIO_CD:
744 {
745 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300746
Hans Verkuil26338122008-09-06 17:24:30 -0300747 if (i < 0 || i >= MXB_AUDIOS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
749 return -EINVAL;
750 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
753
754 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
755 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
756
757 return 0;
758 }
759 case MXB_S_AUDIO_LINE:
760 {
761 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300762
Hans Verkuil26338122008-09-06 17:24:30 -0300763 if (i < 0 || i >= MXB_AUDIOS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
765 return -EINVAL;
766 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
769 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
770 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
771
772 return 0;
773 }
774 case VIDIOC_G_AUDIO:
775 {
776 struct v4l2_audio *a = arg;
777
Hans Verkuil26338122008-09-06 17:24:30 -0300778 if (a->index < 0 || a->index > MXB_INPUTS) {
779 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return -EINVAL;
781 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300782
Hans Verkuil26338122008-09-06 17:24:30 -0300783 DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300785
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 return 0;
787 }
788 case VIDIOC_S_AUDIO:
789 {
790 struct v4l2_audio *a = arg;
Hans Verkuil26338122008-09-06 17:24:30 -0300791
792 DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 return 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300794 }
Hans Verkuil26338122008-09-06 17:24:30 -0300795#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuil707ecf42008-09-06 15:40:25 -0300796 case VIDIOC_DBG_S_REGISTER:
797 case VIDIOC_DBG_G_REGISTER:
798 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Hans Verkuil26338122008-09-06 17:24:30 -0300799 return 0;
800#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 default:
802/*
803 DEB2(printk("does not handle this ioctl.\n"));
804*/
805 return -ENOIOCTLCMD;
806 }
807 return 0;
808}
809
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300810static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300812 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 int zero = 0;
814 int one = 1;
815
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300816 if (V4L2_STD_PAL_I == standard->id) {
Michael Hunold6acaba82006-03-13 21:20:41 -0800817 v4l2_std_id std = V4L2_STD_PAL_I;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
820 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300821 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 /* unset the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300823 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
Michael Hunold6acaba82006-03-13 21:20:41 -0800824 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800826 v4l2_std_id std = V4L2_STD_PAL_BG;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300827
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
829 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300830 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 /* set the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300832 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
Michael Hunold6acaba82006-03-13 21:20:41 -0800833 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 }
835 return 0;
836}
837
838static struct saa7146_standard standard[] = {
839 {
840 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
841 .v_offset = 0x17, .v_field = 288,
842 .h_offset = 0x14, .h_pixels = 680,
843 .v_max_out = 576, .h_max_out = 768,
844 }, {
845 .name = "PAL-I", .id = V4L2_STD_PAL_I,
846 .v_offset = 0x17, .v_field = 288,
847 .h_offset = 0x14, .h_pixels = 680,
848 .v_max_out = 576, .h_max_out = 768,
849 }, {
850 .name = "NTSC", .id = V4L2_STD_NTSC,
851 .v_offset = 0x16, .v_field = 240,
852 .h_offset = 0x06, .h_pixels = 708,
853 .v_max_out = 480, .h_max_out = 640,
854 }, {
855 .name = "SECAM", .id = V4L2_STD_SECAM,
856 .v_offset = 0x14, .v_field = 288,
857 .h_offset = 0x14, .h_pixels = 720,
858 .v_max_out = 576, .h_max_out = 768,
859 }
860};
861
862static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300863 .ext_priv = "Multimedia eXtension Board",
864 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865};
866
867static struct pci_device_id pci_tbl[] = {
868 {
869 .vendor = PCI_VENDOR_ID_PHILIPS,
870 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
871 .subvendor = 0x0000,
872 .subdevice = 0x0000,
873 .driver_data = (unsigned long)&mxb,
874 }, {
875 .vendor = 0,
876 }
877};
878
879MODULE_DEVICE_TABLE(pci, pci_tbl);
880
881static struct saa7146_ext_vv vv_data = {
882 .inputs = MXB_INPUTS,
883 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
884 .stds = &standard[0],
885 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300886 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 .ioctls = &ioctls[0],
888 .ioctl = mxb_ioctl,
889};
890
891static struct saa7146_extension extension = {
892 .name = MXB_IDENTIFIER,
893 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300894
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 .pci_tbl = &pci_tbl[0],
896 .module = THIS_MODULE,
897
898 .probe = mxb_probe,
899 .attach = mxb_attach,
900 .detach = mxb_detach,
901
902 .irq_mask = 0,
903 .irq_func = NULL,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300904};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906static int __init mxb_init_module(void)
907{
Hans Verkuil26338122008-09-06 17:24:30 -0300908 if (saa7146_register_extension(&extension)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 DEB_S(("failed to register extension.\n"));
910 return -ENODEV;
911 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 return 0;
914}
915
916static void __exit mxb_cleanup_module(void)
917{
918 saa7146_unregister_extension(&extension);
919}
920
921module_init(mxb_init_module);
922module_exit(mxb_cleanup_module);
923
924MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
925MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
926MODULE_LICENSE("GPL");