blob: 5552ef5019966958959a2b24a6c353824a94ac05 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
7 *
8 * Copyright (C) 1999-2002 Ralph Metzler
9 * & Marcus Metzler for convergence integrated media GmbH
10 *
11 * 26feb2004 Support for FS Activy Card (Grundig tuner) by
12 * Michael Dreher <michael@5dot1.de>,
13 * Oliver Endriss <o.endriss@gmx.de> and
14 * Andreas 'randy' Weinberger
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
20 *
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
32 *
33 *
34 * the project's page is at http://www.linuxtv.org/dvb/
35 */
36
37#include "budget.h"
38#include "stv0299.h"
39#include "ves1x93.h"
40#include "ves1820.h"
41#include "l64781.h"
42#include "tda8083.h"
Andrew de Quincey96bf2f22005-07-07 17:57:53 -070043#include "s5h1420.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45static void Set22K (struct budget *budget, int state)
46{
47 struct saa7146_dev *dev=budget->dev;
48 dprintk(2, "budget: %p\n", budget);
49 saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
50}
51
52/* Diseqc functions only for TT Budget card */
53/* taken from the Skyvision DVB driver by
54 Ralph Metzler <rjkm@metzlerbros.de> */
55
56static void DiseqcSendBit (struct budget *budget, int data)
57{
58 struct saa7146_dev *dev=budget->dev;
59 dprintk(2, "budget: %p\n", budget);
60
61 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
62 udelay(data ? 500 : 1000);
63 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
64 udelay(data ? 1000 : 500);
65}
66
67static void DiseqcSendByte (struct budget *budget, int data)
68{
69 int i, par=1, d;
70
71 dprintk(2, "budget: %p\n", budget);
72
73 for (i=7; i>=0; i--) {
74 d = (data>>i)&1;
75 par ^= d;
76 DiseqcSendBit(budget, d);
77 }
78
79 DiseqcSendBit(budget, par);
80}
81
82static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
83{
84 struct saa7146_dev *dev=budget->dev;
85 int i;
86
87 dprintk(2, "budget: %p\n", budget);
88
89 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
90 mdelay(16);
91
92 for (i=0; i<len; i++)
93 DiseqcSendByte(budget, msg[i]);
94
95 mdelay(16);
96
97 if (burst!=-1) {
98 if (burst)
99 DiseqcSendByte(budget, 0xff);
100 else {
101 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
102 udelay(12500);
103 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
104 }
105 msleep(20);
106 }
107
108 return 0;
109}
110
111/*
112 * Routines for the Fujitsu Siemens Activy budget card
113 * 22 kHz tone and DiSEqC are handled by the frontend.
114 * Voltage must be set here.
115 */
116static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)
117{
118 struct saa7146_dev *dev=budget->dev;
119
120 dprintk(2, "budget: %p\n", budget);
121
122 switch (voltage) {
123 case SEC_VOLTAGE_13:
124 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);
125 break;
126 case SEC_VOLTAGE_18:
127 saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);
128 break;
129 default:
130 return -EINVAL;
131 }
132
133 return 0;
134}
135
136static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
137{
138 struct budget* budget = (struct budget*) fe->dvb->priv;
139
140 return SetVoltage_Activy (budget, voltage);
141}
142
143static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
144{
145 struct budget* budget = (struct budget*) fe->dvb->priv;
146
147 switch (tone) {
148 case SEC_TONE_ON:
149 Set22K (budget, 1);
150 break;
151
152 case SEC_TONE_OFF:
153 Set22K (budget, 0);
154 break;
155
156 default:
157 return -EINVAL;
158 }
159
160 return 0;
161}
162
163static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
164{
165 struct budget* budget = (struct budget*) fe->dvb->priv;
166
167 SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
168
169 return 0;
170}
171
172static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
173{
174 struct budget* budget = (struct budget*) fe->dvb->priv;
175
176 SendDiSEqCMsg (budget, 0, NULL, minicmd);
177
178 return 0;
179}
180
Andrew de Quincey96bf2f22005-07-07 17:57:53 -0700181static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
182{
183 struct budget* budget = (struct budget*) fe->dvb->priv;
184 u8 buf;
185 struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
186
187 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
188
189 switch(voltage) {
190 case SEC_VOLTAGE_13:
191 buf = (buf & 0xf7) | 0x04;
192 break;
193
194 case SEC_VOLTAGE_18:
195 buf = (buf & 0xf7) | 0x0c;
196 break;
197
198 case SEC_VOLTAGE_OFF:
199 buf = buf & 0xf0;
200 break;
201 }
202
203 msg.flags = 0;
204 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
205
206 return 0;
207}
208
209static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
210{
211 struct budget* budget = (struct budget*) fe->dvb->priv;
212 u8 buf;
213 struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
214
215 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
216
217 if (arg) {
218 buf = buf | 0x10;
219 } else {
220 buf = buf & 0xef;
221 }
222
223 msg.flags = 0;
224 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
225
226 return 0;
227}
228
229static void lnbp21_init(struct budget* budget)
230{
231 u8 buf = 0x00;
232 struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
233
234 i2c_transfer (&budget->i2c_adap, &msg, 1);
235}
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
238{
239 struct budget* budget = (struct budget*) fe->dvb->priv;
240 u8 pwr = 0;
241 u8 buf[4];
242 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
243 u32 div = (params->frequency + 479500) / 125;
244
245 if (params->frequency > 2000000) pwr = 3;
246 else if (params->frequency > 1800000) pwr = 2;
247 else if (params->frequency > 1600000) pwr = 1;
248 else if (params->frequency > 1200000) pwr = 0;
249 else if (params->frequency >= 1100000) pwr = 1;
250 else pwr = 2;
251
252 buf[0] = (div >> 8) & 0x7f;
253 buf[1] = div & 0xff;
254 buf[2] = ((div & 0x18000) >> 10) | 0x95;
255 buf[3] = (pwr << 6) | 0x30;
256
257 // NOTE: since we're using a prescaler of 2, we set the
258 // divisor frequency to 62.5kHz and divide by 125 above
259
260 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
261 return 0;
262}
263
264static struct ves1x93_config alps_bsrv2_config =
265{
266 .demod_address = 0x08,
267 .xin = 90100000UL,
268 .invert_pwm = 0,
269 .pll_set = alps_bsrv2_pll_set,
270};
271
272static u8 alps_bsru6_inittab[] = {
273 0x01, 0x15,
274 0x02, 0x00,
275 0x03, 0x00,
276 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
277 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
278 0x06, 0x40, /* DAC not used, set to high impendance mode */
279 0x07, 0x00, /* DAC LSB */
280 0x08, 0x40, /* DiSEqC off, LNB power on OP2/LOCK pin on */
281 0x09, 0x00, /* FIFO */
282 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
283 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
284 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
285 0x10, 0x3f, // AGC2 0x3d
286 0x11, 0x84,
287 0x12, 0xb5, // Lock detect: -64 Carrier freq detect:on
288 0x15, 0xc9, // lock detector threshold
289 0x16, 0x00,
290 0x17, 0x00,
291 0x18, 0x00,
292 0x19, 0x00,
293 0x1a, 0x00,
294 0x1f, 0x50,
295 0x20, 0x00,
296 0x21, 0x00,
297 0x22, 0x00,
298 0x23, 0x00,
299 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
300 0x29, 0x1e, // 1/2 threshold
301 0x2a, 0x14, // 2/3 threshold
302 0x2b, 0x0f, // 3/4 threshold
303 0x2c, 0x09, // 5/6 threshold
304 0x2d, 0x05, // 7/8 threshold
305 0x2e, 0x01,
306 0x31, 0x1f, // test all FECs
307 0x32, 0x19, // viterbi and synchro search
308 0x33, 0xfc, // rs control
309 0x34, 0x93, // error control
310 0x0f, 0x52,
311 0xff, 0xff
312};
313
314static int alps_bsru6_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
315{
316 u8 aclk = 0;
317 u8 bclk = 0;
318
319 if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
320 else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
321 else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
322 else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
323 else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
324 else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
325
326 stv0299_writereg (fe, 0x13, aclk);
327 stv0299_writereg (fe, 0x14, bclk);
328 stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
329 stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
330 stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
331
332 return 0;
333}
334
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700335static int alps_bsru6_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 u8 data[4];
338 u32 div;
339 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
340
341 if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL;
342
343 div = (params->frequency + (125 - 1)) / 125; // round correctly
344 data[0] = (div >> 8) & 0x7f;
345 data[1] = div & 0xff;
346 data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
347 data[3] = 0xC4;
348
349 if (params->frequency > 1530000) data[3] = 0xc0;
350
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700351 if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 return 0;
353}
354
355static struct stv0299_config alps_bsru6_config = {
356
357 .demod_address = 0x68,
358 .inittab = alps_bsru6_inittab,
359 .mclk = 88000000UL,
360 .invert = 1,
361 .enhanced_tuning = 0,
362 .skip_reinit = 0,
363 .lock_output = STV0229_LOCKOUTPUT_1,
364 .volt13_op0_op1 = STV0299_VOLT13_OP1,
365 .min_delay_ms = 100,
366 .set_symbol_rate = alps_bsru6_set_symbol_rate,
367 .pll_set = alps_bsru6_pll_set,
368};
369
370static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
371{
372 struct budget* budget = (struct budget*) fe->dvb->priv;
373 u32 div;
374 u8 data[4];
375 struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
376
377 div = (params->frequency + 35937500 + 31250) / 62500;
378
379 data[0] = (div >> 8) & 0x7f;
380 data[1] = div & 0xff;
381 data[2] = 0x85 | ((div >> 10) & 0x60);
382 data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
383
384 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
385 return 0;
386}
387
388static struct ves1820_config alps_tdbe2_config = {
389 .demod_address = 0x09,
390 .xin = 57840000UL,
391 .invert = 1,
392 .selagc = VES1820_SELAGC_SIGNAMPERR,
393 .pll_set = alps_tdbe2_pll_set,
394};
395
396static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
397{
398 struct budget* budget = (struct budget*) fe->dvb->priv;
399 u32 div;
400 u8 cfg, cpump, band_select;
401 u8 data[4];
402 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
403
404 div = (36125000 + params->frequency) / 166666;
405
406 cfg = 0x88;
407
408 if (params->frequency < 175000000) cpump = 2;
409 else if (params->frequency < 390000000) cpump = 1;
410 else if (params->frequency < 470000000) cpump = 2;
411 else if (params->frequency < 750000000) cpump = 1;
412 else cpump = 3;
413
414 if (params->frequency < 175000000) band_select = 0x0e;
415 else if (params->frequency < 470000000) band_select = 0x05;
416 else band_select = 0x03;
417
418 data[0] = (div >> 8) & 0x7f;
419 data[1] = div & 0xff;
420 data[2] = ((div >> 10) & 0x60) | cfg;
421 data[3] = (cpump << 6) | band_select;
422
423 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
424 return 0;
425}
426
427static struct l64781_config grundig_29504_401_config = {
428 .demod_address = 0x55,
429 .pll_set = grundig_29504_401_pll_set,
430};
431
432static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
433{
434 struct budget* budget = (struct budget*) fe->dvb->priv;
435 u32 div;
436 u8 data[4];
437 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
438
439 div = params->frequency / 125;
440 data[0] = (div >> 8) & 0x7f;
441 data[1] = div & 0xff;
442 data[2] = 0x8e;
443 data[3] = 0x00;
444
445 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
446 return 0;
447}
448
449static struct tda8083_config grundig_29504_451_config = {
450 .demod_address = 0x68,
451 .pll_set = grundig_29504_451_pll_set,
452};
453
Andrew de Quincey96bf2f22005-07-07 17:57:53 -0700454static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
455{
456 struct budget* budget = (struct budget*) fe->dvb->priv;
457 u32 div;
458 u8 data[4];
459 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
460
461 div = params->frequency / 1000;
462 data[0] = (div >> 8) & 0x7f;
463 data[1] = div & 0xff;
464 data[2] = 0xc2;
465
466 if (div < 1450)
467 data[3] = 0x00;
468 else if (div < 1850)
469 data[3] = 0x40;
470 else if (div < 2000)
471 data[3] = 0x80;
472 else
473 data[3] = 0xc0;
474
475 if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
476
477 *freqout = div * 1000;
478 return 0;
479}
480
481static struct s5h1420_config s5h1420_config = {
482 .demod_address = 0x53,
483 .pll_set = s5h1420_pll_set,
484};
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486static u8 read_pwm(struct budget* budget)
487{
488 u8 b = 0xff;
489 u8 pwm;
490 struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
491 { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
492
493 if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
494 pwm = 0x48;
495
496 return pwm;
497}
498
499static void frontend_init(struct budget *budget)
500{
501 switch(budget->dev->pci->subsystem_device) {
502 case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
503 case 0x1013:
504 // try the ALPS BSRV2 first of all
505 budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
506 if (budget->dvb_frontend) {
507 budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
508 budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
509 budget->dvb_frontend->ops->set_tone = budget_set_tone;
510 break;
511 }
512
513 // try the ALPS BSRU6 now
514 budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
515 if (budget->dvb_frontend) {
516 budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
517 budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
518 budget->dvb_frontend->ops->set_tone = budget_set_tone;
519 break;
520 }
521 break;
522
523 case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
524
525 budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
526 if (budget->dvb_frontend) break;
527 break;
528
529 case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
530
531 budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
532 if (budget->dvb_frontend) break;
533 break;
534
535 case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
536 budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
537 if (budget->dvb_frontend) {
538 budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
539 break;
540 }
541 break;
542
543 case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
544 budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
545 if (budget->dvb_frontend) {
546 budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
547 break;
548 }
549 break;
Andrew de Quincey96bf2f22005-07-07 17:57:53 -0700550
551 case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
552 budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
553 if (budget->dvb_frontend) {
554 budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
555 budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
556 lnbp21_init(budget);
557 break;
558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
560
561 if (budget->dvb_frontend == NULL) {
562 printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
563 budget->dev->pci->vendor,
564 budget->dev->pci->device,
565 budget->dev->pci->subsystem_vendor,
566 budget->dev->pci->subsystem_device);
567 } else {
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700568 if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 printk("budget: Frontend registration failed!\n");
570 if (budget->dvb_frontend->ops->release)
571 budget->dvb_frontend->ops->release(budget->dvb_frontend);
572 budget->dvb_frontend = NULL;
573 }
574 }
575}
576
577static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
578{
579 struct budget *budget = NULL;
580 int err;
581
582 budget = kmalloc(sizeof(struct budget), GFP_KERNEL);
583 if( NULL == budget ) {
584 return -ENOMEM;
585 }
586
587 dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);
588
589 dev->ext_priv = budget;
590
591 if ((err = ttpci_budget_init (budget, dev, info, THIS_MODULE))) {
592 printk("==> failed\n");
593 kfree (budget);
594 return err;
595 }
596
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700597 budget->dvb_adapter.priv = budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 frontend_init(budget);
599
600 return 0;
601}
602
603static int budget_detach (struct saa7146_dev* dev)
604{
605 struct budget *budget = (struct budget*) dev->ext_priv;
606 int err;
607
608 if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
609
610 err = ttpci_budget_deinit (budget);
611
612 kfree (budget);
613 dev->ext_priv = NULL;
614
615 return err;
616}
617
618static struct saa7146_extension budget_extension;
619
620MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
621MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
622MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
623MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
624MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
625MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
626
627static struct pci_device_id pci_tbl[] = {
628 MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),
629 MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
630 MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
631 MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
Andrew de Quincey96bf2f22005-07-07 17:57:53 -0700632 MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
634 MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
635 {
636 .vendor = 0,
637 }
638};
639
640MODULE_DEVICE_TABLE(pci, pci_tbl);
641
642static struct saa7146_extension budget_extension = {
643 .name = "budget dvb\0",
644 .flags = 0,
645
646 .module = THIS_MODULE,
647 .pci_tbl = pci_tbl,
648 .attach = budget_attach,
649 .detach = budget_detach,
650
651 .irq_mask = MASK_10,
652 .irq_func = ttpci_budget_irq10_handler,
653};
654
655static int __init budget_init(void)
656{
657 return saa7146_register_extension(&budget_extension);
658}
659
660static void __exit budget_exit(void)
661{
662 saa7146_unregister_extension(&budget_extension);
663}
664
665module_init(budget_init);
666module_exit(budget_exit);
667
668MODULE_LICENSE("GPL");
669MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
670MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
671 "budget PCI DVB cards by Siemens, Technotrend, Hauppauge");