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