blob: e3cbe14c349a788288987200be077322e7ecf3d1 [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,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 };
219
Hans Verkuil9ebeae52008-09-07 08:32:44 -0300220 snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
223 if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
224 DEB_S(("cannot register i2c-device. skipping.\n"));
225 kfree(mxb);
226 return -EFAULT;
227 }
228
229 /* loop through all i2c-devices on the bus and look who is there */
Jean Delvare961f80f2008-01-27 18:14:51 +0100230 device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 /* check if all devices are present */
Al Viro5fa12472008-03-29 03:07:38 +0000233 if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
234 !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 printk("mxb: did not find all i2c devices. aborting\n");
236 i2c_del_adapter(&mxb->i2c_adapter);
237 kfree(mxb);
238 return -ENODEV;
239 }
240
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300241 /* all devices are present, probe was successful */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 /* we store the pointer in our private data field */
244 dev->ext_priv = mxb;
245
246 return 0;
247}
248
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300249/* some init data for the saa7740, the so-called 'sound arena module'.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 there are no specs available, so we simply use some init values */
251static struct {
252 int length;
253 char data[9];
254} mxb_saa7740_init[] = {
255 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
256 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
257 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
258 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
259 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
260 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
261 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
262 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
263 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
264 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
265 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
266 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
267 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
268 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
269 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
270 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
271 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
272 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
273 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
274 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
275 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
276 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
277 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
278 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
279 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
280 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
281 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
282 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
283 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
284 { 3, { 0x48, 0x00, 0x01 } },
285 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
286 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
287 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
288 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
289 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
290 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
291 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
292 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
293 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
294 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
295 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
296 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
297 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
298 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
299 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
300 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
301 { 3, { 0x80, 0xb3, 0x0a } },
Hans Verkuil26338122008-09-06 17:24:30 -0300302 {-1, { 0 } }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303};
304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305/* bring hardware to a sane state. this has to be done, just in case someone
306 wants to capture from this device before it has been properly initialized.
307 the capture engine would badly fail, because no valid signal arrives on the
308 saa7146, thus leading to timeouts and stuff. */
309static int mxb_init_done(struct saa7146_dev* dev)
310{
311 struct mxb* mxb = (struct mxb*)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct i2c_msg msg;
Mauro Carvalho Chehab85369df2005-07-12 13:58:59 -0700313 struct tuner_setup tun_setup;
Michael Hunold6acaba82006-03-13 21:20:41 -0800314 v4l2_std_id std = V4L2_STD_PAL_BG;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300315 struct v4l2_routing route;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 int i = 0, err = 0;
Hans Verkuil26338122008-09-06 17:24:30 -0300318 struct tea6415c_multiplex vm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 /* select video mode in saa7111a */
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 */
Hans Verkuil26338122008-09-06 17:24:30 -0300345 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]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349
350 /* switch to tuner-channel on tea6415c*/
351 vm.out = 17;
352 vm.in = 3;
Hans Verkuil26338122008-09-06 17:24:30 -0300353 mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355 /* select tuner-output on multicable on tea6415c*/
356 vm.in = 3;
357 vm.out = 13;
Hans Verkuil26338122008-09-06 17:24:30 -0300358 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
Hans Verkuil26338122008-09-06 17:24:30 -0300375 err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
376 if (err == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 /* the sound arena module is a pos, that's probably the reason
378 philips refuses to hand out a datasheet for the saa7740...
379 it seems to screw up the i2c bus, so we disable fast irq
380 based i2c transactions here and rely on the slow and safe
381 polling method ... */
382 extension.flags &= ~SAA7146_USE_I2C_IRQ;
Hans Verkuil26338122008-09-06 17:24:30 -0300383 for (i = 1; ; i++) {
384 if (-1 == mxb_saa7740_init[i].length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
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];
Hans Verkuil26338122008-09-06 17:24:30 -0300389 err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
390 if (err != 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 DEB_D(("failed to initialize 'sound arena module'.\n"));
392 goto err;
393 }
394 }
395 INFO(("'sound arena module' detected.\n"));
396 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300397err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 /* the rest for saa7146: you should definitely set some basic values
399 for the input-port handling of the saa7146. */
400
401 /* ext->saa has been filled by the core driver */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 /* some stuff is done via variables */
Hans Verkuil26338122008-09-06 17:24:30 -0300404 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
405 input_port_selection[mxb->cur_input].hps_sync);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
407 /* some stuff is done via direct write to the registers */
408
409 /* this is ugly, but because of the fact that this is completely
410 hardware dependend, it should be done directly... */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300411 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 saa7146_write(dev, DD1_INIT, 0x02000200);
413 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
414
415 return 0;
416}
417
418/* interrupt-handler. this gets called when irq_mask is != 0.
419 it must clear the interrupt-bits in irq_mask it has handled */
420/*
421void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
422{
423 struct mxb* mxb = (struct mxb*)dev->ext_priv;
424}
425*/
426
427static struct saa7146_ext_vv vv_data;
428
429/* this function only gets called when the probing was successful */
Hans Verkuil26338122008-09-06 17:24:30 -0300430static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Hans Verkuil26338122008-09-06 17:24:30 -0300432 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300433
Hans Verkuil26338122008-09-06 17:24:30 -0300434 DEB_EE(("dev:%p\n", dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 /* checking for i2c-devices can be omitted here, because we
437 already did this in "mxb_vl42_probe" */
438
Hans Verkuila8327812008-07-25 10:31:23 -0300439 saa7146_vv_init(dev, &vv_data);
440 if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 ERR(("cannot register capture v4l2 device. skipping.\n"));
442 return -1;
443 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300444
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
Hans Verkuila8327812008-07-25 10:31:23 -0300446 if (MXB_BOARD_CAN_DO_VBI(dev)) {
447 if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 ERR(("cannot register vbi v4l2 device. skipping.\n"));
449 }
450 }
451
452 i2c_use_client(mxb->tea6420_1);
453 i2c_use_client(mxb->tea6420_2);
454 i2c_use_client(mxb->tea6415c);
455 i2c_use_client(mxb->tda9840);
456 i2c_use_client(mxb->saa7111a);
457 i2c_use_client(mxb->tuner);
458
Hans Verkuila8327812008-07-25 10:31:23 -0300459 printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 mxb_num++;
462 mxb_init_done(dev);
463 return 0;
464}
465
Hans Verkuil26338122008-09-06 17:24:30 -0300466static int mxb_detach(struct saa7146_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
Hans Verkuil26338122008-09-06 17:24:30 -0300468 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
Hans Verkuil26338122008-09-06 17:24:30 -0300470 DEB_EE(("dev:%p\n", dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 i2c_release_client(mxb->tea6420_1);
473 i2c_release_client(mxb->tea6420_2);
474 i2c_release_client(mxb->tea6415c);
475 i2c_release_client(mxb->tda9840);
476 i2c_release_client(mxb->saa7111a);
477 i2c_release_client(mxb->tuner);
478
479 saa7146_unregister_device(&mxb->video_dev,dev);
Hans Verkuil26338122008-09-06 17:24:30 -0300480 if (MXB_BOARD_CAN_DO_VBI(dev))
481 saa7146_unregister_device(&mxb->vbi_dev, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 saa7146_vv_release(dev);
483
484 mxb_num--;
485
486 i2c_del_adapter(&mxb->i2c_adapter);
487 kfree(mxb);
488
489 return 0;
490}
491
Hans Verkuil069b7472008-12-30 07:04:34 -0300492static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493{
494 struct saa7146_dev *dev = fh->dev;
Hans Verkuil26338122008-09-06 17:24:30 -0300495 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300496 struct saa7146_vv *vv = dev->vv_data;
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 switch(cmd) {
499 case VIDIOC_ENUMINPUT:
500 {
501 struct v4l2_input *i = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
Hans Verkuil26338122008-09-06 17:24:30 -0300504 if (i->index < 0 || i->index >= MXB_INPUTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 return 0;
508 }
509 /* the saa7146 provides some controls (brightness, contrast, saturation)
510 which gets registered *after* this function. because of this we have
511 to return with a value != 0 even if the function succeded.. */
512 case VIDIOC_QUERYCTRL:
513 {
514 struct v4l2_queryctrl *qc = arg;
515 int i;
516
517 for (i = MAXCONTROLS - 1; i >= 0; i--) {
518 if (mxb_controls[i].id == qc->id) {
519 *qc = mxb_controls[i];
Hans Verkuil26338122008-09-06 17:24:30 -0300520 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 return 0;
522 }
523 }
524 return -EAGAIN;
525 }
526 case VIDIOC_G_CTRL:
527 {
528 struct v4l2_control *vc = arg;
529 int i;
530
531 for (i = MAXCONTROLS - 1; i >= 0; i--) {
Hans Verkuil26338122008-09-06 17:24:30 -0300532 if (mxb_controls[i].id == vc->id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300535
Hans Verkuil26338122008-09-06 17:24:30 -0300536 if (i < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return -EAGAIN;
Hans Verkuil26338122008-09-06 17:24:30 -0300538
539 if (vc->id == V4L2_CID_AUDIO_MUTE) {
540 vc->value = mxb->cur_mute;
541 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
542 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300544
Hans Verkuil26338122008-09-06 17:24:30 -0300545 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 return 0;
547 }
548
549 case VIDIOC_S_CTRL:
550 {
Hans Verkuil26338122008-09-06 17:24:30 -0300551 struct v4l2_control *vc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 int i = 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300553
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 for (i = MAXCONTROLS - 1; i >= 0; i--) {
Hans Verkuil26338122008-09-06 17:24:30 -0300555 if (mxb_controls[i].id == vc->id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300558
Hans Verkuil26338122008-09-06 17:24:30 -0300559 if (i < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 return -EAGAIN;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300561
Hans Verkuil26338122008-09-06 17:24:30 -0300562 if (vc->id == V4L2_CID_AUDIO_MUTE) {
563 mxb->cur_mute = vc->value;
564 if (!vc->value) {
565 /* switch the audio-source */
566 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
567 &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
568 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
569 &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
570 } else {
571 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
572 &TEA6420_line[6][0]);
573 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
574 &TEA6420_line[6][1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 }
Hans Verkuil26338122008-09-06 17:24:30 -0300576 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
578 return 0;
579 }
580 case VIDIOC_G_INPUT:
581 {
582 int *input = (int *)arg;
583 *input = mxb->cur_input;
584
Hans Verkuil26338122008-09-06 17:24:30 -0300585 DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300586 return 0;
587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 case VIDIOC_S_INPUT:
589 {
590 int input = *(int *)arg;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300591 struct tea6415c_multiplex vm;
592 struct v4l2_routing route;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 int i = 0;
594
Hans Verkuil26338122008-09-06 17:24:30 -0300595 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Hans Verkuil26338122008-09-06 17:24:30 -0300597 if (input < 0 || input >= MXB_INPUTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300599
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 mxb->cur_input = input;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300601
Hans Verkuil26338122008-09-06 17:24:30 -0300602 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
603 input_port_selection[input].hps_sync);
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300604
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 /* prepare switching of tea6415c and saa7111a;
606 have a look at the 'background'-file for further informations */
Hans Verkuil26338122008-09-06 17:24:30 -0300607 switch (input) {
608 case TUNER:
609 i = SAA7115_COMPOSITE0;
610 vm.in = 3;
611 vm.out = 17;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300612
Hans Verkuil26338122008-09-06 17:24:30 -0300613 if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
614 printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
615 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 }
Hans Verkuil26338122008-09-06 17:24:30 -0300617 /* connect tuner-output always to multicable */
618 vm.in = 3;
619 vm.out = 13;
620 break;
621 case AUX3_YC:
622 /* nothing to be done here. aux3_yc is
623 directly connected to the saa711a */
624 i = SAA7115_SVIDEO1;
625 break;
626 case AUX3:
627 /* nothing to be done here. aux3 is
628 directly connected to the saa711a */
629 i = SAA7115_COMPOSITE1;
630 break;
631 case AUX1:
632 i = SAA7115_COMPOSITE0;
633 vm.in = 1;
634 vm.out = 17;
635 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
637
638 /* switch video in tea6415c only if necessary */
Hans Verkuil26338122008-09-06 17:24:30 -0300639 switch (input) {
640 case TUNER:
641 case AUX1:
642 if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
643 printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
644 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 }
Hans Verkuil26338122008-09-06 17:24:30 -0300646 break;
647 default:
648 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300650
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 /* switch video in saa7111a */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300652 route.input = i;
653 route.output = 0;
654 if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 /* switch the audio-source only if necessary */
658 if( 0 == mxb->cur_mute ) {
Hans Verkuil26338122008-09-06 17:24:30 -0300659 mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
660 &TEA6420_line[video_audio_connect[input]][0]);
661 mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
662 &TEA6420_line[video_audio_connect[input]][1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
664
665 return 0;
666 }
667 case VIDIOC_G_TUNER:
668 {
669 struct v4l2_tuner *t = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Hans Verkuil707ecf42008-09-06 15:40:25 -0300671 if (t->index) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
673 return -EINVAL;
674 }
675
676 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
677
Hans Verkuil707ecf42008-09-06 15:40:25 -0300678 memset(t, 0, sizeof(*t));
679 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Hans Verkuil707ecf42008-09-06 15:40:25 -0300681 strlcpy(t->name, "TV Tuner", sizeof(t->name));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 t->type = V4L2_TUNER_ANALOG_TV;
Hans Verkuil707ecf42008-09-06 15:40:25 -0300683 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
684 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 t->audmode = mxb->cur_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return 0;
687 }
688 case VIDIOC_S_TUNER:
689 {
690 struct v4l2_tuner *t = arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300691
Hans Verkuil707ecf42008-09-06 15:40:25 -0300692 if (t->index) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
694 return -EINVAL;
695 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300696
Hans Verkuil707ecf42008-09-06 15:40:25 -0300697 mxb->cur_mode = t->audmode;
698 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 return 0;
700 }
701 case VIDIOC_G_FREQUENCY:
702 {
703 struct v4l2_frequency *f = arg;
704
Hans Verkuil26338122008-09-06 17:24:30 -0300705 if (mxb->cur_input) {
706 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
707 mxb->cur_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 return -EINVAL;
709 }
710
Michael Hunold9d2599d2005-07-27 11:46:00 -0700711 *f = mxb->cur_freq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
Michael Hunold9d2599d2005-07-27 11:46:00 -0700713 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 return 0;
715 }
716 case VIDIOC_S_FREQUENCY:
717 {
718 struct v4l2_frequency *f = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Hans Verkuil26338122008-09-06 17:24:30 -0300720 if (f->tuner)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return -EINVAL;
722
723 if (V4L2_TUNER_ANALOG_TV != f->type)
724 return -EINVAL;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300725
Hans Verkuil707ecf42008-09-06 15:40:25 -0300726 if (mxb->cur_input) {
727 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return -EINVAL;
729 }
730
Michael Hunold9d2599d2005-07-27 11:46:00 -0700731 mxb->cur_freq = *f;
732 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300734 /* tune in desired frequency */
Michael Hunold9d2599d2005-07-27 11:46:00 -0700735 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
737 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
738 spin_lock(&dev->slock);
739 vv->vbi_fieldcount = 0;
740 spin_unlock(&dev->slock);
741
742 return 0;
743 }
744 case MXB_S_AUDIO_CD:
745 {
746 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300747
Hans Verkuil26338122008-09-06 17:24:30 -0300748 if (i < 0 || i >= MXB_AUDIOS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
750 return -EINVAL;
751 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300752
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
754
755 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
756 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
757
758 return 0;
759 }
760 case MXB_S_AUDIO_LINE:
761 {
762 int i = *(int*)arg;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300763
Hans Verkuil26338122008-09-06 17:24:30 -0300764 if (i < 0 || i >= MXB_AUDIOS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: 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_LINE: i:%d.\n",i));
770 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
771 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
772
773 return 0;
774 }
775 case VIDIOC_G_AUDIO:
776 {
777 struct v4l2_audio *a = arg;
778
Hans Verkuil26338122008-09-06 17:24:30 -0300779 if (a->index < 0 || a->index > MXB_INPUTS) {
780 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return -EINVAL;
782 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300783
Hans Verkuil26338122008-09-06 17:24:30 -0300784 DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300786
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 return 0;
788 }
789 case VIDIOC_S_AUDIO:
790 {
791 struct v4l2_audio *a = arg;
Hans Verkuil26338122008-09-06 17:24:30 -0300792
793 DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 return 0;
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300795 }
Hans Verkuil26338122008-09-06 17:24:30 -0300796#ifdef CONFIG_VIDEO_ADV_DEBUG
Hans Verkuil707ecf42008-09-06 15:40:25 -0300797 case VIDIOC_DBG_S_REGISTER:
798 case VIDIOC_DBG_G_REGISTER:
799 i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
Hans Verkuil26338122008-09-06 17:24:30 -0300800 return 0;
801#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 default:
803/*
804 DEB2(printk("does not handle this ioctl.\n"));
805*/
806 return -ENOIOCTLCMD;
807 }
808 return 0;
809}
810
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300811static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300813 struct mxb *mxb = (struct mxb *)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 int zero = 0;
815 int one = 1;
816
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300817 if (V4L2_STD_PAL_I == standard->id) {
Michael Hunold6acaba82006-03-13 21:20:41 -0800818 v4l2_std_id std = V4L2_STD_PAL_I;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
821 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300822 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 /* unset the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300824 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
Michael Hunold6acaba82006-03-13 21:20:41 -0800825 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 } else {
Michael Hunold6acaba82006-03-13 21:20:41 -0800827 v4l2_std_id std = V4L2_STD_PAL_BG;
Hans Verkuilc6eb8ea2008-09-03 17:11:54 -0300828
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
830 /* set the 7146 gpio register -- I don't know what this does exactly */
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300831 saa7146_write(dev, GPIO_CTRL, 0x00404050);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 /* set the 7111 gpio register -- I don't know what this does exactly */
Hans Verkuil707ecf42008-09-06 15:40:25 -0300833 mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
Michael Hunold6acaba82006-03-13 21:20:41 -0800834 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 }
836 return 0;
837}
838
839static struct saa7146_standard standard[] = {
840 {
841 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
842 .v_offset = 0x17, .v_field = 288,
843 .h_offset = 0x14, .h_pixels = 680,
844 .v_max_out = 576, .h_max_out = 768,
845 }, {
846 .name = "PAL-I", .id = V4L2_STD_PAL_I,
847 .v_offset = 0x17, .v_field = 288,
848 .h_offset = 0x14, .h_pixels = 680,
849 .v_max_out = 576, .h_max_out = 768,
850 }, {
851 .name = "NTSC", .id = V4L2_STD_NTSC,
852 .v_offset = 0x16, .v_field = 240,
853 .h_offset = 0x06, .h_pixels = 708,
854 .v_max_out = 480, .h_max_out = 640,
855 }, {
856 .name = "SECAM", .id = V4L2_STD_SECAM,
857 .v_offset = 0x14, .v_field = 288,
858 .h_offset = 0x14, .h_pixels = 720,
859 .v_max_out = 576, .h_max_out = 768,
860 }
861};
862
863static struct saa7146_pci_extension_data mxb = {
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300864 .ext_priv = "Multimedia eXtension Board",
865 .ext = &extension,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866};
867
868static struct pci_device_id pci_tbl[] = {
869 {
870 .vendor = PCI_VENDOR_ID_PHILIPS,
871 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
872 .subvendor = 0x0000,
873 .subdevice = 0x0000,
874 .driver_data = (unsigned long)&mxb,
875 }, {
876 .vendor = 0,
877 }
878};
879
880MODULE_DEVICE_TABLE(pci, pci_tbl);
881
882static struct saa7146_ext_vv vv_data = {
883 .inputs = MXB_INPUTS,
884 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
885 .stds = &standard[0],
886 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300887 .std_callback = &std_callback,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 .ioctls = &ioctls[0],
889 .ioctl = mxb_ioctl,
890};
891
892static struct saa7146_extension extension = {
893 .name = MXB_IDENTIFIER,
894 .flags = SAA7146_USE_I2C_IRQ,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300895
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 .pci_tbl = &pci_tbl[0],
897 .module = THIS_MODULE,
898
899 .probe = mxb_probe,
900 .attach = mxb_attach,
901 .detach = mxb_detach,
902
903 .irq_mask = 0,
904 .irq_func = NULL,
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300905};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
907static int __init mxb_init_module(void)
908{
Hans Verkuil26338122008-09-06 17:24:30 -0300909 if (saa7146_register_extension(&extension)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 DEB_S(("failed to register extension.\n"));
911 return -ENODEV;
912 }
Mauro Carvalho Chehaba8733ca2006-03-17 10:37:02 -0300913
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 return 0;
915}
916
917static void __exit mxb_cleanup_module(void)
918{
919 saa7146_unregister_extension(&extension);
920}
921
922module_init(mxb_init_module);
923module_exit(mxb_cleanup_module);
924
925MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
926MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
927MODULE_LICENSE("GPL");