Path: blob/master/drivers/media/dvb/ttpci/budget.c
15112 views
/*1* budget.c: driver for the SAA7146 based Budget DVB cards2*3* Compiled from various sources by Michael Hunold <[email protected]>4*5* Copyright (C) 2002 Ralph Metzler <[email protected]>6*7* Copyright (C) 1999-2002 Ralph Metzler8* & Marcus Metzler for convergence integrated media GmbH9*10* 26feb2004 Support for FS Activy Card (Grundig tuner) by11* Michael Dreher <[email protected]>,12* Oliver Endriss <[email protected]> and13* Andreas 'randy' Weinberger14*15* This program is free software; you can redistribute it and/or16* modify it under the terms of the GNU General Public License17* as published by the Free Software Foundation; either version 218* of the License, or (at your option) any later version.19*20*21* This program is distributed in the hope that it will be useful,22* but WITHOUT ANY WARRANTY; without even the implied warranty of23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the24* GNU General Public License for more details.25*26*27* You should have received a copy of the GNU General Public License28* along with this program; if not, write to the Free Software29* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.30* Or, point your browser to http://www.gnu.org/copyleft/gpl.html31*32*33* the project's page is at http://www.linuxtv.org/34*/3536#include "budget.h"37#include "stv0299.h"38#include "ves1x93.h"39#include "ves1820.h"40#include "l64781.h"41#include "tda8083.h"42#include "s5h1420.h"43#include "tda10086.h"44#include "tda826x.h"45#include "lnbp21.h"46#include "bsru6.h"47#include "bsbe1.h"48#include "tdhd1.h"49#include "stv6110x.h"50#include "stv090x.h"51#include "isl6423.h"5253static int diseqc_method;54module_param(diseqc_method, int, 0444);55MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");5657DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);5859static void Set22K (struct budget *budget, int state)60{61struct saa7146_dev *dev=budget->dev;62dprintk(2, "budget: %p\n", budget);63saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));64}6566/* Diseqc functions only for TT Budget card */67/* taken from the Skyvision DVB driver by68Ralph Metzler <[email protected]> */6970static void DiseqcSendBit (struct budget *budget, int data)71{72struct saa7146_dev *dev=budget->dev;73dprintk(2, "budget: %p\n", budget);7475saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);76udelay(data ? 500 : 1000);77saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);78udelay(data ? 1000 : 500);79}8081static void DiseqcSendByte (struct budget *budget, int data)82{83int i, par=1, d;8485dprintk(2, "budget: %p\n", budget);8687for (i=7; i>=0; i--) {88d = (data>>i)&1;89par ^= d;90DiseqcSendBit(budget, d);91}9293DiseqcSendBit(budget, par);94}9596static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)97{98struct saa7146_dev *dev=budget->dev;99int i;100101dprintk(2, "budget: %p\n", budget);102103saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);104mdelay(16);105106for (i=0; i<len; i++)107DiseqcSendByte(budget, msg[i]);108109mdelay(16);110111if (burst!=-1) {112if (burst)113DiseqcSendByte(budget, 0xff);114else {115saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);116mdelay(12);117udelay(500);118saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);119}120msleep(20);121}122123return 0;124}125126/*127* Routines for the Fujitsu Siemens Activy budget card128* 22 kHz tone and DiSEqC are handled by the frontend.129* Voltage must be set here.130* GPIO 1: LNBP EN, GPIO 2: LNBP VSEL131*/132static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage)133{134struct saa7146_dev *dev=budget->dev;135136dprintk(2, "budget: %p\n", budget);137138switch (voltage) {139case SEC_VOLTAGE_13:140saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);141saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);142break;143case SEC_VOLTAGE_18:144saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);145saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);146break;147case SEC_VOLTAGE_OFF:148saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);149break;150default:151return -EINVAL;152}153154return 0;155}156157static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)158{159struct budget* budget = (struct budget*) fe->dvb->priv;160161return SetVoltage_Activy (budget, voltage);162}163164static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)165{166struct budget* budget = (struct budget*) fe->dvb->priv;167168switch (tone) {169case SEC_TONE_ON:170Set22K (budget, 1);171break;172173case SEC_TONE_OFF:174Set22K (budget, 0);175break;176177default:178return -EINVAL;179}180181return 0;182}183184static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)185{186struct budget* budget = (struct budget*) fe->dvb->priv;187188SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);189190return 0;191}192193static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)194{195struct budget* budget = (struct budget*) fe->dvb->priv;196197SendDiSEqCMsg (budget, 0, NULL, minicmd);198199return 0;200}201202static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)203{204struct budget* budget = (struct budget*) fe->dvb->priv;205u8 pwr = 0;206u8 buf[4];207struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };208u32 div = (params->frequency + 479500) / 125;209210if (params->frequency > 2000000) pwr = 3;211else if (params->frequency > 1800000) pwr = 2;212else if (params->frequency > 1600000) pwr = 1;213else if (params->frequency > 1200000) pwr = 0;214else if (params->frequency >= 1100000) pwr = 1;215else pwr = 2;216217buf[0] = (div >> 8) & 0x7f;218buf[1] = div & 0xff;219buf[2] = ((div & 0x18000) >> 10) | 0x95;220buf[3] = (pwr << 6) | 0x30;221222// NOTE: since we're using a prescaler of 2, we set the223// divisor frequency to 62.5kHz and divide by 125 above224225if (fe->ops.i2c_gate_ctrl)226fe->ops.i2c_gate_ctrl(fe, 1);227if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;228return 0;229}230231static struct ves1x93_config alps_bsrv2_config =232{233.demod_address = 0x08,234.xin = 90100000UL,235.invert_pwm = 0,236};237238static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)239{240struct budget* budget = (struct budget*) fe->dvb->priv;241u32 div;242u8 data[4];243struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };244245div = (params->frequency + 35937500 + 31250) / 62500;246247data[0] = (div >> 8) & 0x7f;248data[1] = div & 0xff;249data[2] = 0x85 | ((div >> 10) & 0x60);250data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);251252if (fe->ops.i2c_gate_ctrl)253fe->ops.i2c_gate_ctrl(fe, 1);254if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;255return 0;256}257258static struct ves1820_config alps_tdbe2_config = {259.demod_address = 0x09,260.xin = 57840000UL,261.invert = 1,262.selagc = VES1820_SELAGC_SIGNAMPERR,263};264265static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)266{267struct budget *budget = fe->dvb->priv;268u8 *tuner_addr = fe->tuner_priv;269u32 div;270u8 cfg, cpump, band_select;271u8 data[4];272struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };273274if (tuner_addr)275msg.addr = *tuner_addr;276else277msg.addr = 0x61;278279div = (36125000 + params->frequency) / 166666;280281cfg = 0x88;282283if (params->frequency < 175000000) cpump = 2;284else if (params->frequency < 390000000) cpump = 1;285else if (params->frequency < 470000000) cpump = 2;286else if (params->frequency < 750000000) cpump = 1;287else cpump = 3;288289if (params->frequency < 175000000) band_select = 0x0e;290else if (params->frequency < 470000000) band_select = 0x05;291else band_select = 0x03;292293data[0] = (div >> 8) & 0x7f;294data[1] = div & 0xff;295data[2] = ((div >> 10) & 0x60) | cfg;296data[3] = (cpump << 6) | band_select;297298if (fe->ops.i2c_gate_ctrl)299fe->ops.i2c_gate_ctrl(fe, 1);300if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;301return 0;302}303304static struct l64781_config grundig_29504_401_config = {305.demod_address = 0x55,306};307308static struct l64781_config grundig_29504_401_config_activy = {309.demod_address = 0x54,310};311312static u8 tuner_address_grundig_29504_401_activy = 0x60;313314static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)315{316struct budget* budget = (struct budget*) fe->dvb->priv;317u32 div;318u8 data[4];319struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };320321div = params->frequency / 125;322data[0] = (div >> 8) & 0x7f;323data[1] = div & 0xff;324data[2] = 0x8e;325data[3] = 0x00;326327if (fe->ops.i2c_gate_ctrl)328fe->ops.i2c_gate_ctrl(fe, 1);329if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;330return 0;331}332333static struct tda8083_config grundig_29504_451_config = {334.demod_address = 0x68,335};336337static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)338{339struct budget* budget = (struct budget*) fe->dvb->priv;340u32 div;341u8 data[4];342struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };343344div = params->frequency / 1000;345data[0] = (div >> 8) & 0x7f;346data[1] = div & 0xff;347data[2] = 0xc2;348349if (div < 1450)350data[3] = 0x00;351else if (div < 1850)352data[3] = 0x40;353else if (div < 2000)354data[3] = 0x80;355else356data[3] = 0xc0;357358if (fe->ops.i2c_gate_ctrl)359fe->ops.i2c_gate_ctrl(fe, 1);360if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;361362return 0;363}364365static struct s5h1420_config s5h1420_config = {366.demod_address = 0x53,367.invert = 1,368.cdclk_polarity = 1,369};370371static struct tda10086_config tda10086_config = {372.demod_address = 0x0e,373.invert = 0,374.diseqc_tone = 1,375.xtal_freq = TDA10086_XTAL_16M,376};377378static struct stv0299_config alps_bsru6_config_activy = {379.demod_address = 0x68,380.inittab = alps_bsru6_inittab,381.mclk = 88000000UL,382.invert = 1,383.op0_off = 1,384.min_delay_ms = 100,385.set_symbol_rate = alps_bsru6_set_symbol_rate,386};387388static struct stv0299_config alps_bsbe1_config_activy = {389.demod_address = 0x68,390.inittab = alps_bsbe1_inittab,391.mclk = 88000000UL,392.invert = 1,393.op0_off = 1,394.min_delay_ms = 100,395.set_symbol_rate = alps_bsbe1_set_symbol_rate,396};397398static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)399{400struct budget *budget = (struct budget *)fe->dvb->priv;401402return request_firmware(fw, name, &budget->dev->pci->dev);403}404405406static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)407{408u8 val;409struct i2c_msg msg[] = {410{ .addr = adr, .flags = 0, .buf = ®, .len = 1 },411{ .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }412};413414return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;415}416417static u8 read_pwm(struct budget* budget)418{419u8 b = 0xff;420u8 pwm;421struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },422{ .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };423424if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))425pwm = 0x48;426427return pwm;428}429430static struct stv090x_config tt1600_stv090x_config = {431.device = STV0903,432.demod_mode = STV090x_SINGLE,433.clk_mode = STV090x_CLK_EXT,434435.xtal = 13500000,436.address = 0x68,437438.ts1_mode = STV090x_TSMODE_DVBCI,439.ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS,440441.repeater_level = STV090x_RPTLEVEL_16,442443.tuner_init = NULL,444.tuner_sleep = NULL,445.tuner_set_mode = NULL,446.tuner_set_frequency = NULL,447.tuner_get_frequency = NULL,448.tuner_set_bandwidth = NULL,449.tuner_get_bandwidth = NULL,450.tuner_set_bbgain = NULL,451.tuner_get_bbgain = NULL,452.tuner_set_refclk = NULL,453.tuner_get_status = NULL,454};455456static struct stv6110x_config tt1600_stv6110x_config = {457.addr = 0x60,458.refclk = 27000000,459.clk_div = 2,460};461462static struct isl6423_config tt1600_isl6423_config = {463.current_max = SEC_CURRENT_515m,464.curlim = SEC_CURRENT_LIM_ON,465.mod_extern = 1,466.addr = 0x08,467};468469static void frontend_init(struct budget *budget)470{471(void)alps_bsbe1_config; /* avoid warning */472473switch(budget->dev->pci->subsystem_device) {474case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))475case 0x1013:476// try the ALPS BSRV2 first of all477budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);478if (budget->dvb_frontend) {479budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;480budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;481budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;482budget->dvb_frontend->ops.set_tone = budget_set_tone;483break;484}485486// try the ALPS BSRU6 now487budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);488if (budget->dvb_frontend) {489budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;490budget->dvb_frontend->tuner_priv = &budget->i2c_adap;491if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) {492budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;493budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;494budget->dvb_frontend->ops.set_tone = budget_set_tone;495}496break;497}498break;499500case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))501502budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));503if (budget->dvb_frontend) {504budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;505break;506}507break;508509case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))510511budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);512if (budget->dvb_frontend) {513budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;514budget->dvb_frontend->tuner_priv = NULL;515break;516}517break;518519case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */520{521int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);522523if (subtype < 0)524break;525/* fixme: find a better way to identify the card */526if (subtype < 0x36) {527/* assume ALPS BSRU6 */528budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);529if (budget->dvb_frontend) {530printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n");531budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;532budget->dvb_frontend->tuner_priv = &budget->i2c_adap;533budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;534budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;535break;536}537} else {538/* assume ALPS BSBE1 */539/* reset tuner */540saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);541msleep(50);542saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);543msleep(250);544budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);545if (budget->dvb_frontend) {546printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n");547budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;548budget->dvb_frontend->tuner_priv = &budget->i2c_adap;549budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;550budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;551break;552}553}554break;555}556557case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))558budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);559if (budget->dvb_frontend) {560budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;561budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;562budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;563}564break;565566case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */567budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);568if (budget->dvb_frontend) {569budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;570budget->dvb_frontend->tuner_priv = &budget->i2c_adap;571}572break;573574case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */575budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);576if (budget->dvb_frontend) {577budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;578budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;579}580break;581582case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))583budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);584if (budget->dvb_frontend) {585budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;586if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {587printk("%s: No LNBP21 found!\n", __func__);588goto error_out;589}590break;591}592593case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)594// gpio2 is connected to CLB - reset it + leave it high595saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);596msleep(1);597saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);598msleep(1);599600budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);601if (budget->dvb_frontend) {602if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)603printk("%s: No tda826x found!\n", __func__);604if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {605printk("%s: No LNBP21 found!\n", __func__);606goto error_out;607}608break;609}610611case 0x101c: { /* TT S2-1600 */612struct stv6110x_devctl *ctl;613saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);614msleep(50);615saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);616msleep(250);617618budget->dvb_frontend = dvb_attach(stv090x_attach,619&tt1600_stv090x_config,620&budget->i2c_adap,621STV090x_DEMODULATOR_0);622623if (budget->dvb_frontend) {624625ctl = dvb_attach(stv6110x_attach,626budget->dvb_frontend,627&tt1600_stv6110x_config,628&budget->i2c_adap);629630if (ctl) {631tt1600_stv090x_config.tuner_init = ctl->tuner_init;632tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep;633tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode;634tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;635tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;636tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;637tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;638tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain;639tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain;640tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk;641tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status;642643/* call the init function once to initialize644tuner's clock output divider and demod's645master clock */646if (budget->dvb_frontend->ops.init)647budget->dvb_frontend->ops.init(budget->dvb_frontend);648649if (dvb_attach(isl6423_attach,650budget->dvb_frontend,651&budget->i2c_adap,652&tt1600_isl6423_config) == NULL) {653printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__);654goto error_out;655}656} else {657printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);658goto error_out;659}660}661}662break;663}664665if (budget->dvb_frontend == NULL) {666printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",667budget->dev->pci->vendor,668budget->dev->pci->device,669budget->dev->pci->subsystem_vendor,670budget->dev->pci->subsystem_device);671} else {672if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))673goto error_out;674}675return;676677error_out:678printk("budget: Frontend registration failed!\n");679dvb_frontend_detach(budget->dvb_frontend);680budget->dvb_frontend = NULL;681return;682}683684static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)685{686struct budget *budget = NULL;687int err;688689budget = kmalloc(sizeof(struct budget), GFP_KERNEL);690if( NULL == budget ) {691return -ENOMEM;692}693694dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);695696dev->ext_priv = budget;697698err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);699if (err) {700printk("==> failed\n");701kfree (budget);702return err;703}704705budget->dvb_adapter.priv = budget;706frontend_init(budget);707708ttpci_budget_init_hooks(budget);709710return 0;711}712713static int budget_detach (struct saa7146_dev* dev)714{715struct budget *budget = (struct budget*) dev->ext_priv;716int err;717718if (budget->dvb_frontend) {719dvb_unregister_frontend(budget->dvb_frontend);720dvb_frontend_detach(budget->dvb_frontend);721}722723err = ttpci_budget_deinit (budget);724725kfree (budget);726dev->ext_priv = NULL;727728return err;729}730731static struct saa7146_extension budget_extension;732733MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);734MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);735MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);736MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);737MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);738MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);739MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);740MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);741MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);742MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);743744static struct pci_device_id pci_tbl[] = {745MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003),746MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),747MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),748MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),749MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),750MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),751MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),752MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),753MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),754MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),755MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),756{757.vendor = 0,758}759};760761MODULE_DEVICE_TABLE(pci, pci_tbl);762763static struct saa7146_extension budget_extension = {764.name = "budget dvb",765.flags = SAA7146_USE_I2C_IRQ,766767.module = THIS_MODULE,768.pci_tbl = pci_tbl,769.attach = budget_attach,770.detach = budget_detach,771772.irq_mask = MASK_10,773.irq_func = ttpci_budget_irq10_handler,774};775776static int __init budget_init(void)777{778return saa7146_register_extension(&budget_extension);779}780781static void __exit budget_exit(void)782{783saa7146_unregister_extension(&budget_extension);784}785786module_init(budget_init);787module_exit(budget_exit);788789MODULE_LICENSE("GPL");790MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");791MODULE_DESCRIPTION("driver for the SAA7146 based so-called "792"budget PCI DVB cards by Siemens, Technotrend, Hauppauge");793794795