1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#define DEBUG_VARIABLE debug
25
26#include <media/saa7146_vv.h>
27#include <media/tuner.h>
28#include <media/v4l2-common.h>
29#include <media/saa7115.h>
30
31#include "mxb.h"
32#include "tea6415c.h"
33#include "tea6420.h"
34
35#define I2C_SAA5246A 0x11
36#define I2C_SAA7111A 0x24
37#define I2C_TDA9840 0x42
38#define I2C_TEA6415C 0x43
39#define I2C_TEA6420_1 0x4c
40#define I2C_TEA6420_2 0x4d
41#define I2C_TUNER 0x60
42
43#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
44
45
46static int mxb_num;
47
48
49
50
51static int freq = 4148;
52module_param(freq, int, 0644);
53MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
54
55static int debug;
56module_param(debug, int, 0644);
57MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
58
59#define MXB_INPUTS 4
60enum { TUNER, AUX1, AUX3, AUX3_YC };
61
62static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
63 { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
64 { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
65 { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
66 { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
67};
68
69
70
71static struct {
72 int hps_source;
73 int hps_sync;
74} input_port_selection[MXB_INPUTS] = {
75 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
76 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
77 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
78 { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
79};
80
81
82
83static int video_audio_connect[MXB_INPUTS] =
84 { 0, 1, 3, 3 };
85
86struct mxb_routing {
87 u32 input;
88 u32 output;
89};
90
91
92
93static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
94 { { 1, 1 }, { 1, 1 } },
95 { { 5, 1 }, { 6, 1 } },
96 { { 4, 1 }, { 6, 1 } },
97 { { 3, 1 }, { 6, 1 } },
98 { { 1, 1 }, { 3, 1 } },
99 { { 1, 1 }, { 2, 1 } },
100 { { 6, 1 }, { 6, 1 } }
101};
102
103
104
105static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
106 { { 2, 3 }, { 1, 2 } },
107 { { 5, 3 }, { 6, 2 } },
108 { { 4, 3 }, { 6, 2 } },
109 { { 3, 3 }, { 6, 2 } },
110 { { 2, 3 }, { 3, 2 } },
111 { { 2, 3 }, { 2, 2 } },
112 { { 6, 3 }, { 6, 2 } }
113};
114
115#define MAXCONTROLS 1
116static struct v4l2_queryctrl mxb_controls[] = {
117 { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
118};
119
120struct mxb
121{
122 struct video_device *video_dev;
123 struct video_device *vbi_dev;
124
125 struct i2c_adapter i2c_adapter;
126
127 struct v4l2_subdev *saa7111a;
128 struct v4l2_subdev *tda9840;
129 struct v4l2_subdev *tea6415c;
130 struct v4l2_subdev *tuner;
131 struct v4l2_subdev *tea6420_1;
132 struct v4l2_subdev *tea6420_2;
133
134 int cur_mode;
135 int cur_input;
136 int cur_mute;
137 struct v4l2_frequency cur_freq;
138};
139
140#define saa7111a_call(mxb, o, f, args...) \
141 v4l2_subdev_call(mxb->saa7111a, o, f, ##args)
142#define tda9840_call(mxb, o, f, args...) \
143 v4l2_subdev_call(mxb->tda9840, o, f, ##args)
144#define tea6415c_call(mxb, o, f, args...) \
145 v4l2_subdev_call(mxb->tea6415c, o, f, ##args)
146#define tuner_call(mxb, o, f, args...) \
147 v4l2_subdev_call(mxb->tuner, o, f, ##args)
148#define call_all(dev, o, f, args...) \
149 v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
150
151static inline void tea6420_route_cd(struct mxb *mxb, int idx)
152{
153 v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
154 TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0);
155 v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
156 TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0);
157}
158
159static inline void tea6420_route_line(struct mxb *mxb, int idx)
160{
161 v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
162 TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0);
163 v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
164 TEA6420_line[idx][1].input, TEA6420_line[idx][1].output, 0);
165}
166
167static struct saa7146_extension extension;
168
169static int mxb_probe(struct saa7146_dev *dev)
170{
171 struct mxb *mxb = NULL;
172
173 mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
174 if (mxb == NULL) {
175 DEB_D(("not enough kernel memory.\n"));
176 return -ENOMEM;
177 }
178
179 snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
180
181 saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
182 if (i2c_add_adapter(&mxb->i2c_adapter) < 0) {
183 DEB_S(("cannot register i2c-device. skipping.\n"));
184 kfree(mxb);
185 return -EFAULT;
186 }
187
188 mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
189 "saa7115", "saa7111", I2C_SAA7111A, NULL);
190 mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
191 "tea6420", "tea6420", I2C_TEA6420_1, NULL);
192 mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
193 "tea6420", "tea6420", I2C_TEA6420_2, NULL);
194 mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
195 "tea6415c", "tea6415c", I2C_TEA6415C, NULL);
196 mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
197 "tda9840", "tda9840", I2C_TDA9840, NULL);
198 mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
199 "tuner", "tuner", I2C_TUNER, NULL);
200 if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
201 "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) {
202 printk(KERN_INFO "mxb: found teletext decoder\n");
203 }
204
205
206 if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
207 !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
208 printk("mxb: did not find all i2c devices. aborting\n");
209 i2c_del_adapter(&mxb->i2c_adapter);
210 kfree(mxb);
211 return -ENODEV;
212 }
213
214
215
216
217 dev->ext_priv = mxb;
218
219 return 0;
220}
221
222
223
224static struct {
225 int length;
226 char data[9];
227} mxb_saa7740_init[] = {
228 { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
229 { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
230 { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
231 { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
232 { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
233 { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
234 { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
235 { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
236 { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
237 { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
238 { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
239 { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
240 { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
241 { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
242 { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
243 { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
244 { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
245 { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
246 { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
247 { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
248 { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
249 { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
250 { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
251 { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
252 { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
253 { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
254 { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
255 { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
256 { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
257 { 3, { 0x48, 0x00, 0x01 } },
258 { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
259 { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
260 { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
261 { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
262 { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
263 { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
264 { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
265 { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
266 { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
267 { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
268 { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
269 { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
270 { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
271 { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
272 { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
273 { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
274 { 3, { 0x80, 0xb3, 0x0a } },
275 {-1, { 0 } }
276};
277
278
279
280
281
282static int mxb_init_done(struct saa7146_dev* dev)
283{
284 struct mxb* mxb = (struct mxb*)dev->ext_priv;
285 struct i2c_msg msg;
286 struct tuner_setup tun_setup;
287 v4l2_std_id std = V4L2_STD_PAL_BG;
288
289 int i = 0, err = 0;
290
291
292 saa7111a_call(mxb, core, s_std, std);
293
294
295 i = 0;
296 saa7111a_call(mxb, video, s_routing, SAA7115_COMPOSITE0,
297 SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS, 0);
298
299
300 tun_setup.mode_mask = T_ANALOG_TV;
301 tun_setup.addr = ADDR_UNSET;
302 tun_setup.type = TUNER_PHILIPS_PAL;
303 tuner_call(mxb, tuner, s_type_addr, &tun_setup);
304
305 mxb->cur_freq.tuner = 0;
306 mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
307 mxb->cur_freq.frequency = freq;
308 tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
309
310
311 tuner_call(mxb, core, s_std, std);
312
313
314 tea6420_route_line(mxb, 6);
315 tea6420_route_cd(mxb, 6);
316
317
318 tea6415c_call(mxb, video, s_routing, 3, 17, 0);
319
320
321 tea6415c_call(mxb, video, s_routing, 3, 13, 0);
322
323
324 mxb->cur_input = 0;
325 mxb->cur_mute = 1;
326
327 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
328
329
330
331
332
333 msg.addr = 0x1b;
334 msg.flags = 0;
335 msg.len = mxb_saa7740_init[0].length;
336 msg.buf = &mxb_saa7740_init[0].data[0];
337
338 err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
339 if (err == 1) {
340
341
342
343
344
345 extension.flags &= ~SAA7146_USE_I2C_IRQ;
346 for (i = 1; ; i++) {
347 if (-1 == mxb_saa7740_init[i].length)
348 break;
349
350 msg.len = mxb_saa7740_init[i].length;
351 msg.buf = &mxb_saa7740_init[i].data[0];
352 err = i2c_transfer(&mxb->i2c_adapter, &msg, 1);
353 if (err != 1) {
354 DEB_D(("failed to initialize 'sound arena module'.\n"));
355 goto err;
356 }
357 }
358 INFO(("'sound arena module' detected.\n"));
359 }
360err:
361
362
363
364
365
366
367 saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source,
368 input_port_selection[mxb->cur_input].hps_sync);
369
370
371
372
373
374 saa7146_write(dev, DD1_STREAM_B, 0x00000000);
375 saa7146_write(dev, DD1_INIT, 0x02000200);
376 saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
377
378 return 0;
379}
380
381
382
383
384
385
386
387
388
389
390static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
391{
392 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
393 int i;
394
395 for (i = MAXCONTROLS - 1; i >= 0; i--) {
396 if (mxb_controls[i].id == qc->id) {
397 *qc = mxb_controls[i];
398 DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
399 return 0;
400 }
401 }
402 return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
403}
404
405static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
406{
407 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
408 struct mxb *mxb = (struct mxb *)dev->ext_priv;
409 int i;
410
411 for (i = MAXCONTROLS - 1; i >= 0; i--) {
412 if (mxb_controls[i].id == vc->id)
413 break;
414 }
415
416 if (i < 0)
417 return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
418
419 if (vc->id == V4L2_CID_AUDIO_MUTE) {
420 vc->value = mxb->cur_mute;
421 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
422 return 0;
423 }
424
425 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
426 return 0;
427}
428
429static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
430{
431 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
432 struct mxb *mxb = (struct mxb *)dev->ext_priv;
433 int i = 0;
434
435 for (i = MAXCONTROLS - 1; i >= 0; i--) {
436 if (mxb_controls[i].id == vc->id)
437 break;
438 }
439
440 if (i < 0)
441 return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
442
443 if (vc->id == V4L2_CID_AUDIO_MUTE) {
444 mxb->cur_mute = vc->value;
445
446 tea6420_route_line(mxb, vc->value ? 6 :
447 video_audio_connect[mxb->cur_input]);
448 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
449 }
450 return 0;
451}
452
453static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
454{
455 DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
456 if (i->index >= MXB_INPUTS)
457 return -EINVAL;
458 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
459 return 0;
460}
461
462static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
463{
464 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
465 struct mxb *mxb = (struct mxb *)dev->ext_priv;
466 *i = mxb->cur_input;
467
468 DEB_EE(("VIDIOC_G_INPUT %d.\n", *i));
469 return 0;
470}
471
472static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
473{
474 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
475 struct mxb *mxb = (struct mxb *)dev->ext_priv;
476 int err = 0;
477 int i = 0;
478
479 DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
480
481 if (input < 0 || input >= MXB_INPUTS)
482 return -EINVAL;
483
484 mxb->cur_input = input;
485
486 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
487 input_port_selection[input].hps_sync);
488
489
490
491 switch (input) {
492 case TUNER:
493 i = SAA7115_COMPOSITE0;
494
495 err = tea6415c_call(mxb, video, s_routing, 3, 17, 0);
496
497
498 if (!err)
499 err = tea6415c_call(mxb, video, s_routing, 3, 13, 0);
500 break;
501 case AUX3_YC:
502
503
504 i = SAA7115_SVIDEO1;
505 break;
506 case AUX3:
507
508
509 i = SAA7115_COMPOSITE1;
510 break;
511 case AUX1:
512 i = SAA7115_COMPOSITE0;
513 err = tea6415c_call(mxb, video, s_routing, 1, 17, 0);
514 break;
515 }
516
517 if (err)
518 return err;
519
520
521 if (saa7111a_call(mxb, video, s_routing, i, 0, 0))
522 printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
523
524
525 if (0 == mxb->cur_mute)
526 tea6420_route_line(mxb, video_audio_connect[input]);
527
528 return 0;
529}
530
531static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
532{
533 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
534 struct mxb *mxb = (struct mxb *)dev->ext_priv;
535
536 if (t->index) {
537 DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
538 return -EINVAL;
539 }
540
541 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
542
543 memset(t, 0, sizeof(*t));
544 strlcpy(t->name, "TV Tuner", sizeof(t->name));
545 t->type = V4L2_TUNER_ANALOG_TV;
546 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
547 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
548 t->audmode = mxb->cur_mode;
549 return call_all(dev, tuner, g_tuner, t);
550}
551
552static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
553{
554 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
555 struct mxb *mxb = (struct mxb *)dev->ext_priv;
556
557 if (t->index) {
558 DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index));
559 return -EINVAL;
560 }
561
562 mxb->cur_mode = t->audmode;
563 return call_all(dev, tuner, s_tuner, t);
564}
565
566static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
567{
568 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
569 struct mxb *mxb = (struct mxb *)dev->ext_priv;
570
571 if (mxb->cur_input) {
572 DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
573 mxb->cur_input));
574 return -EINVAL;
575 }
576
577 *f = mxb->cur_freq;
578
579 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
580 return 0;
581}
582
583static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
584{
585 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
586 struct mxb *mxb = (struct mxb *)dev->ext_priv;
587 struct saa7146_vv *vv = dev->vv_data;
588
589 if (f->tuner)
590 return -EINVAL;
591
592 if (V4L2_TUNER_ANALOG_TV != f->type)
593 return -EINVAL;
594
595 if (mxb->cur_input) {
596 DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
597 return -EINVAL;
598 }
599
600 mxb->cur_freq = *f;
601 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
602
603
604 tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
605
606
607 spin_lock(&dev->slock);
608 vv->vbi_fieldcount = 0;
609 spin_unlock(&dev->slock);
610
611 return 0;
612}
613
614static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
615{
616 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
617 struct mxb *mxb = (struct mxb *)dev->ext_priv;
618
619 if (a->index > MXB_INPUTS) {
620 DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
621 return -EINVAL;
622 }
623
624 DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
625 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
626 return 0;
627}
628
629static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
630{
631 DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
632 return 0;
633}
634
635#ifdef CONFIG_VIDEO_ADV_DEBUG
636static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
637{
638 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
639
640 return call_all(dev, core, g_register, reg);
641}
642
643static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
644{
645 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
646
647 return call_all(dev, core, s_register, reg);
648}
649#endif
650
651static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
652{
653 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
654 struct mxb *mxb = (struct mxb *)dev->ext_priv;
655
656 switch (cmd) {
657 case MXB_S_AUDIO_CD:
658 {
659 int i = *(int *)arg;
660
661 if (i < 0 || i >= MXB_AUDIOS) {
662 DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i));
663 return -EINVAL;
664 }
665
666 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
667
668 tea6420_route_cd(mxb, i);
669 return 0;
670 }
671 case MXB_S_AUDIO_LINE:
672 {
673 int i = *(int *)arg;
674
675 if (i < 0 || i >= MXB_AUDIOS) {
676 DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i));
677 return -EINVAL;
678 }
679
680 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
681 tea6420_route_line(mxb, i);
682 return 0;
683 }
684 default:
685
686
687
688 return -ENOIOCTLCMD;
689 }
690 return 0;
691}
692
693static struct saa7146_ext_vv vv_data;
694
695
696static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
697{
698 struct mxb *mxb = (struct mxb *)dev->ext_priv;
699
700 DEB_EE(("dev:%p\n", dev));
701
702
703
704
705 saa7146_vv_init(dev, &vv_data);
706 vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
707 vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
708 vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
709 vv_data.ops.vidioc_enum_input = vidioc_enum_input;
710 vv_data.ops.vidioc_g_input = vidioc_g_input;
711 vv_data.ops.vidioc_s_input = vidioc_s_input;
712 vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
713 vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
714 vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
715 vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
716 vv_data.ops.vidioc_g_audio = vidioc_g_audio;
717 vv_data.ops.vidioc_s_audio = vidioc_s_audio;
718#ifdef CONFIG_VIDEO_ADV_DEBUG
719 vv_data.ops.vidioc_g_register = vidioc_g_register;
720 vv_data.ops.vidioc_s_register = vidioc_s_register;
721#endif
722 vv_data.ops.vidioc_default = vidioc_default;
723 if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
724 ERR(("cannot register capture v4l2 device. skipping.\n"));
725 return -1;
726 }
727
728
729 if (MXB_BOARD_CAN_DO_VBI(dev)) {
730 if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
731 ERR(("cannot register vbi v4l2 device. skipping.\n"));
732 }
733 }
734
735 printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
736
737 mxb_num++;
738 mxb_init_done(dev);
739 return 0;
740}
741
742static int mxb_detach(struct saa7146_dev *dev)
743{
744 struct mxb *mxb = (struct mxb *)dev->ext_priv;
745
746 DEB_EE(("dev:%p\n", dev));
747
748 saa7146_unregister_device(&mxb->video_dev,dev);
749 if (MXB_BOARD_CAN_DO_VBI(dev))
750 saa7146_unregister_device(&mxb->vbi_dev, dev);
751 saa7146_vv_release(dev);
752
753 mxb_num--;
754
755 i2c_del_adapter(&mxb->i2c_adapter);
756 kfree(mxb);
757
758 return 0;
759}
760
761static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
762{
763 struct mxb *mxb = (struct mxb *)dev->ext_priv;
764
765 if (V4L2_STD_PAL_I == standard->id) {
766 v4l2_std_id std = V4L2_STD_PAL_I;
767
768 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
769
770 saa7146_write(dev, GPIO_CTRL, 0x00404050);
771
772 saa7111a_call(mxb, core, s_gpio, 0);
773 tuner_call(mxb, core, s_std, std);
774 } else {
775 v4l2_std_id std = V4L2_STD_PAL_BG;
776
777 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
778
779 saa7146_write(dev, GPIO_CTRL, 0x00404050);
780
781 saa7111a_call(mxb, core, s_gpio, 1);
782 tuner_call(mxb, core, s_std, std);
783 }
784 return 0;
785}
786
787static struct saa7146_standard standard[] = {
788 {
789 .name = "PAL-BG", .id = V4L2_STD_PAL_BG,
790 .v_offset = 0x17, .v_field = 288,
791 .h_offset = 0x14, .h_pixels = 680,
792 .v_max_out = 576, .h_max_out = 768,
793 }, {
794 .name = "PAL-I", .id = V4L2_STD_PAL_I,
795 .v_offset = 0x17, .v_field = 288,
796 .h_offset = 0x14, .h_pixels = 680,
797 .v_max_out = 576, .h_max_out = 768,
798 }, {
799 .name = "NTSC", .id = V4L2_STD_NTSC,
800 .v_offset = 0x16, .v_field = 240,
801 .h_offset = 0x06, .h_pixels = 708,
802 .v_max_out = 480, .h_max_out = 640,
803 }, {
804 .name = "SECAM", .id = V4L2_STD_SECAM,
805 .v_offset = 0x14, .v_field = 288,
806 .h_offset = 0x14, .h_pixels = 720,
807 .v_max_out = 576, .h_max_out = 768,
808 }
809};
810
811static struct saa7146_pci_extension_data mxb = {
812 .ext_priv = "Multimedia eXtension Board",
813 .ext = &extension,
814};
815
816static struct pci_device_id pci_tbl[] = {
817 {
818 .vendor = PCI_VENDOR_ID_PHILIPS,
819 .device = PCI_DEVICE_ID_PHILIPS_SAA7146,
820 .subvendor = 0x0000,
821 .subdevice = 0x0000,
822 .driver_data = (unsigned long)&mxb,
823 }, {
824 .vendor = 0,
825 }
826};
827
828MODULE_DEVICE_TABLE(pci, pci_tbl);
829
830static struct saa7146_ext_vv vv_data = {
831 .inputs = MXB_INPUTS,
832 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
833 .stds = &standard[0],
834 .num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
835 .std_callback = &std_callback,
836};
837
838static struct saa7146_extension extension = {
839 .name = MXB_IDENTIFIER,
840 .flags = SAA7146_USE_I2C_IRQ,
841
842 .pci_tbl = &pci_tbl[0],
843 .module = THIS_MODULE,
844
845 .probe = mxb_probe,
846 .attach = mxb_attach,
847 .detach = mxb_detach,
848
849 .irq_mask = 0,
850 .irq_func = NULL,
851};
852
853static int __init mxb_init_module(void)
854{
855 if (saa7146_register_extension(&extension)) {
856 DEB_S(("failed to register extension.\n"));
857 return -ENODEV;
858 }
859
860 return 0;
861}
862
863static void __exit mxb_cleanup_module(void)
864{
865 saa7146_unregister_extension(&extension);
866}
867
868module_init(mxb_init_module);
869module_exit(mxb_cleanup_module);
870
871MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
872MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
873MODULE_LICENSE("GPL");
874