ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / media / dvb / ttpci / budget-ci.c
1 /*
2  * budget-ci.c: driver for the SAA7146 based Budget DVB cards 
3  *
4  * Compiled from various sources by Michael Hunold <michael@mihu.de> 
5  *
6  *     msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7  *     partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8  *
9  * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27  * 
28  *
29  * the project's page is at http://www.linuxtv.org/dvb/
30  */
31
32 #include "budget.h"
33
34 #include <linux/module.h>
35 #include <linux/errno.h>
36 #include <linux/slab.h>
37 #include <linux/interrupt.h>
38 #include <linux/input.h>
39 #include <linux/spinlock.h>
40
41 #include "dvb_functions.h"
42 #include "dvb_ca_en50221.h"
43
44 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
45 #include "input_fake.h"
46 #endif
47
48 #define DEBIADDR_IR             0x1234
49 #define DEBIADDR_CICONTROL      0x0000
50 #define DEBIADDR_CIVERSION      0x4000
51 #define DEBIADDR_IO             0x1000
52 #define DEBIADDR_ATTR           0x3000
53
54 #define CICONTROL_RESET         0x01
55 #define CICONTROL_ENABLETS      0x02
56 #define CICONTROL_CAMDETECT     0x08
57
58 #define DEBICICTL               0x00420000
59 #define DEBICICAM               0x02420000
60
61 #define SLOTSTATUS_NONE         1
62 #define SLOTSTATUS_PRESENT      2
63 #define SLOTSTATUS_RESET        4
64 #define SLOTSTATUS_READY        8
65 #define SLOTSTATUS_OCCUPIED     (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
66
67 struct budget_ci {
68         struct budget budget;
69         struct input_dev input_dev;
70         struct tasklet_struct msp430_irq_tasklet;
71         struct tasklet_struct ciintf_irq_tasklet;
72         spinlock_t debilock;
73         int slot_status;
74         struct dvb_ca_en50221 ca;
75         char ir_dev_name[50];
76 };
77
78 static u32 budget_debiread (struct budget_ci* budget_ci, u32 config, int addr, int count)
79 {
80         struct saa7146_dev *saa = budget_ci->budget.dev;
81         u32 result = 0;
82
83         if (count > 4 || count <= 0)
84                 return 0;
85
86         spin_lock(&budget_ci->debilock);
87
88         if (saa7146_wait_for_debi_done(saa) < 0) {
89                 spin_unlock(&budget_ci->debilock);
90                 return 0;
91         }
92
93         saa7146_write (saa, DEBI_COMMAND,
94                        (count << 17) | 0x10000 | (addr & 0xffff));
95         saa7146_write(saa, DEBI_CONFIG, config);
96         saa7146_write(saa, DEBI_PAGE, 0);
97         saa7146_write(saa, MC2, (2 << 16) | 2);
98
99         saa7146_wait_for_debi_done(saa);
100
101         result = saa7146_read(saa, 0x88);
102         result &= (0xffffffffUL >> ((4 - count) * 8));
103
104         spin_unlock(&budget_ci->debilock);
105         return result;
106 }
107
108 static u8 budget_debiwrite (struct budget_ci* budget_ci, u32 config, int addr, int count, u32 value)
109 {
110         struct saa7146_dev *saa = budget_ci->budget.dev;
111
112         if (count > 4 || count <= 0)
113                 return 0;
114
115         spin_lock(&budget_ci->debilock);
116
117         if (saa7146_wait_for_debi_done(saa) < 0) {
118                 spin_unlock(&budget_ci->debilock);
119                 return 0;
120         }
121
122         saa7146_write (saa, DEBI_COMMAND,
123                        (count << 17) | 0x00000 | (addr & 0xffff));
124         saa7146_write(saa, DEBI_CONFIG, config);
125         saa7146_write(saa, DEBI_PAGE, 0);
126         saa7146_write(saa, DEBI_AD, value);
127         saa7146_write(saa, MC2, (2 << 16) | 2);
128
129         saa7146_wait_for_debi_done(saa);
130
131         spin_unlock(&budget_ci->debilock);
132         return 0;
133 }
134
135
136 /* from reading the following remotes:
137    Zenith Universal 7 / TV Mode 807 / VCR Mode 837
138    Hauppauge (from NOVA-CI-s box product)
139    i've taken a "middle of the road" approach and note the differences
140 */
141 static  u16 key_map[64] = {
142         /* 0x0X */
143         KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
144         KEY_9,
145         KEY_ENTER,
146         KEY_RED,
147         KEY_POWER,              /* RADIO on Hauppauge */
148         KEY_MUTE,
149         0,
150         KEY_A,                  /* TV on Hauppauge */
151         /* 0x1X */
152         KEY_VOLUMEUP, KEY_VOLUMEDOWN,
153         0, 0,
154         KEY_B,
155         0, 0, 0, 0, 0, 0, 0,
156         KEY_UP, KEY_DOWN,
157         KEY_OPTION,             /* RESERVED on Hauppauge */
158         KEY_BREAK,
159         /* 0x2X */
160         KEY_CHANNELUP, KEY_CHANNELDOWN,
161         KEY_PREVIOUS,           /* Prev. Ch on Zenith, SOURCE on Hauppauge */
162         0, KEY_RESTART, KEY_OK,
163         KEY_CYCLEWINDOWS,       /* MINIMIZE on Hauppauge */
164         0,
165         KEY_ENTER,              /* VCR mode on Zenith */
166         KEY_PAUSE,
167         0,
168         KEY_RIGHT, KEY_LEFT,
169         0,
170         KEY_MENU,               /* FULL SCREEN on Hauppauge */
171         0,
172         /* 0x3X */
173         KEY_SLOW,
174         KEY_PREVIOUS,           /* VCR mode on Zenith */
175         KEY_REWIND,
176         0,
177         KEY_FASTFORWARD,
178         KEY_PLAY, KEY_STOP,
179         KEY_RECORD,
180         KEY_TUNER,              /* TV/VCR on Zenith */
181         0,
182         KEY_C,
183         0,
184         KEY_EXIT,
185         KEY_POWER2,
186         KEY_TUNER,              /* VCR mode on Zenith */
187         0,
188 };
189
190
191 static void msp430_ir_debounce (unsigned long data)
192 {
193         struct input_dev *dev = (struct input_dev *) data;
194
195         if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
196                 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
197                 return;
198         }
199
200         dev->rep[0] = 0;
201         dev->timer.expires = jiffies + HZ * 350 / 1000;
202         add_timer(&dev->timer);
203         input_event(dev, EV_KEY, key_map[dev->repeat_key], 2);  /* REPEAT */
204 }
205
206
207
208 static void msp430_ir_interrupt (unsigned long data)
209 {
210         struct budget_ci *budget_ci = (struct budget_ci*) data;
211         struct input_dev *dev = &budget_ci->input_dev;
212         unsigned int code = budget_debiread(budget_ci, DEBINOSWAP, DEBIADDR_IR, 2) >> 8;
213
214         if (code & 0x40) {
215                 code &= 0x3f;
216
217                 if (timer_pending(&dev->timer)) {
218                         if (code == dev->repeat_key) {
219                                 ++dev->rep[0];
220                                 return;
221                         }
222                         del_timer(&dev->timer);
223                         input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
224                 }
225
226                 if (!key_map[code]) {
227                         printk ("DVB (%s): no key for %02x!\n",
228                                 __FUNCTION__, code);
229                         return;
230                 }
231
232                 /* initialize debounce and repeat */
233                 dev->repeat_key = code;
234                 /* Zenith remote _always_ sends 2 sequences */
235                 dev->rep[0] = ~0;
236                 /* 350 milliseconds */
237                 dev->timer.expires = jiffies + HZ * 350 / 1000;
238                 /* MAKE */
239                 input_event(dev, EV_KEY, key_map[code], !0);
240                 add_timer(&dev->timer);
241         }
242 }
243
244
245 static int msp430_ir_init (struct budget_ci *budget_ci)
246 {
247         struct saa7146_dev *saa = budget_ci->budget.dev;
248         int i;
249
250         memset(&budget_ci->input_dev, 0, sizeof(struct input_dev));
251
252         sprintf (budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
253         budget_ci->input_dev.name = budget_ci->ir_dev_name;
254
255         set_bit(EV_KEY, budget_ci->input_dev.evbit);
256
257         for (i=0; i<sizeof(key_map)/sizeof(*key_map); i++)
258                 if (key_map[i])
259                         set_bit(key_map[i], budget_ci->input_dev.keybit);
260
261         input_register_device(&budget_ci->input_dev);
262
263         budget_ci->input_dev.timer.function = msp430_ir_debounce;
264
265         saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
266
267         saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); 
268
269         return 0;
270 }
271
272
273 static void msp430_ir_deinit (struct budget_ci *budget_ci)
274 {
275         struct saa7146_dev *saa = budget_ci->budget.dev;
276         struct input_dev *dev = &budget_ci->input_dev;
277
278         saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
279         saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
280
281         if (del_timer(&dev->timer))
282                 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
283
284         input_unregister_device(dev);
285 }
286
287 static int ciintf_read_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address) {
288         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
289
290         if (slot != 0) return -EINVAL;
291
292         return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1);
293 }
294
295 static int ciintf_write_attribute_mem(struct dvb_ca_en50221* ca, int slot, int address, u8 value) {
296         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
297
298         if (slot != 0) return -EINVAL;
299
300         return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_ATTR | (address & 0xfff), 1, value);
301 }
302
303 static int ciintf_read_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address) {
304         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
305
306         if (slot != 0) return -EINVAL;
307
308         return budget_debiread(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1);
309 }
310
311 static int ciintf_write_cam_control(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value) {
312         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
313
314         if (slot != 0) return -EINVAL;
315
316         return budget_debiwrite(budget_ci, DEBICICAM, DEBIADDR_IO | (address & 3), 1, value);
317 }
318
319 static int ciintf_slot_reset(struct dvb_ca_en50221* ca, int slot) {
320         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
321         struct saa7146_dev *saa = budget_ci->budget.dev;
322
323         if (slot != 0) return -EINVAL;
324
325         // trigger on RISING edge during reset so we know when READY is re-asserted
326         saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
327         budget_ci->slot_status = SLOTSTATUS_RESET;
328         budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
329         dvb_delay(1);
330         budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
331
332         saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
333         ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
334         return 0;
335 }
336
337 static int ciintf_slot_shutdown(struct dvb_ca_en50221* ca, int slot) {
338         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
339         struct saa7146_dev *saa = budget_ci->budget.dev;
340
341         if (slot != 0) return -EINVAL;
342
343         saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
344         ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
345         return 0;
346 }
347
348 static int ciintf_slot_ts_enable(struct dvb_ca_en50221* ca, int slot) {
349         struct budget_ci* budget_ci = (struct budget_ci*) ca->data;
350         struct saa7146_dev *saa = budget_ci->budget.dev;
351         int tmp;
352
353         if (slot != 0) return -EINVAL;
354
355
356         saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
357
358         tmp = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
359         budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, tmp | CICONTROL_ENABLETS);
360
361         ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
362         return 0;
363 }
364
365
366 static void ciintf_interrupt (unsigned long data)
367 {
368         struct budget_ci *budget_ci = (struct budget_ci*) data;
369         struct saa7146_dev *saa = budget_ci->budget.dev;
370         unsigned int flags;
371
372         // ensure we don't get spurious IRQs during initialisation
373         if (!budget_ci->budget.ci_present) return;
374
375         flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
376
377         // always set the GPIO mode back to "normal", in case the card is
378         // yanked at an inopportune moment
379         saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
380
381         if (flags & CICONTROL_CAMDETECT) {
382
383                 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
384                         // CAM insertion IRQ
385                         budget_ci->slot_status = SLOTSTATUS_PRESENT;
386                         dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_INSERTED);
387
388                 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
389                         // CAM ready (reset completed)
390                         budget_ci->slot_status = SLOTSTATUS_READY;
391                         dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
392
393                 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
394                         // FR/DA IRQ
395                         dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
396                 }
397         } else {
398                 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
399                         budget_ci->slot_status = SLOTSTATUS_NONE;
400                         dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, DVB_CA_EN50221_CAMCHANGE_REMOVED);
401                 }
402         }
403 }
404
405 static int ciintf_init(struct budget_ci* budget_ci)
406 {
407         struct saa7146_dev *saa = budget_ci->budget.dev;
408         int flags;
409         int result;
410
411         memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
412
413         // enable DEBI pins
414         saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
415
416         // test if it is there
417         if ((budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CIVERSION, 1) & 0xa0) != 0xa0) {
418                 result = -ENODEV;
419                 goto error;
420         }
421
422         // determine whether a CAM is present or not
423         flags = budget_debiread(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1);
424         budget_ci->slot_status = SLOTSTATUS_NONE;
425         if (flags & CICONTROL_CAMDETECT) budget_ci->slot_status = SLOTSTATUS_PRESENT;
426
427
428         // register CI interface
429         budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
430         budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
431         budget_ci->ca.read_cam_control = ciintf_read_cam_control;
432         budget_ci->ca.write_cam_control = ciintf_write_cam_control;
433         budget_ci->ca.slot_reset = ciintf_slot_reset;
434         budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
435         budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
436         budget_ci->ca.data = budget_ci;
437         if ((result = dvb_ca_en50221_init(budget_ci->budget.dvb_adapter,
438                                           &budget_ci->ca,
439                                           DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
440                                           DVB_CA_EN50221_FLAG_IRQ_FR |
441                                           DVB_CA_EN50221_FLAG_IRQ_DA,
442                                   1)) != 0) {
443                 printk("budget_ci: CI interface detected, but initialisation failed.\n");
444                 goto error;
445         }
446
447         // Setup CI slot IRQ
448         tasklet_init (&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
449         saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
450         saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
451         budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
452
453         // success!
454         printk("budget_ci: CI interface initialised\n");
455         budget_ci->budget.ci_present = 1;
456
457         // forge a fake CI IRQ so the CAM state is setup correctly
458         flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
459         if (budget_ci->slot_status != SLOTSTATUS_NONE) flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
460         dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
461
462         return 0;
463
464 error:
465         saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
466         return result;
467 }
468
469 static void ciintf_deinit(struct budget_ci* budget_ci)
470 {
471         struct saa7146_dev *saa = budget_ci->budget.dev;
472
473         // disable CI interrupts
474         saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
475         saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
476         tasklet_kill(&budget_ci->ciintf_irq_tasklet);
477         budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, 0);
478         dvb_delay(1);
479         budget_debiwrite(budget_ci, DEBICICTL, DEBIADDR_CICONTROL, 1, CICONTROL_RESET);
480
481         // disable TS data stream to CI interface
482         saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
483
484         // release the CA device
485         dvb_ca_en50221_release(&budget_ci->ca);
486
487         // disable DEBI pins
488         saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
489 }
490
491 static void budget_ci_irq (struct saa7146_dev *dev, u32 *isr)
492 {
493         struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv;
494
495         DEB_EE(("dev: %p, budget_ci: %p\n", dev, budget_ci));
496
497         if (*isr & MASK_06)
498                 tasklet_schedule (&budget_ci->msp430_irq_tasklet);
499
500         if (*isr & MASK_10)
501                 ttpci_budget_irq10_handler (dev, isr);
502
503         if ((*isr & MASK_03) && (budget_ci->budget.ci_present))
504                 tasklet_schedule (&budget_ci->ciintf_irq_tasklet);
505 }
506
507
508
509 static int budget_ci_attach (struct saa7146_dev* dev,
510                       struct saa7146_pci_extension_data *info)
511 {
512         struct budget_ci *budget_ci;
513         int err;
514
515         if (!(budget_ci = kmalloc (sizeof(struct budget_ci), GFP_KERNEL)))
516                 return -ENOMEM;
517
518         DEB_EE(("budget_ci: %p\n", budget_ci));
519
520         spin_lock_init(&budget_ci->debilock);
521         budget_ci->budget.ci_present = 0;
522
523         if ((err = ttpci_budget_init (&budget_ci->budget, dev, info))) {
524                 kfree (budget_ci);
525                 return err;
526         }
527
528         dev->ext_priv = budget_ci;
529
530         tasklet_init (&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
531                       (unsigned long) budget_ci);
532
533         msp430_ir_init (budget_ci);
534
535         // UNCOMMENT TO TEST CI INTERFACE
536 //      ciintf_init(budget_ci);
537
538         return 0;
539 }
540
541
542
543 static int budget_ci_detach (struct saa7146_dev* dev)
544 {
545         struct budget_ci *budget_ci = (struct budget_ci*) dev->ext_priv;
546         struct saa7146_dev *saa = budget_ci->budget.dev;
547         int err;
548
549         if (budget_ci->budget.ci_present) ciintf_deinit(budget_ci);
550
551         err = ttpci_budget_deinit (&budget_ci->budget);
552
553         tasklet_kill (&budget_ci->msp430_irq_tasklet);
554
555         msp430_ir_deinit (budget_ci);
556
557         // disable frontend and CI interface
558         saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
559
560         kfree (budget_ci);
561
562         return err;
563 }
564
565
566
567 static struct saa7146_extension budget_extension; 
568
569 MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI",  BUDGET_TT_HW_DISEQC);
570 MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T  PCI",  BUDGET_TT);
571
572 static struct pci_device_id pci_tbl[] = {
573         MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
574         MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
575         MAKE_EXTENSION_PCI(ttbt2,  0x13c2, 0x1011),
576         {
577                 .vendor    = 0,
578         }
579 };
580
581 MODULE_DEVICE_TABLE(pci, pci_tbl);
582
583 static struct saa7146_extension budget_extension = {
584         .name           = "budget_ci dvb\0",
585         .flags          = 0,
586
587         .module         = THIS_MODULE,
588         .pci_tbl        = &pci_tbl[0],
589         .attach         = budget_ci_attach,
590         .detach         = budget_ci_detach,
591
592         .irq_mask       = MASK_03 | MASK_06 | MASK_10,
593         .irq_func       = budget_ci_irq,
594 };      
595
596
597 static int __init budget_ci_init(void) 
598 {
599         return saa7146_register_extension(&budget_extension);
600 }
601
602
603 static void __exit budget_ci_exit(void)
604 {
605         DEB_EE((".\n"));
606         saa7146_unregister_extension(&budget_extension); 
607 }
608
609 module_init(budget_ci_init);
610 module_exit(budget_ci_exit);
611
612 MODULE_LICENSE("GPL");
613 MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
614 MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
615                    "budget PCI DVB cards w/ CI-module produced by "
616                    "Siemens, Technotrend, Hauppauge");
617