blob: e64a609cf4ff4825ac119047b3dd7cfddc7d7cdb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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_ca_en50221.h"
42#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070043#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030045#include "lnbp21.h"
46#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030047#include "bsru6.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#define DEBIADDR_IR 0x1234
50#define DEBIADDR_CICONTROL 0x0000
51#define DEBIADDR_CIVERSION 0x4000
52#define DEBIADDR_IO 0x1000
53#define DEBIADDR_ATTR 0x3000
54
55#define CICONTROL_RESET 0x01
56#define CICONTROL_ENABLETS 0x02
57#define CICONTROL_CAMDETECT 0x08
58
59#define DEBICICTL 0x00420000
60#define DEBICICAM 0x02420000
61
62#define SLOTSTATUS_NONE 1
63#define SLOTSTATUS_PRESENT 2
64#define SLOTSTATUS_RESET 4
65#define SLOTSTATUS_READY 8
66#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
67
68struct budget_ci {
69 struct budget budget;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -050070 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 struct tasklet_struct msp430_irq_tasklet;
72 struct tasklet_struct ciintf_irq_tasklet;
73 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -030074 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 struct dvb_ca_en50221 ca;
76 char ir_dev_name[50];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -070077 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
80/* from reading the following remotes:
81 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
82 Hauppauge (from NOVA-CI-s box product)
83 i've taken a "middle of the road" approach and note the differences
84*/
85static u16 key_map[64] = {
86 /* 0x0X */
87 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
88 KEY_9,
89 KEY_ENTER,
90 KEY_RED,
91 KEY_POWER, /* RADIO on Hauppauge */
92 KEY_MUTE,
93 0,
94 KEY_A, /* TV on Hauppauge */
95 /* 0x1X */
96 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
97 0, 0,
98 KEY_B,
99 0, 0, 0, 0, 0, 0, 0,
100 KEY_UP, KEY_DOWN,
101 KEY_OPTION, /* RESERVED on Hauppauge */
102 KEY_BREAK,
103 /* 0x2X */
104 KEY_CHANNELUP, KEY_CHANNELDOWN,
105 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
106 0, KEY_RESTART, KEY_OK,
107 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
108 0,
109 KEY_ENTER, /* VCR mode on Zenith */
110 KEY_PAUSE,
111 0,
112 KEY_RIGHT, KEY_LEFT,
113 0,
114 KEY_MENU, /* FULL SCREEN on Hauppauge */
115 0,
116 /* 0x3X */
117 KEY_SLOW,
118 KEY_PREVIOUS, /* VCR mode on Zenith */
119 KEY_REWIND,
120 0,
121 KEY_FASTFORWARD,
122 KEY_PLAY, KEY_STOP,
123 KEY_RECORD,
124 KEY_TUNER, /* TV/VCR on Zenith */
125 0,
126 KEY_C,
127 0,
128 KEY_EXIT,
129 KEY_POWER2,
130 KEY_TUNER, /* VCR mode on Zenith */
131 0,
132};
133
134static void msp430_ir_debounce(unsigned long data)
135{
136 struct input_dev *dev = (struct input_dev *) data;
137
138 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
139 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
140 return;
141 }
142
143 dev->rep[0] = 0;
144 dev->timer.expires = jiffies + HZ * 350 / 1000;
145 add_timer(&dev->timer);
146 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
147}
148
149static void msp430_ir_interrupt(unsigned long data)
150{
151 struct budget_ci *budget_ci = (struct budget_ci *) data;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500152 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 unsigned int code =
154 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
155
156 if (code & 0x40) {
157 code &= 0x3f;
158
159 if (timer_pending(&dev->timer)) {
160 if (code == dev->repeat_key) {
161 ++dev->rep[0];
162 return;
163 }
164 del_timer(&dev->timer);
165 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
166 }
167
168 if (!key_map[code]) {
169 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
170 return;
171 }
172
173 /* initialize debounce and repeat */
174 dev->repeat_key = code;
175 /* Zenith remote _always_ sends 2 sequences */
176 dev->rep[0] = ~0;
177 /* 350 milliseconds */
178 dev->timer.expires = jiffies + HZ * 350 / 1000;
179 /* MAKE */
180 input_event(dev, EV_KEY, key_map[code], !0);
181 add_timer(&dev->timer);
182 }
183}
184
185static int msp430_ir_init(struct budget_ci *budget_ci)
186{
187 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500188 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 int i;
190
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500191 budget_ci->input_dev = input_dev = input_allocate_device();
192 if (!input_dev)
193 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500197 input_dev->name = budget_ci->ir_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500199 set_bit(EV_KEY, input_dev->evbit);
200 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500202 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500204 input_register_device(budget_ci->input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500206 input_dev->timer.function = msp430_ir_debounce;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
210
211 return 0;
212}
213
214static void msp430_ir_deinit(struct budget_ci *budget_ci)
215{
216 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500217 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
220 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
221
222 if (del_timer(&dev->timer))
223 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
224
225 input_unregister_device(dev);
226}
227
228static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
229{
230 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
231
232 if (slot != 0)
233 return -EINVAL;
234
235 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
236 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
237}
238
239static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
240{
241 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
242
243 if (slot != 0)
244 return -EINVAL;
245
246 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
247 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
248}
249
250static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
251{
252 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
253
254 if (slot != 0)
255 return -EINVAL;
256
257 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
258 DEBIADDR_IO | (address & 3), 1, 1, 0);
259}
260
261static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
262{
263 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
264
265 if (slot != 0)
266 return -EINVAL;
267
268 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
269 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
270}
271
272static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
273{
274 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
275 struct saa7146_dev *saa = budget_ci->budget.dev;
276
277 if (slot != 0)
278 return -EINVAL;
279
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300280 if (budget_ci->ci_irq) {
281 // trigger on RISING edge during reset so we know when READY is re-asserted
282 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 budget_ci->slot_status = SLOTSTATUS_RESET;
285 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
286 msleep(1);
287 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
288 CICONTROL_RESET, 1, 0);
289
290 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
291 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
292 return 0;
293}
294
295static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
296{
297 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
298 struct saa7146_dev *saa = budget_ci->budget.dev;
299
300 if (slot != 0)
301 return -EINVAL;
302
303 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
304 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
305 return 0;
306}
307
308static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
309{
310 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
311 struct saa7146_dev *saa = budget_ci->budget.dev;
312 int tmp;
313
314 if (slot != 0)
315 return -EINVAL;
316
317 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
318
319 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
320 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
321 tmp | CICONTROL_ENABLETS, 1, 0);
322
323 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
324 return 0;
325}
326
327static void ciintf_interrupt(unsigned long data)
328{
329 struct budget_ci *budget_ci = (struct budget_ci *) data;
330 struct saa7146_dev *saa = budget_ci->budget.dev;
331 unsigned int flags;
332
333 // ensure we don't get spurious IRQs during initialisation
334 if (!budget_ci->budget.ci_present)
335 return;
336
337 // read the CAM status
338 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
339 if (flags & CICONTROL_CAMDETECT) {
340
341 // GPIO should be set to trigger on falling edge if a CAM is present
342 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
343
344 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
345 // CAM insertion IRQ
346 budget_ci->slot_status = SLOTSTATUS_PRESENT;
347 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
348 DVB_CA_EN50221_CAMCHANGE_INSERTED);
349
350 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
351 // CAM ready (reset completed)
352 budget_ci->slot_status = SLOTSTATUS_READY;
353 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
354
355 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
356 // FR/DA IRQ
357 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
358 }
359 } else {
360
361 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
362 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
363 // the CAM might not actually be ready yet.
364 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
365
366 // generate a CAM removal IRQ if we haven't already
367 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
368 // CAM removal IRQ
369 budget_ci->slot_status = SLOTSTATUS_NONE;
370 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
371 DVB_CA_EN50221_CAMCHANGE_REMOVED);
372 }
373 }
374}
375
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300376static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
377{
378 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
379 unsigned int flags;
380
381 // ensure we don't get spurious IRQs during initialisation
382 if (!budget_ci->budget.ci_present)
383 return -EINVAL;
384
385 // read the CAM status
386 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
387 if (flags & CICONTROL_CAMDETECT) {
388 // mark it as present if it wasn't before
389 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
390 budget_ci->slot_status = SLOTSTATUS_PRESENT;
391 }
392
393 // during a RESET, we check if we can read from IO memory to see when CAM is ready
394 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
395 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
396 budget_ci->slot_status = SLOTSTATUS_READY;
397 }
398 }
399 } else {
400 budget_ci->slot_status = SLOTSTATUS_NONE;
401 }
402
403 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
404 if (budget_ci->slot_status & SLOTSTATUS_READY) {
405 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
406 }
407 return DVB_CA_EN50221_POLL_CAM_PRESENT;
408 }
409
410 return 0;
411}
412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static int ciintf_init(struct budget_ci *budget_ci)
414{
415 struct saa7146_dev *saa = budget_ci->budget.dev;
416 int flags;
417 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300418 int ci_version;
419 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
422
423 // enable DEBI pins
424 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
425
426 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300427 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
428 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 result = -ENODEV;
430 goto error;
431 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 // determine whether a CAM is present or not
434 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
435 budget_ci->slot_status = SLOTSTATUS_NONE;
436 if (flags & CICONTROL_CAMDETECT)
437 budget_ci->slot_status = SLOTSTATUS_PRESENT;
438
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300439 // version 0xa2 of the CI firmware doesn't generate interrupts
440 if (ci_version == 0xa2) {
441 ca_flags = 0;
442 budget_ci->ci_irq = 0;
443 } else {
444 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
445 DVB_CA_EN50221_FLAG_IRQ_FR |
446 DVB_CA_EN50221_FLAG_IRQ_DA;
447 budget_ci->ci_irq = 1;
448 }
449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 // register CI interface
451 budget_ci->ca.owner = THIS_MODULE;
452 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
453 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
454 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
455 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
456 budget_ci->ca.slot_reset = ciintf_slot_reset;
457 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
458 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300459 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700461 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300463 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 printk("budget_ci: CI interface detected, but initialisation failed.\n");
465 goto error;
466 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300469 if (budget_ci->ci_irq) {
470 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
471 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
472 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
473 } else {
474 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
475 }
476 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300478
479 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
481 CICONTROL_RESET, 1, 0);
482
483 // success!
484 printk("budget_ci: CI interface initialised\n");
485 budget_ci->budget.ci_present = 1;
486
487 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300488 if (budget_ci->ci_irq) {
489 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
490 if (budget_ci->slot_status != SLOTSTATUS_NONE)
491 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
492 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 return 0;
496
497error:
498 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
499 return result;
500}
501
502static void ciintf_deinit(struct budget_ci *budget_ci)
503{
504 struct saa7146_dev *saa = budget_ci->budget.dev;
505
506 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507 if (budget_ci->ci_irq) {
508 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
509 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
510 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
511 }
512
513 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
515 msleep(1);
516 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
517 CICONTROL_RESET, 1, 0);
518
519 // disable TS data stream to CI interface
520 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
521
522 // release the CA device
523 dvb_ca_en50221_release(&budget_ci->ca);
524
525 // disable DEBI pins
526 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
527}
528
529static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
530{
531 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
532
533 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
534
535 if (*isr & MASK_06)
536 tasklet_schedule(&budget_ci->msp430_irq_tasklet);
537
538 if (*isr & MASK_10)
539 ttpci_budget_irq10_handler(dev, isr);
540
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300541 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
543}
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545static u8 philips_su1278_tt_inittab[] = {
546 0x01, 0x0f,
547 0x02, 0x30,
548 0x03, 0x00,
549 0x04, 0x5b,
550 0x05, 0x85,
551 0x06, 0x02,
552 0x07, 0x00,
553 0x08, 0x02,
554 0x09, 0x00,
555 0x0C, 0x01,
556 0x0D, 0x81,
557 0x0E, 0x44,
558 0x0f, 0x14,
559 0x10, 0x3c,
560 0x11, 0x84,
561 0x12, 0xda,
562 0x13, 0x97,
563 0x14, 0x95,
564 0x15, 0xc9,
565 0x16, 0x19,
566 0x17, 0x8c,
567 0x18, 0x59,
568 0x19, 0xf8,
569 0x1a, 0xfe,
570 0x1c, 0x7f,
571 0x1d, 0x00,
572 0x1e, 0x00,
573 0x1f, 0x50,
574 0x20, 0x00,
575 0x21, 0x00,
576 0x22, 0x00,
577 0x23, 0x00,
578 0x28, 0x00,
579 0x29, 0x28,
580 0x2a, 0x14,
581 0x2b, 0x0f,
582 0x2c, 0x09,
583 0x2d, 0x09,
584 0x31, 0x1f,
585 0x32, 0x19,
586 0x33, 0xfc,
587 0x34, 0x93,
588 0xff, 0xff
589};
590
591static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
592{
593 stv0299_writereg(fe, 0x0e, 0x44);
594 if (srate >= 10000000) {
595 stv0299_writereg(fe, 0x13, 0x97);
596 stv0299_writereg(fe, 0x14, 0x95);
597 stv0299_writereg(fe, 0x15, 0xc9);
598 stv0299_writereg(fe, 0x17, 0x8c);
599 stv0299_writereg(fe, 0x1a, 0xfe);
600 stv0299_writereg(fe, 0x1c, 0x7f);
601 stv0299_writereg(fe, 0x2d, 0x09);
602 } else {
603 stv0299_writereg(fe, 0x13, 0x99);
604 stv0299_writereg(fe, 0x14, 0x8d);
605 stv0299_writereg(fe, 0x15, 0xce);
606 stv0299_writereg(fe, 0x17, 0x43);
607 stv0299_writereg(fe, 0x1a, 0x1d);
608 stv0299_writereg(fe, 0x1c, 0x12);
609 stv0299_writereg(fe, 0x2d, 0x05);
610 }
611 stv0299_writereg(fe, 0x0e, 0x23);
612 stv0299_writereg(fe, 0x0f, 0x94);
613 stv0299_writereg(fe, 0x10, 0x39);
614 stv0299_writereg(fe, 0x15, 0xc9);
615
616 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
617 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
618 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
619
620 return 0;
621}
622
623static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700624 struct i2c_adapter *i2c,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 struct dvb_frontend_parameters *params)
626{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 u32 div;
628 u8 buf[4];
629 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
630
631 if ((params->frequency < 950000) || (params->frequency > 2150000))
632 return -EINVAL;
633
634 div = (params->frequency + (500 - 1)) / 500; // round correctly
635 buf[0] = (div >> 8) & 0x7f;
636 buf[1] = div & 0xff;
637 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
638 buf[3] = 0x20;
639
640 if (params->u.qpsk.symbol_rate < 4000000)
641 buf[3] |= 1;
642
643 if (params->frequency < 1250000)
644 buf[3] |= 0;
645 else if (params->frequency < 1550000)
646 buf[3] |= 0x40;
647 else if (params->frequency < 2050000)
648 buf[3] |= 0x80;
649 else if (params->frequency < 2150000)
650 buf[3] |= 0xC0;
651
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700652 if (i2c_transfer(i2c, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 return -EIO;
654 return 0;
655}
656
657static struct stv0299_config philips_su1278_tt_config = {
658
659 .demod_address = 0x68,
660 .inittab = philips_su1278_tt_inittab,
661 .mclk = 64000000UL,
662 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 .skip_reinit = 1,
664 .lock_output = STV0229_LOCKOUTPUT_1,
665 .volt13_op0_op1 = STV0299_VOLT13_OP1,
666 .min_delay_ms = 50,
667 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
668 .pll_set = philips_su1278_tt_pll_set,
669};
670
671
672
673static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
674{
675 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
676 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
677 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700678 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 sizeof(td1316_init) };
680
681 // setup PLL configuration
682 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
683 return -EIO;
684 msleep(1);
685
686 // disable the mc44BC374c (do not check for errors)
687 tuner_msg.addr = 0x65;
688 tuner_msg.buf = disable_mc44BC374c;
689 tuner_msg.len = sizeof(disable_mc44BC374c);
690 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
691 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
692 }
693
694 return 0;
695}
696
697static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
698{
699 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
700 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700701 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 int tuner_frequency = 0;
703 u8 band, cp, filter;
704
705 // determine charge pump
706 tuner_frequency = params->frequency + 36130000;
707 if (tuner_frequency < 87000000)
708 return -EINVAL;
709 else if (tuner_frequency < 130000000)
710 cp = 3;
711 else if (tuner_frequency < 160000000)
712 cp = 5;
713 else if (tuner_frequency < 200000000)
714 cp = 6;
715 else if (tuner_frequency < 290000000)
716 cp = 3;
717 else if (tuner_frequency < 420000000)
718 cp = 5;
719 else if (tuner_frequency < 480000000)
720 cp = 6;
721 else if (tuner_frequency < 620000000)
722 cp = 3;
723 else if (tuner_frequency < 830000000)
724 cp = 5;
725 else if (tuner_frequency < 895000000)
726 cp = 7;
727 else
728 return -EINVAL;
729
730 // determine band
731 if (params->frequency < 49000000)
732 return -EINVAL;
733 else if (params->frequency < 159000000)
734 band = 1;
735 else if (params->frequency < 444000000)
736 band = 2;
737 else if (params->frequency < 861000000)
738 band = 4;
739 else
740 return -EINVAL;
741
742 // setup PLL filter and TDA9889
743 switch (params->u.ofdm.bandwidth) {
744 case BANDWIDTH_6_MHZ:
745 tda1004x_write_byte(fe, 0x0C, 0x14);
746 filter = 0;
747 break;
748
749 case BANDWIDTH_7_MHZ:
750 tda1004x_write_byte(fe, 0x0C, 0x80);
751 filter = 0;
752 break;
753
754 case BANDWIDTH_8_MHZ:
755 tda1004x_write_byte(fe, 0x0C, 0x14);
756 filter = 1;
757 break;
758
759 default:
760 return -EINVAL;
761 }
762
763 // calculate divisor
764 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
765 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
766
767 // setup tuner buffer
768 tuner_buf[0] = tuner_frequency >> 8;
769 tuner_buf[1] = tuner_frequency & 0xff;
770 tuner_buf[2] = 0xca;
771 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
772
773 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
774 return -EIO;
775
776 msleep(1);
777 return 0;
778}
779
780static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
781 const struct firmware **fw, char *name)
782{
783 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
784
785 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
786}
787
788static struct tda1004x_config philips_tdm1316l_config = {
789
790 .demod_address = 0x8,
791 .invert = 0,
792 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700793 .xtal_freq = TDA10046_XTAL_4M,
794 .agc_config = TDA10046_AGC_DEFAULT,
795 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 .pll_init = philips_tdm1316l_pll_init,
797 .pll_set = philips_tdm1316l_pll_set,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700798 .pll_sleep = NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 .request_firmware = philips_tdm1316l_request_firmware,
800};
801
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700802static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
803{
804 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
805 u8 tuner_buf[5];
806 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
807 .flags = 0,
808 .buf = tuner_buf,
809 .len = sizeof(tuner_buf) };
810 int tuner_frequency = 0;
811 u8 band, cp, filter;
812
813 // determine charge pump
814 tuner_frequency = params->frequency + 36125000;
815 if (tuner_frequency < 87000000)
816 return -EINVAL;
817 else if (tuner_frequency < 130000000) {
818 cp = 3;
819 band = 1;
820 } else if (tuner_frequency < 160000000) {
821 cp = 5;
822 band = 1;
823 } else if (tuner_frequency < 200000000) {
824 cp = 6;
825 band = 1;
826 } else if (tuner_frequency < 290000000) {
827 cp = 3;
828 band = 2;
829 } else if (tuner_frequency < 420000000) {
830 cp = 5;
831 band = 2;
832 } else if (tuner_frequency < 480000000) {
833 cp = 6;
834 band = 2;
835 } else if (tuner_frequency < 620000000) {
836 cp = 3;
837 band = 4;
838 } else if (tuner_frequency < 830000000) {
839 cp = 5;
840 band = 4;
841 } else if (tuner_frequency < 895000000) {
842 cp = 7;
843 band = 4;
844 } else
845 return -EINVAL;
846
847 // assume PLL filter should always be 8MHz for the moment.
848 filter = 1;
849
850 // calculate divisor
851 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
852
853 // setup tuner buffer
854 tuner_buf[0] = tuner_frequency >> 8;
855 tuner_buf[1] = tuner_frequency & 0xff;
856 tuner_buf[2] = 0xc8;
857 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
858 tuner_buf[4] = 0x80;
859
860 stv0297_enable_plli2c(fe);
861 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
862 return -EIO;
863
864 msleep(50);
865
866 stv0297_enable_plli2c(fe);
867 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
868 return -EIO;
869
870 msleep(1);
871
872 return 0;
873}
874
875static u8 dvbc_philips_tdm1316l_inittab[] = {
876 0x80, 0x01,
877 0x80, 0x00,
878 0x81, 0x01,
879 0x81, 0x00,
880 0x00, 0x09,
881 0x01, 0x69,
882 0x03, 0x00,
883 0x04, 0x00,
884 0x07, 0x00,
885 0x08, 0x00,
886 0x20, 0x00,
887 0x21, 0x40,
888 0x22, 0x00,
889 0x23, 0x00,
890 0x24, 0x40,
891 0x25, 0x88,
892 0x30, 0xff,
893 0x31, 0x00,
894 0x32, 0xff,
895 0x33, 0x00,
896 0x34, 0x50,
897 0x35, 0x7f,
898 0x36, 0x00,
899 0x37, 0x20,
900 0x38, 0x00,
901 0x40, 0x1c,
902 0x41, 0xff,
903 0x42, 0x29,
904 0x43, 0x20,
905 0x44, 0xff,
906 0x45, 0x00,
907 0x46, 0x00,
908 0x49, 0x04,
909 0x4a, 0x00,
910 0x4b, 0x7b,
911 0x52, 0x30,
912 0x55, 0xae,
913 0x56, 0x47,
914 0x57, 0xe1,
915 0x58, 0x3a,
916 0x5a, 0x1e,
917 0x5b, 0x34,
918 0x60, 0x00,
919 0x63, 0x00,
920 0x64, 0x00,
921 0x65, 0x00,
922 0x66, 0x00,
923 0x67, 0x00,
924 0x68, 0x00,
925 0x69, 0x00,
926 0x6a, 0x02,
927 0x6b, 0x00,
928 0x70, 0xff,
929 0x71, 0x00,
930 0x72, 0x00,
931 0x73, 0x00,
932 0x74, 0x0c,
933 0x80, 0x00,
934 0x81, 0x00,
935 0x82, 0x00,
936 0x83, 0x00,
937 0x84, 0x04,
938 0x85, 0x80,
939 0x86, 0x24,
940 0x87, 0x78,
941 0x88, 0x10,
942 0x89, 0x00,
943 0x90, 0x01,
944 0x91, 0x01,
945 0xa0, 0x04,
946 0xa1, 0x00,
947 0xa2, 0x00,
948 0xb0, 0x91,
949 0xb1, 0x0b,
950 0xc0, 0x53,
951 0xc1, 0x70,
952 0xc2, 0x12,
953 0xd0, 0x00,
954 0xd1, 0x00,
955 0xd2, 0x00,
956 0xd3, 0x00,
957 0xd4, 0x00,
958 0xd5, 0x00,
959 0xde, 0x00,
960 0xdf, 0x00,
961 0x61, 0x38,
962 0x62, 0x0a,
963 0x53, 0x13,
964 0x59, 0x08,
965 0xff, 0xff,
966};
967
968static struct stv0297_config dvbc_philips_tdm1316l_config = {
969 .demod_address = 0x1c,
970 .inittab = dvbc_philips_tdm1316l_inittab,
971 .invert = 0,
972 .pll_set = dvbc_philips_tdm1316l_pll_set,
973};
974
975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977
978static void frontend_init(struct budget_ci *budget_ci)
979{
980 switch (budget_ci->budget.dev->pci->subsystem_device) {
981 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
982 budget_ci->budget.dvb_frontend =
983 stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
984 if (budget_ci->budget.dvb_frontend) {
985 break;
986 }
987 break;
988
989 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
990 budget_ci->budget.dvb_frontend =
991 stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
992 if (budget_ci->budget.dvb_frontend) {
993 break;
994 }
995 break;
996
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700997 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
998 budget_ci->tuner_pll_address = 0x61;
999 budget_ci->budget.dvb_frontend =
1000 stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
1001 if (budget_ci->budget.dvb_frontend) {
1002 break;
1003 }
1004 break;
1005
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001007 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 budget_ci->budget.dvb_frontend =
1009 tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
1010 if (budget_ci->budget.dvb_frontend) {
1011 break;
1012 }
1013 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001014
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001015 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001016 budget_ci->tuner_pll_address = 0x60;
1017 budget_ci->budget.dvb_frontend =
1018 tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
1019 if (budget_ci->budget.dvb_frontend) {
1020 break;
1021 }
1022 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001023
1024 case 0x1017: // TT S-1500 PCI
1025 budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
1026 if (budget_ci->budget.dvb_frontend) {
1027 budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
1028 if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
1029 printk("%s: No LNBP21 found!\n", __FUNCTION__);
1030 if (budget_ci->budget.dvb_frontend->ops->release)
1031 budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
1032 budget_ci->budget.dvb_frontend = NULL;
1033 }
1034 }
1035
1036 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
1038
1039 if (budget_ci->budget.dvb_frontend == NULL) {
1040 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1041 budget_ci->budget.dev->pci->vendor,
1042 budget_ci->budget.dev->pci->device,
1043 budget_ci->budget.dev->pci->subsystem_vendor,
1044 budget_ci->budget.dev->pci->subsystem_device);
1045 } else {
1046 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001047 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 printk("budget-ci: Frontend registration failed!\n");
1049 if (budget_ci->budget.dvb_frontend->ops->release)
1050 budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
1051 budget_ci->budget.dvb_frontend = NULL;
1052 }
1053 }
1054}
1055
1056static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1057{
1058 struct budget_ci *budget_ci;
1059 int err;
1060
1061 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1062 return -ENOMEM;
1063
1064 dprintk(2, "budget_ci: %p\n", budget_ci);
1065
1066 budget_ci->budget.ci_present = 0;
1067
1068 dev->ext_priv = budget_ci;
1069
1070 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1071 kfree(budget_ci);
1072 return err;
1073 }
1074
1075 tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
1076 (unsigned long) budget_ci);
1077
1078 msp430_ir_init(budget_ci);
1079
1080 ciintf_init(budget_ci);
1081
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001082 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 frontend_init(budget_ci);
1084
1085 return 0;
1086}
1087
1088static int budget_ci_detach(struct saa7146_dev *dev)
1089{
1090 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1091 struct saa7146_dev *saa = budget_ci->budget.dev;
1092 int err;
1093
1094 if (budget_ci->budget.ci_present)
1095 ciintf_deinit(budget_ci);
1096 if (budget_ci->budget.dvb_frontend)
1097 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
1098 err = ttpci_budget_deinit(&budget_ci->budget);
1099
1100 tasklet_kill(&budget_ci->msp430_irq_tasklet);
1101
1102 msp430_ir_deinit(budget_ci);
1103
1104 // disable frontend and CI interface
1105 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1106
1107 kfree(budget_ci);
1108
1109 return err;
1110}
1111
1112static struct saa7146_extension budget_extension;
1113
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001114MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1116MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001117MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001118MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120static struct pci_device_id pci_tbl[] = {
1121 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1122 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001123 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001125 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001126 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 {
1128 .vendor = 0,
1129 }
1130};
1131
1132MODULE_DEVICE_TABLE(pci, pci_tbl);
1133
1134static struct saa7146_extension budget_extension = {
1135 .name = "budget_ci dvb\0",
Oliver Endriss69459f3d2005-12-01 00:51:48 -08001136 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 .module = THIS_MODULE,
1139 .pci_tbl = &pci_tbl[0],
1140 .attach = budget_ci_attach,
1141 .detach = budget_ci_detach,
1142
1143 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1144 .irq_func = budget_ci_irq,
1145};
1146
1147static int __init budget_ci_init(void)
1148{
1149 return saa7146_register_extension(&budget_extension);
1150}
1151
1152static void __exit budget_ci_exit(void)
1153{
1154 saa7146_unregister_extension(&budget_extension);
1155}
1156
1157module_init(budget_ci_init);
1158module_exit(budget_ci_exit);
1159
1160MODULE_LICENSE("GPL");
1161MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1162MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1163 "budget PCI DVB cards w/ CI-module produced by "
1164 "Siemens, Technotrend, Hauppauge");