]> err.no Git - linux-2.6/blob - drivers/media/video/mxb.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[linux-2.6] / drivers / media / video / mxb.c
1 /*
2     mxb - v4l2 driver for the Multimedia eXtension Board
3
4     Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
5
6     Visit http://www.mihu.de/linux/saa7146/mxb/
7     for further details about this card.
8
9     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>
29 #include <media/v4l2-common.h>
30
31 #include "mxb.h"
32 #include "tea6415c.h"
33 #include "tea6420.h"
34 #include "tda9840.h"
35
36 #define I2C_SAA7111 0x24
37
38 #define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
39
40 /* global variable */
41 static int mxb_num;
42
43 /* initial frequence the tuner will be tuned to.
44    in verden (lower saxony, germany) 4148 is a
45    channel called "phoenix" */
46 static int freq = 4148;
47 module_param(freq, int, 0644);
48 MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
49
50 static int debug;
51 module_param(debug, int, 0644);
52 MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
53
54 #define MXB_INPUTS 4
55 enum { TUNER, AUX1, AUX3, AUX3_YC };
56
57 static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
58         { TUNER,        "Tuner",                V4L2_INPUT_TYPE_TUNER,  1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
59         { AUX1,         "AUX1",                 V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
60         { AUX3,         "AUX3 Composite",       V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
61         { AUX3_YC,      "AUX3 S-Video",         V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
62 };
63
64 /* this array holds the information, which port of the saa7146 each
65    input actually uses. the mxb uses port 0 for every input */
66 static struct {
67         int hps_source;
68         int hps_sync;
69 } input_port_selection[MXB_INPUTS] = {
70         { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
71         { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
72         { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
73         { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
74 };
75
76 /* this array holds the information of the audio source (mxb_audios),
77    which has to be switched corresponding to the video source (mxb_channels) */
78 static int video_audio_connect[MXB_INPUTS] =
79         { 0, 1, 3, 3 };
80
81 /* these are the necessary input-output-pins for bringing one audio source
82 (see above) to the CD-output */
83 static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
84                 {
85                 {{1,1,0},{1,1,0}},      /* Tuner */
86                 {{5,1,0},{6,1,0}},      /* AUX 1 */
87                 {{4,1,0},{6,1,0}},      /* AUX 2 */
88                 {{3,1,0},{6,1,0}},      /* AUX 3 */
89                 {{1,1,0},{3,1,0}},      /* Radio */
90                 {{1,1,0},{2,1,0}},      /* CD-Rom */
91                 {{6,1,0},{6,1,0}}       /* Mute */
92                 };
93
94 /* these are the necessary input-output-pins for bringing one audio source
95 (see above) to the line-output */
96 static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
97                 {
98                 {{2,3,0},{1,2,0}},
99                 {{5,3,0},{6,2,0}},
100                 {{4,3,0},{6,2,0}},
101                 {{3,3,0},{6,2,0}},
102                 {{2,3,0},{3,2,0}},
103                 {{2,3,0},{2,2,0}},
104                 {{6,3,0},{6,2,0}}       /* Mute */
105                 };
106
107 #define MAXCONTROLS     1
108 static struct v4l2_queryctrl mxb_controls[] = {
109         { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
110 };
111
112 static struct saa7146_extension_ioctls ioctls[] = {
113         { VIDIOC_ENUMINPUT,     SAA7146_EXCLUSIVE },
114         { VIDIOC_G_INPUT,       SAA7146_EXCLUSIVE },
115         { VIDIOC_S_INPUT,       SAA7146_EXCLUSIVE },
116         { VIDIOC_QUERYCTRL,     SAA7146_BEFORE },
117         { VIDIOC_G_CTRL,        SAA7146_BEFORE },
118         { VIDIOC_S_CTRL,        SAA7146_BEFORE },
119         { VIDIOC_G_TUNER,       SAA7146_EXCLUSIVE },
120         { VIDIOC_S_TUNER,       SAA7146_EXCLUSIVE },
121         { VIDIOC_G_FREQUENCY,   SAA7146_EXCLUSIVE },
122         { VIDIOC_S_FREQUENCY,   SAA7146_EXCLUSIVE },
123         { VIDIOC_G_AUDIO,       SAA7146_EXCLUSIVE },
124         { VIDIOC_S_AUDIO,       SAA7146_EXCLUSIVE },
125         { MXB_S_AUDIO_CD,       SAA7146_EXCLUSIVE },    /* custom control */
126         { MXB_S_AUDIO_LINE,     SAA7146_EXCLUSIVE },    /* custom control */
127         { 0,                    0 }
128 };
129
130 struct mxb
131 {
132         struct video_device     *video_dev;
133         struct video_device     *vbi_dev;
134
135         struct i2c_adapter      i2c_adapter;
136
137         struct i2c_client*      saa7111a;
138         struct i2c_client*      tda9840;
139         struct i2c_client*      tea6415c;
140         struct i2c_client*      tuner;
141         struct i2c_client*      tea6420_1;
142         struct i2c_client*      tea6420_2;
143
144         int     cur_mode;       /* current audio mode (mono, stereo, ...) */
145         int     cur_input;      /* current input */
146         int     cur_mute;       /* current mute status */
147         struct v4l2_frequency   cur_freq;       /* current frequency the tuner is tuned to */
148 };
149
150 static struct saa7146_extension extension;
151
152 static int mxb_check_clients(struct device *dev, void *data)
153 {
154         struct mxb* mxb = data;
155         struct i2c_client *client = i2c_verify_client(dev);
156
157         if( !client )
158                 return 0;
159
160         if( I2C_ADDR_TEA6420_1 == client->addr )
161                 mxb->tea6420_1 = client;
162         if( I2C_ADDR_TEA6420_2 == client->addr )
163                 mxb->tea6420_2 = client;
164         if( I2C_TEA6415C_2 == client->addr )
165                 mxb->tea6415c = client;
166         if( I2C_ADDR_TDA9840 == client->addr )
167                 mxb->tda9840 = client;
168         if( I2C_SAA7111 == client->addr )
169                 mxb->saa7111a = client;
170         if( 0x60 == client->addr )
171                 mxb->tuner = client;
172
173         return 0;
174 }
175
176 static int mxb_probe(struct saa7146_dev* dev)
177 {
178         struct mxb* mxb = NULL;
179         int result;
180
181         if ((result = request_module("saa7111")) < 0) {
182                 printk("mxb: saa7111 i2c module not available.\n");
183                 return -ENODEV;
184         }
185         if ((result = request_module("tea6420")) < 0) {
186                 printk("mxb: tea6420 i2c module not available.\n");
187                 return -ENODEV;
188         }
189         if ((result = request_module("tea6415c")) < 0) {
190                 printk("mxb: tea6415c i2c module not available.\n");
191                 return -ENODEV;
192         }
193         if ((result = request_module("tda9840")) < 0) {
194                 printk("mxb: tda9840 i2c module not available.\n");
195                 return -ENODEV;
196         }
197         if ((result = request_module("tuner")) < 0) {
198                 printk("mxb: tuner i2c module not available.\n");
199                 return -ENODEV;
200         }
201
202         mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
203         if( NULL == mxb ) {
204                 DEB_D(("not enough kernel memory.\n"));
205                 return -ENOMEM;
206         }
207
208         mxb->i2c_adapter = (struct i2c_adapter) {
209                 .class = I2C_CLASS_TV_ANALOG,
210                 .name = "mxb",
211         };
212
213         saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
214         if(i2c_add_adapter(&mxb->i2c_adapter) < 0) {
215                 DEB_S(("cannot register i2c-device. skipping.\n"));
216                 kfree(mxb);
217                 return -EFAULT;
218         }
219
220         /* loop through all i2c-devices on the bus and look who is there */
221         device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
222
223         /* check if all devices are present */
224         if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
225             !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
226                 printk("mxb: did not find all i2c devices. aborting\n");
227                 i2c_del_adapter(&mxb->i2c_adapter);
228                 kfree(mxb);
229                 return -ENODEV;
230         }
231
232         /* all devices are present, probe was successful */
233
234         /* we store the pointer in our private data field */
235         dev->ext_priv = mxb;
236
237         return 0;
238 }
239
240 /* some init data for the saa7740, the so-called 'sound arena module'.
241    there are no specs available, so we simply use some init values */
242 static struct {
243         int     length;
244         char    data[9];
245 } mxb_saa7740_init[] = {
246         { 3, { 0x80, 0x00, 0x00 } },{ 3, { 0x80, 0x89, 0x00 } },
247         { 3, { 0x80, 0xb0, 0x0a } },{ 3, { 0x00, 0x00, 0x00 } },
248         { 3, { 0x49, 0x00, 0x00 } },{ 3, { 0x4a, 0x00, 0x00 } },
249         { 3, { 0x4b, 0x00, 0x00 } },{ 3, { 0x4c, 0x00, 0x00 } },
250         { 3, { 0x4d, 0x00, 0x00 } },{ 3, { 0x4e, 0x00, 0x00 } },
251         { 3, { 0x4f, 0x00, 0x00 } },{ 3, { 0x50, 0x00, 0x00 } },
252         { 3, { 0x51, 0x00, 0x00 } },{ 3, { 0x52, 0x00, 0x00 } },
253         { 3, { 0x53, 0x00, 0x00 } },{ 3, { 0x54, 0x00, 0x00 } },
254         { 3, { 0x55, 0x00, 0x00 } },{ 3, { 0x56, 0x00, 0x00 } },
255         { 3, { 0x57, 0x00, 0x00 } },{ 3, { 0x58, 0x00, 0x00 } },
256         { 3, { 0x59, 0x00, 0x00 } },{ 3, { 0x5a, 0x00, 0x00 } },
257         { 3, { 0x5b, 0x00, 0x00 } },{ 3, { 0x5c, 0x00, 0x00 } },
258         { 3, { 0x5d, 0x00, 0x00 } },{ 3, { 0x5e, 0x00, 0x00 } },
259         { 3, { 0x5f, 0x00, 0x00 } },{ 3, { 0x60, 0x00, 0x00 } },
260         { 3, { 0x61, 0x00, 0x00 } },{ 3, { 0x62, 0x00, 0x00 } },
261         { 3, { 0x63, 0x00, 0x00 } },{ 3, { 0x64, 0x00, 0x00 } },
262         { 3, { 0x65, 0x00, 0x00 } },{ 3, { 0x66, 0x00, 0x00 } },
263         { 3, { 0x67, 0x00, 0x00 } },{ 3, { 0x68, 0x00, 0x00 } },
264         { 3, { 0x69, 0x00, 0x00 } },{ 3, { 0x6a, 0x00, 0x00 } },
265         { 3, { 0x6b, 0x00, 0x00 } },{ 3, { 0x6c, 0x00, 0x00 } },
266         { 3, { 0x6d, 0x00, 0x00 } },{ 3, { 0x6e, 0x00, 0x00 } },
267         { 3, { 0x6f, 0x00, 0x00 } },{ 3, { 0x70, 0x00, 0x00 } },
268         { 3, { 0x71, 0x00, 0x00 } },{ 3, { 0x72, 0x00, 0x00 } },
269         { 3, { 0x73, 0x00, 0x00 } },{ 3, { 0x74, 0x00, 0x00 } },
270         { 3, { 0x75, 0x00, 0x00 } },{ 3, { 0x76, 0x00, 0x00 } },
271         { 3, { 0x77, 0x00, 0x00 } },{ 3, { 0x41, 0x00, 0x42 } },
272         { 3, { 0x42, 0x10, 0x42 } },{ 3, { 0x43, 0x20, 0x42 } },
273         { 3, { 0x44, 0x30, 0x42 } },{ 3, { 0x45, 0x00, 0x01 } },
274         { 3, { 0x46, 0x00, 0x01 } },{ 3, { 0x47, 0x00, 0x01 } },
275         { 3, { 0x48, 0x00, 0x01 } },
276         { 9, { 0x01, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
277         { 9, { 0x21, 0x03, 0xc5, 0x5c, 0x7a, 0x85, 0x01, 0x00, 0x54 } },
278         { 9, { 0x09, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
279         { 9, { 0x29, 0x0b, 0xb4, 0x6b, 0x74, 0x85, 0x95, 0x00, 0x34 } },
280         { 9, { 0x11, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
281         { 9, { 0x31, 0x17, 0x43, 0x62, 0x68, 0x89, 0xd1, 0xff, 0xb0 } },
282         { 9, { 0x19, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
283         { 9, { 0x39, 0x20, 0x62, 0x51, 0x5a, 0x95, 0x19, 0x01, 0x50 } },
284         { 9, { 0x05, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
285         { 9, { 0x25, 0x3e, 0xd2, 0x69, 0x4e, 0x9a, 0x51, 0x00, 0xf0 } },
286         { 9, { 0x0d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
287         { 9, { 0x2d, 0x3d, 0xa1, 0x40, 0x7d, 0x9f, 0x29, 0xfe, 0x14 } },
288         { 9, { 0x15, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
289         { 9, { 0x35, 0x73, 0xa1, 0x50, 0x5d, 0xa6, 0xf5, 0xfe, 0x38 } },
290         { 9, { 0x1d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
291         { 9, { 0x3d, 0xed, 0xd0, 0x68, 0x29, 0xb4, 0xe1, 0x00, 0xb8 } },
292         { 3, { 0x80, 0xb3, 0x0a } },
293         {-1, { 0} }
294 };
295
296 static const unsigned char mxb_saa7111_init[] = {
297         0x00, 0x00,       /* 00 - ID byte */
298         0x01, 0x00,       /* 01 - reserved */
299
300         /*front end */
301         0x02, 0xd8,       /* 02 - FUSE=x, GUDL=x, MODE=x */
302         0x03, 0x23,       /* 03 - HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0, GAFIX=0, GAI1=256, GAI2=256 */
303         0x04, 0x00,       /* 04 - GAI1=256 */
304         0x05, 0x00,       /* 05 - GAI2=256 */
305
306         /* decoder */
307         0x06, 0xf0,       /* 06 - HSB at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
308         0x07, 0x30,       /* 07 - HSS at  xx(50Hz) /  xx(60Hz) pixels after end of last line */
309         0x08, 0xa8,       /* 08 - AUFD=x, FSEL=x, EXFIL=x, VTRC=x, HPLL=x, VNOI=x */
310         0x09, 0x02,       /* 09 - BYPS=x, PREF=x, BPSS=x, VBLB=x, UPTCV=x, APER=x */
311         0x0a, 0x80,       /* 0a - BRIG=128 */
312         0x0b, 0x47,       /* 0b - CONT=1.109 */
313         0x0c, 0x40,       /* 0c - SATN=1.0 */
314         0x0d, 0x00,       /* 0d - HUE=0 */
315         0x0e, 0x01,       /* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
316         0x0f, 0x00,       /* 0f - reserved */
317         0x10, 0xd0,       /* 10 - OFTS=x, HDEL=x, VRLN=x, YDEL=x */
318         0x11, 0x8c,       /* 11 - GPSW=x, CM99=x, FECO=x, COMPO=x, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
319         0x12, 0x80,       /* 12 - xx output control 2 */
320         0x13, 0x30,       /* 13 - xx output control 3 */
321         0x14, 0x00,       /* 14 - reserved */
322         0x15, 0x15,       /* 15 - VBI */
323         0x16, 0x04,       /* 16 - VBI */
324         0x17, 0x00,       /* 17 - VBI */
325 };
326
327 /* bring hardware to a sane state. this has to be done, just in case someone
328    wants to capture from this device before it has been properly initialized.
329    the capture engine would badly fail, because no valid signal arrives on the
330    saa7146, thus leading to timeouts and stuff. */
331 static int mxb_init_done(struct saa7146_dev* dev)
332 {
333         struct mxb* mxb = (struct mxb*)dev->ext_priv;
334         struct video_decoder_init init;
335         struct i2c_msg msg;
336         struct tuner_setup tun_setup;
337         v4l2_std_id std = V4L2_STD_PAL_BG;
338
339         int i = 0, err = 0;
340         struct  tea6415c_multiplex vm;
341
342         /* select video mode in saa7111a */
343         i = VIDEO_MODE_PAL;
344         /* fixme: currently pointless: gets overwritten by configuration below */
345         mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_NORM, &i);
346
347         /* write configuration to saa7111a */
348         init.data = mxb_saa7111_init;
349         init.len = sizeof(mxb_saa7111_init);
350         mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_INIT, &init);
351
352         /* select tuner-output on saa7111a */
353         i = 0;
354         mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i);
355
356         /* enable vbi bypass */
357         i = 1;
358         mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
359
360         /* select a tuner type */
361         tun_setup.mode_mask = T_ANALOG_TV;
362         tun_setup.addr = ADDR_UNSET;
363         tun_setup.type = TUNER_PHILIPS_PAL;
364         mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
365         /* tune in some frequency on tuner */
366         mxb->cur_freq.tuner = 0;
367         mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
368         mxb->cur_freq.frequency = freq;
369         mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
370                                         &mxb->cur_freq);
371
372         /* set a default video standard */
373         mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
374
375         /* mute audio on tea6420s */
376         mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
377         mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
378         mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[6][0]);
379         mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[6][1]);
380
381         /* switch to tuner-channel on tea6415c*/
382         vm.out = 17;
383         vm.in  = 3;
384         mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
385
386         /* select tuner-output on multicable on tea6415c*/
387         vm.in  = 3;
388         vm.out = 13;
389         mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
390
391         /* the rest for mxb */
392         mxb->cur_input = 0;
393         mxb->cur_mute = 1;
394
395         mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
396         mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
397
398         /* check if the saa7740 (aka 'sound arena module') is present
399            on the mxb. if so, we must initialize it. due to lack of
400            informations about the saa7740, the values were reverse
401            engineered. */
402         msg.addr = 0x1b;
403         msg.flags = 0;
404         msg.len = mxb_saa7740_init[0].length;
405         msg.buf = &mxb_saa7740_init[0].data[0];
406
407         if( 1 == (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
408                 /* the sound arena module is a pos, that's probably the reason
409                    philips refuses to hand out a datasheet for the saa7740...
410                    it seems to screw up the i2c bus, so we disable fast irq
411                    based i2c transactions here and rely on the slow and safe
412                    polling method ... */
413                 extension.flags &= ~SAA7146_USE_I2C_IRQ;
414                 for(i = 1;;i++) {
415                         if( -1 == mxb_saa7740_init[i].length ) {
416                                 break;
417                         }
418
419                         msg.len = mxb_saa7740_init[i].length;
420                         msg.buf = &mxb_saa7740_init[i].data[0];
421                         if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
422                                 DEB_D(("failed to initialize 'sound arena module'.\n"));
423                                 goto err;
424                         }
425                 }
426                 INFO(("'sound arena module' detected.\n"));
427         }
428 err:
429         /* the rest for saa7146: you should definitely set some basic values
430            for the input-port handling of the saa7146. */
431
432         /* ext->saa has been filled by the core driver */
433
434         /* some stuff is done via variables */
435         saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
436
437         /* some stuff is done via direct write to the registers */
438
439         /* this is ugly, but because of the fact that this is completely
440            hardware dependend, it should be done directly... */
441         saa7146_write(dev, DD1_STREAM_B,        0x00000000);
442         saa7146_write(dev, DD1_INIT,            0x02000200);
443         saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
444
445         return 0;
446 }
447
448 /* interrupt-handler. this gets called when irq_mask is != 0.
449    it must clear the interrupt-bits in irq_mask it has handled */
450 /*
451 void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
452 {
453         struct mxb* mxb = (struct mxb*)dev->ext_priv;
454 }
455 */
456
457 static struct saa7146_ext_vv vv_data;
458
459 /* this function only gets called when the probing was successful */
460 static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
461 {
462         struct mxb* mxb = (struct mxb*)dev->ext_priv;
463
464         DEB_EE(("dev:%p\n",dev));
465
466         /* checking for i2c-devices can be omitted here, because we
467            already did this in "mxb_vl42_probe" */
468
469         saa7146_vv_init(dev,&vv_data);
470         if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
471                 ERR(("cannot register capture v4l2 device. skipping.\n"));
472                 return -1;
473         }
474
475         /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
476         if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
477                 if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
478                         ERR(("cannot register vbi v4l2 device. skipping.\n"));
479                 }
480         }
481
482         i2c_use_client(mxb->tea6420_1);
483         i2c_use_client(mxb->tea6420_2);
484         i2c_use_client(mxb->tea6415c);
485         i2c_use_client(mxb->tda9840);
486         i2c_use_client(mxb->saa7111a);
487         i2c_use_client(mxb->tuner);
488
489         printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num);
490
491         mxb_num++;
492         mxb_init_done(dev);
493         return 0;
494 }
495
496 static int mxb_detach(struct saa7146_dev* dev)
497 {
498         struct mxb* mxb = (struct mxb*)dev->ext_priv;
499
500         DEB_EE(("dev:%p\n",dev));
501
502         i2c_release_client(mxb->tea6420_1);
503         i2c_release_client(mxb->tea6420_2);
504         i2c_release_client(mxb->tea6415c);
505         i2c_release_client(mxb->tda9840);
506         i2c_release_client(mxb->saa7111a);
507         i2c_release_client(mxb->tuner);
508
509         saa7146_unregister_device(&mxb->video_dev,dev);
510         if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
511                 saa7146_unregister_device(&mxb->vbi_dev,dev);
512         }
513         saa7146_vv_release(dev);
514
515         mxb_num--;
516
517         i2c_del_adapter(&mxb->i2c_adapter);
518         kfree(mxb);
519
520         return 0;
521 }
522
523 static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
524 {
525         struct saa7146_dev *dev = fh->dev;
526         struct mxb* mxb = (struct mxb*)dev->ext_priv;
527         struct saa7146_vv *vv = dev->vv_data;
528
529         switch(cmd) {
530         case VIDIOC_ENUMINPUT:
531         {
532                 struct v4l2_input *i = arg;
533
534                 DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
535                 if( i->index < 0 || i->index >= MXB_INPUTS) {
536                         return -EINVAL;
537                 }
538                 memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
539
540                 return 0;
541         }
542         /* the saa7146 provides some controls (brightness, contrast, saturation)
543            which gets registered *after* this function. because of this we have
544            to return with a value != 0 even if the function succeded.. */
545         case VIDIOC_QUERYCTRL:
546         {
547                 struct v4l2_queryctrl *qc = arg;
548                 int i;
549
550                 for (i = MAXCONTROLS - 1; i >= 0; i--) {
551                         if (mxb_controls[i].id == qc->id) {
552                                 *qc = mxb_controls[i];
553                                 DEB_D(("VIDIOC_QUERYCTRL %d.\n",qc->id));
554                                 return 0;
555                         }
556                 }
557                 return -EAGAIN;
558         }
559         case VIDIOC_G_CTRL:
560         {
561                 struct v4l2_control *vc = arg;
562                 int i;
563
564                 for (i = MAXCONTROLS - 1; i >= 0; i--) {
565                         if (mxb_controls[i].id == vc->id) {
566                                 break;
567                         }
568                 }
569
570                 if( i < 0 ) {
571                         return -EAGAIN;
572                 }
573
574                 switch (vc->id ) {
575                         case V4L2_CID_AUDIO_MUTE: {
576                                 vc->value = mxb->cur_mute;
577                                 DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
578                                 return 0;
579                         }
580                 }
581
582                 DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
583                 return 0;
584         }
585
586         case VIDIOC_S_CTRL:
587         {
588                 struct  v4l2_control    *vc = arg;
589                 int i = 0;
590
591                 for (i = MAXCONTROLS - 1; i >= 0; i--) {
592                         if (mxb_controls[i].id == vc->id) {
593                                 break;
594                         }
595                 }
596
597                 if( i < 0 ) {
598                         return -EAGAIN;
599                 }
600
601                 switch (vc->id ) {
602                         case V4L2_CID_AUDIO_MUTE: {
603                                 mxb->cur_mute = vc->value;
604                                 if( 0 == vc->value ) {
605                                         /* switch the audio-source */
606                                         mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
607                                         mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
608                                 } else {
609                                         mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
610                                         mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
611                                 }
612                                 DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n",vc->value));
613                                 break;
614                         }
615                 }
616                 return 0;
617         }
618         case VIDIOC_G_INPUT:
619         {
620                 int *input = (int *)arg;
621                 *input = mxb->cur_input;
622
623                 DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
624                 return 0;
625         }
626         case VIDIOC_S_INPUT:
627         {
628                 int input = *(int *)arg;
629                 struct  tea6415c_multiplex vm;
630                 int i = 0;
631
632                 DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
633
634                 if (input < 0 || input >= MXB_INPUTS) {
635                         return -EINVAL;
636                 }
637
638                 /* fixme: locke das setzen des inputs mit hilfe des mutexes
639                 mutex_lock(&dev->lock);
640                 video_mux(dev,*i);
641                 mutex_unlock(&dev->lock);
642                 */
643
644                 /* fixme: check if streaming capture
645                 if ( 0 != dev->streaming ) {
646                         DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
647                         return -EPERM;
648                 }
649                 */
650
651                 mxb->cur_input = input;
652
653                 saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
654
655                 /* prepare switching of tea6415c and saa7111a;
656                    have a look at the 'background'-file for further informations  */
657                 switch( input ) {
658
659                         case TUNER:
660                         {
661                                 i = 0;
662                                 vm.in  = 3;
663                                 vm.out = 17;
664
665                         if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
666                                         printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
667                                         return -EFAULT;
668                                 }
669                                 /* connect tuner-output always to multicable */
670                                 vm.in  = 3;
671                                 vm.out = 13;
672                                 break;
673                         }
674                         case AUX3_YC:
675                         {
676                                 /* nothing to be done here. aux3_yc is
677                                    directly connected to the saa711a */
678                                 i = 5;
679                                 break;
680                         }
681                         case AUX3:
682                         {
683                                 /* nothing to be done here. aux3 is
684                                    directly connected to the saa711a */
685                                 i = 1;
686                                 break;
687                         }
688                         case AUX1:
689                         {
690                                 i = 0;
691                                 vm.in  = 1;
692                                 vm.out = 17;
693                                 break;
694                         }
695                 }
696
697                 /* switch video in tea6415c only if necessary */
698                 switch( input ) {
699                         case TUNER:
700                         case AUX1:
701                         {
702                                 if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
703                                         printk("VIDIOC_S_INPUT: could not address tea6415c #3\n");
704                                         return -EFAULT;
705                                 }
706                                 break;
707                         }
708                         default:
709                         {
710                                 break;
711                         }
712                 }
713
714                 /* switch video in saa7111a */
715                 if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
716                         printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
717                 }
718
719                 /* switch the audio-source only if necessary */
720                 if( 0 == mxb->cur_mute ) {
721                         mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][0]);
722                         mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[video_audio_connect[input]][1]);
723                 }
724
725                 return 0;
726         }
727         case VIDIOC_G_TUNER:
728         {
729                 struct v4l2_tuner *t = arg;
730                 int byte = 0;
731
732                 if( 0 != t->index ) {
733                         DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
734                         return -EINVAL;
735                 }
736
737                 DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
738
739                 memset(t,0,sizeof(*t));
740                 strcpy(t->name, "Television");
741
742                 t->type = V4L2_TUNER_ANALOG_TV;
743                 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
744                 t->rangelow = 772;      /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
745                 t->rangehigh = 13684;   /* 855.25 MHz / 62.5 kHz = 13684 */
746                 /* FIXME: add the real signal strength here */
747                 t->signal = 0xffff;
748                 t->afc = 0;
749
750                 mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
751                 t->audmode = mxb->cur_mode;
752
753                 if( byte < 0 ) {
754                         t->rxsubchans  = V4L2_TUNER_SUB_MONO;
755                 } else {
756                         switch(byte) {
757                                 case TDA9840_MONO_DETECT: {
758                                         t->rxsubchans   = V4L2_TUNER_SUB_MONO;
759                                         DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_MONO.\n"));
760                                         break;
761                                 }
762                                 case TDA9840_DUAL_DETECT: {
763                                         t->rxsubchans   = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
764                                         DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_LANG1.\n"));
765                                         break;
766                                 }
767                                 case TDA9840_STEREO_DETECT: {
768                                         t->rxsubchans   = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
769                                         DEB_D(("VIDIOC_G_TUNER: V4L2_TUNER_MODE_STEREO.\n"));
770                                         break;
771                                 }
772                                 default: { /* TDA9840_INCORRECT_DETECT */
773                                         t->rxsubchans   = V4L2_TUNER_MODE_MONO;
774                                         DEB_D(("VIDIOC_G_TUNER: TDA9840_INCORRECT_DETECT => V4L2_TUNER_MODE_MONO\n"));
775                                         break;
776                                 }
777                         }
778                 }
779
780                 return 0;
781         }
782         case VIDIOC_S_TUNER:
783         {
784                 struct v4l2_tuner *t = arg;
785                 int result = 0;
786                 int byte = 0;
787
788                 if( 0 != t->index ) {
789                         DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
790                         return -EINVAL;
791                 }
792
793                 switch(t->audmode) {
794                         case V4L2_TUNER_MODE_STEREO: {
795                                 mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
796                                 byte = TDA9840_SET_STEREO;
797                                 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
798                                 break;
799                         }
800                         case V4L2_TUNER_MODE_LANG1_LANG2: {
801                                 mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
802                                 byte = TDA9840_SET_BOTH;
803                                 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
804                                 break;
805                         }
806                         case V4L2_TUNER_MODE_LANG1: {
807                                 mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
808                                 byte = TDA9840_SET_LANG1;
809                                 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"));
810                                 break;
811                         }
812                         case V4L2_TUNER_MODE_LANG2: {
813                                 mxb->cur_mode = V4L2_TUNER_MODE_LANG2;
814                                 byte = TDA9840_SET_LANG2;
815                                 DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"));
816                                 break;
817                         }
818                         default: { /* case V4L2_TUNER_MODE_MONO: {*/
819                                 mxb->cur_mode = V4L2_TUNER_MODE_MONO;
820                                 byte = TDA9840_SET_MONO;
821                                 DEB_D(("VIDIOC_S_TUNER: TDA9840_SET_MONO\n"));
822                                 break;
823                         }
824                 }
825
826                 if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
827                         printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
828                 }
829
830                 return 0;
831         }
832         case VIDIOC_G_FREQUENCY:
833         {
834                 struct v4l2_frequency *f = arg;
835
836                 if(0 != mxb->cur_input) {
837                         DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
838                         return -EINVAL;
839                 }
840
841                 *f = mxb->cur_freq;
842
843                 DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
844                 return 0;
845         }
846         case VIDIOC_S_FREQUENCY:
847         {
848                 struct v4l2_frequency *f = arg;
849
850                 if (0 != f->tuner)
851                         return -EINVAL;
852
853                 if (V4L2_TUNER_ANALOG_TV != f->type)
854                         return -EINVAL;
855
856                 if(0 != mxb->cur_input) {
857                         DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
858                         return -EINVAL;
859                 }
860
861                 mxb->cur_freq = *f;
862                 DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
863
864                 /* tune in desired frequency */
865                 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
866
867                 /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
868                 spin_lock(&dev->slock);
869                 vv->vbi_fieldcount = 0;
870                 spin_unlock(&dev->slock);
871
872                 return 0;
873         }
874         case MXB_S_AUDIO_CD:
875         {
876                 int i = *(int*)arg;
877
878                 if( i < 0 || i >= MXB_AUDIOS ) {
879                         DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
880                         return -EINVAL;
881                 }
882
883                 DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
884
885                 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
886                 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
887
888                 return 0;
889         }
890         case MXB_S_AUDIO_LINE:
891         {
892                 int i = *(int*)arg;
893
894                 if( i < 0 || i >= MXB_AUDIOS ) {
895                         DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
896                         return -EINVAL;
897                 }
898
899                 DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
900                 mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
901                 mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
902
903                 return 0;
904         }
905         case VIDIOC_G_AUDIO:
906         {
907                 struct v4l2_audio *a = arg;
908
909                 if( a->index < 0 || a->index > MXB_INPUTS ) {
910                         DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
911                         return -EINVAL;
912                 }
913
914                 DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
915                 memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
916
917                 return 0;
918         }
919         case VIDIOC_S_AUDIO:
920         {
921                 struct v4l2_audio *a = arg;
922                 DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
923                 return 0;
924         }
925         default:
926 /*
927                 DEB2(printk("does not handle this ioctl.\n"));
928 */
929                 return -ENOIOCTLCMD;
930         }
931         return 0;
932 }
933
934 static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
935 {
936         struct mxb *mxb = (struct mxb *)dev->ext_priv;
937         int zero = 0;
938         int one = 1;
939
940         if (V4L2_STD_PAL_I == standard->id) {
941                 v4l2_std_id std = V4L2_STD_PAL_I;
942
943                 DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
944                 /* set the 7146 gpio register -- I don't know what this does exactly */
945                 saa7146_write(dev, GPIO_CTRL, 0x00404050);
946                 /* unset the 7111 gpio register -- I don't know what this does exactly */
947                 mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero);
948                 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
949         } else {
950                 v4l2_std_id std = V4L2_STD_PAL_BG;
951
952                 DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
953                 /* set the 7146 gpio register -- I don't know what this does exactly */
954                 saa7146_write(dev, GPIO_CTRL, 0x00404050);
955                 /* set the 7111 gpio register -- I don't know what this does exactly */
956                 mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one);
957                 mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
958         }
959         return 0;
960 }
961
962 static struct saa7146_standard standard[] = {
963         {
964                 .name   = "PAL-BG",     .id     = V4L2_STD_PAL_BG,
965                 .v_offset       = 0x17, .v_field        = 288,
966                 .h_offset       = 0x14, .h_pixels       = 680,
967                 .v_max_out      = 576,  .h_max_out      = 768,
968         }, {
969                 .name   = "PAL-I",      .id     = V4L2_STD_PAL_I,
970                 .v_offset       = 0x17, .v_field        = 288,
971                 .h_offset       = 0x14, .h_pixels       = 680,
972                 .v_max_out      = 576,  .h_max_out      = 768,
973         }, {
974                 .name   = "NTSC",       .id     = V4L2_STD_NTSC,
975                 .v_offset       = 0x16, .v_field        = 240,
976                 .h_offset       = 0x06, .h_pixels       = 708,
977                 .v_max_out      = 480,  .h_max_out      = 640,
978         }, {
979                 .name   = "SECAM",      .id     = V4L2_STD_SECAM,
980                 .v_offset       = 0x14, .v_field        = 288,
981                 .h_offset       = 0x14, .h_pixels       = 720,
982                 .v_max_out      = 576,  .h_max_out      = 768,
983         }
984 };
985
986 static struct saa7146_pci_extension_data mxb = {
987         .ext_priv = "Multimedia eXtension Board",
988         .ext = &extension,
989 };
990
991 static struct pci_device_id pci_tbl[] = {
992         {
993                 .vendor    = PCI_VENDOR_ID_PHILIPS,
994                 .device    = PCI_DEVICE_ID_PHILIPS_SAA7146,
995                 .subvendor = 0x0000,
996                 .subdevice = 0x0000,
997                 .driver_data = (unsigned long)&mxb,
998         }, {
999                 .vendor = 0,
1000         }
1001 };
1002
1003 MODULE_DEVICE_TABLE(pci, pci_tbl);
1004
1005 static struct saa7146_ext_vv vv_data = {
1006         .inputs         = MXB_INPUTS,
1007         .capabilities   = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
1008         .stds           = &standard[0],
1009         .num_stds       = sizeof(standard)/sizeof(struct saa7146_standard),
1010         .std_callback   = &std_callback,
1011         .ioctls         = &ioctls[0],
1012         .ioctl          = mxb_ioctl,
1013 };
1014
1015 static struct saa7146_extension extension = {
1016         .name           = MXB_IDENTIFIER,
1017         .flags          = SAA7146_USE_I2C_IRQ,
1018
1019         .pci_tbl        = &pci_tbl[0],
1020         .module         = THIS_MODULE,
1021
1022         .probe          = mxb_probe,
1023         .attach         = mxb_attach,
1024         .detach         = mxb_detach,
1025
1026         .irq_mask       = 0,
1027         .irq_func       = NULL,
1028 };
1029
1030 static int __init mxb_init_module(void)
1031 {
1032         if( 0 != saa7146_register_extension(&extension)) {
1033                 DEB_S(("failed to register extension.\n"));
1034                 return -ENODEV;
1035         }
1036
1037         return 0;
1038 }
1039
1040 static void __exit mxb_cleanup_module(void)
1041 {
1042         saa7146_unregister_extension(&extension);
1043 }
1044
1045 module_init(mxb_init_module);
1046 module_exit(mxb_cleanup_module);
1047
1048 MODULE_DESCRIPTION("video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board'");
1049 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
1050 MODULE_LICENSE("GPL");